aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-10-07 22:12:54 +0200
committerChristophe Besson <cbesson@gmail.com>2026-10-07 22:20:45 +0200
commit462d76898a306981fbeac859cd54da1468e80639 (patch)
tree9a49723da751b4a7225e3dd37181ecceed192f3a /packages/meshbay-hub/src
parent92e6b9823119b5461efc304a81e79e186a928e6d (diff)
downloadmeshbay-462d76898a306981fbeac859cd54da1468e80639.tar.gz
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 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/src')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/nodes.py3
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/auth.py9
2 files changed, 10 insertions, 2 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/nodes.py b/packages/meshbay-hub/src/meshbay_hub/api/nodes.py
index b158621..b35f11e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/nodes.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/nodes.py
@@ -64,7 +64,8 @@ async def mnp_token(
# `not_a_member`, which is the answer that case has always had.
"mnp_token": issue_mnp_token(current_user.id,
groups=[group_id] if member else [],
- node_pk=(body.node_pk if body else "")),
+ node_pk=(body.node_pk if body else ""),
+ username=current_user.username),
"expires_in": 900,
}
diff --git a/packages/meshbay-hub/src/meshbay_hub/auth.py b/packages/meshbay-hub/src/meshbay_hub/auth.py
index 1d09581..41fb159 100644
--- a/packages/meshbay-hub/src/meshbay_hub/auth.py
+++ b/packages/meshbay-hub/src/meshbay_hub/auth.py
@@ -241,7 +241,8 @@ def issue_access_token(
def issue_mnp_token(user_id: str, groups: list[str] | None = None,
- node_pk: str | None = None, ttl: int = 900) -> str:
+ node_pk: str | None = None, ttl: int = 900,
+ username: str = "") -> str:
"""Issue the short-lived token a member presents to a node in the handshake.
`aud=MNP_AUD`, so it is accepted by `authorize_token` and refused by the hub
@@ -254,6 +255,11 @@ def issue_mnp_token(user_id: str, groups: list[str] | None = None,
cannot be replayed to another node the member also belongs to — the node
checks it in `authorize_token` (E10). The client knows the target node's key
before it connects and asks for a token bound to it.
+
+ `username` is the account's name, so the node can show a person by name in
+ its audit log and roster. Admission by link, by device or into an open group
+ carries no name of its own; without this the node knew those members only
+ by id. It is a label, never authority: the node decides on `sub`.
"""
if _hub_sk_pem is None:
raise RuntimeError("Hub keypair not loaded")
@@ -261,6 +267,7 @@ def issue_mnp_token(user_id: str, groups: list[str] | None = None,
payload = {
"iss": _hub_id,
"sub": user_id,
+ "username": username,
"jti": str(uuid.uuid4()),
"iat": now,
"exp": now + ttl,