Fix NIP-71 publish pubkey normalization

This commit is contained in:
thePR0M3TH3AN committed 2025-10-26 14:43:04 -04:00
1 parent 08afaf86c9
commit 4d3bf6f993
2 files changed
+95 -10

No files matched your search

+19 -10
View File
@@ -3378,6 +3378,15 @@ export class NostrClient {
async publishVideo(videoPayload, pubkey) {
if (!pubkey) throw new Error("Not logged in to publish video.");
const normalizedPubkey =
typeof pubkey === "string" ? pubkey.trim() : "";
if (!normalizedPubkey) {
throw new Error("Not logged in to publish video.");
}
const userPubkeyLower = normalizedPubkey.toLowerCase();
const { videoData, nip71Metadata } = extractVideoPublishPayload(videoPayload);
const nip71EditedFlag =
videoPayload && typeof videoPayload === "object"
@@ -3389,7 +3398,7 @@ export class NostrClient {
// controllers and revert helpers so all paths stay in lockstep.
devLogger.log("Publishing new video with data:", videoData);
if (nip71Metadata) {
devLogger.log("Including NIP-71 metadata:", nip71Metadata);
devLogger.log("Including NIP-71 metadata:", nip71Metadata);
}
const rawMagnet = typeof videoData.magnet === "string" ? videoData.magnet : "";
@@ -3455,7 +3464,7 @@ export class NostrClient {
);
const event = buildVideoPostEvent({
pubkey,
pubkey: normalizedPubkey,
created_at: createdAt,
dTagValue,
content: contentObject,
@@ -3463,7 +3472,7 @@ export class NostrClient {
});
devLogger.log("Publish event with brand-new root:", videoRootId);
devLogger.log("Event content:", event.content);
devLogger.log("Event content:", event.content);
try {
const { signedEvent } = await this.signAndPublishEvent(event, {
@@ -3496,7 +3505,7 @@ export class NostrClient {
}
const mirrorEvent = buildVideoMirrorEvent({
pubkey,
pubkey: normalizedPubkey,
created_at: createdAt,
tags: mirrorTags,
content: altText,
@@ -3536,10 +3545,10 @@ export class NostrClient {
description: contentObject.description,
url: contentObject.url,
magnet: contentObject.magnet,
thumbnail: contentObject.thumbnail,
mode: contentObject.mode,
isPrivate: wantPrivate,
isNsfw: contentObject.isNsfw,
thumbnail: contentObject.thumbnail,
mode: contentObject.mode,
isPrivate: wantPrivate,
isNsfw: contentObject.isNsfw,
isForKids: contentObject.isForKids,
};
@@ -3559,8 +3568,8 @@ export class NostrClient {
},
userPubkeyLower,
{
videoRootId: oldRootId,
dTag: newD,
videoRootId,
dTag: dTagValue,
eventId: signedEvent.id,
}
);
+76
View File
@@ -283,9 +283,85 @@ try {
}
}
async function testPublishVideoNormalizesPubkeyForNip71Metadata() {
const uppercasePubkey = "AB".repeat(32);
const originalSignAndPublish = nostrClient.signAndPublishEvent;
const originalPublishNip71 = nostrClient.publishNip71Video;
const publishedEvents = [];
const nip71Calls = [];
nostrClient.signAndPublishEvent = async (event, options = {}) => {
publishedEvents.push({ event, options });
const contextLabel =
typeof options?.context === "string" && options.context
? options.context
: "event";
return {
signedEvent: {
...event,
id: event?.id || `signed-${contextLabel}`,
},
};
};
nostrClient.publishNip71Video = async (payload, pubkey, pointerOptions) => {
nip71Calls.push({ payload, pubkey, pointerOptions });
return null;
};
try {
const result = await nostrClient.publishVideo(
{
legacyFormData: {
title: "Metadata Video",
description: "Video with metadata",
url: "https://cdn.example/video.mp4",
mode: "live",
},
nip71: {
title: "Metadata Video",
imeta: [{ url: "https://cdn.example/video.mp4", m: "video/mp4" }],
},
},
uppercasePubkey,
);
assert.equal(typeof result?.id, "string", "publishVideo should resolve with a signed event");
assert.ok(
publishedEvents.some((entry) => entry.options?.context === "video note"),
"publishVideo should sign the primary video note",
);
assert.equal(
nip71Calls.length,
1,
"publishVideo should invoke publishNip71Video when metadata is provided",
);
assert.equal(
nip71Calls[0]?.pubkey,
uppercasePubkey.toLowerCase(),
"publishVideo should normalize the pubkey passed to publishNip71Video",
);
assert.ok(
typeof nip71Calls[0]?.pointerOptions?.videoRootId === "string" &&
nip71Calls[0]?.pointerOptions?.videoRootId.length > 0,
"publishVideo should supply pointer metadata for the new video",
);
assert.ok(
typeof nip71Calls[0]?.pointerOptions?.dTag === "string" &&
nip71Calls[0]?.pointerOptions?.dTag.length > 0,
"publishVideo should provide the new d tag as a pointer",
);
} finally {
nostrClient.signAndPublishEvent = originalSignAndPublish;
nostrClient.publishNip71Video = originalPublishNip71;
}
}
await testPublishVideoRejectsWhenAllRelaysFail();
await testPublishSubscriptionListRejectsWhenAllRelaysFail();
await testPublishBlockListRejectsWhenAllRelaysFail();
await testPublishVideoNormalizesPubkeyForNip71Metadata();
console.log("nostr publish rejection tests passed");
} finally {