From 462d76898a306981fbeac859cd54da1468e80639 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 7 Oct 2026 22:12:54 +0200 Subject: fix(node): name members admitted without an invitation name A member who joined by link, by a new device or into an open group was pinned in the roster with no name, so the audit log showed only the first characters of their id. The hub's MNP token now carries the account's username, and after the handshake the node writes it into the roster for an account whose name is empty. An invitation's name is never overwritten; the name is a label, authority stays on `sub`. Co-Authored-By: Claude Opus 5.5 --- packages/meshbay-node/tests/test_roster_pairing.py | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'packages/meshbay-node/tests/test_roster_pairing.py') diff --git a/packages/meshbay-node/tests/test_roster_pairing.py b/packages/meshbay-node/tests/test_roster_pairing.py index 585a909..5687215 100644 --- a/packages/meshbay-node/tests/test_roster_pairing.py +++ b/packages/meshbay-node/tests/test_roster_pairing.py @@ -1339,3 +1339,39 @@ async def test_an_operator_cannot_revoke_themselves(tmp_path, roster): session._do_member_revoke({"user_id": session._user_id}) assert _last(session).get("detail") == "Cannot revoke yourself" + + +# ── Names from the token ────────────────────────────────────────────────────── + +async def test_link_admission_is_named_from_the_token(roster): + """A link carries no name, so the account was pinned nameless and the audit + log showed it as a bare id. The token's name fills it.""" + _, pk_ed, pk_x = _keypair() + await roster.pin_identity(user_id="u-link", username="", pk_ed25519=pk_ed, + pk_x25519=pk_x, via="link") + assert await roster.name_identity("u-link", "StephISGoD") + assert (await roster.get_identity("u-link"))["username"] == "StephISGoD" + + +async def test_token_name_never_overwrites_the_invitation(roster): + _, pk_ed, pk_x = _keypair() + await roster.pin_identity(user_id="u-code", username="grenet", pk_ed25519=pk_ed, + pk_x25519=pk_x, via="code") + assert not await roster.name_identity("u-code", "someone-else") + assert not await roster.name_identity("u-code", "") + assert (await roster.get_identity("u-code"))["username"] == "grenet" + + +async def test_handshake_records_the_token_name(roster): + _, pk_ed, pk_x = _keypair() + await roster.pin_identity(user_id="u-open", username="", pk_ed25519=pk_ed, + pk_x25519=pk_x, via="tofu") + + class _Session: + _ctx = {"roster": roster} + _user_id = "u-open" + _username = "alice" + + await WebRTCPeerSession._name_identity(_Session()) + assert (await roster.get_identity("u-open"))["username"] == "alice" + assert "self._spawn(self._name_identity())" in session_method("_complete_handshake") -- cgit v1.2.3