clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

main
tinyrelay / scripts / tiny-signing.test.mjs
tiny-signing.test.mjs 3.0K
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";56const 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});89function setup(signEvent) {10 const window = {nostr: {signEvent}, NostrSigner: {verifyEvent}};11 const tiny = {};12 return sharedSigning(window, tiny);13}1415test("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});2021test("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});2930test("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});4344test("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});4849test("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});5556test("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});