fix(relay): materialize NIP-OA owner for direct members on closed relays (#4223) - #4260
fix(relay): materialize NIP-OA owner for direct members on closed relays (#4223)#4260iroiro147 wants to merge 1 commit into
Conversation
…ays (block#4223) On a closed relay (`require_relay_membership = true`), when an agent is already a direct relay member, the NIP-OA auth tag was silently dropped — `enforce_relay_membership` returns `Ok(None)` for direct members, and the `or_else` branch in `bridge.rs` skipped `extract_nip_oa_owner` when `require_relay_membership` was true. The owner was never materialized in `users.agent_owner_pubkey`, making `channel_add_policy: owner_only` unenforceable and owner-scoped lookups return nothing. The NIP-OA auth tag is cryptographically self-proving: if it verifies against the signing pubkey, the owner relationship is authentic regardless of which membership branch granted access. The fix hoists `extract_nip_oa_owner` out of the `require_relay_membership` conditional so it runs unconditionally when `enforce_relay_membership` returns `Ok(None)`. The behavioral matrix after the fix: - Open relay, no tag → None (unchanged) - Open relay, valid tag → Some(owner) (unchanged) - Closed relay, direct member, no tag → None (unchanged) - Closed relay, direct member, valid tag → Some(owner) ✓ (fixed) - Closed relay, via owner → Some(owner) (unchanged, `or_else` not called) - Closed relay, denied → Err (unchanged) `cargo check -p buzz-relay` — clean. `cargo test -p buzz-relay --lib nip_oa` — 1/1 passed. `cargo test -p buzz-relay --lib bridge` — 59/59 passed, 0 failed. Refs block#4223 Signed-off-by: Sarthak Singh <sarthak.singh@juspay.in>
|
Heads-up rather than a competing claim: I've opened #5581, which includes this same hoist plus the Your diagnosis is right and it predates mine. What sent me to the WS path is that #5581 puts the resolution in one shared pure helper so the HTTP and WS paths can't drift apart again, and adds unit tests (the module currently only tests I'm not asking you to close this — if maintainers would rather land your smaller diff first, I'll happily reduce mine to the |
|
@rmichelena thank you for the careful heads-up — and for checking priority, which you didn't have to do. I verified rather than took it on faith: #5581 touches So I'm closing this one in favour of #5581 — yours is strictly more complete and I'd rather reviewers read one PR than two. No need to reduce yours to the For maintainers: #5581 supersedes this PR and is the one worth review time. |
What
On a closed relay (
require_relay_membership = true), an agent that is already a direct relay member has its NIP-OA auth tag silently dropped.enforce_relay_membershipreturnsOk(None)for direct members (theMemberbranch), and theor_elseinbridge.rs:812-818skippedextract_nip_oa_ownerwhenrequire_relay_membershipwas true — soagent_owner_pubkeywas never materialized inusers.This made
channel_add_policy: owner_onlyunenforceable in the intended direction (no owner on record to match against), and owner-scoped lookups (buzz users get --owner <hex>) returned nothing. The issue author's reproduction is unambiguous: removing the direct relay membership and republishing the identical event materializes the owner correctly.Fix
The NIP-OA auth tag is cryptographically self-proving — if
verify_auth_tagsucceeds, the owner relationship is authentic regardless of which membership branch granted access. Hoistextract_nip_oa_ownerout of therequire_relay_membershipconditional so it runs unconditionally whenenforce_relay_membershipreturnsOk(None):The
if !require_relay_membershipguard was originally there becauseextract_nip_oa_ownerwas the open-relay fallback path. But the function itself has no dependency on the relay mode — it just verifies the auth tag signature. The guard was excluding exactly the case where it matters most.Behavioral matrix (after fix)
or_elsenot called)Tests
cargo check -p buzz-relay— cleancargo test -p buzz-relay --lib nip_oa— 1/1 passed (existingextract_nip_oa_ownerunit test)cargo test -p buzz-relay --lib bridge— 59/59 passed, 0 failedThe existing
extract_nip_oa_ownerunit tests (valid tag → Some(owner), no tag → None, invalid tag → None) already cover the function being called in the new position. The bridge handler tests that require Postgres are#[ignore]and not run here, but the 59 non-ignored bridge tests all pass.Linked issue
Refs #4223