예제 #1
0
 async def get_user_devices_info(self, user_id: UserID = None) -> List[DeviceInfo]:
     """
     Raises:
         BackendConnectionError
     """
     user_id = user_id or self.device.user_id
     try:
         user_certif, revoked_user_certif, device_certifs = await self._remote_devices_manager.get_user_and_devices(
             user_id, no_cache=True
         )
     except RemoteDevicesManagerBackendOfflineError as exc:
         raise BackendNotAvailable(str(exc)) from exc
     except RemoteDevicesManagerNotFoundError as exc:
         raise BackendNotFoundError(str(exc)) from exc
     except RemoteDevicesManagerError as exc:
         # TODO: we should be using our own kind of exception instead of borowing BackendConnectionError...
         raise BackendConnectionError(
             f"Error while fetching user {user_id} certificates"
         ) from exc
     results = []
     for device_certif in device_certifs:
         results.append(
             DeviceInfo(
                 device_id=device_certif.device_id,
                 device_label=device_certif.device_label,
                 created_on=device_certif.timestamp,
             )
         )
     return results
예제 #2
0
 async def find_humans(
     self,
     query: str = None,
     page: int = 1,
     per_page: int = 100,
     omit_revoked: bool = False,
     omit_non_human: bool = False,
 ) -> Tuple[List[UserInfo], int]:
     """
     Raises:
         BackendConnectionError
     """
     rep = await self._backend_conn.cmds.human_find(
         query=query,
         page=page,
         per_page=per_page,
         omit_revoked=omit_revoked,
         omit_non_human=omit_non_human,
     )
     if rep["status"] != "ok":
         raise BackendConnectionError(f"Backend error: {rep}")
     results = []
     for item in rep["results"]:
         # Note `BackendNotFoundError` should never occurs (unless backend is broken !)
         # here given we are feeding the backend the user IDs it has provided us
         user_info = await self.get_user_info(item["user_id"])
         results.append(user_info)
     return (results, rep["total"])
예제 #3
0
 async def find_humans(
     self,
     query: str = None,
     page: int = 1,
     per_page: int = 100,
     omit_revoked: bool = False,
     omit_non_human: bool = False,
 ) -> Tuple[List[UserInfo], int]:
     """
     Raises:
         BackendConnectionError
     """
     rep = await self._backend_conn.cmds.human_find(
         query=query,
         page=page,
         per_page=per_page,
         omit_revoked=omit_revoked,
         omit_non_human=omit_non_human,
     )
     if rep["status"] != "ok":
         raise BackendConnectionError(f"Backend error: {rep}")
     results = []
     for item in rep["results"]:
         user_info = await self.get_user_info(item["user_id"])
         results.append(user_info)
     return (results, rep["total"])
예제 #4
0
    async def new_device_invitation(
        self, send_email: bool
    ) -> Tuple[BackendInvitationAddr, InvitationEmailSentStatus]:
        """
        Raises:
            BackendConnectionError
        """
        rep = await self._backend_conn.cmds.invite_new(
            type=InvitationType.DEVICE, send_email=send_email)
        if rep["status"] != "ok":
            raise BackendConnectionError(f"Backend error: {rep}")

        if not ("email_sent" in rep):
            email_sent = InvitationEmailSentStatus.SUCCESS
        else:
            email_sent = rep["email_sent"]

        return (
            BackendInvitationAddr.build(
                backend_addr=self.device.organization_addr.get_backend_addr(),
                organization_id=self.device.organization_id,
                invitation_type=InvitationType.DEVICE,
                token=rep["token"],
            ),
            email_sent,
        )
예제 #5
0
    async def new_user_invitation(
        self, email: str, send_email: bool
    ) -> Tuple[BackendInvitationAddr, InvitationEmailSentStatus]:
        """
        Raises:
            BackendConnectionError
        """
        rep = await self._backend_conn.cmds.invite_new(
            type=InvitationType.USER,
            claimer_email=email,
            send_email=send_email)
        if rep["status"] == "already_member":
            raise BackendInvitationOnExistingMember(
                "An user already exist with this email")
        elif rep["status"] != "ok":
            raise BackendConnectionError(f"Backend error: {rep}")

        if not ("email_sent" in rep):
            email_sent = InvitationEmailSentStatus.SUCCESS
        else:
            email_sent = rep["email_sent"]

        return (
            BackendInvitationAddr.build(
                backend_addr=self.device.organization_addr.get_backend_addr(),
                organization_id=self.device.organization_id,
                invitation_type=InvitationType.USER,
                token=rep["token"],
            ),
            email_sent,
        )
예제 #6
0
 async def list_invitations(self) -> List[dict]:  # TODO: better return type
     """
     Raises:
         BackendConnectionError
     """
     rep = await self._backend_conn.cmds.invite_list()
     if rep["status"] != "ok":
         raise BackendConnectionError(f"Backend error: {rep}")
     return rep["invitations"]
예제 #7
0
 async def delete_invitation(
     self, token: UUID, reason: InvitationDeletedReason = InvitationDeletedReason.CANCELLED
 ) -> None:
     """
     Raises:
         BackendConnectionError
     """
     rep = await self._backend_conn.cmds.invite_delete(token=token, reason=reason)
     if rep["status"] != "ok":
         raise BackendConnectionError(f"Backend error: {rep}")
예제 #8
0
 async def get_organization_stats(self) -> OrganizationStats:
     """
     Raises:
         BackendConnectionError
     """
     rep = await self._backend_conn.cmds.organization_stats()
     if rep["status"] != "ok":
         raise BackendConnectionError(f"Backend error: {rep}")
     return OrganizationStats(
         users=rep["users"], data_size=rep["data_size"], metadata_size=rep["metadata_size"]
     )
예제 #9
0
async def _create_new_device_for_self(
        original_device: LocalDevice,
        new_device_label: DeviceLabel) -> LocalDevice:
    """
    Raises:
        BackendConnectionError
    """
    new_device = LocalDevice(
        organization_addr=original_device.organization_addr,
        device_id=DeviceID(f"{original_device.user_id}@{DeviceName.new()}"),
        device_label=new_device_label,
        human_handle=original_device.human_handle,
        profile=original_device.profile,
        private_key=original_device.private_key,
        signing_key=SigningKey.generate(),
        user_manifest_id=original_device.user_manifest_id,
        user_manifest_key=original_device.user_manifest_key,
        local_symkey=SecretKey.generate(),
    )
    now = pendulum_now()

    device_certificate = DeviceCertificateContent(
        author=original_device.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(
        original_device.signing_key)
    redacted_device_certificate = redacted_device_certificate.dump_and_sign(
        original_device.signing_key)

    async with backend_authenticated_cmds_factory(
            addr=original_device.organization_addr,
            device_id=original_device.device_id,
            signing_key=original_device.signing_key,
    ) as cmds:
        rep = await cmds.device_create(
            device_certificate=device_certificate,
            redacted_device_certificate=redacted_device_certificate,
        )

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

    return new_device
예제 #10
0
 async def new_device_invitation(self, send_email: bool) -> BackendInvitationAddr:
     """
     Raises:
         BackendConnectionError
     """
     rep = await self._backend_conn.cmds.invite_new(
         type=InvitationType.DEVICE, send_email=send_email
     )
     if rep["status"] != "ok":
         raise BackendConnectionError(f"Backend error: {rep}")
     return BackendInvitationAddr.build(
         backend_addr=self.device.organization_addr,
         organization_id=self.device.organization_id,
         invitation_type=InvitationType.DEVICE,
         token=rep["token"],
     )
예제 #11
0
    async def revoke_user(self, user_id: UserID) -> None:
        """
        Raises:
            BackendConnectionError
        """
        now = pendulum_now()
        revoked_user_certificate = RevokedUserCertificateContent(
            author=self.device.device_id, timestamp=now, user_id=user_id
        ).dump_and_sign(self.device.signing_key)
        rep = await self._backend_conn.cmds.user_revoke(
            revoked_user_certificate=revoked_user_certificate
        )
        if rep["status"] != "ok":
            raise BackendConnectionError(f"Error while trying to revoke user {user_id}: {rep}")

        # Invalidate potential cache to avoid displaying the user as not-revoked
        self._remote_devices_manager.invalidate_user_cache(user_id)
예제 #12
0
 async def delete_invitation(
     self,
     token: UUID,
     reason: InvitationDeletedReason = InvitationDeletedReason.CANCELLED
 ) -> None:
     """
     Raises:
         BackendConnectionError
     """
     rep = await self._backend_conn.cmds.invite_delete(token=token,
                                                       reason=reason)
     if rep["status"] == "not_found":
         raise BackendInvitationNotFound("Invitation not found")
     elif rep["status"] == "already_deleted":
         raise BackendInvitationAlreadyUsed("Invitation already used")
     elif rep["status"] != "ok":
         raise BackendConnectionError(f"Backend error: {rep}")
예제 #13
0
 async def new_user_invitation(self, email: str, send_email: bool) -> BackendInvitationAddr:
     """
     Raises:
         BackendConnectionError
     """
     rep = await self._backend_conn.cmds.invite_new(
         type=InvitationType.USER, claimer_email=email, send_email=send_email
     )
     if rep["status"] == "already_member":
         raise InviteAlreadyMemberError()
     elif rep["status"] != "ok":
         raise BackendConnectionError(f"Backend error: {rep}")
     return BackendInvitationAddr.build(
         backend_addr=self.device.organization_addr,
         organization_id=self.device.organization_id,
         invitation_type=InvitationType.USER,
         token=rep["token"],
     )
예제 #14
0
    async def get_organization_stats(self) -> OrganizationStats:
        """
        Raises:
            BackendConnectionError
        """

        rep = await self._backend_conn.cmds.organization_stats()
        if rep["status"] != "ok":
            raise BackendConnectionError(f"Backend error: {rep}")
        return OrganizationStats(
            data_size=rep["data_size"],
            metadata_size=rep["metadata_size"],
            realms=rep["realms"],
            users=rep["users"],
            active_users=rep["active_users"],
            users_per_profile_detail=[
                UsersPerProfileDetailItem(**x)
                for x in rep["users_per_profile_detail"]
            ],
        )
예제 #15
0
 async def get_user_info(self, user_id: UserID) -> UserInfo:
     """
     Raises:
         BackendConnectionError
     """
     try:
         user_certif, revoked_user_certif = await self._remote_devices_manager.get_user(user_id)
     except RemoteDevicesManagerBackendOfflineError as exc:
         raise BackendNotAvailable(str(exc)) from exc
     except RemoteDevicesManagerNotFoundError as exc:
         raise BackendNotFoundError(str(exc)) from exc
     except RemoteDevicesManagerError as exc:
         # TODO: we should be using our own kind of exception instead of borowing BackendConnectionError...
         raise BackendConnectionError(
             f"Error while fetching user {user_id} certificates"
         ) from exc
     return UserInfo(
         user_id=user_certif.user_id,
         human_handle=user_certif.human_handle,
         profile=user_certif.profile,
         revoked_on=revoked_user_certif.timestamp if revoked_user_certif else None,
         created_on=user_certif.timestamp,
     )