mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-28 16:32:28 +00:00
Handle missing signer when decrypting watch history
This commit is contained in:
1 parent
db0461e9c7
commit
61c8b3a8ee
2 files changed
+148
-3
No files matched your search
+75
-3
@@ -1778,6 +1778,9 @@ class NostrClient {
|
||||
delivered: previousEntry?.delivered instanceof Set
|
||||
? new Set(previousEntry.delivered)
|
||||
: new Set(),
|
||||
chunkNeedsSigner: previousEntry?.chunkNeedsSigner instanceof Set
|
||||
? new Set(previousEntry.chunkNeedsSigner)
|
||||
: new Set(),
|
||||
};
|
||||
|
||||
const validKeys = new Set(entry.items.map((item) => pointerKey(item)));
|
||||
@@ -1801,6 +1804,11 @@ class NostrClient {
|
||||
entry.delivered.delete(key);
|
||||
}
|
||||
}
|
||||
for (const key of [...entry.chunkNeedsSigner]) {
|
||||
if (!validKeys.has(key)) {
|
||||
entry.chunkNeedsSigner.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
const previousChunkPointers = previousEntry?.chunkPointers;
|
||||
const headPointer = previousChunkPointers?.head
|
||||
@@ -2077,12 +2085,39 @@ class NostrClient {
|
||||
}
|
||||
|
||||
const normalizedLogged =
|
||||
typeof this.pubkey === "string" ? this.pubkey.toLowerCase() : "";
|
||||
typeof this.pubkey === "string" && this.pubkey.trim()
|
||||
? this.pubkey.trim().toLowerCase()
|
||||
: "";
|
||||
const pointerAuthor =
|
||||
typeof pointerEvent?.pubkey === "string" && pointerEvent.pubkey.trim()
|
||||
? pointerEvent.pubkey.trim().toLowerCase()
|
||||
: "";
|
||||
const hasExtensionDecrypt =
|
||||
typeof window?.nostr?.nip04?.decrypt === "function";
|
||||
|
||||
const shouldDeferMissingSigner =
|
||||
normalizedActor &&
|
||||
normalizedActor === normalizedLogged &&
|
||||
pointerAuthor &&
|
||||
pointerAuthor === normalizedActor &&
|
||||
!hasExtensionDecrypt;
|
||||
|
||||
if (shouldDeferMissingSigner) {
|
||||
fallbackPayload.needsSignerRetry = true;
|
||||
const warningMeta = {
|
||||
actor: normalizedActor,
|
||||
};
|
||||
if (typeof pointerEvent?.id === "string" && pointerEvent.id) {
|
||||
warningMeta.event = pointerEvent.id;
|
||||
}
|
||||
console.warn("[nostr] watch-history-decrypt-missing-signer", warningMeta);
|
||||
return fallbackPayload;
|
||||
}
|
||||
|
||||
if (
|
||||
normalizedActor &&
|
||||
normalizedActor === normalizedLogged &&
|
||||
window?.nostr?.nip04?.decrypt
|
||||
hasExtensionDecrypt
|
||||
) {
|
||||
try {
|
||||
const plaintext = await window.nostr.nip04.decrypt(
|
||||
@@ -3932,7 +3967,11 @@ class NostrClient {
|
||||
indexEvent: null,
|
||||
chunkAddresses: new Set(),
|
||||
expectedChunkIdentifiers: new Set(),
|
||||
needsSignerRetry: new Set(),
|
||||
};
|
||||
if (!(bucket.needsSignerRetry instanceof Set)) {
|
||||
bucket.needsSignerRetry = new Set();
|
||||
}
|
||||
|
||||
bucket.chunks.set(chunkIndex, {
|
||||
event,
|
||||
@@ -3941,6 +3980,7 @@ class NostrClient {
|
||||
snapshot: snapshotId,
|
||||
chunkIndex,
|
||||
totalChunks,
|
||||
needsSignerRetry: !!payload?.needsSignerRetry,
|
||||
},
|
||||
created_at: typeof event.created_at === "number" ? event.created_at : 0,
|
||||
});
|
||||
@@ -3951,6 +3991,11 @@ class NostrClient {
|
||||
bucket.latestCreatedAt = createdAt;
|
||||
}
|
||||
bucket.version = Math.max(bucket.version, payload.version || 0);
|
||||
if (payload?.needsSignerRetry) {
|
||||
bucket.needsSignerRetry.add(chunkIndex);
|
||||
} else {
|
||||
bucket.needsSignerRetry.delete(chunkIndex);
|
||||
}
|
||||
const chunkAddress = eventToAddressPointer(event);
|
||||
if (chunkAddress) {
|
||||
bucket.chunkAddresses.add(chunkAddress);
|
||||
@@ -3971,7 +4016,11 @@ class NostrClient {
|
||||
indexEvent: null,
|
||||
chunkAddresses: new Set(),
|
||||
expectedChunkIdentifiers: new Set(),
|
||||
needsSignerRetry: new Set(),
|
||||
};
|
||||
if (!(bucket.needsSignerRetry instanceof Set)) {
|
||||
bucket.needsSignerRetry = new Set();
|
||||
}
|
||||
|
||||
if (meta.event) {
|
||||
const createdAt =
|
||||
@@ -4060,6 +4109,9 @@ class NostrClient {
|
||||
expectedChunkIdentifiers: bucket.expectedChunkIdentifiers instanceof Set
|
||||
? new Set(bucket.expectedChunkIdentifiers)
|
||||
: new Set(),
|
||||
needsSignerRetry: bucket.needsSignerRetry instanceof Set
|
||||
? new Set(bucket.needsSignerRetry)
|
||||
: new Set(),
|
||||
};
|
||||
|
||||
if (!fallbackSnapshot) {
|
||||
@@ -4124,6 +4176,12 @@ class NostrClient {
|
||||
entry.chunkEvents.clear();
|
||||
}
|
||||
|
||||
if (!(entry.chunkNeedsSigner instanceof Set)) {
|
||||
entry.chunkNeedsSigner = new Set();
|
||||
} else {
|
||||
entry.chunkNeedsSigner.clear();
|
||||
}
|
||||
|
||||
const chunkPointerItemsForEntry = [];
|
||||
const chunkPointerKeys = new Set();
|
||||
let indexPointerForEntry = null;
|
||||
@@ -4178,8 +4236,22 @@ class NostrClient {
|
||||
continue;
|
||||
}
|
||||
const clonedChunkEvent = cloneEventForCache(chunk.event);
|
||||
if (clonedChunkEvent) {
|
||||
const chunkPayloadIndex = Number.isFinite(chunk.payload?.chunkIndex)
|
||||
? Math.max(0, Math.floor(chunk.payload.chunkIndex))
|
||||
: null;
|
||||
const flaggedBySnapshot =
|
||||
chunkPayloadIndex !== null &&
|
||||
effectiveSnapshot?.needsSignerRetry instanceof Set &&
|
||||
effectiveSnapshot.needsSignerRetry.has(chunkPayloadIndex);
|
||||
const needsSignerRetry =
|
||||
!!chunk.payload?.needsSignerRetry || flaggedBySnapshot;
|
||||
if (needsSignerRetry) {
|
||||
entry.chunkNeedsSigner.add(key);
|
||||
entry.resolved.delete(key);
|
||||
} else if (clonedChunkEvent) {
|
||||
entry.chunkEvents.set(key, clonedChunkEvent);
|
||||
} else {
|
||||
entry.chunkEvents.set(key, chunk.event);
|
||||
}
|
||||
chunkPointerKeys.add(key);
|
||||
chunkPointerItemsForEntry.push(pointer);
|
||||
|
||||
@@ -1381,6 +1381,79 @@ try {
|
||||
}
|
||||
}
|
||||
|
||||
const missingSignerClient = createDecryptClient(LOGGED_ACTOR);
|
||||
missingSignerClient.pubkey = LOGGED_ACTOR;
|
||||
missingSignerClient.sessionActor = null;
|
||||
|
||||
let missingSignerEnsureCalls = 0;
|
||||
missingSignerClient.ensureSessionActor = async () => {
|
||||
missingSignerEnsureCalls += 1;
|
||||
return LOGGED_ACTOR;
|
||||
};
|
||||
|
||||
const priorMissingSignerNostr = globalThis.window.nostr;
|
||||
const priorMissingSignerSessionDecrypt = globalThis.window.NostrTools.nip04.decrypt;
|
||||
let missingSignerSessionDecryptCalls = 0;
|
||||
|
||||
try {
|
||||
delete globalThis.window.nostr;
|
||||
globalThis.window.NostrTools.nip04.decrypt = async () => {
|
||||
missingSignerSessionDecryptCalls += 1;
|
||||
return JSON.stringify(encryptedPayload);
|
||||
};
|
||||
|
||||
const missingSignerChunkEvent = {
|
||||
...encryptedChunkEvent,
|
||||
pubkey: LOGGED_ACTOR,
|
||||
id: "missing-signer-event",
|
||||
};
|
||||
|
||||
const missingSignerResult = await missingSignerClient.decryptWatchHistoryEvent(
|
||||
missingSignerChunkEvent,
|
||||
LOGGED_ACTOR
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
missingSignerEnsureCalls,
|
||||
0,
|
||||
"missing signer should not trigger session actor ensure"
|
||||
);
|
||||
assert.equal(
|
||||
missingSignerSessionDecryptCalls,
|
||||
0,
|
||||
"missing signer should skip session decrypt fallback"
|
||||
);
|
||||
assert.equal(
|
||||
missingSignerResult.needsSignerRetry,
|
||||
true,
|
||||
"missing signer fallback should mark retry flag"
|
||||
);
|
||||
assert.deepEqual(
|
||||
missingSignerResult.items.map((item) => ({
|
||||
type: item.type,
|
||||
value: item.value,
|
||||
relay: item.relay || null,
|
||||
})),
|
||||
encryptedPayload.items.map((item) => ({
|
||||
type: item.type,
|
||||
value: item.value,
|
||||
relay: item.relay || null,
|
||||
})),
|
||||
"missing signer fallback should preserve pointer metadata"
|
||||
);
|
||||
} finally {
|
||||
if (priorMissingSignerNostr === undefined) {
|
||||
delete globalThis.window.nostr;
|
||||
} else {
|
||||
globalThis.window.nostr = priorMissingSignerNostr;
|
||||
}
|
||||
if (priorMissingSignerSessionDecrypt === undefined) {
|
||||
delete globalThis.window.NostrTools.nip04.decrypt;
|
||||
} else {
|
||||
globalThis.window.NostrTools.nip04.decrypt = priorMissingSignerSessionDecrypt;
|
||||
}
|
||||
}
|
||||
|
||||
const unsortedVideos = [
|
||||
{ id: "alpha", watchHistory: { watchedAt: 1_700_000_000_500 } },
|
||||
{ id: "bravo", watchHistory: { watchedAt: 1_700_000_010_000 } },
|
||||
|
||||
Reference in new issue
Block a user