mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Enforce reaction event id requirements
This commit is contained in:
1 parent
5fde1bb80c
commit
995ba14c14
2 files changed
+152
-17
No files matched your search
+27
-17
@@ -173,17 +173,6 @@ export async function publishVideoReaction(
|
||||
? pointer.relay.trim()
|
||||
: optionRelay;
|
||||
|
||||
const pointerTag =
|
||||
pointer.type === "a"
|
||||
? pointerRelay
|
||||
? ["a", pointer.value, pointerRelay]
|
||||
: ["a", pointer.value]
|
||||
: pointerRelay
|
||||
? ["e", pointer.value, pointerRelay]
|
||||
: ["e", pointer.value];
|
||||
|
||||
const pointerTags = [pointerTag];
|
||||
|
||||
let pointerEventId = normalizeString(pointer.type === "e" ? pointer.value : "");
|
||||
if (!pointerEventId) {
|
||||
pointerEventId = extractEventIdFromPointerInput(pointerInput);
|
||||
@@ -219,12 +208,33 @@ export async function publishVideoReaction(
|
||||
pointerEventRelay = pointerRelay;
|
||||
}
|
||||
|
||||
if (pointerEventId) {
|
||||
if (pointerEventRelay) {
|
||||
pointerTags.push(["e", pointerEventId, pointerEventRelay]);
|
||||
} else {
|
||||
pointerTags.push(["e", pointerEventId]);
|
||||
}
|
||||
if (!pointerEventId) {
|
||||
const errorDetails = pointer.type === "a"
|
||||
? "Unable to resolve event id for address reaction target."
|
||||
: "Unable to resolve event id for reaction target.";
|
||||
devLogger.warn("[nostr] " + errorDetails, pointerInput);
|
||||
return { ok: false, error: "missing-pointer-event-id", details: errorDetails };
|
||||
}
|
||||
|
||||
const pointerTags = [];
|
||||
let pointerTag = null;
|
||||
|
||||
if (pointer.type === "a") {
|
||||
const addressTag = pointerRelay
|
||||
? ["a", pointer.value, pointerRelay]
|
||||
: ["a", pointer.value];
|
||||
pointerTags.push(addressTag);
|
||||
pointerTag = addressTag;
|
||||
}
|
||||
|
||||
const eventTag = pointerEventRelay
|
||||
? ["e", pointerEventId, pointerEventRelay]
|
||||
: ["e", pointerEventId];
|
||||
|
||||
pointerTags.push(eventTag);
|
||||
|
||||
if (!pointerTag) {
|
||||
pointerTag = eventTag;
|
||||
}
|
||||
|
||||
const normalizedPointer = {
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
const { publishVideoReaction } = await import("../../js/nostr/reactionEvents.js");
|
||||
|
||||
function createReactionClient({ actorPubkey = "" } = {}) {
|
||||
const publishCalls = [];
|
||||
const pool = {
|
||||
publish(urls, event) {
|
||||
publishCalls.push({ urls, event });
|
||||
return {
|
||||
on(eventName, handler) {
|
||||
if (eventName === "ok") {
|
||||
handler();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const client = {
|
||||
pubkey: actorPubkey,
|
||||
relays: ["wss://relay.example"],
|
||||
pool,
|
||||
ensureExtensionPermissions: async () => ({ ok: true }),
|
||||
async ensureSessionActor() {
|
||||
if (!this.sessionActor) {
|
||||
this.sessionActor = {
|
||||
pubkey: actorPubkey,
|
||||
privateKey: "session-private-key",
|
||||
};
|
||||
}
|
||||
return actorPubkey;
|
||||
},
|
||||
};
|
||||
|
||||
if (actorPubkey) {
|
||||
client.sessionActor = {
|
||||
pubkey: actorPubkey,
|
||||
privateKey: "session-private-key",
|
||||
};
|
||||
}
|
||||
|
||||
return { client, publishCalls };
|
||||
}
|
||||
|
||||
const resolveActiveSignerStub = () => ({
|
||||
signEvent: async (event) => ({
|
||||
...event,
|
||||
id: `${event.kind}-${event.created_at}`,
|
||||
sig: "active-signature",
|
||||
}),
|
||||
});
|
||||
|
||||
const shouldRequestExtensionPermissionsStub = () => false;
|
||||
|
||||
const signEventWithPrivateKeyStub = (event) => ({
|
||||
...event,
|
||||
id: `${event.kind}-${event.created_at}-session`,
|
||||
sig: "session-signature",
|
||||
});
|
||||
|
||||
test("publishVideoReaction includes both address and event tags when reacting to addressable content", async () => {
|
||||
const actorPubkey = "0".repeat(64);
|
||||
const { client, publishCalls } = createReactionClient({ actorPubkey });
|
||||
|
||||
const result = await publishVideoReaction(
|
||||
client,
|
||||
{ type: "a", value: "30078:deadbeefcafebabe:clip-1", relay: "wss://relay.address" },
|
||||
{
|
||||
pointerEventId: "target-event-id",
|
||||
pointerEventRelay: "wss://event.relay",
|
||||
},
|
||||
{
|
||||
resolveActiveSigner: resolveActiveSignerStub,
|
||||
shouldRequestExtensionPermissions: shouldRequestExtensionPermissionsStub,
|
||||
signEventWithPrivateKey: signEventWithPrivateKeyStub,
|
||||
DEFAULT_NIP07_PERMISSION_METHODS: [],
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(result.ok, true, "reaction publish should succeed");
|
||||
assert.equal(publishCalls.length, 1, "reaction should publish exactly once");
|
||||
|
||||
const tags = publishCalls[0].event.tags || [];
|
||||
const addressTags = tags.filter((tag) => Array.isArray(tag) && tag[0] === "a");
|
||||
const eventTags = tags.filter((tag) => Array.isArray(tag) && tag[0] === "e");
|
||||
|
||||
assert.deepEqual(addressTags, [[
|
||||
"a",
|
||||
"30078:deadbeefcafebabe:clip-1",
|
||||
"wss://relay.address",
|
||||
]]);
|
||||
|
||||
assert.deepEqual(eventTags, [["e", "target-event-id", "wss://event.relay"]]);
|
||||
});
|
||||
|
||||
test("publishVideoReaction aborts when address pointer is missing a resolvable event id", async () => {
|
||||
const actorPubkey = "f".repeat(64);
|
||||
const { client, publishCalls } = createReactionClient({ actorPubkey });
|
||||
|
||||
const result = await publishVideoReaction(
|
||||
client,
|
||||
"30078:abcdef:clip-1",
|
||||
{},
|
||||
{
|
||||
resolveActiveSigner: () => {
|
||||
throw new Error("resolveActiveSigner should not be called when validation fails");
|
||||
},
|
||||
shouldRequestExtensionPermissions: shouldRequestExtensionPermissionsStub,
|
||||
signEventWithPrivateKey: signEventWithPrivateKeyStub,
|
||||
DEFAULT_NIP07_PERMISSION_METHODS: [],
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(result.ok, false, "reaction publish should fail when event id is missing");
|
||||
assert.equal(result.error, "missing-pointer-event-id");
|
||||
assert.match(
|
||||
result.details,
|
||||
/Unable to resolve event id/,
|
||||
"error details should explain why the publish failed",
|
||||
);
|
||||
assert.equal(publishCalls.length, 0, "reaction should not publish when validation fails");
|
||||
});
|
||||
Reference in new issue
Block a user