def test_device_certificate(): from parsec.api.data.certif import ( _RsDeviceCertificateContent, DeviceCertificateContent, _PyDeviceCertificateContent, ) assert DeviceCertificateContent is _RsDeviceCertificateContent def _assert_device_certificate_eq(py, rs): assert py.author == rs.author assert py.timestamp == rs.timestamp assert py.device_id == rs.device_id assert py.device_label == rs.device_label assert py.verify_key == rs.verify_key kwargs = { "author": DeviceID.new(), "timestamp": pendulum.now(), "device_id": DeviceID("bob@dev1"), "device_label": DeviceLabel("dev machine"), "verify_key": SigningKey.generate().verify_key, } py_dc = _PyDeviceCertificateContent(**kwargs) rs_dc = DeviceCertificateContent(**kwargs) _assert_device_certificate_eq(py_dc, rs_dc) kwargs = { "author": DeviceID.new(), "timestamp": pendulum.now(), "device_id": DeviceID("alice@dev1"), "device_label": None, "verify_key": SigningKey.generate().verify_key, } py_dc = py_dc.evolve(**kwargs) rs_dc = rs_dc.evolve(**kwargs) _assert_device_certificate_eq(py_dc, rs_dc) sign_key = SigningKey.generate() py_data = py_dc.dump_and_sign(sign_key) rs_data = rs_dc.dump_and_sign(sign_key) py_dc = _PyDeviceCertificateContent.verify_and_load( rs_data, sign_key.verify_key, expected_author=py_dc.author, expected_device=py_dc.device_id ) rs_dc = DeviceCertificateContent.verify_and_load( py_data, sign_key.verify_key, expected_author=rs_dc.author, expected_device=rs_dc.device_id ) _assert_device_certificate_eq(py_dc, rs_dc) py_dc = _PyDeviceCertificateContent.unsecure_load(rs_data) rs_dc = DeviceCertificateContent.unsecure_load(py_data) _assert_device_certificate_eq(py_dc, rs_dc)
def _create_new_user_certificates( author: LocalDevice, device_label: Optional[DeviceLabel], human_handle: Optional[HumanHandle], profile: UserProfile, public_key: PublicKey, verify_key: VerifyKey, ) -> Tuple[bytes, bytes, bytes, bytes, InviteUserConfirmation]: """Helper to prepare the creation of a new user.""" device_id = DeviceID.new() try: timestamp = author.timestamp() user_certificate = UserCertificateContent( author=author.device_id, timestamp=timestamp, user_id=device_id.user_id, human_handle=human_handle, public_key=public_key, profile=profile, ) redacted_user_certificate = user_certificate.evolve(human_handle=None) device_certificate = DeviceCertificateContent( author=author.device_id, timestamp=timestamp, device_id=device_id, device_label=device_label, verify_key=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 invite_user_confirmation = InviteUserConfirmation( device_id=device_id, device_label=device_label, human_handle=human_handle, profile=profile, root_verify_key=author.root_verify_key, ) return ( user_certificate, redacted_user_certificate, device_certificate, redacted_device_certificate, invite_user_confirmation, )
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()
async def bootstrap_organization( cmds: APIV1_BackendAnonymousCmds, human_handle: Optional[HumanHandle], device_label: Optional[str], ) -> LocalDevice: root_signing_key = SigningKey.generate() root_verify_key = root_signing_key.verify_key organization_addr = BackendOrganizationAddr.build( backend_addr=cmds.addr, organization_id=cmds.addr.organization_id, root_verify_key=root_verify_key, ) device = generate_new_device( device_id=DeviceID.new(), organization_addr=organization_addr, profile=UserProfile.ADMIN, human_handle=human_handle, device_label=device_label, ) 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.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) redacted_user_certificate = redacted_user_certificate.dump_and_sign( root_signing_key) device_certificate = device_certificate.dump_and_sign(root_signing_key) redacted_device_certificate = redacted_device_certificate.dump_and_sign( root_signing_key) await cmds.organization_bootstrap( organization_id=cmds.addr.organization_id, bootstrap_token=cmds.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, ) return device
def test_revoked_user_certificate(): from parsec.api.data.certif import ( _RsRevokedUserCertificateContent, RevokedUserCertificateContent, _PyRevokedUserCertificateContent, ) assert RevokedUserCertificateContent is _RsRevokedUserCertificateContent def _assert_revoked_user_certificate_eq(py, rs): assert py.author == rs.author assert py.timestamp == rs.timestamp assert py.user_id == rs.user_id kwargs = {"author": DeviceID.new(), "timestamp": pendulum.now(), "user_id": UserID("bob")} py_ruc = _PyRevokedUserCertificateContent(**kwargs) rs_ruc = RevokedUserCertificateContent(**kwargs) _assert_revoked_user_certificate_eq(py_ruc, rs_ruc) kwargs = {"author": DeviceID.new(), "timestamp": pendulum.now(), "user_id": UserID("alice")} py_ruc = py_ruc.evolve(**kwargs) rs_ruc = rs_ruc.evolve(**kwargs) _assert_revoked_user_certificate_eq(py_ruc, rs_ruc) sign_key = SigningKey.generate() py_data = py_ruc.dump_and_sign(sign_key) rs_data = rs_ruc.dump_and_sign(sign_key) py_ruc = _PyRevokedUserCertificateContent.verify_and_load( rs_data, sign_key.verify_key, expected_author=py_ruc.author, expected_user=py_ruc.user_id ) rs_ruc = RevokedUserCertificateContent.verify_and_load( py_data, sign_key.verify_key, expected_author=rs_ruc.author, expected_user=rs_ruc.user_id ) _assert_revoked_user_certificate_eq(py_ruc, rs_ruc) py_ruc = _PyRevokedUserCertificateContent.unsecure_load(rs_data) rs_ruc = RevokedUserCertificateContent.unsecure_load(py_data) _assert_revoked_user_certificate_eq(py_ruc, rs_ruc)
def generate_new_device( organization_addr: BackendOrganizationAddr, device_id: Optional[DeviceID] = None, profile: UserProfile = UserProfile.STANDARD, human_handle: Optional[HumanHandle] = None, device_label: Optional[DeviceLabel] = 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.new(), user_manifest_key=SecretKey.generate(), local_symkey=SecretKey.generate(), )
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)
def test_user_certificate(): from parsec.api.data.certif import ( _RsUserCertificateContent, UserCertificateContent, _PyUserCertificateContent, ) assert UserCertificateContent is _RsUserCertificateContent def _assert_user_certificate_eq(py, rs): assert py.is_admin == rs.is_admin assert py.author == rs.author assert py.timestamp == rs.timestamp assert py.user_id == rs.user_id assert py.human_handle == rs.human_handle assert py.public_key == rs.public_key assert py.profile == rs.profile kwargs = { "author": DeviceID.new(), "timestamp": pendulum.now(), "user_id": UserID("bob"), "human_handle": HumanHandle("*****@*****.**", "Boby McBobFace"), "public_key": PrivateKey.generate().public_key, "profile": UserProfile.ADMIN, } py_uc = _PyUserCertificateContent(**kwargs) rs_uc = UserCertificateContent(**kwargs) _assert_user_certificate_eq(py_uc, rs_uc) kwargs = { "author": DeviceID.new(), "timestamp": pendulum.now(), "user_id": UserID("alice"), "human_handle": None, "public_key": PrivateKey.generate().public_key, "profile": UserProfile.STANDARD, } py_uc = py_uc.evolve(**kwargs) rs_uc = rs_uc.evolve(**kwargs) _assert_user_certificate_eq(py_uc, rs_uc) sign_key = SigningKey.generate() py_data = py_uc.dump_and_sign(sign_key) rs_data = rs_uc.dump_and_sign(sign_key) py_uc = _PyUserCertificateContent.verify_and_load( rs_data, sign_key.verify_key, expected_author=py_uc.author, expected_user=py_uc.user_id, expected_human_handle=py_uc.human_handle, ) rs_uc = UserCertificateContent.verify_and_load( py_data, sign_key.verify_key, expected_author=rs_uc.author, expected_user=rs_uc.user_id, expected_human_handle=rs_uc.human_handle, ) _assert_user_certificate_eq(py_uc, rs_uc) py_uc = _PyUserCertificateContent.unsecure_load(rs_data) rs_uc = UserCertificateContent.unsecure_load(py_data) _assert_user_certificate_eq(py_uc, rs_uc)
def test_complete_scenario(): storage = Storage() with freeze_time("2000-01-01"): base = manifest = LocalFileManifest.new_placeholder( DeviceID.new(), parent=EntryID.new(), 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)