From 016198c3014d642e16c7d8d105b2b37a10bfa9e4 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 20 Nov 2023 17:52:37 -0600 Subject: [PATCH] Sign NIP-46 events with proof-of-work --- src/api/hooks/nostr/useSignerStream.ts | 2 +- src/features/nostr/sign.ts | 15 +++++++++++++-- src/schemas/nostr.ts | 7 ++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/api/hooks/nostr/useSignerStream.ts b/src/api/hooks/nostr/useSignerStream.ts index 6780351c8..216c3a8e3 100644 --- a/src/api/hooks/nostr/useSignerStream.ts +++ b/src/api/hooks/nostr/useSignerStream.ts @@ -36,7 +36,7 @@ function useSignerStream() { const respMsg = { id: reqMsg.data.id, - result: await signEvent(reqMsg.data.params[0]), + result: await signEvent(reqMsg.data.params[0], reqMsg.data.params[1]), }; const respEvent = await signEvent({ diff --git a/src/features/nostr/sign.ts b/src/features/nostr/sign.ts index 5a9b72082..8158d734d 100644 --- a/src/features/nostr/sign.ts +++ b/src/features/nostr/sign.ts @@ -7,6 +7,8 @@ import { nip04 as _nip04, } from 'nostr-tools'; +import { powWorker } from 'soapbox/workers'; + /** localStorage key for the Nostr private key (if not using NIP-07). */ const LOCAL_KEY = 'soapbox:nostr:privateKey'; @@ -28,9 +30,18 @@ async function getPublicKey(): Promise { return window.nostr ? window.nostr.getPublicKey() : _getPublicKey(getPrivateKey()); } +interface SignEventOpts { + pow?: number; +} + /** Sign an event with NIP-07, or the locally generated key. */ -async function signEvent(event: EventTemplate): Promise> { - return window.nostr ? window.nostr.signEvent(event) as Promise> : finishEvent(event, getPrivateKey()) ; +async function signEvent(template: EventTemplate, opts: SignEventOpts = {}): Promise> { + if (opts.pow) { + const event = await powWorker.mine({ ...template, pubkey: await getPublicKey() }, opts.pow) as Omit, 'sig'>; + return window.nostr ? window.nostr.signEvent(event) as Promise> : finishEvent(event, getPrivateKey()) ; + } else { + return window.nostr ? window.nostr.signEvent(template) as Promise> : finishEvent(template, getPrivateKey()) ; + } } /** Crypto function with NIP-07, or the local key. */ diff --git a/src/schemas/nostr.ts b/src/schemas/nostr.ts index 1dcd0c466..03e93d12f 100644 --- a/src/schemas/nostr.ts +++ b/src/schemas/nostr.ts @@ -24,11 +24,16 @@ const eventSchema = eventTemplateSchema.extend({ /** Nostr event schema that also verifies the event's signature. */ const signedEventSchema = eventSchema.refine(verifySignature); +/** NIP-46 signer options. */ +const signEventOptsSchema = z.object({ + pow: z.number().int().nonnegative(), +}); + /** NIP-46 signer request. */ const connectRequestSchema = z.object({ id: z.string(), method: z.literal('sign_event'), - params: z.tuple([eventTemplateSchema]), + params: z.tuple([eventTemplateSchema]).or(z.tuple([eventTemplateSchema, signEventOptsSchema])), }); export { nostrIdSchema, kindSchema, eventSchema, signedEventSchema, connectRequestSchema }; \ No newline at end of file