Example #1
0
    async def _process_message_sharing_revoked(
            self, msg: SharingRevokedMessageContent) -> None:
        """
        Raises:
            FSError
            FSBackendOfflineError
        """
        # Unlike when somebody grant us workspace access, here we should no
        # longer be able to access the workspace.
        # This also include workspace participants, hence we have no way
        # verifying the sender is manager/owner... But this is not really a trouble:
        # if we cannot access the workspace info, we have been revoked anyway !
        try:
            await self.remote_loader.load_realm_current_roles(msg.id)

        except FSWorkspaceNoAccess:
            # Exactly what we expected !
            pass

        else:
            # We still have access over the workspace, nothing to do then
            return

        async with self._update_user_manifest_lock:
            user_manifest = self.get_user_manifest()

            # Save the revocation information in the user manifest
            existing_workspace_entry = user_manifest.get_workspace_entry(
                msg.id)
            if not existing_workspace_entry:
                # No workspace entry, nothing to update then
                return

            timestamp = self.device.timestamp()
            workspace_entry = merge_workspace_entry(
                None,
                existing_workspace_entry,
                existing_workspace_entry.evolve(role=None,
                                                role_cached_on=timestamp),
            )
            if existing_workspace_entry == workspace_entry:
                # Cheap idempotent check
                return

            timestamp = self.device.timestamp()
            user_manifest = user_manifest.evolve_workspaces_and_mark_updated(
                timestamp, workspace_entry)
            await self.set_user_manifest(user_manifest)
            self.event_bus.send(CoreEvent.USERFS_UPDATED)
            self.event_bus.send(
                CoreEvent.SHARING_UPDATED,
                new_entry=workspace_entry,
                previous_entry=existing_workspace_entry,
            )
Example #2
0
    async def _process_message_sharing_granted(
        self, msg: Union[SharingRevokedMessageContent, SharingReencryptedMessageContent]
    ):
        """
        Raises:
            FSError
            FSBackendOfflineError
            FSSharingNotAllowedError
        """
        # We cannot blindly trust the message sender ! Hence we first
        # interrogate the backend to make sure he is a workspace manager/owner.
        # Note this means we refuse to process messages from a former-manager,
        # even if the message was sent at a time the user was manager (in such
        # case the user can still ask for another manager to re-do the sharing
        # so it's no big deal).
        try:
            roles = await self.remote_loader.load_realm_current_roles(msg.id)

        except FSWorkspaceNoAccess:
            # Seems we lost the access roles anyway, nothing to do then
            return

        if roles.get(msg.author.user_id, None) not in (WorkspaceRole.OWNER, WorkspaceRole.MANAGER):
            raise FSSharingNotAllowedError(
                f"User {msg.author.user_id} cannot share workspace `{msg.id}`"
                " with us (requires owner or manager right)"
            )

        # Determine the access roles we have been given to
        self_role = roles.get(self.device.user_id)

        # Finally insert the new workspace entry into our user manifest
        workspace_entry = WorkspaceEntry(
            # Name are not required to be unique across workspaces, so no check to do here
            name=f"{msg.name} (shared by {msg.author.user_id})",
            id=msg.id,
            key=msg.key,
            encryption_revision=msg.encryption_revision,
            encrypted_on=msg.encrypted_on,
            role=self_role,
            role_cached_on=pendulum_now(),
        )

        async with self._update_user_manifest_lock:
            user_manifest = self.get_user_manifest()

            # Check if we already know this workspace
            already_existing_entry = user_manifest.get_workspace_entry(msg.id)
            if already_existing_entry:
                # Merge with existing as target to keep possible workpace rename
                workspace_entry = merge_workspace_entry(
                    None, workspace_entry, already_existing_entry
                )

            user_manifest = user_manifest.evolve_workspaces_and_mark_updated(workspace_entry)
            await self.set_user_manifest(user_manifest)
            self.event_bus.send("userfs.updated")

            if not already_existing_entry:
                # TODO: remove this event ?
                self.event_bus.send("fs.entry.synced", id=workspace_entry.id)

            self.event_bus.send(
                "sharing.updated", new_entry=workspace_entry, previous_entry=already_existing_entry
            )