def test_merge_folder_manifests():
    my_device = DeviceID("b@b")
    other_device = DeviceID("a@a")
    parent = EntryID()
    v1 = LocalFolderManifest.new_placeholder(
        my_device, parent=parent).to_remote(author=other_device)

    # Initial base manifest
    m1 = LocalFolderManifest.from_remote(v1, empty_filter)
    assert merge_manifests(my_device, empty_filter, m1) == m1

    # Local change
    m2 = m1.evolve_children_and_mark_updated({"a": EntryID()}, empty_filter)
    assert merge_manifests(my_device, empty_filter, m2) == m2

    # Successful upload
    v2 = m2.to_remote(author=my_device)
    m3 = merge_manifests(my_device, empty_filter, m2, v2)
    assert m3 == LocalFolderManifest.from_remote(v2, empty_filter)

    # Two local changes
    m4 = m3.evolve_children_and_mark_updated({"b": EntryID()}, empty_filter)
    assert merge_manifests(my_device, empty_filter, m4) == m4
    m5 = m4.evolve_children_and_mark_updated({"c": EntryID()}, empty_filter)
    assert merge_manifests(my_device, empty_filter, m4) == m4

    # M4 has been successfully uploaded
    v3 = m4.to_remote(author=my_device)
    m6 = merge_manifests(my_device, empty_filter, m5, v3)
    assert m6 == m5.evolve(base=v3)

    # The remote has changed
    v4 = v3.evolve(version=4,
                   children={
                       "d": EntryID(),
                       **v3.children
                   },
                   author=other_device)
    m7 = merge_manifests(my_device, empty_filter, m6, v4)
    assert m7.base_version == 4
    assert sorted(m7.children) == ["a", "b", "c", "d"]
    assert m7.need_sync

    # Successful upload
    v5 = m7.to_remote(author=my_device)
    m8 = merge_manifests(my_device, empty_filter, m7, v5)
    assert m8 == LocalFolderManifest.from_remote(v5, empty_filter)

    # The remote has changed
    v6 = v5.evolve(version=6,
                   children={
                       "e": EntryID(),
                       **v5.children
                   },
                   author=other_device)
    m9 = merge_manifests(my_device, empty_filter, m8, v6)
    assert m9 == LocalFolderManifest.from_remote(v6, empty_filter)
Esempio n. 2
0
async def test_path_info_remote_loader_exceptions(monkeypatch, alice_workspace,
                                                  alice):
    manifest, _ = await alice_workspace.transactions._get_manifest_from_path(
        FsPath("/foo/bar"))
    async with alice_workspace.local_storage.lock_entry_id(manifest.id):
        await alice_workspace.local_storage.clear_manifest(manifest.id)

    vanilla_file_manifest_deserialize = BaseRemoteManifest._deserialize

    def mocked_file_manifest_deserialize(*args, **kwargs):
        return vanilla_file_manifest_deserialize(
            *args, **kwargs).evolve(**manifest_modifiers)

    monkeypatch.setattr(BaseRemoteManifest, "_deserialize",
                        mocked_file_manifest_deserialize)

    manifest_modifiers = {"id": EntryID()}
    with pytest.raises(FSError) as exc:
        await alice_workspace.path_info(FsPath("/foo/bar"))
    assert f"Invalid entry ID: expected `{manifest.id}`, got `{manifest_modifiers['id']}`" in str(
        exc.value)

    manifest_modifiers = {"version": 4}
    with pytest.raises(FSError) as exc:
        await alice_workspace.path_info(FsPath("/foo/bar"))
    assert "Invalid version: expected `1`, got `4`" in str(exc.value)

    manifest_modifiers = {"author": DeviceID("mallory@pc1")}
    with pytest.raises(FSError) as exc:
        await alice_workspace.path_info(FsPath("/foo/bar"))
    assert "Invalid author: expected `alice@dev1`, got `mallory@pc1`" in str(
        exc.value)
Esempio n. 3
0
 def __init__(self) -> None:
     super().__init__()
     self.oracle = open(tmpdir / "oracle.txt", "w+b")
     self.manifest = LocalFileManifest.new_placeholder(
         DeviceID.new(), parent=EntryID(), blocksize=8
     )
     self.storage = Storage()
Esempio n. 4
0
    def _from_url_parse_and_consume_params(cls, params):
        kwargs = super()._from_url_parse_and_consume_params(params)

        value = params.pop("action", ())
        if len(value) != 1:
            raise ValueError("Missing mandatory `action` param")
        if value[0] != "claim_device":
            raise ValueError("Expected `action=claim_device` value")

        value = params.pop("device_id", ())
        if len(value) != 1:
            raise ValueError("Missing mandatory `device_id` param")
        try:
            kwargs["device_id"] = DeviceID(value[0])
        except ValueError as exc:
            raise ValueError("Invalid `device_id` param value") from exc

        value = params.pop("token", ())
        if len(value) > 0:
            try:
                kwargs["token"] = value[0]
            except ValueError:
                raise ValueError("Invalid `token` param value")

        return kwargs
Esempio n. 5
0
 def validate(self, string, pos):
     try:
         if len(string) == 0:
             return QValidator.Intermediate, string, pos
         DeviceID(string)
         return QValidator.Acceptable, string, pos
     except ValueError:
         return QValidator.Invalid, string, pos
Esempio n. 6
0
 async def get(self, organization_id: OrganizationID, recipient: UserID,
               offset: int) -> List[Tuple[DeviceID, DateTime, bytes]]:
     async with self.dbh.pool.acquire() as conn:
         data = await conn.fetch(
             *_q_get_messages(organization_id=organization_id,
                              recipient=recipient,
                              offset=offset))
     return [(DeviceID(d[0]), d[1], d[2]) for d in data]
def test_merge_file_manifests():
    my_device = DeviceID("b@b")
    other_device = DeviceID("a@a")
    parent = EntryID()
    v1 = LocalFileManifest.new_placeholder(
        my_device, parent=parent).to_remote(author=other_device)

    def evolve(m, n):
        chunk = Chunk.new(0, n).evolve_as_block(b"a" * n)
        blocks = ((chunk, ), )
        return m1.evolve_and_mark_updated(size=n, blocks=blocks)

    # Initial base manifest
    m1 = LocalFileManifest.from_remote(v1)
    assert merge_manifests(my_device, empty_filter, m1) == m1

    # Local change
    m2 = evolve(m1, 1)
    assert merge_manifests(my_device, empty_filter, m2) == m2

    # Successful upload
    v2 = m2.to_remote(author=my_device)
    m3 = merge_manifests(my_device, empty_filter, m2, v2)
    assert m3 == LocalFileManifest.from_remote(v2)

    # Two local changes
    m4 = evolve(m3, 2)
    assert merge_manifests(my_device, empty_filter, m4) == m4
    m5 = evolve(m4, 3)
    assert merge_manifests(my_device, empty_filter, m4) == m4

    # M4 has been successfully uploaded
    v3 = m4.to_remote(author=my_device)
    m6 = merge_manifests(my_device, empty_filter, m5, v3)
    assert m6 == m5.evolve(base=v3)

    # The remote has changed
    v4 = v3.evolve(version=4, size=0, author=other_device)
    with pytest.raises(FSFileConflictError):
        merge_manifests(my_device, empty_filter, m6, v4)
def test_merge_manifests_with_a_placeholder():
    my_device = DeviceID("b@b")
    other_device = DeviceID("a@a")
    parent = EntryID()

    m1 = LocalFolderManifest.new_placeholder(my_device, parent=parent)
    m2 = merge_manifests(my_device, empty_filter, m1)
    assert m2 == m1
    v1 = m1.to_remote(author=my_device)

    m2a = merge_manifests(my_device, empty_filter, m1, v1)
    assert m2a == LocalFolderManifest.from_remote(v1, empty_filter)

    m2b = m1.evolve_children_and_mark_updated({"a": EntryID()}, empty_filter)
    m3b = merge_manifests(my_device, empty_filter, m2b, v1)
    assert m3b == m2b.evolve(base=v1)

    v2 = v1.evolve(version=2, author=other_device, children={"b": EntryID()})
    m2c = m1.evolve_children_and_mark_updated({"a": EntryID()}, empty_filter)
    m3c = merge_manifests(my_device, empty_filter, m2c, v2)
    children = {**v2.children, **m2c.children}
    assert m3c == m2c.evolve(base=v2, children=children, updated=m3c.updated)
Esempio n. 9
0
async def _get_user_invitation(conn, organization_id: OrganizationID, user_id: UserID):
    if await _user_exists(conn, organization_id, user_id):
        raise UserAlreadyExistsError(f"User `{user_id}` already exists")

    result = await conn.fetchrow(
        *_q_get_invitation(organization_id=organization_id, user_id=user_id)
    )
    if not result:
        raise UserNotFoundError(user_id)

    return UserInvitation(
        user_id=user_id, creator=DeviceID(result["creator"]), created_on=result["created_on"]
    )
Esempio n. 10
0
async def _get_device_invitation(conn, organization_id: OrganizationID,
                                 device_id: DeviceID) -> DeviceInvitation:
    if await _device_exists(conn, organization_id, device_id):
        raise UserAlreadyExistsError(f"Device `{device_id}` already exists")

    result = await conn.fetchrow(*_q_get_invitation(
        organization_id=organization_id, device_id=device_id))
    if not result:
        raise UserNotFoundError(device_id)

    return DeviceInvitation(device_id=device_id,
                            creator=DeviceID(result["creator"]),
                            created_on=result["created_on"])
Esempio n. 11
0
async def _get_user_devices(conn, organization_id: OrganizationID,
                            user_id: UserID) -> Tuple[Device]:
    results = await conn.fetch(
        *_q_get_user_devices(organization_id=organization_id, user_id=user_id))

    return tuple(
        Device(
            device_id=DeviceID(row["device_id"]),
            device_label=row["device_label"],
            device_certificate=row["device_certificate"],
            redacted_device_certificate=row["redacted_device_certificate"],
            device_certifier=row["device_certifier"],
            created_on=row["created_on"],
        ) for row in results)
Esempio n. 12
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]
Esempio n. 13
0
async def test_user_create_human_handle_with_revoked_previous_one(
        alice_backend_sock, alice, bob, backend_data_binder):
    # First revoke bob
    await backend_data_binder.bind_revocation(user_id=bob.user_id,
                                              certifier=alice)

    # Now recreate another user with bob's human handle
    now = pendulum.now()
    bob2_device_id = DeviceID("bob2@dev1")
    user_certificate = UserCertificateContent(
        author=alice.device_id,
        timestamp=now,
        user_id=bob2_device_id.user_id,
        human_handle=bob.human_handle,
        public_key=bob.public_key,
        profile=UserProfile.STANDARD,
    )
    redacted_user_certificate = user_certificate.evolve(human_handle=None)
    device_certificate = DeviceCertificateContent(
        author=alice.device_id,
        timestamp=now,
        device_id=bob2_device_id,
        device_label=bob.
        device_label,  # Device label doesn't have to be unique
        verify_key=bob.verify_key,
    )
    redacted_device_certificate = device_certificate.evolve(device_label=None)

    user_certificate = user_certificate.dump_and_sign(alice.signing_key)
    redacted_user_certificate = redacted_user_certificate.dump_and_sign(
        alice.signing_key)
    device_certificate = device_certificate.dump_and_sign(alice.signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(
        alice.signing_key)

    rep = await user_create(
        alice_backend_sock,
        user_certificate=user_certificate,
        device_certificate=device_certificate,
        redacted_user_certificate=redacted_user_certificate,
        redacted_device_certificate=redacted_device_certificate,
    )
    assert rep == {"status": "ok"}
Esempio n. 14
0
async def test_user_create_human_handle_already_exists(alice_backend_sock,
                                                       alice, bob):
    now = pendulum.now()
    bob2_device_id = DeviceID("bob2@dev1")
    user_certificate = UserCertificateContent(
        author=alice.device_id,
        timestamp=now,
        user_id=bob2_device_id.user_id,
        human_handle=bob.human_handle,
        public_key=bob.public_key,
        profile=UserProfile.STANDARD,
    )
    redacted_user_certificate = user_certificate.evolve(human_handle=None)
    device_certificate = DeviceCertificateContent(
        author=alice.device_id,
        timestamp=now,
        device_id=bob2_device_id,
        device_label="dev2",
        verify_key=bob.verify_key,
    )
    redacted_device_certificate = device_certificate.evolve(device_label=None)

    user_certificate = user_certificate.dump_and_sign(alice.signing_key)
    redacted_user_certificate = redacted_user_certificate.dump_and_sign(
        alice.signing_key)
    device_certificate = device_certificate.dump_and_sign(alice.signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(
        alice.signing_key)

    rep = await user_create(
        alice_backend_sock,
        user_certificate=user_certificate,
        device_certificate=device_certificate,
        redacted_user_certificate=redacted_user_certificate,
        redacted_device_certificate=redacted_device_certificate,
    )
    assert rep == {
        "status":
        "already_exists",
        "reason":
        f"Human handle `{bob.human_handle}` already corresponds to a non-revoked user",
    }
Esempio n. 15
0
def generate_new_device(
    organization_addr: BackendOrganizationAddr,
    profile: UserProfile = UserProfile.STANDARD,
    device_id: Optional[DeviceID] = None,
    human_handle: Optional[HumanHandle] = None,
    device_label: Optional[str] = None,
    signing_key: Optional[SigningKey] = None,
    private_key: Optional[PrivateKey] = None,
) -> LocalDevice:
    return LocalDevice(
        organization_addr=organization_addr,
        device_id=device_id or DeviceID.new(),
        device_label=device_label,
        human_handle=human_handle,
        signing_key=signing_key or SigningKey.generate(),
        private_key=private_key or PrivateKey.generate(),
        profile=profile,
        user_manifest_id=EntryID(),
        user_manifest_key=SecretKey.generate(),
        local_symkey=SecretKey.generate(),
    )
Esempio n. 16
0
async def _register_new_device(cmds: BackendAuthenticatedCmds,
                               author: LocalDevice,
                               device_label: Optional[str]):
    new_device = LocalDevice(
        organization_addr=author.organization_addr,
        device_id=DeviceID(f"{author.user_id}@{DeviceName.new()}"),
        device_label=device_label,
        human_handle=author.human_handle,
        profile=author.profile,
        private_key=author.private_key,
        signing_key=SigningKey.generate(),
        user_manifest_id=author.user_manifest_id,
        user_manifest_key=author.user_manifest_key,
        local_symkey=author.local_symkey,
    )
    now = pendulum_now()

    device_certificate = DeviceCertificateContent(
        author=author.device_id,
        timestamp=now,
        device_id=new_device.device_id,
        device_label=new_device.device_label,
        verify_key=new_device.verify_key,
    )
    redacted_device_certificate = device_certificate.evolve(device_label=None)

    device_certificate = device_certificate.dump_and_sign(author.signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(
        author.signing_key)

    rep = await cmds.device_create(
        device_certificate=device_certificate,
        redacted_device_certificate=redacted_device_certificate,
    )

    if rep["status"] != "ok":
        raise RuntimeError(f"Cannot create device: {rep}")

    return new_device
Esempio n. 17
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]
Esempio n. 18
0
def test_device_id(raw):
    user_id, device_name = raw.split("@")
    device_id = DeviceID(raw)
    assert device_id == raw
    assert device_id.user_id == user_id
    assert device_id.device_name == device_name
Esempio n. 19
0
def test_complete_scenario():
    storage = Storage()

    with freeze_time("2000-01-01"):
        base = manifest = LocalFileManifest.new_placeholder(
            DeviceID.new(), parent=EntryID(), blocksize=16
        )
        assert manifest == base.evolve(size=0)

    with freeze_time("2000-01-02") as t2:
        manifest = storage.write(manifest, b"Hello ", 0)
        assert storage.read(manifest, 6, 0) == b"Hello "

    ((chunk0,),) = manifest.blocks
    assert manifest == base.evolve(size=6, blocks=((chunk0,),), updated=t2)
    assert chunk0 == Chunk(id=chunk0.id, start=0, stop=6, raw_offset=0, raw_size=6, access=None)
    assert storage[chunk0.id] == b"Hello "

    with freeze_time("2000-01-03") as t3:
        manifest = storage.write(manifest, b"world !", 6)
        assert storage.read(manifest, 13, 0) == b"Hello world !"

    ((_, chunk1),) = manifest.blocks
    assert manifest == base.evolve(size=13, blocks=((chunk0, chunk1),), updated=t3)
    assert chunk1 == Chunk(id=chunk1.id, start=6, stop=13, raw_offset=6, raw_size=7, access=None)
    assert storage[chunk1.id] == b"world !"

    with freeze_time("2000-01-04") as t4:
        manifest = storage.write(manifest, b"\n More kontent", 13)
        assert storage.read(manifest, 27, 0) == b"Hello world !\n More kontent"

    (_, _, chunk2), (chunk3,) = manifest.blocks
    assert storage[chunk2.id] == b"\n M"
    assert storage[chunk3.id] == b"ore kontent"
    assert manifest == base.evolve(
        size=27, blocks=((chunk0, chunk1, chunk2), (chunk3,)), updated=t4
    )

    with freeze_time("2000-01-05") as t5:
        manifest = storage.write(manifest, b"c", 20)
        assert storage.read(manifest, 27, 0) == b"Hello world !\n More content"

    chunk4, chunk5, chunk6 = manifest.blocks[1]
    assert chunk3.id == chunk4.id == chunk6.id
    assert storage[chunk5.id] == b"c"
    assert manifest == base.evolve(
        size=27, blocks=((chunk0, chunk1, chunk2), (chunk4, chunk5, chunk6)), updated=t5
    )

    with freeze_time("2000-01-06") as t6:
        manifest = storage.resize(manifest, 40)
        expected = b"Hello world !\n More content" + b"\x00" * 13
        assert storage.read(manifest, 40, 0) == expected

    (_, _, _, chunk7), (chunk8,) = manifest.blocks[1:]
    assert storage[chunk7.id] == b"\x00" * 5
    assert storage[chunk8.id] == b"\x00" * 8
    assert manifest == base.evolve(
        size=40,
        blocks=((chunk0, chunk1, chunk2), (chunk4, chunk5, chunk6, chunk7), (chunk8,)),
        updated=t6,
    )

    with freeze_time("2000-01-07") as t7:
        manifest = storage.resize(manifest, 25)
        expected = b"Hello world !\n More conte"
        assert storage.read(manifest, 25, 0) == expected

    ((_, _, chunk9),) = manifest.blocks[1:]
    assert chunk9.id == chunk6.id
    assert manifest == base.evolve(
        size=25, blocks=((chunk0, chunk1, chunk2), (chunk4, chunk5, chunk9)), updated=t7
    )

    with freeze_time("2000-01-08"):
        assert not manifest.is_reshaped()
        manifest = storage.reshape(manifest)
        expected = b"Hello world !\n More conte"
        assert storage.read(manifest, 25, 0) == expected
        assert manifest.is_reshaped()

    (chunk10,), (chunk11,) = manifest.blocks
    assert storage[chunk10.id] == b"Hello world !\n M"
    assert storage[chunk11.id] == b"ore conte"
    assert manifest == base.evolve(size=25, blocks=((chunk10,), (chunk11,)), updated=t7)
Esempio n. 20
0
def test_bad_device_id(raw):
    with pytest.raises(ValueError):
        DeviceID(raw)
Esempio n. 21
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)
Esempio n. 22
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(
            org_addr,
            profile,
            device_id=device_id,
            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
Esempio n. 23
0
            "parsec://foo:42/org?action=claim_user&user_id=alice&token=123&rvk=dummy",
            "Invalid `rvk` param value",
        ),
    ],
)
def test_backend_organization_claim_user_addr_bad_value(
        url, exc_msg, exported_verify_key):
    url = url.replace("<rvk>", exported_verify_key)
    with pytest.raises(ValueError) as exc:
        BackendOrganizationClaimUserAddr.from_url(url)
    assert str(exc.value) == exc_msg


@pytest.mark.parametrize(
    "device_id,token",
    [(DeviceID("alice@dev"), "123"),
     (DeviceID("alice@dev"), None)],  # Token is not mandatory
)
def test_backend_organization_claim_device_addr_good(organization_addr,
                                                     device_id, token):
    addr = BackendOrganizationClaimDeviceAddr.build(organization_addr,
                                                    device_id, token)

    assert addr.hostname == organization_addr.hostname
    assert addr.port == organization_addr.port
    assert addr.use_ssl == organization_addr.use_ssl
    assert addr.organization_id == organization_addr.organization_id
    assert addr.root_verify_key == organization_addr.root_verify_key

    assert isinstance(addr.device_id, DeviceID)
    assert addr.device_id == device_id
Esempio n. 24
0
    async def do_create_new_user(
        self,
        author: LocalDevice,
        device_label: Optional[str],
        human_handle: Optional[HumanHandle],
        profile: UserProfile,
    ) -> None:
        device_id = DeviceID.new()
        try:
            now = pendulum_now()

            user_certificate = UserCertificateContent(
                author=author.device_id,
                timestamp=now,
                user_id=device_id.user_id,
                human_handle=human_handle,
                public_key=self._public_key,
                profile=profile,
            )
            redacted_user_certificate = user_certificate.evolve(
                human_handle=None)

            device_certificate = DeviceCertificateContent(
                author=author.device_id,
                timestamp=now,
                device_id=device_id,
                device_label=device_label,
                verify_key=self._verify_key,
            )
            redacted_device_certificate = device_certificate.evolve(
                device_label=None)

            user_certificate = user_certificate.dump_and_sign(
                author.signing_key)
            redacted_user_certificate = redacted_user_certificate.dump_and_sign(
                author.signing_key)
            device_certificate = device_certificate.dump_and_sign(
                author.signing_key)
            redacted_device_certificate = redacted_device_certificate.dump_and_sign(
                author.signing_key)

        except DataError as exc:
            raise InviteError(
                f"Cannot generate device certificate: {exc}") from exc

        rep = await self._cmds.user_create(
            user_certificate=user_certificate,
            device_certificate=device_certificate,
            redacted_user_certificate=redacted_user_certificate,
            redacted_device_certificate=redacted_device_certificate,
        )
        if rep["status"] != "ok":
            raise InviteError(f"Cannot create device: {rep}")

        try:
            payload = InviteUserConfirmation(
                device_id=device_id,
                device_label=device_label,
                human_handle=human_handle,
                profile=profile,
                root_verify_key=author.root_verify_key,
            ).dump_and_encrypt(key=self._shared_secret_key)
        except DataError as exc:
            raise InviteError(
                "Cannot generate InviteUserConfirmation payload") from exc

        rep = await self._cmds.invite_4_greeter_communicate(token=self.token,
                                                            payload=payload)
        _check_rep(rep, step_name="step 4 (confirmation exchange)")

        await self._cmds.invite_delete(token=self.token,
                                       reason=InvitationDeletedReason.FINISHED)
Esempio n. 25
0
def test_max_bytes_size_device_id(data):
    with pytest.raises(ValueError):
        DeviceID(data)
Esempio n. 26
0
def test_good_pattern_device_id(data):
    DeviceID(data)
Esempio n. 27
0
from guardata.types import UUID4
from guardata.crypto import SecretKey, HashDigest
from guardata.serde import fields, validate, post_load, OneOfSchema, pre_load
from guardata.api.protocol import RealmRole, RealmRoleField, DeviceID
from guardata.api.data.base import (
    BaseData,
    BaseSchema,
    BaseAPISignedData,
    BaseSignedDataSchema,
    DataValidationError,
)
from guardata.api.data.entry import EntryID, EntryIDField, EntryName, EntryNameField
from enum import Enum

LOCAL_AUTHOR_LEGACY_PLACEHOLDER = DeviceID(
    "LOCAL_AUTHOR_LEGACY_PLACEHOLDER@LOCAL_AUTHOR_LEGACY_PLACEHOLDER")


class BlockID(UUID4):
    pass


BlockIDField = fields.uuid_based_field_factory(BlockID)


class ManifestType(Enum):
    FILE_MANIFEST = "file_manifest"
    FOLDER_MANIFEST = "folder_manifest"
    WORKSPACE_MANIFEST = "workspace_manifest"
    USER_MANIFEST = "user_manifest"