Example #1
0
def view(click_config, config_file):
    """
    View existing Alice's configuration.
    """
    emitter = _setup_emitter(click_config)

    configuration_file_location = config_file or AliceConfiguration.default_filepath()
    response = AliceConfiguration._read_configuration_file(filepath=configuration_file_location)
    return emitter.ipc(response=response, request_id=0, duration=0)  # FIXME: what are request_id and duration here?
Example #2
0
def view(general_config, config_file):
    """
    View existing Alice's configuration.
    """
    emitter = _setup_emitter(general_config)
    configuration_file_location = config_file or AliceConfiguration.default_filepath()
    response = AliceConfiguration._read_configuration_file(filepath=configuration_file_location)
    emitter.echo(f"Alice Configuration {configuration_file_location} \n {'='*55}")
    return emitter.echo(json.dumps(response, indent=4))
Example #3
0
def alice(
    click_config,
    action,

    # Mode
    dev,
    force,
    dry_run,

    # Network
    teacher_uri,
    min_stake,
    federated_only,
    network,
    discovery_port,
    controller_port,

    # Filesystem
    config_root,
    config_file,

    # Blockchain
    pay_with,
    provider_uri,
    geth,
    sync,
    poa,
    registry_filepath,
    hw_wallet,

    # Alice
    bob_encrypting_key,
    bob_verifying_key,
    label,
    m,
    n,
    value,
    rate,
    duration_periods,
    expiration,
    message_kit,
):
    """
    "Alice the Policy Authority" management commands.

    \b
    Actions
    -------------------------------------------------
    \b
    init                  Create a brand new persistent Alice
    view                  View existing Alice's configuration.
    run                   Start Alice's controller.
    destroy               Delete existing Alice's configuration.
    public-keys           Obtain Alice's public verification and encryption keys.
    derive-policy-pubkey  Get a policy public key from a policy label.
    grant                 Create and enact an access policy for some Bob.
    revoke                Revoke a policy.
    decrypt               Decrypt data encrypted under an Alice's policy public key.

    """

    #
    # Validate
    #

    if federated_only and geth:
        raise click.BadOptionUsage(
            option_name="--geth",
            message="Federated only cannot be used with the --geth flag")

    # Banner
    emitter = click_config.emitter
    emitter.clear()
    emitter.banner(ALICE_BANNER)

    #
    # Managed Ethereum Client
    #

    ETH_NODE = NO_BLOCKCHAIN_CONNECTION
    if geth:
        ETH_NODE = actions.get_provider_process()
        provider_uri = ETH_NODE.provider_uri(scheme='file')

    #
    # Eager Actions (No Authentication Required)
    #

    if action == 'init':
        """Create a brand-new persistent Alice"""

        if dev:
            raise click.BadArgumentUsage(
                "Cannot create a persistent development character")

        if not provider_uri and not federated_only:
            raise click.BadOptionUsage(
                option_name='--provider',
                message=
                "--provider is required to create a new decentralized alice.")

        if not config_root:  # Flag
            config_root = click_config.config_file  # Envvar

        if not pay_with and not federated_only:
            pay_with = select_client_account(emitter=emitter,
                                             provider_uri=provider_uri)

        new_alice_config = AliceConfiguration.generate(
            password=get_nucypher_password(confirm=True),
            config_root=config_root,
            checksum_address=pay_with,
            domains={network} if network else None,
            federated_only=federated_only,
            registry_filepath=registry_filepath,
            provider_process=ETH_NODE,
            poa=poa,
            provider_uri=provider_uri,
            m=m,
            n=n,
            duration_periods=duration_periods,
            rate=rate)

        painting.paint_new_installation_help(
            emitter, new_configuration=new_alice_config)
        return  # Exit

    elif action == "view":
        """Paint an existing configuration to the console"""
        configuration_file_location = config_file or AliceConfiguration.default_filepath(
        )
        response = AliceConfiguration._read_configuration_file(
            filepath=configuration_file_location)
        return emitter.ipc(
            response=response, request_id=0,
            duration=0)  # FIXME: what are request_id and duration here?

    #
    # Get Alice Configuration
    #

    if dev:
        alice_config = AliceConfiguration(
            dev_mode=True,
            network_middleware=click_config.middleware,
            domains={network},
            provider_process=ETH_NODE,
            provider_uri=provider_uri,
            federated_only=True)

    else:
        try:
            alice_config = AliceConfiguration.from_configuration_file(
                dev_mode=False,
                filepath=config_file,
                domains={network} if network else None,
                network_middleware=click_config.middleware,
                rest_port=discovery_port,
                checksum_address=pay_with,
                provider_process=ETH_NODE,
                provider_uri=provider_uri,
                registry_filepath=registry_filepath)
        except FileNotFoundError:
            return actions.handle_missing_configuration_file(
                character_config_class=AliceConfiguration,
                config_file=config_file)

    if action == "destroy":
        """Delete all configuration files from the disk"""
        if dev:
            message = "'nucypher alice destroy' cannot be used in --dev mode"
            raise click.BadOptionUsage(option_name='--dev', message=message)
        return actions.destroy_configuration(emitter,
                                             character_config=alice_config,
                                             force=force)

    #
    # Produce Alice
    #

    # TODO: OH MY.
    client_password = None
    if not alice_config.federated_only:
        if (not hw_wallet or not dev) and not click_config.json_ipc:
            client_password = get_client_password(
                checksum_address=alice_config.checksum_address)

    try:
        ALICE = actions.make_cli_character(character_config=alice_config,
                                           click_config=click_config,
                                           dev=dev,
                                           teacher_uri=teacher_uri,
                                           min_stake=min_stake,
                                           client_password=client_password)
    except NucypherKeyring.AuthenticationFailed as e:
        emitter.echo(str(e), color='red', bold=True)
        click.get_current_context().exit(1)
        # TODO: Exit codes (not only for this, but for other exceptions)

    #
    # Admin Actions
    #

    if action == "run":
        """Start Alice Controller"""

        try:

            # RPC
            if click_config.json_ipc:
                rpc_controller = ALICE.make_rpc_controller()
                _transport = rpc_controller.make_control_transport()
                rpc_controller.start()
                return

            # HTTP
            else:
                emitter.message(
                    f"Alice Verifying Key {bytes(ALICE.stamp).hex()}",
                    color="green",
                    bold=True)
                controller = ALICE.make_web_controller(
                    crash_on_error=click_config.debug)
                ALICE.log.info('Starting HTTP Character Web Controller')
                emitter.message(
                    f'Running HTTP Alice Controller at http://localhost:{controller_port}'
                )
                return controller.start(http_port=controller_port,
                                        dry_run=dry_run)

        # Handle Crash
        except Exception as e:
            alice_config.log.critical(str(e))
            emitter.message(f"{e.__class__.__name__} {e}",
                            color='red',
                            bold=True)
            if click_config.debug:
                raise  # Crash :-(
            return

    #
    # Alice API
    #

    elif action == "public-keys":
        response = ALICE.controller.public_keys()
        return response

    elif action == "derive-policy-pubkey":

        # Validate
        if not label:
            raise click.BadOptionUsage(
                option_name='label',
                message=
                "--label is required for deriving a policy encrypting key.")

        # Request
        return ALICE.controller.derive_policy_encrypting_key(label=label)

    elif action == "grant":

        # Validate
        if not all((bob_verifying_key, bob_encrypting_key, label)):
            raise click.BadArgumentUsage(
                message=
                "--bob-verifying-key, --bob-encrypting-key, and --label are "
                "required options to grant (optionally --m, --n, and --expiration)."
            )

        # Request
        grant_request = {
            'bob_encrypting_key': bob_encrypting_key,
            'bob_verifying_key': bob_verifying_key,
            'label': label,
            'm': m,
            'n': n,
            'expiration': expiration,
        }

        if not ALICE.federated_only:
            grant_request.update({'value': value})
        return ALICE.controller.grant(request=grant_request)

    elif action == "revoke":

        # Validate
        if not label and bob_verifying_key:
            raise click.BadArgumentUsage(
                message=
                f"--label and --bob-verifying-key are required options for revoke."
            )

        # Request
        revoke_request = {
            'label': label,
            'bob_verifying_key': bob_verifying_key
        }
        return ALICE.controller.revoke(request=revoke_request)

    elif action == "decrypt":

        # Validate
        if not all((label, message_kit)):
            input_specification, output_specification = ALICE.controller.get_specifications(
                interface_name=action)
            required_fields = ', '.join(input_specification)
            raise click.BadArgumentUsage(
                f'{required_fields} are required flags to decrypt')

        # Request
        request_data = {'label': label, 'message_kit': message_kit}
        response = ALICE.controller.decrypt(request=request_data)
        return response

    else:
        raise click.BadArgumentUsage(f"No such argument {action}")
Example #4
0
def alice(
        click_config,
        action,

        # Mode
        dev,
        force,
        dry_run,

        # Network
        teacher_uri,
        min_stake,
        federated_only,
        network,
        discovery_port,
        controller_port,

        # Filesystem
        config_root,
        config_file,

        # Blockchain
        pay_with,
        provider_uri,
        geth,
        sync,
        poa,
        no_registry,
        registry_filepath,

        # Alice
        bob_encrypting_key,
        bob_verifying_key,
        label,
        m,
        n,
        value,
        rate,
        duration,
        expiration,
        message_kit):

    #
    # Validate
    #

    if federated_only and geth:
        raise click.BadOptionUsage(
            option_name="--geth",
            message="Federated only cannot be used with the --geth flag")

    # Banner
    click.clear()
    if not click_config.json_ipc and not click_config.quiet:
        click.secho(ALICE_BANNER)

    #
    # Managed Ethereum Client
    #

    ETH_NODE = NO_BLOCKCHAIN_CONNECTION
    if geth:
        ETH_NODE = actions.get_provider_process()
        provider_uri = ETH_NODE.provider_uri(scheme='file')

    #
    # Eager Actions (No Authentication Required)
    #

    if action == 'init':
        """Create a brand-new persistent Alice"""

        if dev:
            raise click.BadArgumentUsage(
                "Cannot create a persistent development character")

        if not config_root:  # Flag
            config_root = click_config.config_file  # Envvar

        new_alice_config = AliceConfiguration.generate(
            password=click_config.get_password(confirm=True),
            config_root=config_root,
            checksum_address=pay_with,
            rest_host="localhost",
            domains={network} if network else None,
            federated_only=federated_only,
            download_registry=no_registry,
            registry_filepath=registry_filepath,
            provider_process=ETH_NODE,
            poa=poa,
            provider_uri=provider_uri,
            m=m,
            n=n,
            duration=duration,
            rate=rate)

        painting.paint_new_installation_help(
            new_configuration=new_alice_config,
            config_root=config_root,
            config_file=config_file)
        return  # Exit

    elif action == "view":
        """Paint an existing configuration to the console"""
        configuration_file_location = config_file or AliceConfiguration.DEFAULT_CONFIG_FILE_LOCATION
        response = AliceConfiguration._read_configuration_file(
            filepath=configuration_file_location)
        click_config.emit(response)
        return  # Exit

    #
    # Make Alice
    #

    if dev:
        alice_config = AliceConfiguration(
            dev_mode=True,
            network_middleware=click_config.middleware,
            domains={network},
            provider_process=ETH_NODE,
            provider_uri=provider_uri,
            federated_only=True)

    else:
        try:
            alice_config = AliceConfiguration.from_configuration_file(
                filepath=config_file,
                domains={network} if network else None,
                network_middleware=click_config.middleware,
                rest_port=discovery_port,
                checksum_address=pay_with,
                provider_process=ETH_NODE,
                provider_uri=provider_uri)
        except FileNotFoundError:
            return actions.handle_missing_configuration_file(
                character_config_class=AliceConfiguration,
                config_file=config_file)

    ALICE = actions.make_cli_character(character_config=alice_config,
                                       click_config=click_config,
                                       dev=dev,
                                       teacher_uri=teacher_uri,
                                       min_stake=min_stake,
                                       sync=sync)

    #
    # Admin Actions
    #

    if action == "run":
        """Start Alice Web Controller"""
        ALICE.controller.emitter(
            message=f"Alice Verifying Key {bytes(ALICE.stamp).hex()}",
            color="green",
            bold=True)
        controller = ALICE.make_web_controller(
            crash_on_error=click_config.debug)
        ALICE.log.info('Starting Alice Web Controller')
        return controller.start(http_port=controller_port
                                or alice_config.controller_port,
                                dry_run=dry_run)

    elif action == "destroy":
        """Delete all configuration files from the disk"""
        if dev:
            message = "'nucypher alice destroy' cannot be used in --dev mode"
            raise click.BadOptionUsage(option_name='--dev', message=message)
        return actions.destroy_configuration(character_config=alice_config,
                                             force=force)

    #
    # Alice API
    #

    elif action == "public-keys":
        response = ALICE.controller.public_keys()
        return response

    elif action == "derive-policy-pubkey":

        # Validate
        if not label:
            raise click.BadOptionUsage(
                option_name='label',
                message=
                "--label is required for deriving a policy encrypting key.")

        # Request
        return ALICE.controller.derive_policy_encrypting_key(label=label)

    elif action == "grant":

        # Validate
        if not all((bob_verifying_key, bob_encrypting_key, label)):
            raise click.BadArgumentUsage(
                message=
                "--bob-verifying-key, --bob-encrypting-key, and --label are "
                "required options to grant (optionally --m, --n, and --expiration)."
            )

        # Request
        grant_request = {
            'bob_encrypting_key': bob_encrypting_key,
            'bob_verifying_key': bob_verifying_key,
            'label': label,
            'm': m,
            'n': n,
            'expiration': expiration,
        }

        if not ALICE.federated_only:
            grant_request.update({'value': value})

        return ALICE.controller.grant(request=grant_request)

    elif action == "revoke":

        # Validate
        if not label and bob_verifying_key:
            raise click.BadArgumentUsage(
                message=
                f"--label and --bob-verifying-key are required options for revoke."
            )

        # Request
        revoke_request = {
            'label': label,
            'bob_verifying_key': bob_verifying_key
        }
        return ALICE.controller.revoke(request=revoke_request)

    elif action == "decrypt":

        # Validate
        if not all((label, message_kit)):
            input_specification, output_specification = ALICE.controller.get_specifications(
                interface_name=action)
            required_fields = ', '.join(input_specification)
            raise click.BadArgumentUsage(
                f'{required_fields} are required flags to decrypt')

        # Request
        request_data = {'label': label, 'message_kit': message_kit}
        response = ALICE.controller.decrypt(request=request_data)
        return response

    else:
        raise click.BadArgumentUsage(f"No such argument {action}")
Example #5
0
def alice(click_config, action, teacher_uri, min_stake, http_port,
          discovery_port, federated_only, network, config_root, config_file,
          provider_uri, no_registry, registry_filepath, dev, force, dry_run,
          bob_encrypting_key, bob_verifying_key, policy_encrypting_key, label,
          m, n):
    """
    Start and manage an "Alice" character.
    """

    if not click_config.json_ipc and not click_config.quiet:
        click.secho(ALICE_BANNER)

    if action == 'init':
        """Create a brand-new persistent Alice"""

        if not network:
            raise click.BadArgumentUsage(
                '--network is required to initialize a new configuration.')

        if dev:
            click_config.emitter(
                message="WARNING: Using temporary storage area",
                color='yellow')

        if not config_root:  # Flag
            config_root = click_config.config_file  # Envvar

        new_alice_config = AliceConfiguration.generate(
            password=click_config._get_password(confirm=True),
            config_root=config_root,
            rest_host="localhost",
            domains={network} if network else None,
            federated_only=federated_only,
            no_registry=no_registry,
            registry_filepath=registry_filepath,
            provider_uri=provider_uri)

        return painting.paint_new_installation_help(
            new_configuration=new_alice_config,
            config_root=config_root,
            config_file=config_file)

    elif action == "destroy":
        """Delete all configuration files from the disk"""
        if dev:
            message = "'nucypher ursula destroy' cannot be used in --dev mode"
            raise click.BadOptionUsage(option_name='--dev', message=message)

        destroyed_path = actions.destroy_system_configuration(
            config_class=AliceConfiguration,
            config_file=config_file,
            network=network,
            config_root=config_root,
            force=force)

        return nucypher_click_config.emitter(
            message=f"Destroyed {destroyed_path}", color='red')

    #
    # Get Alice Configuration
    #

    if dev:
        alice_config = AliceConfiguration(
            dev_mode=True,
            network_middleware=click_config.middleware,
            domains={network},
            provider_uri=provider_uri,
            federated_only=True)

    else:
        alice_config = AliceConfiguration.from_configuration_file(
            filepath=config_file,
            domains={network or GLOBAL_DOMAIN},
            network_middleware=click_config.middleware,
            rest_port=discovery_port,
            provider_uri=provider_uri)

    if not dev:
        click_config.unlock_keyring(character_configuration=alice_config)

    # Teacher Ursula
    teacher_uris = [teacher_uri] if teacher_uri else list()
    teacher_nodes = actions.load_seednodes(
        teacher_uris=teacher_uris,
        min_stake=min_stake,
        federated_only=federated_only,
        network_middleware=click_config.middleware)
    # Produce
    ALICE = alice_config(known_nodes=teacher_nodes,
                         network_middleware=click_config.middleware)

    # Switch to character control emitter
    if click_config.json_ipc:
        ALICE.controller.emitter = IPCStdoutEmitter(quiet=click_config.quiet)

    if action == "run":
        """Start Alice Web Controller"""
        ALICE.controller.emitter(
            message=f"Alice Verifying Key {bytes(ALICE.stamp).hex()}",
            color="green",
            bold=True)
        controller = ALICE.make_web_controller(
            crash_on_error=click_config.debug)
        ALICE.log.info('Starting HTTP Character Web Controller')
        return controller.start(http_port=http_port, dry_run=dry_run)

    elif action == "view":
        """Paint an existing configuration to the console"""
        configuration_file_location = config_file or alice_config.config_file_location
        response = AliceConfiguration._read_configuration_file(
            filepath=configuration_file_location)
        return ALICE.controller.emitter(
            response=response)  # TODO: Uses character control instead

    elif action == "public-keys":
        response = ALICE.controller.public_keys()
        return response

    elif action == "create-policy":
        if not all((bob_verifying_key, bob_encrypting_key, label)):
            raise click.BadArgumentUsage(
                message=
                "--bob-verifying-key, --bob-encrypting-key, and --label are "
                "required options to create a new policy.")

        create_policy_request = {
            'bob_encrypting_key': bob_encrypting_key,
            'bob_verifying_key': bob_verifying_key,
            'label': label,
            'm': m,
            'n': n,
        }

        return ALICE.controller.create_policy(request=create_policy_request)

    elif action == "derive-policy-pubkey":
        return ALICE.controller.derive_policy_encrypting_key(label=label)

    elif action == "grant":
        grant_request = {
            'bob_encrypting_key': bob_encrypting_key,
            'bob_verifying_key': bob_verifying_key,
            'label': label,
            'm': m,
            'n': n,
            'expiration':
            (maya.now() + datetime.timedelta(days=3)).iso8601(),  # TODO
        }

        return ALICE.controller.grant(request=grant_request)

    elif action == "revoke":
        return ALICE.controller.revoke(
            policy_encrypting_key=policy_encrypting_key)

    else:
        raise click.BadArgumentUsage(f"No such argument {action}")