mirror of
https://github.com/penpot/penpot.git
synced 2026-10-30 14:30:37 +00:00
GHSA-m53j-2766-6jqw. A subscription is authorized once, when it is opened, and that decision is trusted for the rest of the connection's life. A member whose access is revoked keeps receiving the live file diff for as long as their tab stays open. Closing the connection from the mutation does not work: the registry is local to one backend instance, while the RPC that revokes access runs on whichever instance received the request. So the revocation travels over the message bus instead, which every instance shares, and each instance re-verifies the subscriptions it owns. `revalidate-profile-subscriptions` looks the profile up in the new index, then re-checks every file and team subscription with the same `has-read-permissions?` predicates that `:subscribe-file` and `:subscribe-team` authorize with. The event is only the trigger; the fresh check is the decision, so the watcher keeps no second copy of the permission rules. That is what makes a downgrade to viewer keep its subscription, and keeps the read-only access of a non-member organization owner. `close-team-subscription` mirrors `close-file-subscription` for team traffic. Both now forget the subscription instead of leaving a stale one behind, which makes them idempotent and stops `:pointer-update` from publishing to a topic the connection no longer relays. The internal topic is separate from the `uuid/zero` system topic, which is piped straight to the client. No client can reach it: `:subscribe-file` and `:subscribe-team` only accept ids that already passed a permission check. Closes #12155 AI-assisted-by: space-bunny-free