async def _alice_nd_claim():
        async with apiv1_backend_anonymous_cmds_factory(alice.organization_addr) as cmds:
            ret = await cmds.device_get_invitation_creator(nd_id)
            assert ret["status"] == "ok"
            assert ret["trustchain"] == {"devices": [], "revoked_users": [], "users": []}
            creator = UserCertificateContent.unsecure_load(ret["user_certificate"])
            creator_device = DeviceCertificateContent.unsecure_load(ret["device_certificate"])
            assert creator_device.device_id.user_id == creator.user_id

            answer_private_key = PrivateKey.generate()
            encrypted_claim = APIV1_DeviceClaimContent(
                token=token,
                device_id=nd_id,
                verify_key=nd_signing_key.verify_key,
                answer_public_key=answer_private_key.public_key,
            ).dump_and_encrypt_for(recipient_pubkey=creator.public_key)
            with trio.fail_after(1):
                ret = await cmds.device_claim(nd_id, encrypted_claim)
                assert ret["status"] == "ok"

            assert ret["device_certificate"] == device_certificate
            answer = APIV1_DeviceClaimAnswerContent.decrypt_and_load_for(
                ret["encrypted_answer"], recipient_privkey=answer_private_key
            )
            assert answer == APIV1_DeviceClaimAnswerContent(
                private_key=alice.private_key,
                user_manifest_id=alice.user_manifest_id,
                user_manifest_key=alice.user_manifest_key,
            )
async def test_create_organization_same_name(
    gui,
    aqtbot,
    running_backend,
    catch_create_org_widget,
    autoclose_dialog,
    organization_bootstrap_addr,
):
    # Create an org
    human_handle = HumanHandle(email="*****@*****.**", label="Zack")

    async with apiv1_backend_anonymous_cmds_factory(
            addr=organization_bootstrap_addr) as cmds:
        await bootstrap_organization(cmds,
                                     human_handle=human_handle,
                                     device_label="PC1")

    # Now create an org with the same name
    await aqtbot.key_click(gui, "n", QtCore.Qt.ControlModifier, 200)

    co_w = await catch_create_org_widget()
    assert co_w

    await _do_creation_process(aqtbot, co_w)

    def _modal_shown():
        assert autoclose_dialog.dialogs == [
            ("Error", "This organization name is already used.")
        ]

    await aqtbot.wait_until(_modal_shown)
Example #3
0
async def test_handshake_unknown_organization(running_backend, coolorg):
    unknown_org_addr = BackendOrganizationAddr.build(
        backend_addr=coolorg.addr, organization_id="dummy", root_verify_key=coolorg.root_verify_key
    )
    with pytest.raises(BackendConnectionRefused) as exc:
        async with apiv1_backend_anonymous_cmds_factory(unknown_org_addr) as cmds:
            await cmds.ping()
    assert str(exc.value) == "Invalid handshake information"
async def test_handshake_organization_expired(running_backend, expiredorg):
    with running_backend.backend.event_bus.listen() as spy:
        with pytest.raises(BackendConnectionRefused) as exc:
            async with apiv1_backend_anonymous_cmds_factory(
                    expiredorg.addr) as cmds:
                await cmds.ping()
        await spy.wait_with_timeout(BackendEvent.ORGANIZATION_EXPIRED)
    assert str(exc.value) == "Trial organization has expired"
Example #5
0
async def test_handshake_rvk_mismatch(running_backend, coolorg, otherorg):
    bad_rvk_org_addr = BackendOrganizationAddr.build(
        backend_addr=coolorg.addr,
        organization_id=coolorg.organization_id,
        root_verify_key=otherorg.root_verify_key,
    )
    with pytest.raises(BackendConnectionRefused) as exc:
        async with apiv1_backend_anonymous_cmds_factory(bad_rvk_org_addr) as cmds:
            await cmds.ping()
    assert str(exc.value) == "Root verify key for organization differs between client and server"
async def test_good(
    running_backend, backend, alice, bob, alice_backend_cmds, user_fs_factory, with_labels
):
    org_id = OrganizationID("NewOrg")
    org_token = "123456"
    await backend.organization.create(org_id, org_token)

    organization_addr = BackendOrganizationBootstrapAddr.build(
        running_backend.addr, org_id, org_token
    )

    if with_labels:
        human_handle = HumanHandle(email="*****@*****.**", label="Zack")
        device_label = "PC1"
    else:
        human_handle = None
        device_label = None

    async with apiv1_backend_anonymous_cmds_factory(addr=organization_addr) as cmds:
        new_device = await bootstrap_organization(
            cmds, human_handle=human_handle, device_label=device_label
        )

    assert new_device is not None
    assert new_device.organization_id == org_id
    assert new_device.device_label == device_label
    assert new_device.human_handle == human_handle
    assert new_device.profile == UserProfile.ADMIN

    # Test the behavior of this new device
    async with user_fs_factory(new_device, initialize_in_v0=True) as newfs:
        await newfs.workspace_create("wa")
        await newfs.sync()

    # Test the device in correct in the backend
    backend_user, backend_device = await backend.user.get_user_with_device(
        org_id, new_device.device_id
    )
    assert backend_user.user_id == new_device.user_id
    assert backend_user.human_handle == new_device.human_handle
    assert backend_user.profile == new_device.profile
    assert backend_user.user_certifier is None
    if with_labels:
        assert backend_user.user_certificate != backend_user.redacted_user_certificate
    else:
        assert backend_user.user_certificate == backend_user.redacted_user_certificate

    assert backend_device.device_id == new_device.device_id
    assert backend_device.device_label == new_device.device_label
    assert backend_device.device_certifier is None
    if with_labels:
        assert backend_device.device_certificate != backend_device.redacted_device_certificate
    else:
        assert backend_device.device_certificate == backend_device.redacted_device_certificate
async def _bootstrap_organization(debug, device_id,
                                  organization_bootstrap_addr, config_dir,
                                  force, password):
    root_signing_key = SigningKey.generate()
    root_verify_key = root_signing_key.verify_key
    organization_addr = organization_bootstrap_addr.generate_organization_addr(
        root_verify_key)

    device_display = click.style(device_id, fg="yellow")
    device = generate_new_device(device_id,
                                 organization_addr,
                                 profile=UserProfile.ADMIN)

    with operation(f"Creating locally {device_display}"):
        save_device_with_password(config_dir, device, password, force=force)

    now = pendulum.now()
    user_certificate = UserCertificateContent(
        author=None,
        timestamp=now,
        user_id=device.user_id,
        public_key=device.public_key,
        profile=device.profile,
    )
    redacted_user_certificate = user_certificate.evolve(human_handle=None)
    device_certificate = DeviceCertificateContent(author=None,
                                                  timestamp=now,
                                                  device_id=device_id,
                                                  verify_key=device.verify_key)
    redacted_device_certificate = device_certificate.evolve(device_label=None)

    user_certificate = user_certificate.dump_and_sign(root_signing_key)
    device_certificate = device_certificate.dump_and_sign(root_signing_key)
    redacted_user_certificate = redacted_user_certificate.dump_and_sign(
        root_signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(
        root_signing_key)

    async with spinner(f"Sending {device_display} to server"):
        async with apiv1_backend_anonymous_cmds_factory(
                organization_bootstrap_addr) as cmds:
            await cmds.organization_bootstrap(
                organization_id=organization_bootstrap_addr.organization_id,
                bootstrap_token=organization_bootstrap_addr.token,
                root_verify_key=root_verify_key,
                user_certificate=user_certificate,
                device_certificate=device_certificate,
                redacted_user_certificate=redacted_user_certificate,
                redacted_device_certificate=redacted_device_certificate,
            )

    organization_addr_display = click.style(organization_addr.to_url(),
                                            fg="yellow")
    click.echo(f"Organization url: {organization_addr_display}")
async def test_invalid_token(running_backend, backend):
    org_id = OrganizationID("NewOrg")
    old_token = "123456"
    new_token = "abcdef"
    await backend.organization.create(org_id, old_token)
    await backend.organization.create(org_id, new_token)

    organization_addr = BackendOrganizationBootstrapAddr.build(
        running_backend.addr, org_id, old_token
    )

    async with apiv1_backend_anonymous_cmds_factory(addr=organization_addr) as cmds:
        with pytest.raises(InviteNotFoundError):
            await bootstrap_organization(cmds, human_handle=None, device_label=None)
async def test_already_bootstrapped(
    running_backend, backend, alice, bob, alice_backend_cmds, user_fs_factory
):
    org_id = OrganizationID("NewOrg")
    org_token = "123456"
    await backend.organization.create(org_id, org_token)

    organization_addr = BackendOrganizationBootstrapAddr.build(
        running_backend.addr, org_id, org_token
    )

    async with apiv1_backend_anonymous_cmds_factory(addr=organization_addr) as cmds:
        await bootstrap_organization(cmds, human_handle=None, device_label=None)

        with pytest.raises(InviteAlreadyUsedError):
            await bootstrap_organization(cmds, human_handle=None, device_label=None)
async def _do_create_org(config, human_handle, device_name, password,
                         backend_addr):
    try:
        async with apiv1_backend_anonymous_cmds_factory(
                addr=backend_addr) as cmds:
            new_device = await bootstrap_organization(
                cmds=cmds, human_handle=human_handle, device_label=device_name)
            save_device_with_password(config_dir=config.config_dir,
                                      device=new_device,
                                      password=password)
            return new_device, password
    except InviteAlreadyUsedError as exc:
        raise JobResultError("invite-already-used", exc=exc)
    except BackendConnectionRefused as exc:
        raise JobResultError("connection-refused", exc=exc)
    except BackendNotAvailable as exc:
        raise JobResultError("connection-error", exc=exc)
Example #11
0
async def _bootstrap_organization(config, addr, password, force):
    label = await aprompt("User fullname")
    email = await aprompt("User email")
    human_handle = HumanHandle(email=email, label=label)
    device_label = await aprompt("Device label", default=platform.node())

    async with apiv1_backend_anonymous_cmds_factory(addr=addr) as cmds:
        async with spinner("Bootstrapping organization in the backend"):
            new_device = await do_bootstrap_organization(
                cmds=cmds,
                human_handle=human_handle,
                device_label=device_label)

        device_display = click.style(new_device.slughash, fg="yellow")
        with operation(f"Saving device {device_display}"):
            save_device_with_password(config_dir=config.config_dir,
                                      device=new_device,
                                      password=password,
                                      force=force)
Example #12
0
async def failsafe_organization_bootstrap(
    addr: BackendOrganizationBootstrapAddr,
    root_verify_key: VerifyKey,
    user_certificate: bytes,
    device_certificate: bytes,
    redacted_user_certificate: bytes,
    redacted_device_certificate: bytes,
) -> dict:
    # Try the new anonymous API
    try:
        rep = await cmd_organization_bootstrap(
            addr=addr,
            root_verify_key=root_verify_key,
            user_certificate=user_certificate,
            device_certificate=device_certificate,
            redacted_user_certificate=redacted_user_certificate,
            redacted_device_certificate=redacted_device_certificate,
        )
    # If we get a 404 error, maybe the backend is too old to know about the anonymous route (API version < 2.6)
    except BackendNotAvailable as exc:
        inner_exc = exc.args[0]
        if getattr(inner_exc, "status", None) != 404:
            raise
    # If we get an "unknown_command" status, the backend might be too old to know about the "organization_bootstrap" command (API version < 2.7)
    else:
        if rep["status"] != "unknown_command":
            return rep
    # Then we try again with the legacy version
    async with apiv1_backend_anonymous_cmds_factory(addr) as anonymous_cmds:
        return await anonymous_cmds.organization_bootstrap(
            organization_id=addr.organization_id,
            bootstrap_token=addr.token,
            root_verify_key=root_verify_key,
            user_certificate=user_certificate,
            device_certificate=device_certificate,
            redacted_user_certificate=redacted_user_certificate,
            redacted_device_certificate=redacted_device_certificate,
        )
async def _bootstrap_organization(config, addr, password, device_label, human_label, human_email):
    if not human_label:
        human_label = await aprompt("User fullname")
    if not human_email:
        human_email = await aprompt("User email")
    human_handle = HumanHandle(email=human_email, label=human_label)
    if not device_label:
        device_label = await aprompt("Device label", default=platform.node())

    async with apiv1_backend_anonymous_cmds_factory(addr=addr) as cmds:
        async with spinner("Bootstrapping organization in the backend"):
            new_device = await do_bootstrap_organization(
                cmds=cmds, human_handle=human_handle, device_label=device_label
            )

        device_display = click.style(new_device.slughash, fg="yellow")
        # We don't have to worry about overwritting an existing keyfile
        # given their names are base on the device's slughash which is intended
        # to be globally unique.
        with operation(f"Saving device {device_display}"):
            save_device_with_password(
                config_dir=config.config_dir, device=new_device, password=password
            )
Example #14
0
    async def _mallory_claim():
        async with apiv1_backend_anonymous_cmds_factory(
                mallory.organization_addr) as cmds:
            rep = await cmds.user_get_invitation_creator(mallory.user_id)
            assert rep["trustchain"] == {
                "devices": [],
                "revoked_users": [],
                "users": []
            }
            creator = UserCertificateContent.unsecure_load(
                rep["user_certificate"])
            creator_device = DeviceCertificateContent.unsecure_load(
                rep["device_certificate"])
            assert creator_device.device_id.user_id == creator.user_id

            encrypted_claim = APIV1_UserClaimContent(
                device_id=mallory.device_id,
                token=token,
                public_key=mallory.public_key,
                verify_key=mallory.verify_key,
            ).dump_and_encrypt_for(recipient_pubkey=creator.public_key)
            with trio.fail_after(1):
                rep = await cmds.user_claim(mallory.user_id, encrypted_claim)
                assert rep["status"] == "ok"
async def test_backend_switch_offline(running_backend, coolorg):
    async with apiv1_backend_anonymous_cmds_factory(coolorg.addr) as cmds:
        await cmds.ping()
        with running_backend.offline():
            with pytest.raises(BackendNotAvailable):
                await cmds.ping()
Example #16
0
async def apiv1_anonymous_backend_cmds(running_backend, coolorg):
    async with apiv1_backend_anonymous_cmds_factory(coolorg.addr) as cmds:
        yield cmds
Example #17
0
 def _cmds_factory(keepalive):
     return apiv1_backend_anonymous_cmds_factory(coolorg.addr,
                                                 keepalive=keepalive)
Example #18
0
async def initialize_test_organization(
    config_dir: Path,
    backend_address: BackendAddr,
    password: str,
    administration_token: str,
    force: bool,
) -> Tuple[LocalDevice, LocalDevice, LocalDevice]:

    configure_logging("WARNING")

    organization_id = OrganizationID("Org")

    # Create organization

    async with apiv1_backend_administration_cmds_factory(
        backend_address, administration_token
    ) as administration_cmds:

        rep = await administration_cmds.organization_create(organization_id)
        assert rep["status"] == "ok"
        bootstrap_token = rep["bootstrap_token"]

        organization_bootstrap_addr = BackendOrganizationBootstrapAddr.build(
            backend_address, organization_id, bootstrap_token
        )

    # Bootstrap organization and Alice user

    async with apiv1_backend_anonymous_cmds_factory(organization_bootstrap_addr) as anonymous_cmds:
        alice_device = await bootstrap_organization(
            cmds=anonymous_cmds,
            human_handle=HumanHandle(label="Alice", email="*****@*****.**"),
            device_label="laptop",
        )
        save_device_with_password(config_dir, alice_device, password, force=force)

    # Create a workspace for Alice

    config = load_config(config_dir, debug="DEBUG" in os.environ)
    async with logged_core_factory(config, alice_device) as core:
        alice_ws_id = await core.user_fs.workspace_create("alice_workspace")
        await core.user_fs.sync()

    # Register a new device for Alice

    other_alice_device = None
    async with backend_authenticated_cmds_factory(
        addr=alice_device.organization_addr,
        device_id=alice_device.device_id,
        signing_key=alice_device.signing_key,
    ) as alice_cmds:
        rep = await alice_cmds.invite_new(type=InvitationType.DEVICE)
        assert rep["status"] == "ok"
        invitation_addr = BackendInvitationAddr.build(
            backend_addr=alice_device.organization_addr,
            organization_id=alice_device.organization_id,
            invitation_type=InvitationType.DEVICE,
            token=rep["token"],
        )

        async with backend_invited_cmds_factory(addr=invitation_addr) as invited_cmds:

            async def invite_task():
                initial_ctx = DeviceGreetInitialCtx(cmds=alice_cmds, token=invitation_addr.token)
                in_progress_ctx = await initial_ctx.do_wait_peer()
                in_progress_ctx = await in_progress_ctx.do_wait_peer_trust()
                in_progress_ctx = await in_progress_ctx.do_signify_trust()
                in_progress_ctx = await in_progress_ctx.do_get_claim_requests()
                await in_progress_ctx.do_create_new_device(
                    author=alice_device, device_label=in_progress_ctx.requested_device_label
                )

            async def claim_task():
                nonlocal other_alice_device
                initial_ctx = await claimer_retrieve_info(cmds=invited_cmds)
                in_progress_ctx = await initial_ctx.do_wait_peer()
                in_progress_ctx = await in_progress_ctx.do_signify_trust()
                in_progress_ctx = await in_progress_ctx.do_wait_peer_trust()
                other_alice_device = await in_progress_ctx.do_claim_device(
                    requested_device_label="pc"
                )

            async with trio.open_service_nursery() as nursery:
                nursery.start_soon(invite_task)
                nursery.start_soon(claim_task)

            save_device_with_password(config_dir, other_alice_device, password, force=force)

        # Invite Bob in

        bob_device = None
        rep = await alice_cmds.invite_new(type=InvitationType.USER, claimer_email="*****@*****.**")
        assert rep["status"] == "ok"
        invitation_addr = BackendInvitationAddr.build(
            backend_addr=alice_device.organization_addr,
            organization_id=alice_device.organization_id,
            invitation_type=InvitationType.USER,
            token=rep["token"],
        )

        async with backend_invited_cmds_factory(addr=invitation_addr) as invited_cmds:

            async def invite_task():
                initial_ctx = UserGreetInitialCtx(cmds=alice_cmds, token=invitation_addr.token)
                in_progress_ctx = await initial_ctx.do_wait_peer()
                in_progress_ctx = await in_progress_ctx.do_wait_peer_trust()
                in_progress_ctx = await in_progress_ctx.do_signify_trust()
                in_progress_ctx = await in_progress_ctx.do_get_claim_requests()
                await in_progress_ctx.do_create_new_user(
                    author=alice_device,
                    human_handle=in_progress_ctx.requested_human_handle,
                    device_label=in_progress_ctx.requested_device_label,
                    profile=UserProfile.STANDARD,
                )

            async def claim_task():
                nonlocal bob_device
                initial_ctx = await claimer_retrieve_info(cmds=invited_cmds)
                in_progress_ctx = await initial_ctx.do_wait_peer()
                in_progress_ctx = await in_progress_ctx.do_signify_trust()
                in_progress_ctx = await in_progress_ctx.do_wait_peer_trust()
                bob_device = await in_progress_ctx.do_claim_user(
                    requested_human_handle=HumanHandle(label="Bob", email="*****@*****.**"),
                    requested_device_label="laptop",
                )

            async with trio.open_service_nursery() as nursery:
                nursery.start_soon(invite_task)
                nursery.start_soon(claim_task)

            save_device_with_password(config_dir, bob_device, password, force=force)

    # Create bob workspace and share with Alice

    async with logged_core_factory(config, bob_device) as core:
        bob_ws_id = await core.user_fs.workspace_create("bob_workspace")
        await core.user_fs.workspace_share(bob_ws_id, alice_device.user_id, WorkspaceRole.MANAGER)

    # Share Alice workspace with bob

    async with logged_core_factory(config, alice_device) as core:
        await core.user_fs.workspace_share(alice_ws_id, bob_device.user_id, WorkspaceRole.MANAGER)

    # Synchronize every device
    for device in (alice_device, other_alice_device, bob_device):
        async with logged_core_factory(config, device) as core:
            await core.user_fs.process_last_messages()
            await core.user_fs.sync()

    return (alice_device, other_alice_device, bob_device)
Example #19
0
async def claim_user(
    organization_addr: BackendOrganizationAddr,
    new_device_id: DeviceID,
    token: str,
    keepalive: Optional[int] = None,
) -> LocalDevice:
    """
    Raises:
        InviteClaimError
        InviteClaimBackendOfflineError
        InviteClaimValidationError
        InviteClaimPackingError
        InviteClaimCryptoError
    """
    new_device = generate_new_device(new_device_id, organization_addr)

    try:
        async with apiv1_backend_anonymous_cmds_factory(
                organization_addr, keepalive=keepalive) as cmds:
            # 1) Retrieve invitation creator
            try:
                invitation_creator_user, invitation_creator_device = await get_user_invitation_creator(
                    cmds, new_device.root_verify_key, new_device.user_id)

            except RemoteDevicesManagerBackendOfflineError as exc:
                raise InviteClaimBackendOfflineError(str(exc)) from exc

            except RemoteDevicesManagerError as exc:
                raise InviteClaimError(
                    f"Cannot retrieve invitation creator: {exc}") from exc

            # 2) Generate claim info for invitation creator
            try:
                encrypted_claim = APIV1_UserClaimContent(
                    device_id=new_device_id,
                    token=token,
                    public_key=new_device.public_key,
                    verify_key=new_device.verify_key,
                ).dump_and_encrypt_for(
                    recipient_pubkey=invitation_creator_user.public_key)

            except DataError as exc:
                raise InviteClaimError(
                    f"Cannot generate user claim message: {exc}") from exc

            # 3) Send claim
            rep = await cmds.user_claim(new_device_id.user_id, encrypted_claim)
            if rep["status"] != "ok":
                raise InviteClaimError(f"Cannot claim user: {rep}")

            # 4) Verify user&device certificates and check admin status
            try:
                user = UserCertificateContent.verify_and_load(
                    rep["user_certificate"],
                    author_verify_key=invitation_creator_device.verify_key,
                    expected_author=invitation_creator_device.device_id,
                    expected_user=new_device_id.user_id,
                )

                DeviceCertificateContent.verify_and_load(
                    rep["device_certificate"],
                    author_verify_key=invitation_creator_device.verify_key,
                    expected_author=invitation_creator_device.device_id,
                    expected_device=new_device_id,
                )

                new_device = new_device.evolve(profile=user.profile)

            except DataError as exc:
                raise InviteClaimCryptoError(str(exc)) from exc

    except BackendNotAvailable as exc:
        raise InviteClaimBackendOfflineError(str(exc)) from exc

    except BackendConnectionError as exc:
        raise InviteClaimError(f"Cannot claim user: {exc}") from exc

    return new_device
Example #20
0
async def claim_device(
    organization_addr: BackendOrganizationAddr,
    new_device_id: DeviceID,
    token: str,
    keepalive: Optional[int] = None,
) -> LocalDevice:
    """
    Raises:
        InviteClaimError
        InviteClaimBackendOfflineError
        InviteClaimValidationError
        InviteClaimPackingError
        InviteClaimCryptoError
    """
    device_signing_key = SigningKey.generate()
    answer_private_key = PrivateKey.generate()

    try:
        async with apiv1_backend_anonymous_cmds_factory(
                organization_addr, keepalive=keepalive) as cmds:
            # 1) Retrieve invitation creator
            try:
                invitation_creator_user, invitation_creator_device = await get_device_invitation_creator(
                    cmds, organization_addr.root_verify_key, new_device_id)

            except RemoteDevicesManagerBackendOfflineError as exc:
                raise InviteClaimBackendOfflineError(str(exc)) from exc

            except RemoteDevicesManagerError as exc:
                raise InviteClaimError(
                    f"Cannot retrieve invitation creator: {exc}") from exc

            # 2) Generate claim info for invitation creator
            try:
                encrypted_claim = APIV1_DeviceClaimContent(
                    token=token,
                    device_id=new_device_id,
                    verify_key=device_signing_key.verify_key,
                    answer_public_key=answer_private_key.public_key,
                ).dump_and_encrypt_for(
                    recipient_pubkey=invitation_creator_user.public_key)

            except DataError as exc:
                raise InviteClaimError(
                    f"Cannot generate device claim message: {exc}") from exc

            # 3) Send claim
            rep = await cmds.device_claim(new_device_id, encrypted_claim)
            if rep["status"] != "ok":
                raise InviteClaimError(f"Claim request error: {rep}")

            # 4) Verify device certificate
            try:
                DeviceCertificateContent.verify_and_load(
                    rep["device_certificate"],
                    author_verify_key=invitation_creator_device.verify_key,
                    expected_author=invitation_creator_device.device_id,
                    expected_device=new_device_id,
                )

            except DataError as exc:
                raise InviteClaimCryptoError(str(exc)) from exc

            try:
                answer = APIV1_DeviceClaimAnswerContent.decrypt_and_load_for(
                    rep["encrypted_answer"],
                    recipient_privkey=answer_private_key)

            except DataError as exc:
                raise InviteClaimCryptoError(
                    f"Cannot decrypt device claim answer: {exc}") from exc

    except BackendNotAvailable as exc:
        raise InviteClaimBackendOfflineError(str(exc)) from exc

    except BackendConnectionError as exc:
        raise InviteClaimError(f"Cannot claim device: {exc}") from exc

    return LocalDevice(
        organization_addr=organization_addr,
        device_id=new_device_id,
        signing_key=device_signing_key,
        private_key=answer.private_key,
        profile=UserProfile.ADMIN
        if invitation_creator_user.is_admin else UserProfile.STANDARD,
        user_manifest_id=answer.user_manifest_id,
        user_manifest_key=answer.user_manifest_key,
        local_symkey=SecretKey.generate(),
    )
Example #21
0
async def test_handshake_organization_expired(running_backend, expiredorg):
    with pytest.raises(BackendConnectionRefused) as exc:
        async with apiv1_backend_anonymous_cmds_factory(expiredorg.addr) as cmds:
            await cmds.ping()
    assert str(exc.value) == "Trial organization has expired"
async def test_backend_closed_cmds(running_backend, coolorg):
    async with apiv1_backend_anonymous_cmds_factory(coolorg.addr) as cmds:
        pass
    with pytest.raises(trio.ClosedResourceError):
        await cmds.ping()
async def test_ping(running_backend, coolorg):
    async with apiv1_backend_anonymous_cmds_factory(coolorg.addr) as cmds:
        rep = await cmds.ping("Hello World !")
        assert rep == {"status": "ok", "pong": "Hello World !"}
Example #24
0
async def initialize_test_organization(
    config_dir: Path,
    backend_address: BackendAddr,
    password: str,
    administration_token: str,
    additional_users_number: int,
    additional_devices_number: int,
) -> Tuple[LocalDevice, LocalDevice, LocalDevice]:
    configure_logging(log_level="WARNING")
    organization_id = OrganizationID("Org")

    # Create organization
    async with apiv1_backend_administration_cmds_factory(
        backend_address, administration_token) as administration_cmds:

        rep = await administration_cmds.organization_create(organization_id)
        assert rep["status"] == "ok", rep
        bootstrap_token = rep["bootstrap_token"]

        organization_bootstrap_addr = BackendOrganizationBootstrapAddr.build(
            backend_address, organization_id, bootstrap_token)
    # Bootstrap organization and Alice user and create device "laptop" for Alice

    async with apiv1_backend_anonymous_cmds_factory(
            organization_bootstrap_addr) as anonymous_cmds:
        alice_device = await bootstrap_organization(
            cmds=anonymous_cmds,
            human_handle=HumanHandle(label="Alice", email="*****@*****.**"),
            device_label="laptop",
        )
        save_device_with_password(config_dir=config_dir,
                                  device=alice_device,
                                  password=password)

    config = load_config(config_dir, debug="DEBUG" in os.environ)
    # Create context manager, alice_core will be needed for the rest of the script
    async with logged_core_factory(config, alice_device) as alice_core:
        async with backend_authenticated_cmds_factory(
                addr=alice_device.organization_addr,
                device_id=alice_device.device_id,
                signing_key=alice_device.signing_key,
        ) as alice_cmds:

            # Create new device "pc" for Alice
            other_alice_device = await _register_new_device(
                cmds=alice_cmds, author=alice_device, device_label="pc")
            save_device_with_password(config_dir=config_dir,
                                      device=other_alice_device,
                                      password=password)
            # Invite Bob in organization
            bob_device = await _register_new_user(
                cmds=alice_cmds,
                author=alice_device,
                device_label="laptop",
                human_handle=HumanHandle(email="*****@*****.**", label="Bob"),
                profile=UserProfile.STANDARD,
            )
            save_device_with_password(config_dir=config_dir,
                                      device=bob_device,
                                      password=password)

            # Invite Toto in organization
            toto_device = await _register_new_user(
                cmds=alice_cmds,
                author=alice_device,
                device_label="laptop",
                human_handle=HumanHandle(email="*****@*****.**",
                                         label="Toto"),
                profile=UserProfile.OUTSIDER,
            )
            save_device_with_password(config_dir=config_dir,
                                      device=toto_device,
                                      password=password)
            # Create Alice workspace
            alice_ws_id = await alice_core.user_fs.workspace_create(
                "alice_workspace")
            # Create context manager
            async with logged_core_factory(config, bob_device) as bob_core:
                # Create Bob workspace
                bob_ws_id = await bob_core.user_fs.workspace_create(
                    "bob_workspace")
                # Bob share workspace with Alice
                await bob_core.user_fs.workspace_share(bob_ws_id,
                                                       alice_device.user_id,
                                                       WorkspaceRole.MANAGER)
                # Alice share workspace with Bob
                await alice_core.user_fs.workspace_share(
                    alice_ws_id, bob_device.user_id, WorkspaceRole.MANAGER)
                # Add additional random users
                await _add_random_users(
                    cmds=alice_cmds,
                    author=alice_device,
                    alice_core=alice_core,
                    bob_core=bob_core,
                    alice_ws_id=alice_ws_id,
                    bob_ws_id=bob_ws_id,
                    additional_users_number=additional_users_number,
                )
                # Add additional random device for alice
                await _add_random_device(
                    cmds=alice_cmds,
                    device=alice_device,
                    additional_devices_number=additional_devices_number,
                )

    # Synchronize every device
    for device in (alice_device, other_alice_device, bob_device):
        async with logged_core_factory(config, device) as core:
            await core.user_fs.process_last_messages()
            await core.user_fs.sync()
    return (alice_device, other_alice_device, bob_device)
async def test_anonymous_cmds_has_right_methods(running_backend, coolorg):
    async with apiv1_backend_anonymous_cmds_factory(coolorg.addr) as cmds:
        for method_name in APIV1_ANONYMOUS_CMDS:
            assert hasattr(cmds, method_name)
        for method_name in ALL_CMDS - APIV1_ANONYMOUS_CMDS:
            assert not hasattr(cmds, method_name)
Example #26
0
async def _do_bootstrap_organization(
    config_dir,
    password: str,
    password_check: str,
    user_id: str,
    device_name: str,
    bootstrap_addr: BackendOrganizationBootstrapAddr,
):
    if password != password_check:
        raise JobResultError("password-mismatch")
    if len(password) < 8:
        raise JobResultError("password-size")

    try:
        device_id = DeviceID(f"{user_id}@{device_name}")
    except ValueError as exc:
        raise JobResultError("bad-device_name") from exc

    root_signing_key = SigningKey.generate()
    root_verify_key = root_signing_key.verify_key
    organization_addr = bootstrap_addr.generate_organization_addr(
        root_verify_key)

    try:
        device = generate_new_device(device_id,
                                     organization_addr,
                                     profile=UserProfile.ADMIN)
        save_device_with_password(config_dir, device, password)

    except LocalDeviceAlreadyExistsError as exc:
        raise JobResultError("user-exists") from exc

    now = pendulum.now()
    user_certificate = UserCertificateContent(
        author=None,
        timestamp=now,
        user_id=device.user_id,
        public_key=device.public_key,
        profile=device.profile,
    ).dump_and_sign(root_signing_key)
    device_certificate = DeviceCertificateContent(
        author=None,
        timestamp=now,
        device_id=device_id,
        verify_key=device.verify_key).dump_and_sign(root_signing_key)

    try:
        async with apiv1_backend_anonymous_cmds_factory(
                bootstrap_addr) as cmds:
            rep = await cmds.organization_bootstrap(
                bootstrap_addr.organization_id,
                bootstrap_addr.token,
                root_verify_key,
                user_certificate,
                device_certificate,
            )

            if rep["status"] == "already_bootstrapped":
                raise JobResultError("already-bootstrapped", info=str(rep))
            elif rep["status"] == "not_found":
                raise JobResultError("invalid-url", info=str(rep))
            elif rep["status"] != "ok":
                raise JobResultError("refused-by-backend", info=str(rep))
        return device, password
    except BackendConnectionRefused as exc:
        raise JobResultError("invalid-url", info=str(exc)) from exc

    except BackendNotAvailable as exc:
        raise JobResultError("backend-offline", info=str(exc)) from exc

    except BackendConnectionError as exc:
        raise JobResultError("refused-by-backend", info=str(exc)) from exc