tinyrelayfile
tinyrelay/scripts/tiny-signing.test.mjs/

scripts/tiny-signing.test.mjs raw
1import assert from "node:assert/strict";
2import test from "node:test";
3import {finalizeEvent, generateSecretKey, getPublicKey, verifyEvent} from "nostr-tools/pure";
4import {sharedSigning} from "./test-signing.mjs";
5
6const secret = generateSecretKey();
7const reorder = event => ({content: event.content, tags: event.tags, created_at: event.created_at, kind: event.kind, pubkey: event.pubkey, id: event.id, sig: event.sig});
8
9function setup(signEvent) {
10 const window = {nostr: {signEvent}, NostrSigner: {verifyEvent}};
11 const tiny = {};
12 return sharedSigning(window, tiny);
13}
14
15test("signing accepts a valid event when a signer reorders object fields", async () => {
16 const signing = setup(async unsigned => reorder(finalizeEvent(structuredClone(unsigned), secret)));
17 const event = await signing.signEvent({kind: 10002, created_at: 1, content: "", tags: [["r", "wss://relay.example"]]});
18 assert.equal(verifyEvent(event), true);
19});
20
21test("signing still rejects a signer that changes an unsigned field", async () => {
22 const signing = setup(async unsigned => {
23 const event = structuredClone(unsigned);
24 event.content = "changed";
25 return finalizeEvent(event, secret);
26 });
27 await assert.rejects(signing.signEvent({kind: 10002, created_at: 1, content: "", tags: []}), /invalid or changed/);
28});
29
30test("signing compares against a snapshot when the caller mutates its input", async () => {
31 let received;
32 const signing = setup(async unsigned => {
33 received = unsigned;
34 return finalizeEvent(structuredClone(unsigned), secret);
35 });
36 const unsigned = {kind: 10002, created_at: 1, content: "", tags: []};
37 const pending = signing.signEvent(unsigned);
38 unsigned.tags.push(["r", "wss://changed.example"]);
39 const event = await pending;
40 assert.equal(received.tags.length, 0);
41 assert.equal(event.tags.length, 0);
42});
43
44test("signing rejects an invalid signature even when every requested field matches", async () => {
45 const signing = setup(async unsigned => ({...JSON.parse(JSON.stringify(finalizeEvent(structuredClone(unsigned), secret))), sig: "0".repeat(128)}));
46 await assert.rejects(signing.signEvent({content: "", tags: [], created_at: 1, kind: 10050}), /invalid or changed/);
47});
48
49test("signing preserves a requested author and rejects a different signer", async () => {
50 const signing = setup(async unsigned => reorder(finalizeEvent(structuredClone(unsigned), secret)));
51 const unsigned = {pubkey: getPublicKey(secret), content: "", tags: [], created_at: 1, kind: 10002};
52 assert.equal((await signing.signEvent(unsigned)).pubkey, unsigned.pubkey);
53 await assert.rejects(signing.signEvent({...unsigned, pubkey: getPublicKey(generateSecretKey())}), /invalid or changed/);
54});
55
56test("signing rejects reordered tags and signer-side mutations", async () => {
57 const signing = setup(async unsigned => {
58 unsigned.tags.reverse();
59 return finalizeEvent(structuredClone(unsigned), secret);
60 });
61 await assert.rejects(signing.signEvent({content: "", tags: [["r", "wss://first.example"], ["r", "wss://second.example"]], created_at: 1, kind: 10002}), /invalid or changed/);
62});

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs