async def test_create_certif_too_old(alice, alice_backend_sock): now = pendulum.now() # Generate a certificate realm_id = RealmID.from_hex("C0000000000000000000000000000000") certif = RealmRoleCertificateContent.build_realm_root_certif( author=alice.device_id, timestamp=now, realm_id=realm_id).dump_and_sign(alice.signing_key) # Create a realm a tiny bit too late later = now.add(seconds=BALLPARK_CLIENT_LATE_OFFSET) with freeze_time(later): rep = await realm_create(alice_backend_sock, certif) assert rep == { "status": "bad_timestamp", "backend_timestamp": later, "ballpark_client_early_offset": BALLPARK_CLIENT_EARLY_OFFSET, "ballpark_client_late_offset": BALLPARK_CLIENT_LATE_OFFSET, "client_timestamp": now, } # Create a realm late but right before the deadline later = now.add(seconds=BALLPARK_CLIENT_LATE_OFFSET, microseconds=-1) with freeze_time(later): rep = await realm_create(alice_backend_sock, certif) assert rep["status"] == "ok" # Generate a new certificate realm_id = RealmID.from_hex("C0000000000000000000000000000001") certif = RealmRoleCertificateContent.build_realm_root_certif( author=alice.device_id, timestamp=now, realm_id=realm_id).dump_and_sign(alice.signing_key) # Create a realm a tiny bit too soon sooner = now.subtract(seconds=BALLPARK_CLIENT_EARLY_OFFSET) with freeze_time(sooner): rep = await realm_create(alice_backend_sock, certif) assert rep == { "status": "bad_timestamp", "backend_timestamp": sooner, "ballpark_client_early_offset": BALLPARK_CLIENT_EARLY_OFFSET, "ballpark_client_late_offset": BALLPARK_CLIENT_LATE_OFFSET, "client_timestamp": now, } # Create a realm soon but after the limit sooner = now.subtract(seconds=BALLPARK_CLIENT_EARLY_OFFSET, microseconds=-1) with freeze_time(sooner): rep = await realm_create(alice_backend_sock, certif) assert rep["status"] == "ok"
async def test_realm_create_not_allowed_for_outsider(backend, alice, alice_backend_sock): realm_id = UUID("C0000000000000000000000000000000") certif = RealmRoleCertificateContent.build_realm_root_certif( author=alice.device_id, timestamp=pendulum.now(), realm_id=realm_id ).dump_and_sign(alice.signing_key) rep = await realm_create(alice_backend_sock, certif, check_rep=False) assert rep == {"status": "not_allowed", "reason": "Outsider user cannot create realm"}
async def test_create_invalid_certif(backend, alice, bob, alice_backend_sock): realm_id = UUID("C0000000000000000000000000000000") certif = RealmRoleCertificateContent.build_realm_root_certif( author=bob.device_id, timestamp=pendulum.now(), realm_id=realm_id ).dump_and_sign(bob.signing_key) rep = await realm_create(alice_backend_sock, certif) assert rep == { "status": "invalid_certification", "reason": "Invalid certification data (Signature was forged or corrupt).", }
async def test_realm_create(backend, alice, alice_backend_sock): await events_subscribe(alice_backend_sock) realm_id = UUID("C0000000000000000000000000000000") certif = RealmRoleCertificateContent.build_realm_root_certif( author=alice.device_id, timestamp=pendulum.now(), realm_id=realm_id ).dump_and_sign(alice.signing_key) with backend.event_bus.listen() as spy: await realm_create(alice_backend_sock, certif) await spy.wait_with_timeout("realm.roles_updated")
async def _test_create_ok(backend, device, device_backend_sock): await events_subscribe(device_backend_sock) realm_id = RealmID.from_hex("C0000000000000000000000000000000") certif = RealmRoleCertificateContent.build_realm_root_certif( author=device.device_id, timestamp=pendulum.now(), realm_id=realm_id).dump_and_sign(device.signing_key) with backend.event_bus.listen() as spy: rep = await realm_create(device_backend_sock, certif) assert rep == {"status": "ok"} await spy.wait_with_timeout(BackendEvent.REALM_ROLES_UPDATED)
async def test_create_certif_too_old(alice, alice_backend_sock): realm_id = UUID("C0000000000000000000000000000000") now = pendulum.now() certif = RealmRoleCertificateContent.build_realm_root_certif( author=alice.device_id, timestamp=now, realm_id=realm_id).dump_and_sign(alice.signing_key) with freeze_time(now.add(seconds=TIMESTAMP_MAX_DT)): rep = await realm_create(alice_backend_sock, certif) assert rep == { "status": "invalid_certification", "reason": "Invalid timestamp in certification.", }
async def create_realm(self, realm_id: EntryID): """ Raises: FSError FSBackendOfflineError """ certif = RealmRoleCertificateContent.build_realm_root_certif( author=self.device.device_id, timestamp=pendulum_now(), realm_id=realm_id).dump_and_sign(self.device.signing_key) rep = await self._backend_cmds("realm_create", certif) if rep["status"] == "already_exists": # It's possible a previous attempt to create this realm # succeeded but we didn't receive the confirmation, hence # we play idempotent here. return elif rep["status"] != "ok": raise FSError(f"Cannot create realm {realm_id}: `{rep['status']}`")
async def _realm_factory(backend, author, realm_id=None, now=None): realm_id = realm_id or uuid4() now = now or pendulum_now() certif = RealmRoleCertificateContent.build_realm_root_certif( author=author.device_id, timestamp=now, realm_id=realm_id ).dump_and_sign(author.signing_key) with backend.event_bus.listen() as spy: await backend.realm.create( organization_id=author.organization_id, self_granted_role=RealmGrantedRole( realm_id=realm_id, user_id=author.user_id, certificate=certif, role=RealmRole.OWNER, granted_by=author.device_id, granted_on=now, ), ) await spy.wait_with_timeout("realm.roles_updated") return realm_id
async def create_realm(self, realm_id: EntryID) -> None: """ Raises: FSError FSRemoteOperationError FSBackendOfflineError """ timestamp = self.device.timestamp() certif = RealmRoleCertificateContent.build_realm_root_certif( author=self.device.device_id, timestamp=timestamp, realm_id=RealmID(realm_id.uuid)).dump_and_sign( self.device.signing_key) with translate_backend_cmds_errors(): rep = await self.backend_cmds.realm_create(certif) if rep["status"] == "already_exists": # It's possible a previous attempt to create this realm # succeeded but we didn't receive the confirmation, hence # we play idempotent here. return elif rep["status"] != "ok": raise FSError(f"Cannot create realm {realm_id}: `{rep['status']}`")
async def _outbound_sync_inner(self) -> bool: base_um = self.get_user_manifest() if not base_um.need_sync: return True # Make sure the corresponding realm has been created in the backend if base_um.is_placeholder: certif = RealmRoleCertificateContent.build_realm_root_certif( author=self.device.device_id, timestamp=pendulum_now(), realm_id=self.device.user_manifest_id, ).dump_and_sign(self.device.signing_key) try: rep = await self.backend_cmds.realm_create(certif) except BackendNotAvailable as exc: raise FSBackendOfflineError(str(exc)) from exc except BackendConnectionError as exc: raise FSError(f"Cannot create user manifest's realm in backend: {exc}") from exc if rep["status"] == "already_exists": # It's possible a previous attempt to create this realm # succeeded but we didn't receive the confirmation, hence # we play idempotent here. pass elif rep["status"] != "ok": raise FSError(f"Cannot create user manifest's realm in backend: {rep}") # Sync placeholders for w in base_um.workspaces: await self._workspace_minimal_sync(w) # Build vlob now = pendulum_now() to_sync_um = base_um.to_remote(author=self.device.device_id, timestamp=now) ciphered = to_sync_um.dump_sign_and_encrypt( author_signkey=self.device.signing_key, key=self.device.user_manifest_key ) # Sync the vlob with backend try: # Note encryption_revision is always 1 given we never reencrypt # the user manifest's realm if to_sync_um.version == 1: rep = await self.backend_cmds.vlob_create( self.user_manifest_id, 1, self.user_manifest_id, now, ciphered ) else: rep = await self.backend_cmds.vlob_update( 1, self.user_manifest_id, to_sync_um.version, now, ciphered ) except BackendNotAvailable as exc: raise FSBackendOfflineError(str(exc)) from exc except BackendConnectionError as exc: raise FSError(f"Cannot sync user manifest: {exc}") from exc if rep["status"] in ("already_exists", "bad_version"): # Concurrency error (handled by the caller) return False elif rep["status"] == "in_maintenance": raise FSWorkspaceInMaintenance( f"Cannot modify workspace data while it is in maintenance: {rep}" ) elif rep["status"] != "ok": raise FSError(f"Cannot sync user manifest: {rep}") # Merge back the manifest in local async with self._update_user_manifest_lock: diverged_um = self.get_user_manifest() # Final merge could have been achieved by a concurrent operation if to_sync_um.version > diverged_um.base_version: merged_um = merge_local_user_manifests(diverged_um, to_sync_um) await self.set_user_manifest(merged_um) self.event_bus.send("fs.entry.synced", id=self.user_manifest_id) return True
async def test_create_realm_already_exists(alice, alice_backend_sock, realm): certif = RealmRoleCertificateContent.build_realm_root_certif( author=alice.device_id, timestamp=pendulum.now(), realm_id=realm).dump_and_sign(alice.signing_key) rep = await realm_create(alice_backend_sock, certif) assert rep == {"status": "already_exists"}