Example #1
0
def test_bad_organization_id_user_id_and_device_name(raw):
    with pytest.raises(ValueError):
        OrganizationID(raw)
    with pytest.raises(ValueError):
        UserID(raw)
    with pytest.raises(ValueError):
        DeviceName(raw)
Example #2
0
def test_good_invited_handshake(coolorg, invitation_type):
    organization_id = OrganizationID("Org")
    token = uuid4()

    sh = ServerHandshake()
    ch = InvitedClientHandshake(organization_id=organization_id,
                                invitation_type=invitation_type,
                                token=token)
    assert sh.state == "stalled"

    challenge_req = sh.build_challenge_req()
    assert sh.state == "challenge"

    answer_req = ch.process_challenge_req(challenge_req)

    sh.process_answer_req(answer_req)
    assert sh.state == "answer"
    assert sh.answer_type == HandshakeType.INVITED
    assert sh.answer_data == {
        "client_api_version": API_V2_VERSION,
        "organization_id": organization_id,
        "invitation_type": invitation_type,
        "token": token,
    }

    result_req = sh.build_result_req()
    assert sh.state == "result"

    ch.process_result_req(result_req)
    assert sh.client_api_version == API_V2_VERSION
Example #3
0
 def validate(self, string, pos):
     try:
         if len(string) == 0:
             return QValidator.Intermediate, string, pos
         OrganizationID(string)
         return QValidator.Acceptable, string, pos
     except ValueError:
         return QValidator.Invalid, string, pos
Example #4
0
def test_organization_id_user_id_and_device_name(raw):
    organization_id = OrganizationID(raw)
    assert organization_id == raw

    user_id = UserID(raw)
    assert user_id == raw

    device_name = DeviceName(raw)
    assert device_name == raw
Example #5
0
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
Example #6
0
def test_backend_organization_addr_good(base_url, expected, verify_key):
    org = OrganizationID("org")
    backend_addr = BackendAddr.from_url(base_url)
    addr = BackendOrganizationAddr.build(backend_addr,
                                         organization_id=org,
                                         root_verify_key=verify_key)
    assert addr.hostname == "foo"
    assert addr.port == expected["port"]
    assert addr.use_ssl == expected["ssl"]
    assert addr.organization_id == org
    assert addr.root_verify_key == verify_key

    addr2 = BackendOrganizationAddr.from_url(addr.to_url())
    assert addr == addr2
Example #7
0
async def test_get_redirect_invitation(backend_http_send, backend_addr):
    invitation_addr = BackendInvitationAddr.build(
        backend_addr=backend_addr,
        organization_id=OrganizationID("Org"),
        invitation_type=InvitationType.USER,
        token=uuid4(),
    )
    # TODO: should use invitation_addr.to_redirection_url() when available !
    *_, target = invitation_addr.to_url().split("/")
    rep = await backend_http_send(f"/redirect/{target}")
    assert rep.startswith("HTTP/1.1 200 OK\r\n")
    location_match = re.search(
        r'class="parsecLink">\n        <div class="urltxt">(.+)</div>', rep)
    location_addr = BackendInvitationAddr.from_url(location_match.group(1))
    assert location_addr == invitation_addr
Example #8
0
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)
Example #9
0
def test_list_devices_support_legacy_file_with_meaningful_name(config_dir):
    # Legacy path might exceed the 256 characters limit in some cases (see issue #1356)
    # So we use the `\\?\` workaround: https://stackoverflow.com/a/57502760/2846140
    if os.name == "nt":
        config_dir = Path("\\\\?\\" + str(config_dir.resolve()))

    # Device information
    user_id = uuid4().hex
    device_name = uuid4().hex
    organization_id = "Org"
    rvk_hash = (uuid4().hex)[:10]
    device_id = f"{user_id}@{device_name}"
    slug = f"{rvk_hash}#{organization_id}#{device_id}"
    human_label = "Billy Mc BillFace"
    human_email = "*****@*****.**"
    device_label = "My device"

    # Craft file data without the user_id, organization_id and
    # root_verify_key_hash fields
    key_file_data = packb({
        "type":
        "password",
        "salt":
        b"12345",
        "ciphertext":
        b"whatever",
        "human_handle": (human_email.encode(), human_label.encode()),
        "device_label":
        device_label.encode(),
    })

    key_file_path = get_devices_dir(config_dir) / slug / f"{slug}.keys"
    key_file_path.parent.mkdir(parents=True)
    key_file_path.write_bytes(key_file_data)

    devices = list_available_devices(config_dir)
    expected_device = AvailableDevice(
        key_file_path=key_file_path,
        organization_id=OrganizationID(organization_id),
        device_id=DeviceID(device_id),
        human_handle=HumanHandle(human_email, human_label),
        device_label=device_label,
        root_verify_key_hash=rvk_hash,
    )
    assert devices == [expected_device]
Example #10
0
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)
Example #11
0
async def test_handshake_incompatible_version(backend, server_factory):
    async with server_factory(backend.handle_client) as server:
        stream = server.connection_factory()
        transport = await Transport.init_for_client(stream, server.addr.hostname)

        incompatible_version = ApiVersion(API_VERSION.version + 1, 0)
        await transport.recv()  # Get challenge
        req = {
            "handshake": "answer",
            "type": "anonymous",
            "client_api_version": incompatible_version,
            "organization_id": OrganizationID("Org"),
            "token": "whatever",
        }
        await transport.send(packb(req))
        result_req = await transport.recv()
        assert unpackb(result_req) == {
            "handshake": "result",
            "result": "bad_protocol",
            "help": "No overlap between client API versions {3.0} and backend API versions {2.0, 1.2}",
        }
Example #12
0
def test_backend_organization_bootstrap_addr_good(base_url, expected,
                                                  verify_key):
    org = OrganizationID("org")
    backend_addr = BackendAddr.from_url(base_url)
    addr = BackendOrganizationBootstrapAddr.build(backend_addr, org,
                                                  "token-123")
    assert addr.hostname == "foo"
    assert addr.port == expected["port"]
    assert addr.use_ssl == expected["ssl"]
    assert addr.organization_id == org
    assert addr.token == "token-123"

    addr2 = BackendOrganizationBootstrapAddr.from_url(str(addr))
    assert addr == addr2

    org_addr = addr.generate_organization_addr(verify_key)
    assert isinstance(org_addr, BackendOrganizationAddr)
    assert org_addr.root_verify_key == verify_key
    assert org_addr.hostname == addr.hostname
    assert org_addr.port == addr.port
    assert org_addr.use_ssl == addr.use_ssl
    assert org_addr.organization_id == addr.organization_id
Example #13
0
    def _organization_factory(orgname=None, expiration_date=None):
        nonlocal count

        if not orgname:
            count += 1
            orgname = f"Org{count}"

        assert orgname not in organizations
        organization_id = OrganizationID(orgname)
        organizations.add(organization_id)

        bootstrap_token = f"<{orgname}-bootstrap-token>"
        bootstrap_addr = BackendOrganizationBootstrapAddr.build(
            backend_addr,
            organization_id=organization_id,
            token=bootstrap_token)

        root_signing_key = SigningKey.generate()
        addr = bootstrap_addr.generate_organization_addr(
            root_signing_key.verify_key)

        return OrganizationFullData(bootstrap_addr, addr, root_signing_key)
Example #14
0
def test_list_devices_support_legacy_file_without_labels(config_dir):
    # Craft file data without the labels fields
    key_file_data = packb({
        "type": "password",
        "salt": b"12345",
        "ciphertext": b"whatever"
    })
    slug = "9d84fbd57a#Org#Zack@PC1"
    key_file_path = fix_dir(
        get_devices_dir(config_dir) / slug / f"{slug}.keys")
    key_file_path.parent.mkdir(parents=True)
    key_file_path.write_bytes(key_file_data)

    devices = list_available_devices(config_dir)
    expected_device = AvailableDevice(
        key_file_path=key_file_path,
        organization_id=OrganizationID("Org"),
        device_id=DeviceID("Zack@PC1"),
        human_handle=None,
        device_label=None,
        root_verify_key_hash="9d84fbd57a",
    )
    assert devices == [expected_device]
Example #15
0
async def initialize_test_organization(
    config_dir: Path,
    backend_address: BackendAddr,
    password: str,
    administration_token: str,
    force: bool,
    additional_users_number: int,
    additional_devices_number: int,
) -> 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 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,
                                  alice_device,
                                  password,
                                  force=force)

    config = load_config(config_dir, debug="DEBUG" in os.environ)
    # Create context manager, alice_client will be needed for the rest of the script
    async with logged_client_factory(config, alice_device) as alice_client:
        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,
                                      other_alice_device,
                                      password,
                                      force=force)
            # Add additional random device for alice
            if additional_devices_number > 0:
                print(
                    f"Adding {additional_devices_number} devices in the test group"
                )
                print(" ... please wait ...")
                await _add_random_device(
                    cmds=alice_cmds,
                    config_dir=config_dir,
                    force=force,
                    password=password,
                    device=alice_device,
                    additional_devices_number=additional_devices_number,
                )
                print(" Done ")
            # 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,
                                      bob_device,
                                      password,
                                      force=force)
            # Create Alice workspace
            alice_ws_id = await alice_client.user_fs.workspace_create(
                "alice_workspace")
            # Create context manager
            async with logged_client_factory(config, bob_device) as bob_client:
                # Create Bob workspace
                bob_ws_id = await bob_client.user_fs.workspace_create(
                    "bob_workspace")
                # Bob share workspace with Alice
                await bob_client.user_fs.workspace_share(
                    bob_ws_id, alice_device.user_id, WorkspaceRole.MANAGER)
                # Alice share workspace with Bob
                await alice_client.user_fs.workspace_share(
                    alice_ws_id, bob_device.user_id, WorkspaceRole.MANAGER)
                # Add additional random users
                if additional_users_number > 0:
                    print(
                        f"Adding {additional_users_number} users in the test group"
                    )
                    print(" ... please wait ...")
                    await _add_random_users(
                        cmds=alice_cmds,
                        author=alice_device,
                        alice_client=alice_client,
                        bob_client=bob_client,
                        alice_ws_id=alice_ws_id,
                        bob_ws_id=bob_ws_id,
                        additional_users_number=additional_users_number,
                    )
                    print(" Done ")

    # Synchronize every device
    for device in (alice_device, other_alice_device, bob_device):
        async with logged_client_factory(config, device) as client:
            await client.user_fs.process_last_messages()
            await client.user_fs.sync()
    return (alice_device, other_alice_device, bob_device)
Example #16
0
 def load_slug(slug: str) -> Tuple[str, OrganizationID, DeviceID]:
     """
     Raises: ValueError
     """
     rvk_hash, raw_org_id, raw_device_id = slug.split("#")
     return rvk_hash, OrganizationID(raw_org_id), DeviceID(raw_device_id)
async def organization_bootstrap_addr(running_backend):
    org_id = OrganizationID("NewOrg")
    org_token = "123456"
    await running_backend.backend.organization.create(org_id, org_token)
    return BackendOrganizationBootstrapAddr.build(running_backend.addr, org_id, org_token)
Example #18
0
 def _from_url_parse_path(cls, path):
     return {"organization_id": OrganizationID(path[1:])}