async def query_revoke_user( conn, organization_id: OrganizationID, user_id: UserID, revoked_user_certificate: bytes, revoked_user_certifier: DeviceID, revoked_on: pendulum.DateTime = None, ) -> None: result = await conn.execute(*_q_revoke_user( organization_id=organization_id, user_id=user_id, revoked_user_certificate=revoked_user_certificate, revoked_user_certifier=revoked_user_certifier, revoked_on=revoked_on or pendulum.now(), )) if result != "UPDATE 1": # TODO: avoid having to do another query to find the error err_result = await conn.fetchrow(*_q_revoke_user_error( organization_id=organization_id, user_id=user_id)) if not err_result: raise UserNotFoundError(user_id) elif err_result[0]: raise UserAlreadyRevokedError() else: raise UserError(f"Update error: {result}") else: await send_signal(conn, BackendEvent.USER_REVOKED, organization_id=organization_id, user_id=user_id)
async def _get_user(conn, organization_id: OrganizationID, user_id: UserID) -> User: row = await conn.fetchrow( *_q_get_user(organization_id=organization_id, user_id=user_id)) if not row: raise UserNotFoundError(user_id) if row["human_email"]: human_handle = HumanHandle(email=row["human_email"], label=row["human_label"]) else: human_handle = None return User( user_id=user_id, human_handle=human_handle, profile=STR_TO_USER_PROFILE[row["profile"]], user_certificate=row["user_certificate"], redacted_user_certificate=row["redacted_user_certificate"], user_certifier=row["user_certifier"], created_on=row["created_on"], revoked_on=row["revoked_on"], revoked_user_certificate=row["revoked_user_certificate"], revoked_user_certifier=row["revoked_user_certifier"], )
async def revoke_user( self, organization_id: OrganizationID, user_id: UserID, revoked_user_certificate: bytes, revoked_user_certifier: DeviceID, revoked_on: pendulum.DateTime = None, ) -> None: org = self._organizations[organization_id] try: user = org.users[user_id] except KeyError: raise UserNotFoundError(user_id) if user.revoked_on: raise UserAlreadyRevokedError() org.users[user_id] = user.evolve( revoked_on=revoked_on or pendulum.now(), revoked_user_certificate=revoked_user_certificate, revoked_user_certifier=revoked_user_certifier, ) if user.human_handle: del org.human_handle_to_user_id[user.human_handle] await self._send_event(BackendEvent.USER_REVOKED, organization_id=organization_id, user_id=user_id)
async def _create_device(conn, organization_id: OrganizationID, device: Device, first_device: bool = False) -> None: if not first_device: existing_devices = await conn.fetch(*_q_get_user_devices( organization_id=organization_id, user_id=device.user_id)) if not existing_devices: raise UserNotFoundError(f"User `{device.user_id}` doesn't exists") if device.device_id in itertools.chain(*existing_devices): raise UserAlreadyExistsError( f"Device `{device.device_id}` already exists") try: result = await conn.execute(*_q_insert_device( organization_id=organization_id, user_id=device.user_id, device_id=device.device_id, device_label=device.device_label, device_certificate=device.device_certificate, redacted_device_certificate=device.redacted_device_certificate, device_certifier=device.device_certifier, created_on=device.created_on, )) except UniqueViolationError: raise UserAlreadyExistsError( f"Device `{device.device_id}` already exists") if result != "INSERT 0 1": raise UserError(f"Insertion error: {result}")
def _get_device(self, organization_id: OrganizationID, device_id: DeviceID) -> Device: org = self._organizations[organization_id] try: return org.devices[device_id.user_id][device_id.device_name] except KeyError: raise UserNotFoundError(device_id)
def _get_user(self, organization_id: OrganizationID, user_id: UserID) -> User: org = self._organizations[organization_id] try: return org.users[user_id] except KeyError: raise UserNotFoundError(user_id)
async def get_user_invitation(self, organization_id: OrganizationID, user_id: UserID) -> UserInvitation: org = self._organizations[organization_id] if user_id in org.users: raise UserAlreadyExistsError(user_id) try: return org.invitations[user_id] except KeyError: raise UserNotFoundError(user_id)
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"])
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"] )
async def get_device_invitation(self, organization_id: OrganizationID, device_id: DeviceID) -> DeviceInvitation: org = self._organizations[organization_id] user_devices = self._get_user_devices(organization_id, device_id.user_id) if device_id.device_name in user_devices: raise UserAlreadyExistsError(device_id) try: return org.invitations[device_id] except KeyError: raise UserNotFoundError(device_id)
async def _get_device(conn, organization_id: OrganizationID, device_id: DeviceID) -> Device: row = await conn.fetchrow( *_q_get_device(organization_id=organization_id, device_id=device_id)) if not row: raise UserNotFoundError(device_id) return Device( device_id=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"], )
async def create_device(self, organization_id: OrganizationID, device: Device, encrypted_answer: bytes = b"") -> None: org = self._organizations[organization_id] if device.user_id not in org.users: raise UserNotFoundError(f"User `{device.user_id}` doesn't exists") user_devices = org.devices[device.user_id] if device.device_name in user_devices: raise UserAlreadyExistsError( f"Device `{device.device_id}` already exists") user_devices[device.device_name] = device
async def query_get_user_with_device( conn, organization_id: OrganizationID, device_id: DeviceID) -> Tuple[User, Device]: d_row = await conn.fetchrow( *_q_get_device(organization_id=organization_id, device_id=device_id)) u_row = await conn.fetchrow(*_q_get_user(organization_id=organization_id, user_id=device_id.user_id)) if not u_row or not d_row: raise UserNotFoundError(device_id) if u_row["human_email"]: human_handle = HumanHandle(email=u_row["human_email"], label=u_row["human_label"]) else: human_handle = None device = Device( device_id=device_id, device_label=d_row["device_label"], device_certificate=d_row["device_certificate"], redacted_device_certificate=d_row["redacted_device_certificate"], device_certifier=d_row["device_certifier"], created_on=d_row["created_on"], ) user = User( user_id=device_id.user_id, human_handle=human_handle, profile=STR_TO_USER_PROFILE[u_row["profile"]], user_certificate=u_row["user_certificate"], redacted_user_certificate=u_row["redacted_user_certificate"], user_certifier=u_row["user_certifier"], created_on=u_row["created_on"], revoked_on=u_row["revoked_on"], revoked_user_certificate=u_row["revoked_user_certificate"], revoked_user_certifier=u_row["revoked_user_certifier"], ) return user, device