sign: ensure the NIP-46 result matches the template

This commit is contained in:
Alex Gleason 2023-09-02 20:09:28 -05:00
parent 007565b513
commit c8a5da086e
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
2 changed files with 19 additions and 7 deletions

View File

@ -5,14 +5,14 @@ import { type Event, type EventTemplate, finishEvent, HTTPException } from '@/de
import { connectResponseSchema } from '@/schemas/nostr.ts';
import { jsonSchema } from '@/schema.ts';
import { Sub } from '@/subs.ts';
import { Time } from '@/utils.ts';
import { eventMatchesTemplate, Time } from '@/utils.ts';
import { createAdminEvent } from '@/utils/web.ts';
/**
* Sign Nostr event using the app context.
*
* - If a secret key is provided, it will be used to sign the event.
* - If `X-Nostr-Sign` is passed, it will use a NIP-46 to sign the event.
* - If `X-Nostr-Sign` is passed, it will use NIP-46 to sign the event.
*/
async function signEvent<K extends number = number>(event: EventTemplate<K>, c: AppContext): Promise<Event<K>> {
const seckey = c.get('seckey');
@ -54,13 +54,14 @@ async function signNostrConnect<K extends number = number>(event: EventTemplate<
tags: [['p', pubkey]],
}, c);
return awaitSignedEvent<K>(pubkey, messageId, c);
return awaitSignedEvent<K>(pubkey, messageId, event, c);
}
/** Wait for signed event to be sent through Nostr relay. */
async function awaitSignedEvent<K extends number = number>(
pubkey: string,
messageId: string,
template: EventTemplate<K>,
c: AppContext,
): Promise<Event<K>> {
const sub = Sub.sub(messageId, '1', [{ kinds: [24133], authors: [pubkey], '#p': [Conf.pubkey] }]);
@ -79,12 +80,17 @@ async function awaitSignedEvent<K extends number = number>(
for await (const event of sub) {
if (event.kind === 24133) {
const decrypted = await decryptAdmin(event.pubkey, event.content);
const msg = jsonSchema.pipe(connectResponseSchema).parse(decrypted);
if (msg.id === messageId) {
const result = jsonSchema
.pipe(connectResponseSchema)
.refine((msg) => msg.id === messageId)
.refine((msg) => eventMatchesTemplate(msg.result, template))
.safeParse(decrypted);
if (result.success) {
close();
clearTimeout(timeout);
return msg.result as Event<K>;
return result.data.result as Event<K>;
}
}
}

View File

@ -1,4 +1,4 @@
import { type Event, nip19, z } from '@/deps.ts';
import { type Event, type EventTemplate, getEventHash, nip19, z } from '@/deps.ts';
import { getAuthor } from '@/queries.ts';
import { lookupNip05Cached } from '@/utils/nip05.ts';
@ -106,11 +106,17 @@ function dedupeEvents<K extends number>(events: Event<K>[]): Event<K>[] {
return [...new Map(events.map((event) => [event.id, event])).values()];
}
/** Ensure the template and event match on their shared keys. */
function eventMatchesTemplate(event: Event, template: EventTemplate): boolean {
return getEventHash(event) === getEventHash({ pubkey: event.pubkey, ...template });
}
export {
bech32ToPubkey,
dedupeEvents,
eventAge,
eventDateComparator,
eventMatchesTemplate,
findTag,
isFollowing,
isRelay,