aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/transport/webrtc/group_ops.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/transport/webrtc/group_ops.py')
-rw-r--r--packages/meshbay-node/src/meshbay_node/transport/webrtc/group_ops.py84
1 files changed, 0 insertions, 84 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/transport/webrtc/group_ops.py b/packages/meshbay-node/src/meshbay_node/transport/webrtc/group_ops.py
index 3756eac..a94e2aa 100644
--- a/packages/meshbay-node/src/meshbay_node/transport/webrtc/group_ops.py
+++ b/packages/meshbay-node/src/meshbay_node/transport/webrtc/group_ops.py
@@ -5,9 +5,7 @@ from meshbay_common import MNP_VERSION
from meshbay_common.adminop import (
OP_APP_DIRECTORIES,
OP_APPS_ENABLED,
- OP_GEK_ROTATE,
OP_MEMBER_REVOKE,
- OP_MEMBER_UNPIN,
OP_SEARCH_LISTED,
)
from meshbay_common.groupbox import PURPOSE_ROSTER, seal
@@ -41,88 +39,6 @@ class GroupOpsMixin:
return
self._issue_admin_challenge(OP_MEMBER_REVOKE, user_id)
- def _do_gek_rotate(self, msg: dict) -> None:
- """
- Ask for a new group key. Operator only, and signed.
-
- This is what actually removes a revoked member's access: revocation
- stops the node serving the *next* key, and they still hold the current
- one. The node generates the replacement itself — nothing arriving here
- contributes key material, which is what the C5b rule is about.
- """
- group_id = str(msg.get("group_id", "")).strip() or self._group_id
- if not group_id:
- self._send({"type": "error", "detail": "No group on this connection"})
- return
- if not self._has_admin_authority():
- self._send({"type": "error", "detail": "No authorized key for this"})
- return
- self._issue_admin_challenge(OP_GEK_ROTATE, group_id, group_id=group_id)
-
- async def _admin_exec_gek_rotate(
- self, pending: dict, transcript: bytes, sig: bytes,
- ) -> None:
- if not await self._verify_admin_sig(transcript, sig):
- self._send({"type": "error", "detail": "Signature verification failed"})
- self._audit("admin_auth_failed", f"gek_rotate:{pending['subject'][:8]}")
- return
- try:
- result = await self._run_op(
- ops.set_gek, pending["subject"], rotate=True)
- except ops.OpError as e:
- self._send({"type": "error", "detail": e.message})
- return
- # The operator is rotating because somebody left, and the chat archive
- # key is not derived from the group key — so rotating that one does not
- # move this one. Doing both here is what makes "rotate after a removal"
- # mean the same thing for chat as it does for files.
- await self._new_chat_epoch(pending["subject"], "gek_rotate")
- self._audit("gek_rotate", pending["subject"])
- self._send({
- "type": MNP.GEK_ROTATE_ACK, "v": MNP_VERSION,
- "group_id": pending["subject"],
- "authorized_members": result.get("authorized_members", 0),
- # Said plainly, because rotating is the step people skip: content
- # already downloaded stays readable to whoever holds it.
- "note": "members re-receive the key on their next connect; content "
- "already downloaded is unaffected",
- })
-
- def _do_member_unpin(self, msg: dict) -> None:
- """Forget a pinned identity, so someone can pair again with a new key."""
- user_id = str(msg.get("user_id", "")).strip()
- if not user_id:
- self._send({"type": "error", "detail": "Missing user_id"})
- return
- if user_id == self._user_id:
- # Unpinning yourself over the connection your pin authorizes would
- # end that connection's authority mid-operation.
- self._send({"type": "error", "detail": "Cannot unpin yourself"})
- return
- if not self._has_admin_authority():
- self._send({"type": "error", "detail": "No authorized key for this"})
- return
- self._issue_admin_challenge(OP_MEMBER_UNPIN, user_id)
-
- async def _admin_exec_member_unpin(
- self, pending: dict, transcript: bytes, sig: bytes,
- ) -> None:
- user_id = pending["subject"]
- if not await self._verify_admin_sig(transcript, sig):
- self._send({"type": "error", "detail": "Signature verification failed"})
- self._audit("admin_auth_failed", f"member_unpin:{user_id[:8]}")
- return
- try:
- # The new chat epochs and the closed sessions are the op's own
- # (`ops.members._after_removal`), for every door alike.
- await self._run_op(ops.unpin_member, user_id)
- except ops.OpError as e:
- self._send({"type": "error", "detail": e.message})
- return
- self._audit("member_unpin", user_id)
- self._send({"type": MNP.MEMBER_UNPIN_ACK, "v": MNP_VERSION,
- "user_id": user_id})
-
# Every "application" a group can show. Photos joins this set (and
# apps.js's registry, client-side) when it lands; nothing else about
# this handler changes. DEFAULT_APPS (roster.py) deliberately does not