diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-02 10:51:19 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-02 10:51:19 +0200 |
| commit | 754387590fa1754436b4648f969915888c6f6c9e (patch) | |
| tree | 53c833eeb4042e8ce5f96b882b23471daa9d9394 /packages/meshbay-node/tests | |
| parent | c928547ca6e402bfe5e06bb59d55ac91e6822cd0 (diff) | |
| download | meshbay-754387590fa1754436b4648f969915888c6f6c9e.tar.gz | |
refactor(mnp): remove ten operator messages no client sent0.17
node_status, node_settings_set, roster_read, denylist_read, denylist_clear,
node_reload and the signed gek_rotate, member_unpin, transfer_limits,
group_detach leave MNP 6.0; the Node page and the CLI do this work over
loopback. Their ops keep their tests, moved to the ops level.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/tests')
| -rw-r--r-- | packages/meshbay-node/tests/golden/dispatch.json | 3437 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_admin_ops_mnp.py | 174 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_node_status.py | 236 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_security_regressions.py | 97 |
4 files changed, 94 insertions, 3850 deletions
diff --git a/packages/meshbay-node/tests/golden/dispatch.json b/packages/meshbay-node/tests/golden/dispatch.json index 345b077..61bbc45 100644 --- a/packages/meshbay-node/tests/golden/dispatch.json +++ b/packages/meshbay-node/tests/golden/dispatch.json @@ -76,22 +76,6 @@ "_admin_exec_file_delete" ] }, - "gek_rotate": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_admin_exec_gek_rotate" - ] - }, - "group_detach": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_admin_exec_group_detach" - ] - }, "invite_cancel": { "audit": [], "log": [], @@ -124,14 +108,6 @@ "_admin_exec_member_revoke" ] }, - "member_unpin": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_admin_exec_member_unpin" - ] - }, "musicbrainz_enabled": { "audit": [], "log": [], @@ -223,14 +199,6 @@ "spawned": [ "_admin_exec_tmdb_rematch" ] - }, - "transfer_limits": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_admin_exec_transfer_limits" - ] } }, "dispatch": { @@ -4005,646 +3973,6 @@ "sent": [], "spawned": [] }, - "denylist_clear | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear | member | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_clear" - ] - }, - "denylist_clear | member | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_clear" - ] - }, - "denylist_clear | member | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_clear" - ] - }, - "denylist_clear | member | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_clear" - ] - }, - "denylist_clear | operator | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_clear" - ] - }, - "denylist_clear | operator | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_clear" - ] - }, - "denylist_clear | operator | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_clear" - ] - }, - "denylist_clear | operator | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_clear" - ] - }, - "denylist_clear_ack | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear_ack | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear_ack | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear_ack | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear_ack | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear_ack | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear_ack | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear_ack | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_clear_ack | member | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_clear_ack | member | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_clear_ack | member | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_clear_ack | member | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_clear_ack | operator | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_clear_ack | operator | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_clear_ack | operator | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_clear_ack | operator | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_read | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read | member | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_read" - ] - }, - "denylist_read | member | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_read" - ] - }, - "denylist_read | member | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_read" - ] - }, - "denylist_read | member | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_read" - ] - }, - "denylist_read | operator | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_read" - ] - }, - "denylist_read | operator | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_read" - ] - }, - "denylist_read | operator | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_read" - ] - }, - "denylist_read | operator | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_denylist_read" - ] - }, - "denylist_read_ack | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read_ack | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read_ack | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read_ack | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read_ack | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read_ack | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read_ack | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read_ack | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "denylist_read_ack | member | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_read_ack | member | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_read_ack | member | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_read_ack | member | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_read_ack | operator | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_read_ack | operator | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_read_ack | operator | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "denylist_read_ack | operator | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, "device_add | challenged | bare": { "audit": [], "log": [], @@ -8353,759 +7681,6 @@ "sent": [], "spawned": [] }, - "gek_rotate | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | member | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "No authorized key for this", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | member | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "No authorized key for this", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | member | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "No authorized key for this", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | member | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "No authorized key for this", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate | operator | bare": { - "audit": [], - "log": [], - "sent": [ - { - "group_id": "gggggggggggggggggggggggggggggggg", - "node_pk": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w=", - "nonce": "<volatile>", - "op": "gek_rotate", - "op_id": "<volatile>", - "req_id": 4242, - "subject": "gggggggggggggggggggggggggggggggg", - "ts": "<volatile>", - "type": "admin_challenge", - "v": "6.0" - } - ], - "spawned": [] - }, - "gek_rotate | operator | lists": { - "audit": [], - "log": [], - "sent": [ - { - "group_id": "['x']", - "node_pk": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w=", - "nonce": "<volatile>", - "op": "gek_rotate", - "op_id": "<volatile>", - "req_id": 4242, - "subject": "['x']", - "ts": "<volatile>", - "type": "admin_challenge", - "v": "6.0" - } - ], - "spawned": [] - }, - "gek_rotate | operator | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "group_id": "7", - "node_pk": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w=", - "nonce": "<volatile>", - "op": "gek_rotate", - "op_id": "<volatile>", - "req_id": 4242, - "subject": "7", - "ts": "<volatile>", - "type": "admin_challenge", - "v": "6.0" - } - ], - "spawned": [] - }, - "gek_rotate | operator | strings": { - "audit": [], - "log": [], - "sent": [ - { - "group_id": "x", - "node_pk": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w=", - "nonce": "<volatile>", - "op": "gek_rotate", - "op_id": "<volatile>", - "req_id": 4242, - "subject": "x", - "ts": "<volatile>", - "type": "admin_challenge", - "v": "6.0" - } - ], - "spawned": [] - }, - "gek_rotate_ack | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate_ack | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate_ack | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate_ack | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate_ack | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate_ack | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate_ack | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate_ack | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "gek_rotate_ack | member | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "gek_rotate_ack | member | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "gek_rotate_ack | member | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "gek_rotate_ack | member | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "gek_rotate_ack | operator | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "gek_rotate_ack | operator | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "gek_rotate_ack | operator | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "gek_rotate_ack | operator | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "group_detach | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | member | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Missing group name or id", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | member | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "No authorized key for this", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | member | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "No authorized key for this", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | member | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "No authorized key for this", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | operator | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Missing group name or id", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach | operator | lists": { - "audit": [], - "log": [], - "sent": [ - { - "group_id": "", - "node_pk": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w=", - "nonce": "<volatile>", - "op": "group_detach", - "op_id": "<volatile>", - "req_id": 4242, - "subject": "['x']", - "ts": "<volatile>", - "type": "admin_challenge", - "v": "6.0" - } - ], - "spawned": [] - }, - "group_detach | operator | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "group_id": "", - "node_pk": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w=", - "nonce": "<volatile>", - "op": "group_detach", - "op_id": "<volatile>", - "req_id": 4242, - "subject": "7", - "ts": "<volatile>", - "type": "admin_challenge", - "v": "6.0" - } - ], - "spawned": [] - }, - "group_detach | operator | strings": { - "audit": [], - "log": [], - "sent": [ - { - "group_id": "", - "node_pk": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w=", - "nonce": "<volatile>", - "op": "group_detach", - "op_id": "<volatile>", - "req_id": 4242, - "subject": "x", - "ts": "<volatile>", - "type": "admin_challenge", - "v": "6.0" - } - ], - "spawned": [] - }, - "group_detach_ack | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach_ack | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach_ack | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach_ack | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach_ack | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach_ack | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach_ack | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach_ack | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "group_detach_ack | member | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "group_detach_ack | member | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "group_detach_ack | member | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "group_detach_ack | member | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "group_detach_ack | operator | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "group_detach_ack | operator | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "group_detach_ack | operator | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "group_detach_ack | operator | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, "group_roster_req | challenged | bare": { "audit": [], "log": [], @@ -13546,379 +12121,6 @@ "sent": [], "spawned": [] }, - "member_unpin | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | member | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Missing user_id", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | member | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "No authorized key for this", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | member | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "No authorized key for this", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | member | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "No authorized key for this", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | operator | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Missing user_id", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin | operator | lists": { - "audit": [], - "log": [], - "sent": [ - { - "group_id": "gggggggggggggggggggggggggggggggg", - "node_pk": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w=", - "nonce": "<volatile>", - "op": "member_unpin", - "op_id": "<volatile>", - "req_id": 4242, - "subject": "['x']", - "ts": "<volatile>", - "type": "admin_challenge", - "v": "6.0" - } - ], - "spawned": [] - }, - "member_unpin | operator | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "group_id": "gggggggggggggggggggggggggggggggg", - "node_pk": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w=", - "nonce": "<volatile>", - "op": "member_unpin", - "op_id": "<volatile>", - "req_id": 4242, - "subject": "7", - "ts": "<volatile>", - "type": "admin_challenge", - "v": "6.0" - } - ], - "spawned": [] - }, - "member_unpin | operator | strings": { - "audit": [], - "log": [], - "sent": [ - { - "group_id": "gggggggggggggggggggggggggggggggg", - "node_pk": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w=", - "nonce": "<volatile>", - "op": "member_unpin", - "op_id": "<volatile>", - "req_id": 4242, - "subject": "x", - "ts": "<volatile>", - "type": "admin_challenge", - "v": "6.0" - } - ], - "spawned": [] - }, - "member_unpin_ack | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin_ack | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin_ack | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin_ack | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin_ack | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin_ack | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin_ack | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin_ack | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "member_unpin_ack | member | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "member_unpin_ack | member | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "member_unpin_ack | member | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "member_unpin_ack | member | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "member_unpin_ack | operator | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "member_unpin_ack | operator | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "member_unpin_ack | operator | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "member_unpin_ack | operator | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, "music_meta_req | challenged | bare": { "audit": [], "log": [], @@ -14751,966 +12953,6 @@ "sent": [], "spawned": [] }, - "node_reload | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload | member | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_reload" - ] - }, - "node_reload | member | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_reload" - ] - }, - "node_reload | member | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_reload" - ] - }, - "node_reload | member | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_reload" - ] - }, - "node_reload | operator | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_reload" - ] - }, - "node_reload | operator | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_reload" - ] - }, - "node_reload | operator | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_reload" - ] - }, - "node_reload | operator | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_reload" - ] - }, - "node_reload_ack | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload_ack | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload_ack | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload_ack | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload_ack | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload_ack | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload_ack | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload_ack | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_reload_ack | member | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_reload_ack | member | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_reload_ack | member | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_reload_ack | member | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_reload_ack | operator | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_reload_ack | operator | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_reload_ack | operator | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_reload_ack | operator | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_settings_set | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set | member | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_settings_set" - ] - }, - "node_settings_set | member | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_settings_set" - ] - }, - "node_settings_set | member | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_settings_set" - ] - }, - "node_settings_set | member | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_settings_set" - ] - }, - "node_settings_set | operator | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_settings_set" - ] - }, - "node_settings_set | operator | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_settings_set" - ] - }, - "node_settings_set | operator | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_settings_set" - ] - }, - "node_settings_set | operator | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_settings_set" - ] - }, - "node_settings_set_ack | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set_ack | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set_ack | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set_ack | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set_ack | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set_ack | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set_ack | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set_ack | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_settings_set_ack | member | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_settings_set_ack | member | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_settings_set_ack | member | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_settings_set_ack | member | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_settings_set_ack | operator | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_settings_set_ack | operator | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_settings_set_ack | operator | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_settings_set_ack | operator | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_status | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status | member | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_status" - ] - }, - "node_status | member | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_status" - ] - }, - "node_status | member | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_status" - ] - }, - "node_status | member | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_status" - ] - }, - "node_status | operator | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_status" - ] - }, - "node_status | operator | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_status" - ] - }, - "node_status | operator | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_status" - ] - }, - "node_status | operator | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_node_status" - ] - }, - "node_status_ack | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status_ack | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status_ack | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status_ack | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status_ack | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status_ack | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status_ack | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status_ack | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "node_status_ack | member | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_status_ack | member | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_status_ack | member | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_status_ack | member | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_status_ack | operator | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_status_ack | operator | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_status_ack | operator | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "node_status_ack | operator | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, "ping | challenged | bare": { "audit": [], "log": [], @@ -17194,326 +14436,6 @@ "sent": [], "spawned": [] }, - "roster_read | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read | member | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_roster_read" - ] - }, - "roster_read | member | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_roster_read" - ] - }, - "roster_read | member | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_roster_read" - ] - }, - "roster_read | member | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_roster_read" - ] - }, - "roster_read | operator | bare": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_roster_read" - ] - }, - "roster_read | operator | lists": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_roster_read" - ] - }, - "roster_read | operator | numbers": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_roster_read" - ] - }, - "roster_read | operator | strings": { - "audit": [], - "log": [], - "sent": [], - "spawned": [ - "_do_roster_read" - ] - }, - "roster_read_ack | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read_ack | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read_ack | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read_ack | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read_ack | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read_ack | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read_ack | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read_ack | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "roster_read_ack | member | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "roster_read_ack | member | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "roster_read_ack | member | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "roster_read_ack | member | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "roster_read_ack | operator | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "roster_read_ack | operator | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "roster_read_ack | operator | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "roster_read_ack | operator | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, "search_listed | challenged | bare": { "audit": [], "log": [], @@ -21724,365 +18646,6 @@ "sent": [], "spawned": [] }, - "transfer_limits | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | member | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Invalid transfer limits", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | member | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Invalid transfer limits", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | member | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "No authorized key for this", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | member | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Invalid transfer limits", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | operator | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Invalid transfer limits", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | operator | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Invalid transfer limits", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits | operator | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "group_id": "gggggggggggggggggggggggggggggggg", - "node_pk": "iojj3XQJ8ZX9UtstPLpdcspnCb8dlBIb83SIAbQPb1w=", - "nonce": "<volatile>", - "op": "transfer_limits", - "op_id": "<volatile>", - "req_id": 4242, - "subject": "d=7,u=7", - "ts": "<volatile>", - "type": "admin_challenge", - "v": "6.0" - } - ], - "spawned": [] - }, - "transfer_limits | operator | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Invalid transfer limits", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits_ack | challenged | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits_ack | challenged | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits_ack | challenged | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits_ack | challenged | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits_ack | fresh | bare": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits_ack | fresh | lists": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits_ack | fresh | numbers": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits_ack | fresh | strings": { - "audit": [], - "log": [], - "sent": [ - { - "detail": "Handshake required", - "req_id": 4242, - "type": "error" - } - ], - "spawned": [] - }, - "transfer_limits_ack | member | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "transfer_limits_ack | member | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "transfer_limits_ack | member | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "transfer_limits_ack | member | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "transfer_limits_ack | operator | bare": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "transfer_limits_ack | operator | lists": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "transfer_limits_ack | operator | numbers": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, - "transfer_limits_ack | operator | strings": { - "audit": [], - "log": [ - "WARNING Unknown MNP message type on DataChannel: %s" - ], - "sent": [], - "spawned": [] - }, "transfer_open | challenged | bare": { "audit": [], "log": [], diff --git a/packages/meshbay-node/tests/test_admin_ops_mnp.py b/packages/meshbay-node/tests/test_admin_ops_mnp.py index 7fd1c2b..898228e 100644 --- a/packages/meshbay-node/tests/test_admin_ops_mnp.py +++ b/packages/meshbay-node/tests/test_admin_ops_mnp.py @@ -1,17 +1,14 @@ """ -`gek_rotate` and `member_unpin` over MNP. +Rotating the group key and forgetting a pinned identity — `ops.set_gek` and +`ops.unpin_member`, which the Node page and the CLI reach over loopback — and +the H5 rule every signed MNP operation lives under. -Both are destructive and both are new, so the tests are negative assertions: -nobody without the operator's pinned key can reach them, a signature over the -wrong transcript does not count, and the operation cannot be triggered by the -request message alone. - -The rule these live under is worth restating, because it is easy to read -draft-v5 §5.1 as forbidding them: **"nothing arriving over MNP can activate a -GEK" is about key material arriving from outside** (C5b — a member handing the -node a key of their choosing). An operator-signed instruction where the node -generates the key with its own CSPRNG is a different shape, and it is the only -thing that finishes a revocation: the ex-member still holds the current key. +`gek_rotate` and `member_unpin` were MNP messages until 6.0. No client sent +them, so they went; what they did is still tested here, at the door that is +used. **"Nothing arriving over MNP can activate a GEK" is about key material +arriving from outside** (C5b): the node generates the new key with its own +CSPRNG, which is the only thing that finishes a revocation — the ex-member +still holds the current key. """ import base64 @@ -19,14 +16,10 @@ from pathlib import Path import pytest from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey -from meshbay_common.adminop import ( - OP_GEK_ROTATE, - OP_MEMBER_UNPIN, - admin_transcript, -) +from meshbay_common.adminop import OP_CHAT_EPOCH, admin_transcript from meshbay_common.crypto import pk_to_b64 from meshbay_common.join import ROLE_MEMBER, ROLE_OPERATOR -from meshbay_common.protocol import MNP +from meshbay_node import ops from meshbay_node.indexer.group_index import GroupIndex from meshbay_node.roster import open_roster from meshbay_node.transport.webrtc_server import WebRTCPeerSession @@ -127,58 +120,7 @@ async def _drain(session): session.spawned.clear() -async def _sign_and_exec(session, op: str, subject: str, sk, exec_fn): - challenge = _last(session) - assert challenge["type"] == "admin_challenge", challenge - transcript = admin_transcript( - op=op, node_pk_b64=session._node_pk_b64(), group_id=GROUP, - subject=subject, nonce=base64.b64decode(challenge["nonce"]), - ts=challenge["ts"]) - pending = session._admin_ops.get(challenge["op_id"]) or { - "op": op, "subject": subject} - await exec_fn(pending, transcript, sk.sign(transcript)) - - -# ── gek_rotate ─────────────────────────────────────────────────────────────── - -async def test_rotation_needs_an_operator(tmp_path, roster): - """Without a paired operator there is nobody who could sign, so the node - fails closed and says why rather than issuing a challenge nobody can meet.""" - session = await _session(tmp_path, roster, operator=False) - - session._do_gek_rotate({}) - - assert _last(session)["type"] == "error" - assert "authorized key" in _last(session)["detail"] - assert not session._admin_ops - - -async def test_the_request_alone_rotates_nothing(tmp_path, roster): - """The message asks; only a signature acts. A node that rotated here would - let any member lock the group out.""" - session = await _session(tmp_path, roster, operator=True) - before = session._ctx["groups"][GROUP]["gek"] - - session._do_gek_rotate({}) - - assert _last(session)["type"] == "admin_challenge" - assert session._ctx["groups"][GROUP]["gek"] == before - - -async def test_a_members_signature_does_not_rotate(tmp_path, roster): - session = await _session(tmp_path, roster, operator=True) - sk_mallory, pk_mallory = _keypair() - await roster.pin_identity("mallory", "mallory", pk_mallory, pk_mallory, "code") - await roster.set_member(GROUP, "mallory", ROLE_MEMBER, "active", "grenet") - before = session._ctx["groups"][GROUP]["gek"] - - session._do_gek_rotate({}) - await _sign_and_exec(session, OP_GEK_ROTATE, GROUP, sk_mallory, - session._admin_exec_gek_rotate) - - assert _last(session)["type"] == "error" - assert session._ctx["groups"][GROUP]["gek"] == before - +# ── H5: a signature is for one operation ───────────────────────────────────── async def test_a_signature_over_another_operation_does_not_count(tmp_path, roster): """ @@ -191,15 +133,18 @@ async def test_a_signature_over_another_operation_does_not_count(tmp_path, roste control, and the test would pass while proving nothing. """ session = await _session(tmp_path, roster, operator=True) - before = session._ctx["groups"][GROUP]["gek"] + _, pk_bob = _keypair() + await roster.pin_identity("bob", "bob", pk_bob, pk_bob, "code") + await roster.set_member(GROUP, "bob", ROLE_MEMBER, "active", "code") - session._do_gek_rotate({}) + session._do_member_revoke({"user_id": "bob"}) challenge = _last(session) + assert challenge["type"] == "admin_challenge", challenge - # Signed over member_unpin, presented against the pending gek_rotate. + # Signed over chat_epoch, presented against the pending member_revoke. wrong = admin_transcript( - op=OP_MEMBER_UNPIN, node_pk_b64=session._node_pk_b64(), group_id=GROUP, - subject=GROUP, nonce=base64.b64decode(challenge["nonce"]), + op=OP_CHAT_EPOCH, node_pk_b64=session._node_pk_b64(), group_id=GROUP, + subject="bob", nonce=base64.b64decode(challenge["nonce"]), ts=challenge["ts"]) session._do_admin_response({ "op_id": challenge["op_id"], @@ -208,19 +153,18 @@ async def test_a_signature_over_another_operation_does_not_count(tmp_path, roste await _drain(session) assert _last(session)["type"] == "error" - assert session.state["groups_ctx"][GROUP]["gek"] == before + assert (await roster.get_member(GROUP, "bob"))["status"] == "active" -async def test_the_operator_rotates_and_the_node_makes_the_key(tmp_path, roster): +# ── Rotating the group key ─────────────────────────────────────────────────── + +async def test_rotating_makes_a_new_key_on_the_node(tmp_path, roster): session = await _session(tmp_path, roster, operator=True) - before = session._ctx["groups"][GROUP]["gek"] + before = session.state["groups_ctx"][GROUP]["gek"] - session._do_gek_rotate({}) - await _sign_and_exec(session, OP_GEK_ROTATE, GROUP, session.sk_op, - session._admin_exec_gek_rotate) + result = await ops.set_gek(session.state, GROUP, rotate=True) - ack = _last(session) - assert ack["type"] == MNP.GEK_ROTATE_ACK, ack + assert result["rotated"] is True after = session.state["groups_ctx"][GROUP]["gek"] assert after != before, "the key did not change" assert len(after) == 32 @@ -234,54 +178,21 @@ async def test_rotation_reaches_the_index(tmp_path, roster): serve members a listing they cannot open.""" session = await _session(tmp_path, roster, operator=True) - session._do_gek_rotate({}) - await _sign_and_exec(session, OP_GEK_ROTATE, GROUP, session.sk_op, - session._admin_exec_gek_rotate) + await ops.set_gek(session.state, GROUP, rotate=True) assert session.state["indexes"][GROUP].gek == \ session.state["groups_ctx"][GROUP]["gek"] -# ── member_unpin ───────────────────────────────────────────────────────────── - -async def test_unpinning_needs_an_operator(tmp_path, roster): - session = await _session(tmp_path, roster, operator=False) - session._do_member_unpin({"user_id": "bob"}) - assert _last(session)["type"] == "error" - - -async def test_unpinning_yourself_is_refused(tmp_path, roster): - """It would end the authority of the connection performing the operation, - halfway through it.""" - session = await _session(tmp_path, roster, operator=True) - session._do_member_unpin({"user_id": "grenet"}) - assert _last(session)["detail"] == "Cannot unpin yourself" - - -async def test_a_members_signature_does_not_unpin(tmp_path, roster): - session = await _session(tmp_path, roster, operator=True) - sk_bob, pk_bob = _keypair() - await roster.pin_identity("bob", "bob", pk_bob, pk_bob, "code") - - session._do_member_unpin({"user_id": "bob"}) - await _sign_and_exec(session, OP_MEMBER_UNPIN, "bob", sk_bob, - session._admin_exec_member_unpin) - - assert _last(session)["type"] == "error" - assert await roster.get_identity("bob") is not None, ( - "a member removed their own pin — only the operator may") - +# ── Forgetting a pinned identity ───────────────────────────────────────────── -async def test_the_operator_unpins(tmp_path, roster): +async def test_unpinning_forgets_the_identity_and_its_bundle(tmp_path, roster): session = await _session(tmp_path, roster, operator=True) _, pk_bob = _keypair() await roster.pin_identity("bob", "bob", pk_bob, pk_bob, "code") - session._do_member_unpin({"user_id": "bob"}) - await _sign_and_exec(session, OP_MEMBER_UNPIN, "bob", session.sk_op, - session._admin_exec_member_unpin) + await ops.unpin_member(session.state, "bob") - assert _last(session)["type"] == MNP.MEMBER_UNPIN_ACK assert await roster.get_identity("bob") is None # The stored keypair bundle goes too — left behind it blocks the re-join # the unpin exists to enable. @@ -290,8 +201,21 @@ async def test_the_operator_unpins(tmp_path, roster): async def test_unpinning_someone_unknown_says_so(tmp_path, roster): session = await _session(tmp_path, roster, operator=True) - session._do_member_unpin({"user_id": "nobody"}) - await _sign_and_exec(session, OP_MEMBER_UNPIN, "nobody", session.sk_op, - session._admin_exec_member_unpin) - assert _last(session)["type"] == "error" - assert "No such pinned identity" in _last(session)["detail"] + with pytest.raises(ops.OpError, match="No such pinned identity"): + await ops.unpin_member(session.state, "nobody") + + +# ── What MNP no longer carries ─────────────────────────────────────────────── + +@pytest.mark.parametrize("op", ["gek_rotate", "member_unpin", "transfer_limits", + "group_detach"]) +def test_operations_no_client_sent_are_not_signed_ops_any_more(op): + """Gone with MNP 6.0: a door nobody uses is an untested way in. The Node + page and the CLI do the same work over loopback.""" + from meshbay_common import adminop + from meshbay_node.transport.webrtc.admin import _ADMIN_EXECUTORS + from meshbay_node.transport.webrtc.dispatch import _HANDLERS + + assert op not in _HANDLERS + assert op not in _ADMIN_EXECUTORS + assert op not in vars(adminop).values() diff --git a/packages/meshbay-node/tests/test_node_status.py b/packages/meshbay-node/tests/test_node_status.py index 257c60c..075d11f 100644 --- a/packages/meshbay-node/tests/test_node_status.py +++ b/packages/meshbay-node/tests/test_node_status.py @@ -1,25 +1,19 @@ """ -node_status and root_remove over MNP. +The node management panel's server-side behaviour. -These test the D5 node management panel's server-side behaviour: the admin -identity check on node_status, the list_groups operation, and the root -removal flow through the MNP handlers. Adding a root is not an MNP message -(MNP 6.0); `ops.add_root` is still tested here, as the loopback and CLI use it. +The `_is_node_admin` hint, root removal over MNP, and the operations the Node +page and the CLI reach over loopback: listing groups, adding and updating +roots, the roster, the denylist and unpinning. Their own MNP messages +(`node_status`, `root_add`, `roster_read`, …) are gone since MNP 6.0. """ -import base64 from dataclasses import asdict from pathlib import Path import pytest from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey -from meshbay_common.adminop import ( - OP_MEMBER_UNPIN, - admin_transcript, -) from meshbay_common.crypto import pk_to_b64 from meshbay_common.join import ROLE_OPERATOR -from meshbay_common.protocol import MNP from meshbay_node import ops from meshbay_node.indexer.group_index import GroupIndex from meshbay_node.roots import RootSet @@ -134,19 +128,6 @@ async def _session( return session -async def _sign_and_exec(session, op: str, subject: str, sk, exec_fn, - group_id: str = GROUP): - challenge = _last(session) - assert challenge["type"] == "admin_challenge", challenge - transcript = admin_transcript( - op=op, node_pk_b64=session._node_pk_b64(), group_id=group_id, - subject=subject, nonce=base64.b64decode(challenge["nonce"]), - ts=challenge["ts"]) - pending = session._admin_ops.get(challenge["op_id"]) or { - "op": op, "subject": subject} - await exec_fn(pending, transcript, sk.sign(transcript)) - - # ── _is_node_admin ────────────────────────────────────────────────────────── async def test_is_node_admin_matches_user_id(tmp_path, roster): @@ -168,62 +149,6 @@ async def test_is_node_admin_rejects_missing_node_user_id(tmp_path, roster): assert not session._is_node_admin() -# ── node_status ───────────────────────────────────────────────────────────── - -async def test_node_status_returns_groups_for_admin(tmp_path, roster): - session = await _session(tmp_path, roster, operator=True, - node_user_id="grenet") - session._spawn(session._do_node_status({})) - await _drain(session) - msg = _last(session) - assert msg["type"] == MNP.NODE_STATUS_ACK - assert len(msg["groups"]) == 1 - assert msg["groups"][0]["id"] == GROUP - - -async def test_node_status_refused_for_non_admin(tmp_path, roster): - session = await _session(tmp_path, roster, operator=False, - node_user_id="grenet") - session._spawn(session._do_node_status({})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "error" - assert "operator" in msg["detail"].lower() - - -async def test_node_status_refused_when_user_is_operator_but_ids_mismatch( - tmp_path, roster, -): - """A paired operator who is not the node owner cannot see node_status.""" - session = await _session(tmp_path, roster, operator=True, - node_user_id="someone-else") - session._spawn(session._do_node_status({})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "error" - - -async def test_node_status_catches_send_failure(tmp_path, roster): - """If _send itself throws (e.g. msgpack encoding fails), the error must - not silently vanish — it used to, because _send was outside the try block.""" - session = await _session(tmp_path, roster, operator=True, - node_user_id="grenet") - sent = [] - call_count = [0] - - def _exploding_send(msg): - call_count[0] += 1 - if msg.get("type") == "node_status_ack": - raise TypeError("msgpack cannot encode this") - sent.append(msg) - - session._send = _exploding_send - session._spawn(session._do_node_status({})) - await _drain(session) - # The try/except around _send should catch the error and send an error reply - assert any(m.get("type") == "error" for m in sent) - - # ── ops.list_groups ───────────────────────────────────────────────────────── async def test_list_groups_returns_group_metadata(tmp_path): @@ -504,52 +429,32 @@ async def test_root_remove_refuses_missing_fields(tmp_path, roster): assert "Missing" in _last(session)["detail"] -# ── roster_read MNP handler ────────────────────────────────────────────── - -async def test_roster_read_returns_members_for_admin(tmp_path, roster): - session = await _session(tmp_path, roster, operator=True, - node_user_id="grenet") - session._spawn(session._do_roster_read({"group_id": GROUP})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "roster_read_ack" - assert "members" in msg - assert "identities" in msg - - -async def test_roster_read_refused_for_non_admin(tmp_path, roster): - session = await _session(tmp_path, roster, operator=False, - node_user_id="grenet") - session._spawn(session._do_roster_read({"group_id": GROUP})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "error" - +# ── The roster, the denylist and unpinning (loopback, CLI) ────────────────── +# +# Their MNP messages are gone (MNP 6.0, no client sent them); the operations are +# what the Node page and the CLI call. -async def test_roster_read_filters_ghost_members(tmp_path, roster): +async def test_read_roster_filters_ghost_members(tmp_path, roster): """Members whose identity was deleted (revoked then unpinned) are filtered out by read_roster — the LEFT JOIN returns them with pk_ed25519 = NULL but they should never reach the UI.""" session = await _session(tmp_path, roster, operator=True, node_user_id="grenet") - sk2, pk2 = _keypair() + _, pk2 = _keypair() await roster.pin_identity("ghost", "ghost", pk2, pk2, "code") await roster.set_member(GROUP, "ghost", "member", "revoked", "local-cli") await roster._db.execute("DELETE FROM identities WHERE user_id = 'ghost'") await roster._db.commit() # Also add a real member so the roster isn't empty - sk3, pk3 = _keypair() + _, pk3 = _keypair() await roster.pin_identity("real", "real", pk3, pk3, "code") await roster.set_member(GROUP, "real", "member", "active", "local-cli") - session._spawn(session._do_roster_read({"group_id": GROUP})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "roster_read_ack" - ghost = [m for m in msg["members"] if m["user_id"] == "ghost"] - assert len(ghost) == 0, "ghost members must be filtered out" - real = [m for m in msg["members"] if m["user_id"] == "real"] - assert len(real) == 1 + result = await ops.read_roster(session.state, GROUP) + assert "identities" in result + assert not [m for m in result["members"] if m["user_id"] == "ghost"], ( + "ghost members must be filtered out") + assert len([m for m in result["members"] if m["user_id"] == "real"]) == 1 async def test_unpin_fails_for_ghost_member(tmp_path, roster): @@ -557,118 +462,35 @@ async def test_unpin_fails_for_ghost_member(tmp_path, roster): session = await _session(tmp_path, roster, operator=True, node_user_id="grenet") await roster.set_member(GROUP, "ghost", "member", "revoked", "local-cli") - # ghost has no identity row - session._do_member_unpin({"user_id": "ghost"}) - challenge = _last(session) - assert challenge["type"] == "admin_challenge" + with pytest.raises(ops.OpError, match="No such pinned identity"): + await ops.unpin_member(session.state, "ghost") - await _sign_and_exec(session, OP_MEMBER_UNPIN, "ghost", - session.sk_op, session._admin_exec_member_unpin) - msg = _last(session) - assert msg["type"] == "error" - assert "No such pinned identity" in msg["detail"] - - -async def test_unpin_succeeds_for_real_identity(tmp_path, roster): - """Full unpin flow: challenge → sign → exec → identity deleted.""" - session = await _session(tmp_path, roster, operator=True, - node_user_id="grenet") - sk2, pk2 = _keypair() - await roster.pin_identity("target", "target", pk2, pk2, "code") - await roster.set_member(GROUP, "target", "member", "active", "local-cli") - - session._do_member_unpin({"user_id": "target"}) - challenge = _last(session) - assert challenge["type"] == "admin_challenge" - - await _sign_and_exec(session, OP_MEMBER_UNPIN, "target", - session.sk_op, session._admin_exec_member_unpin) - msg = _last(session) - assert msg["type"] == "member_unpin_ack" - assert msg["user_id"] == "target" - - idents = await roster.list_identities() - assert not any(i["user_id"] == "target" for i in idents) - -# ── denylist_read MNP handler ──────────────────────────────────────────── - -async def test_denylist_read_returns_entries_for_admin(tmp_path, roster): +async def test_read_denylist_lists_entries(tmp_path, roster): session = await _session(tmp_path, roster, operator=True, node_user_id="grenet") session.denylist.deny_user("bad-user") - session._spawn(session._do_denylist_read({})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "denylist_read_ack" - assert msg["count"] == 1 - assert "bad-user" in msg["users"] - - -async def test_denylist_read_refused_for_non_admin(tmp_path, roster): - session = await _session(tmp_path, roster, operator=False, - node_user_id="grenet") - session._spawn(session._do_denylist_read({})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "error" - + result = await ops.read_denylist(session.state) + assert result["count"] == 1 + assert "bad-user" in result["users"] -# ── denylist_clear MNP handler ─────────────────────────────────────────── -async def test_denylist_clear_removes_entry_for_admin(tmp_path, roster): +async def test_clear_denylist_removes_one_entry(tmp_path, roster): session = await _session(tmp_path, roster, operator=True, node_user_id="grenet") session.denylist.deny_user("bad-user") session.denylist.deny_user("other-user") - session._spawn(session._do_denylist_clear({"subject": "bad-user"})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "denylist_clear_ack" - assert msg["removed"] == 1 + result = await ops.clear_denylist(session.state, subject="bad-user") + assert result["removed"] == 1 assert "bad-user" not in session.denylist.entries()["users"] assert "other-user" in session.denylist.entries()["users"] -async def test_denylist_clear_all_for_admin(tmp_path, roster): +async def test_clear_denylist_all(tmp_path, roster): session = await _session(tmp_path, roster, operator=True, node_user_id="grenet") session.denylist.deny_user("a") session.denylist.deny_user("b") session.denylist.deny_jti("j") - session._spawn(session._do_denylist_clear({"subject": ""})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "denylist_clear_ack" - assert msg["removed"] == 3 - - -async def test_denylist_clear_refused_for_non_admin(tmp_path, roster): - session = await _session(tmp_path, roster, operator=False, - node_user_id="grenet") - session._spawn(session._do_denylist_clear({"subject": "bad-user"})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "error" - - -# ── node_reload MNP handler ───────────────────────────────────────────── - -async def test_node_reload_runs_for_admin(tmp_path, roster): - session = await _session(tmp_path, roster, operator=True, - node_user_id="grenet") - session._spawn(session._do_node_reload({})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "node_reload_ack" - assert msg["status"] == "reloaded" - assert len(session.reload_called) == 1 - - -async def test_node_reload_refused_for_non_admin(tmp_path, roster): - session = await _session(tmp_path, roster, operator=False, - node_user_id="grenet") - session._spawn(session._do_node_reload({})) - await _drain(session) - msg = _last(session) - assert msg["type"] == "error" + result = await ops.clear_denylist(session.state, subject="") + assert result["removed"] == 3 diff --git a/packages/meshbay-node/tests/test_security_regressions.py b/packages/meshbay-node/tests/test_security_regressions.py index 43e88c2..26a3b1d 100644 --- a/packages/meshbay-node/tests/test_security_regressions.py +++ b/packages/meshbay-node/tests/test_security_regressions.py @@ -842,14 +842,11 @@ def test_node_control_api_serves_no_html(): # ── NS4 / M3: the node's own controls take no authority from the hub ───────── -async def _owner_session(tmp_path, roster, *, device: str = "", - confirmed: bool = False): +async def _owner_session(tmp_path, roster): """A session whose token says it is the account this node belongs to. Which is all a hub can decide: `_user_id` is the `sub` of a JWT it issued, - so this is what an active hub forging a token arrives holding. Whether the - *device* on the connection is one the node pinned as an operator is the - other half, and no token can assert it. + so this is what an active hub forging a token arrives holding. """ from meshbay_node.indexer.group_index import GroupIndex @@ -865,9 +862,6 @@ async def _owner_session(tmp_path, roster, *, device: str = "", } session._group_id = "g" * 32 session._user_id = "the-owner" - session._username = "the-owner" - session._pinned_pk = device - session._device_confirmed = confirmed session._pk_user = "" session.sent = [] session._send = session.sent.append @@ -876,18 +870,18 @@ async def _owner_session(tmp_path, roster, *, device: str = "", @pytest.mark.asyncio -async def test_a_token_naming_the_owner_is_not_node_authority(tmp_path): +@pytest.mark.parametrize("mtype", ["node_status", "node_settings_set", "roster_read", + "denylist_read", "denylist_clear", "node_reload"]) +async def test_a_token_naming_the_owner_reaches_no_node_control(tmp_path, mtype): """ - The hub holds no user keys, so it cannot countersign a device — but it does - choose what a token says. Six node-wide controls used to be gated on the - account id alone, which is the hub's to decide: `node_status` (every group - on the machine, with the operator's absolute paths), `node_settings_set`, - `roster_read`, `denylist_read`, `denylist_clear` (the persisted revocation - H4 exists to keep) and `node_reload`. - - An active hub reaches a completed handshake wherever it can also obtain the - group key, which §3.5 concedes it can in an open-join group. From there, - "the hub says you are the owner" was the whole of the check. + The hub holds no user keys, but it does choose what a token says. Six + node-wide controls were once gated on the account id alone: `node_status` + (every group on the machine, with the operator's absolute paths), + `node_settings_set`, `roster_read`, `denylist_read`, `denylist_clear` (the + persisted revocation H4 exists to keep) and `node_reload`. A device proof + closed that; MNP 6.0 removed the messages, since no client sent them. They + are the loopback API's and the CLI's — on the operator's own machine — and a + peer naming one over MNP is answered by nobody. """ from meshbay_node.roster import Roster @@ -895,67 +889,8 @@ async def test_a_token_naming_the_owner_is_not_node_authority(tmp_path): await roster.open() try: forged = await _owner_session(tmp_path, roster) - await forged._do_node_status({}) - assert forged.sent[-1]["type"] == "error" - assert forged.sent[-1]["code"] == "not_operator" - - forged.sent.clear() - await forged._do_denylist_read({}) - assert forged.sent[-1]["type"] == "error" - - forged.sent.clear() - await forged._do_denylist_clear({"subject": ""}) - assert forged.sent[-1]["type"] == "error", ( - "clearing the denylist undoes a revocation every node enforces") - finally: - await roster.close() - - -@pytest.mark.asyncio -async def test_an_identified_device_that_is_not_an_operator_is_refused(tmp_path): - """Being a pinned member of the group is not being the node's operator. - - The device proof is real here; what it proves is an ordinary member's key, - and `operator_pks()` is rebuilt from the roster on every call so a revoked - one stops working at once. - """ - from meshbay_common.crypto import pk_to_b64 - from meshbay_node.roster import Roster - - roster = Roster(db_path=tmp_path / "roster.db") - await roster.open() - try: - sk = Ed25519PrivateKey.generate() - member_pk = pk_to_b64(sk.public_key()) - await roster.pin_identity("the-owner", "the-owner", member_pk, - member_pk, "code") - session = await _owner_session(tmp_path, roster, device=member_pk, - confirmed=True) - await session._do_node_status({}) - assert session.sent[-1]["type"] == "error" - finally: - await roster.close() - - -@pytest.mark.asyncio -async def test_a_paired_operator_device_is_what_opens_it(tmp_path): - """The positive case, so the test above is about authority and not about - everything being refused.""" - from meshbay_common.crypto import pk_to_b64 - from meshbay_common.join import ROLE_OPERATOR - from meshbay_node.roster import Roster - - roster = Roster(db_path=tmp_path / "roster.db") - await roster.open() - try: - sk = Ed25519PrivateKey.generate() - pk = pk_to_b64(sk.public_key()) - await roster.pin_identity("the-owner", "the-owner", pk, pk, "code") - await roster.set_member("", "the-owner", ROLE_OPERATOR, "active", - "local-cli") - session = await _owner_session(tmp_path, roster, device=pk, - confirmed=True) - await session._do_denylist_read({}) - assert session.sent[-1]["type"] != "error", session.sent[-1] + forged._dispatch_message({"type": mtype, "subject": "", "group_id": "g" * 32, + "settings": {"max_peers": 1}}) + assert forged.sent == [], f"{mtype} answered over MNP: {forged.sent}" finally: await roster.close() |