Short-circuit hex actor keys

This commit is contained in:
thePR0M3TH3AN committed 2025-10-09 15:26:51 -04:00
1 parent cc02228548
commit 89986759e0
2 files changed
+138 -24

No files matched your search

+34 -5
View File
@@ -2323,6 +2323,10 @@ function normalizeActorKey(actor) {
return "";
}
if (/^[0-9a-f]{64}$/i.test(trimmed)) {
return trimmed.toLowerCase();
}
const decodedHex = decodeNpubToHex(trimmed);
if (decodedHex) {
return decodedHex.toLowerCase();
@@ -2587,23 +2591,48 @@ function cloneEventForCache(event) {
}
function decodeNpubToHex(npub) {
if (typeof npub !== "string" || !npub.trim()) {
if (typeof npub !== "string") {
return "";
}
const tools = getCachedNostrTools();
const trimmed = npub.trim();
if (!trimmed) {
return "";
}
if (/^[0-9a-f]{64}$/i.test(trimmed)) {
return trimmed.toLowerCase();
}
const lower = trimmed.toLowerCase();
const hasNpubPrefix = lower.startsWith("npub1");
if (!hasNpubPrefix) {
return "";
}
const warnableNpub = /^npub1[023456789acdefghjklmnpqrstuvwxyz]+$/i.test(
trimmed
);
let tools = cachedNostrTools;
if (!tools || typeof tools?.nip19?.decode !== "function") {
const fallbackTools = readToolkitFromScope();
if (fallbackTools) {
tools = fallbackTools;
}
}
if (!tools?.nip19 || typeof tools.nip19.decode !== "function") {
return "";
}
try {
const decoded = tools.nip19.decode(npub.trim());
const decoded = tools.nip19.decode(trimmed);
if (decoded?.type === "npub" && typeof decoded.data === "string") {
return decoded.data;
}
} catch (error) {
if (isDevMode) {
console.warn(`[nostr] Failed to decode npub: ${npub}`, error);
if (isDevMode && warnableNpub) {
console.warn(`[nostr] Failed to decode npub: ${trimmed}`, error);
}
}
return "";
+104 -19
View File
@@ -20,6 +20,7 @@ const {
const {
nostrClient,
chunkWatchHistoryPayloadItems,
normalizeActorKey,
} = await import("../js/nostr.js");
const { watchHistoryService } = await import("../js/watchHistoryService.js");
const { getApplication, setApplication } = await import(
@@ -348,9 +349,86 @@ function maxCreatedAt(events = []) {
}, 0);
}
async function testNormalizeActorKeyShortCircuit() {
console.log("Running normalizeActorKey short-circuit test...");
const actorHex = "f".repeat(64);
const actorNpub = "npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq";
if (!window.NostrTools || typeof window.NostrTools !== "object") {
window.NostrTools = {};
}
const previousNip19 = window.NostrTools.nip19;
const previousDecode =
previousNip19 && typeof previousNip19.decode === "function"
? previousNip19.decode
: null;
const decodeCalls = [];
window.NostrTools.nip19 = {
...(previousNip19 || {}),
decode(value) {
decodeCalls.push(value);
if (value === actorNpub) {
return { type: "npub", data: actorHex };
}
if (typeof previousDecode === "function") {
return previousDecode(value);
}
throw new Error("unsupported-npub");
},
};
const originalWarn = console.warn;
const warnings = [];
console.warn = (...args) => {
warnings.push(args);
};
try {
const upperHex = actorHex.toUpperCase();
const normalizedHex = normalizeActorKey(upperHex);
assert.equal(
normalizedHex,
actorHex,
"hex inputs should normalize to lowercase hex",
);
assert.equal(
decodeCalls.length,
0,
"hex inputs should not invoke nip19.decode",
);
assert.equal(
warnings.length,
0,
"hex inputs should not emit decode warnings",
);
const normalizedNpub = normalizeActorKey(actorNpub);
assert.equal(normalizedNpub, actorHex, "npub inputs should decode to hex");
assert.equal(
decodeCalls.length,
1,
"npub inputs should invoke nip19.decode",
);
assert.equal(
warnings.length,
0,
"successful npub decode should not emit warnings",
);
} finally {
console.warn = originalWarn;
if (previousNip19) {
window.NostrTools.nip19 = previousNip19;
} else if (window.NostrTools) {
delete window.NostrTools.nip19;
}
}
}
async function testFetchWatchHistoryExtensionDecryptsHexAndNpub() {
const actorHex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
const actorNpub = "npub-test-extension-decrypt";
const actorNpub =
"npub1testextensiondecryptqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq";
const snapshotId = "extension-fetch";
const chunkIdentifier = "chunk-extension";
@@ -401,23 +479,25 @@ async function testFetchWatchHistoryExtensionDecryptsHexAndNpub() {
],
};
const previousNostrTools = window.NostrTools || {};
window.NostrTools = {
...previousNostrTools,
nip19: {
...(previousNostrTools.nip19 || {}),
decode: (value) => {
if (value === actorNpub) {
return { type: "npub", data: actorHex };
}
if (
previousNostrTools.nip19 &&
typeof previousNostrTools.nip19.decode === "function"
) {
return previousNostrTools.nip19.decode(value);
}
throw new Error("unsupported-npub");
},
if (!window.NostrTools || typeof window.NostrTools !== "object") {
window.NostrTools = {};
}
const previousNip19 = window.NostrTools.nip19;
const previousDecode =
previousNip19 && typeof previousNip19.decode === "function"
? previousNip19.decode
: null;
window.NostrTools.nip19 = {
...(previousNip19 || {}),
decode: (value) => {
if (value === actorNpub) {
return { type: "npub", data: actorHex };
}
if (typeof previousDecode === "function") {
return previousDecode(value);
}
throw new Error("unsupported-npub");
},
};
@@ -505,7 +585,11 @@ async function testFetchWatchHistoryExtensionDecryptsHexAndNpub() {
await runVariant("hex", actorHex, actorHex);
await runVariant("npub", actorNpub, actorNpub);
} finally {
window.NostrTools = previousNostrTools;
if (previousNip19) {
window.NostrTools.nip19 = previousNip19;
} else if (window.NostrTools) {
delete window.NostrTools.nip19;
}
nostrClient.ensureSessionActor = originalEnsure;
nostrClient.sessionActor = originalSession;
nostrClient.pubkey = originalPub;
@@ -1573,6 +1657,7 @@ await testWatchHistoryStaleCacheRefresh();
await testWatchHistoryLocalFallbackWhenDisabled();
await testWatchHistorySyncEnabledForLoggedInUsers();
await testWatchHistoryAppLoginFallback();
await testNormalizeActorKeyShortCircuit();
console.log("watch-history.test.mjs completed successfully");