diff --git a/event.test.ts b/event.test.ts index 625447a..ff91ac6 100644 --- a/event.test.ts +++ b/event.test.ts @@ -7,6 +7,7 @@ import { verifySignature, getSignature, Kind, + verifiedSymbol, } from './event.ts' import { getPublicKey } from './keys.ts' @@ -236,7 +237,7 @@ describe('Event', () => { it('should return false for an invalid event signature', () => { const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' - const event = finishEvent( + const { [verifiedSymbol]: _, ...event } = finishEvent( { kind: Kind.Text, tags: [], @@ -247,7 +248,7 @@ describe('Event', () => { ) // tamper with the signature - event.sig = event.sig.replace(/0/g, '1') + event.sig = event.sig.replace(/^.{3}/g, '666') const isValid = verifySignature(event) @@ -260,7 +261,7 @@ describe('Event', () => { const privateKey2 = '5b4a34f4e4b23c63ad55a35e3f84a3b53d96dbf266edf521a8358f71d19cbf67' const publicKey2 = getPublicKey(privateKey2) - const event = finishEvent( + const { [verifiedSymbol]: _, ...event } = finishEvent( { kind: Kind.Text, tags: [], @@ -278,6 +279,27 @@ describe('Event', () => { expect(isValid).toEqual(false) }) + + it('should return false for an invalid event id', () => { + const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' + + const { [verifiedSymbol]: _, ...event } = finishEvent( + { + kind: 1, + tags: [], + content: 'Hello, world!', + created_at: 1617932115, + }, + privateKey, + ) + + // tamper with the id + event.id = event.id.replace(/^.{3}/g, '666') + + const isValid = verifySignature(event) + + expect(isValid).toEqual(false) + }) }) describe('getSignature', () => { @@ -296,9 +318,9 @@ describe('Event', () => { const sig = getSignature(unsignedEvent, privateKey) // verify the signature - // @ts-expect-error const isValid = verifySignature({ ...unsignedEvent, + id: getEventHash(unsignedEvent), sig, }) diff --git a/event.ts b/event.ts index e0440fb..6ddaf11 100644 --- a/event.ts +++ b/event.ts @@ -71,11 +71,12 @@ export function getBlankEvent(kind: K | Kind.Blank = Kind.Blank) { } } -export function finishEvent(t: EventTemplate, privateKey: string): Event { - let event = t as Event +export function finishEvent(t: EventTemplate, privateKey: string): VerifiedEvent { + const event = t as VerifiedEvent event.pubkey = getPublicKey(privateKey) event.id = getEventHash(event) event.sig = getSignature(event, privateKey) + event[verifiedSymbol] = true return event } @@ -115,11 +116,16 @@ export function validateEvent(event: T): event is T & UnsignedEvent { /** Verify the event's signature. This function mutates the event with a `verified` symbol, making it idempotent. */ export function verifySignature(event: Event): event is VerifiedEvent { if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol] + + const hash = getEventHash(event) + if (hash !== event.id) { + return (event[verifiedSymbol] = false) + } + try { - event[verifiedSymbol] = schnorr.verify(event.sig, getEventHash(event), event.pubkey) - return event[verifiedSymbol] + return (event[verifiedSymbol] = schnorr.verify(event.sig, hash, event.pubkey)) } catch (err) { - return false + return (event[verifiedSymbol] = false) } } diff --git a/pool.ts b/pool.ts index bda36bb..7635812 100644 --- a/pool.ts +++ b/pool.ts @@ -79,10 +79,13 @@ export class SimplePool { let eosesMissing = relays.length let eoseSent = false - let eoseTimeout = setTimeout(() => { - eoseSent = true - for (let cb of eoseListeners.values()) cb() - }, opts?.eoseSubTimeout || this.eoseSubTimeout) + let eoseTimeout = setTimeout( + () => { + eoseSent = true + for (let cb of eoseListeners.values()) cb() + }, + opts?.eoseSubTimeout || this.eoseSubTimeout, + ) relays .filter((r, i, a) => a.indexOf(r) === i)