예제 #1
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]:
    organization_id = OrganizationID("Org")
    config = load_config(config_dir, debug="DEBUG" in os.environ)

    # Create organization

    bootstrap_token = await create_organization_req(
        organization_id, backend_address, administration_token
    )
    organization_bootstrap_addr = BackendOrganizationBootstrapAddr.build(
        backend_address, organization_id, bootstrap_token
    )

    # Bootstrap organization and Alice user and create device "laptop" for Alice

    alice_device = await bootstrap_organization(
        organization_bootstrap_addr,
        human_handle=HumanHandle(label="Alice", email="*****@*****.**"),
        device_label=DeviceLabel("laptop"),
    )
    await user_storage_non_speculative_init(data_base_dir=config.data_base_dir, device=alice_device)
    save_device_with_password_in_config(
        config_dir=config_dir, device=alice_device, password=password
    )

    # 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=DeviceLabel("pc")
            )
            save_device_with_password_in_config(
                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=DeviceLabel("laptop"),
                human_handle=HumanHandle(email="*****@*****.**", label="Bob"),
                profile=UserProfile.STANDARD,
            )
            await user_storage_non_speculative_init(
                data_base_dir=config.data_base_dir, device=bob_device
            )
            save_device_with_password_in_config(
                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=DeviceLabel("laptop"),
                human_handle=HumanHandle(email="*****@*****.**", label="Toto"),
                profile=UserProfile.OUTSIDER,
            )
            await user_storage_non_speculative_init(
                data_base_dir=config.data_base_dir, device=toto_device
            )
            save_device_with_password_in_config(
                config_dir=config_dir, device=toto_device, password=password
            )
            # Create Alice workspace
            alice_ws_id = await alice_core.user_fs.workspace_create(EntryName("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(EntryName("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)
예제 #2
0
async def query_find_humans(
    conn,
    organization_id: OrganizationID,
    query: str,
    page: int,
    per_page: int,
    omit_revoked: bool,
    omit_non_human: bool,
) -> Tuple[List[HumanFindResultItem], int]:
    if query:

        if omit_revoked:
            q = _q_human_factory(query=True,
                                 omit_revoked=True,
                                 omit_non_human=omit_non_human)
            args = (pendulum_now(), organization_id, query)

        else:
            q = _q_human_factory(query=True,
                                 omit_revoked=False,
                                 omit_non_human=omit_non_human)
            args = (pendulum_now(), organization_id, query)

    else:

        if omit_revoked:
            q = _q_human_factory(query=False,
                                 omit_revoked=True,
                                 omit_non_human=omit_non_human)
            args = (pendulum_now(), organization_id)

        else:
            q = _q_human_factory(query=False,
                                 omit_revoked=False,
                                 omit_non_human=omit_non_human)
            args = (pendulum_now(), organization_id)

    raw_results = await conn.fetch(q, *args)

    humans = [
        HumanFindResultItem(
            user_id=UserID(user_id),
            human_handle=HumanHandle(email=email, label=label),
            revoked=revoked,
        ) for user_id, email, label, revoked in raw_results
        if email is not None
    ]
    non_humans = [
        HumanFindResultItem(user_id=UserID(user_id),
                            human_handle=None,
                            revoked=revoked)
        for user_id, email, label, revoked in raw_results if email is None
    ]
    results = [
        *sorted(humans,
                key=lambda x:
                (x.human_handle.label.lower(), x.user_id.lower())),
        *sorted(non_humans, key=lambda x: x.user_id.lower()),
    ]
    # TODO: should user LIMIT and OFFSET in the SQL query instead
    return results[(page - 1) * per_page:page * per_page], len(results)
예제 #3
0
    def _local_device_factory(
        base_device_id: Optional[str] = None,
        org: OrganizationFullData = coolorg,
        profile: Optional[UserProfile] = None,
        has_human_handle: bool = True,
        base_human_handle: Optional[str] = None,
        has_device_label: bool = True,
        base_device_label: Optional[str] = None,
    ):
        nonlocal count

        if not base_device_id:
            count += 1
            base_device_id = f"user{count}@dev0"

        org_devices = devices[org.organization_id]
        device_id = DeviceID(base_device_id)
        assert not any(d for d in org_devices if d.device_id == device_id)

        if not has_device_label:
            assert base_device_label is None
            device_label = None
        elif not base_device_label:
            device_label = f"My {device_id.device_name} machine"
        else:
            device_label = base_device_label

        if not has_human_handle:
            assert base_human_handle is None
            human_handle = None
        elif base_human_handle:
            if isinstance(base_human_handle, HumanHandle):
                human_handle = base_human_handle
            else:
                match = re.match(r"(.*) <(.*)>", base_human_handle)
                if match:
                    label, email = match.groups()
                else:
                    label = base_human_handle
                    email = f"{device_id.user_id}@example.com"
                human_handle = HumanHandle(email=email, label=label)
        else:
            name = device_id.user_id.capitalize()
            human_handle = HumanHandle(
                email=f"{device_id.user_id}@example.com",
                label=f"{name}y Mc{name}Face")

        parent_device = None
        try:
            # If the user already exists, we must retrieve it data
            parent_device = next(d for d in org_devices
                                 if d.user_id == device_id.user_id)
            if profile is not None and profile != parent_device.profile:
                raise ValueError(
                    "profile is set but user already exists, with a different profile value."
                )
            profile = parent_device.profile

        except StopIteration:
            profile = profile or UserProfile.STANDARD

        # Force each device to access the backend trough a different hostname so
        # tcp stream spy can switch offline certains while keeping the others online
        org_addr = addr_with_device_subdomain(org.addr, device_id)

        device = generate_new_device(
            organization_addr=org_addr,
            device_id=device_id,
            profile=profile,
            human_handle=human_handle,
            device_label=device_label,
        )
        if parent_device is not None:
            device = device.evolve(
                private_key=parent_device.private_key,
                user_manifest_id=parent_device.user_manifest_id,
                user_manifest_key=parent_device.user_manifest_key,
            )
        org_devices.append(device)
        return device
예제 #4
0
async def test_good_user_claim(backend, running_backend, alice,
                               alice_backend_cmds, user_fs_factory,
                               with_labels):
    claimer_email = "*****@*****.**"

    invitation = await backend.invite.new_for_user(
        organization_id=alice.organization_id,
        greeter_user_id=alice.user_id,
        claimer_email=claimer_email,
    )
    invitation_addr = BackendInvitationAddr.build(
        backend_addr=alice.organization_addr,
        organization_id=alice.organization_id,
        invitation_type=InvitationType.USER,
        token=invitation.token,
    )

    if with_labels:
        # Let's pretent we invited a Fortnite player...
        requested_human_handle = HumanHandle(email="*****@*****.**",
                                             label="xXx_Z4ck_xXx")
        requested_device_label = "Ultr4_B00st"
        granted_human_handle = HumanHandle(email="*****@*****.**",
                                           label="Zack")
        granted_device_label = "Desktop"
    else:
        requested_human_handle = None
        requested_device_label = None
        granted_human_handle = None
        granted_device_label = None
    granted_profile = UserProfile.STANDARD
    new_device = None

    # Simulate out-of-bounds canal
    oob_send, oob_recv = trio.open_memory_channel(0)

    async def _run_claimer():
        async with backend_invited_cmds_factory(addr=invitation_addr) as cmds:
            initial_ctx = await claimer_retrieve_info(cmds)
            assert isinstance(initial_ctx, UserClaimInitialCtx)
            assert initial_ctx.claimer_email == claimer_email
            assert initial_ctx.greeter_user_id == alice.user_id
            assert initial_ctx.greeter_human_handle == alice.human_handle

            in_progress_ctx = await initial_ctx.do_wait_peer()

            choices = in_progress_ctx.generate_greeter_sas_choices(size=4)
            assert len(choices) == 4
            assert in_progress_ctx.greeter_sas in choices

            greeter_sas = await oob_recv.receive()
            assert greeter_sas == in_progress_ctx.greeter_sas

            in_progress_ctx = await in_progress_ctx.do_signify_trust()
            await oob_send.send(in_progress_ctx.claimer_sas)

            in_progress_ctx = await in_progress_ctx.do_wait_peer_trust()

            nonlocal new_device
            new_device = await in_progress_ctx.do_claim_user(
                requested_device_label=requested_device_label,
                requested_human_handle=requested_human_handle,
            )
            assert isinstance(new_device, LocalDevice)

    async def _run_greeter():
        initial_ctx = UserGreetInitialCtx(cmds=alice_backend_cmds,
                                          token=invitation_addr.token)

        in_progress_ctx = await initial_ctx.do_wait_peer()

        await oob_send.send(in_progress_ctx.greeter_sas)

        in_progress_ctx = await in_progress_ctx.do_wait_peer_trust()

        choices = in_progress_ctx.generate_claimer_sas_choices(size=5)
        assert len(choices) == 5
        assert in_progress_ctx.claimer_sas in choices

        claimer_sas = await oob_recv.receive()
        assert claimer_sas == in_progress_ctx.claimer_sas

        in_progress_ctx = await in_progress_ctx.do_signify_trust()

        in_progress_ctx = await in_progress_ctx.do_get_claim_requests()

        assert in_progress_ctx.requested_device_label == requested_device_label
        assert in_progress_ctx.requested_human_handle == requested_human_handle

        await in_progress_ctx.do_create_new_user(
            author=alice,
            device_label=granted_device_label,
            human_handle=granted_human_handle,
            profile=granted_profile,
        )

    with trio.fail_after(1):
        async with trio.open_nursery() as nursery:
            nursery.start_soon(_run_claimer)
            nursery.start_soon(_run_greeter)

    assert new_device is not None
    assert new_device.device_id != alice.device_id
    assert new_device.device_label == granted_device_label
    # Label is normally ignored when comparing HumanLabel
    if with_labels:
        assert new_device.human_handle.label == granted_human_handle.label
        assert new_device.human_handle.email == granted_human_handle.email
    else:
        assert new_device.human_handle is None
    assert new_device.profile == granted_profile
    # Extra check to make sure claimer&greeter data are not mixed
    assert new_device.user_manifest_id != alice.user_manifest_id
    assert new_device.user_manifest_key != alice.user_manifest_key
    assert new_device.local_symkey != alice.local_symkey

    # Now invitation should have been deleted
    rep = await alice_backend_cmds.invite_list()
    assert rep == {"status": "ok", "invitations": []}

    # Verify user&device data in backend
    user, device = await backend.user.get_user_with_device(
        new_device.organization_id, new_device.device_id)
    assert user.profile == granted_profile
    assert user.human_handle == granted_human_handle
    assert device.device_label == granted_device_label
    if with_labels:
        assert user.user_certificate != user.redacted_user_certificate
        assert device.device_certificate != device.redacted_device_certificate
    else:
        assert user.user_certificate == user.redacted_user_certificate
        assert device.device_certificate == device.redacted_device_certificate

    # Test the behavior of this new user device
    async with user_fs_factory(alice) as alicefs:
        async with user_fs_factory(new_device, initialize_in_v0=True) as newfs:
            # Share a workspace with new user
            aw_id = await alicefs.workspace_create("alice_workspace")
            await alicefs.workspace_share(aw_id, new_device.user_id,
                                          WorkspaceRole.CONTRIBUTOR)

            # New user cannot create a new workspace
            zw_id = await newfs.workspace_create("zack_workspace")
            await newfs.workspace_share(zw_id, alice.user_id,
                                        WorkspaceRole.READER)

            # Now both users should have the same workspaces
            await alicefs.process_last_messages()
            await newfs.process_last_messages()
            await newfs.sync()  # Not required, but just to make sure it works

            alice_um = alicefs.get_user_manifest()
            zack_um = newfs.get_user_manifest()

            assert {(w.id, w.key)
                    for w in alice_um.workspaces
                    } == {(w.id, w.key)
                          for w in zack_um.workspaces}
예제 #5
0
 def human_handle(self):
     user_name = validators.trim_user_name(
         self.line_edit_user_full_name.text())
     return HumanHandle(label=user_name,
                        email=self.line_edit_user_email.text())
예제 #6
0
def test_valid_human_handle(email, label):
    HumanHandle(email, label)
예제 #7
0
def test_invalid_human_handle(email, label):
    with pytest.raises(ValueError):
        HumanHandle(email, label)