fix(auth): anonymous view-event session actor no longer reports you as logged out

After watching/opening a video, zapping showed "Log in and connect a wallet"
even though logged in. Recording a view creates an anonymous session actor with
source "session" (SignerManager.ensureSessionActor). isUserLoggedIn() treated any
declaredSource on a different-pubkey session actor as a managed alternate
identity and returned false — so the view-event telemetry actor logged the user
out app-wide (zap gate, etc.).

Fix: "session" is the anonymous telemetry source, not a login identity — only a
managed source (e.g. "nsec") for a different pubkey disqualifies. (Commit
7985a481 intended to allow anonymous actors but only covered the sourceless
shape; the real actor carries source "session".)

tests/app/is-user-logged-in.test.mjs: added the real view-event actor shape
(source "session", different pubkey) → logged in; the "nsec" rejection case still
holds. Mutation-verified.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-06-21 21:52:52 -04:00
1 parent dec5cf8fe1
commit bb33b12649
2 files changed
+32 -1

No files matched your search

+7 -1
View File
@@ -3351,9 +3351,15 @@ class Application {
typeof sessionActor?.source === "string"
? sessionActor.source.trim()
: "";
// The anonymous view-event actor is created with source "session" (see
// SignerManager.ensureSessionActor). It's telemetry, NOT an alternate login
// identity, so it must not disqualify a real login — otherwise watching any
// video flips isUserLoggedIn() to false and breaks zaps/etc. Only a managed
// real source (e.g. "nsec") for a DIFFERENT pubkey disqualifies.
const isManagedSource = Boolean(declaredSource) && declaredSource !== "session";
const isPersisted = sessionActor?.persisted === true;
if (!hasEmbeddedPrivateKey || declaredSource || isPersisted) {
if (!hasEmbeddedPrivateKey || isManagedSource || isPersisted) {
return false;
}
}
+25
View File
@@ -112,6 +112,31 @@ test("isUserLoggedIn ignores anonymous session actor mismatches", () => {
}
});
test("isUserLoggedIn allows the anonymous view-event session actor (source 'session')", () => {
// Regression: watching a video creates an anonymous view-event actor with
// source "session" and a different pubkey. It must NOT log the user out (which
// broke zaps with "Log in and connect a wallet").
const previousPubkey = nostrClient.pubkey;
const previousSessionActor = nostrClient.sessionActor;
try {
const pubkey = "1".repeat(64);
nostrClient.pubkey = pubkey;
nostrClient.sessionActor = {
pubkey: "2".repeat(64),
privateKey: "3".repeat(64),
source: "session",
createdAt: Date.now(),
};
const app = createTestApp(pubkey);
assert.equal(app.isUserLoggedIn(), true);
} finally {
nostrClient.pubkey = previousPubkey;
nostrClient.sessionActor = previousSessionActor;
}
});
test("isUserLoggedIn rejects mismatched managed session actors", () => {
const previousPubkey = nostrClient.pubkey;
const previousSessionActor = nostrClient.sessionActor;