From 940fc7a305d2ead9bd2f858f1210b294832a69ff Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 26 Mar 2024 17:35:08 -0500 Subject: [PATCH] Add DVM module, process domain name requests --- src/pipeline.ts | 2 + src/pipeline/DVM.ts | 107 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 src/pipeline/DVM.ts diff --git a/src/pipeline.ts b/src/pipeline.ts index 1f34b0f..f187570 100644 --- a/src/pipeline.ts +++ b/src/pipeline.ts @@ -6,6 +6,7 @@ import { deleteAttachedMedia } from '@/db/unattached-media.ts'; import { Debug, LNURL, type NostrEvent } from '@/deps.ts'; import { DittoEvent } from '@/interfaces/DittoEvent.ts'; import { isEphemeralKind } from '@/kinds.ts'; +import { DVM } from '@/pipeline/DVM.ts'; import { getAuthor } from '@/queries.ts'; import { updateStats } from '@/stats.ts'; import { purifyEvent } from '@/storages/hydrate.ts'; @@ -36,6 +37,7 @@ async function handleEvent(event: DittoEvent, signal: AbortSignal): Promise { + if (event.kind < 5000 || event.kind > 5999) { + throw new Error('Unsupported event kind'); + } + + switch (event.kind) { + case 5950: + await DVM.nameRegistration(event); + break; + } + } + + static async nameRegistration(event: NostrEvent): Promise { + const admin = await new AdminSigner().getPublicKey(); + + if (event.kind !== 5950 && event.pubkey !== admin) { + throw new Error('Only NIP-05 job requests are permitted'); + } + + const input = event.tags.find(([name]) => name === 'i')?.[1]; + const tagged = !!event.tags.find(([name, value]) => name === 'p' && value === admin); + + if (!input || !NIP05.regex().test(input)) { + return DVM.feedback(event, 'error', `Invalid name: ${input}`); + } + + const [user, host] = input.split('@'); + const nip05 = `${user}@${host}`; + + if ((Conf.url.host !== host) && tagged) { + return DVM.feedback(event, 'error', `Unsupported domain: ${host}`); + } + + if (user === '_') { + return DVM.feedback(event, 'error', `Forbidden user: ${user}`); + } + + const [label] = await eventsDB.query([{ + kinds: [1985], + authors: [admin], + '#L': ['nip05'], + '#l': [nip05], + }]); + + if (label) { + return DVM.feedback(event, 'error', `Name already taken: ${nip05}`); + } + + await DVM.label(nip05, event.pubkey); + await DVM.result(event, nip05); + } + + static async feedback( + event: NostrEvent, + status: 'payment-required' | 'processing' | 'error' | 'success' | 'partial', + info = '', + ): Promise { + const feedback = await new AdminSigner().signEvent({ + kind: 7000, + content: '', + tags: [ + ['status', status, info], + ['e', event.id], + ['p', event.pubkey], + ], + created_at: Math.floor(Date.now() / 1000), + }); + return pipeline.handleEvent(feedback, AbortSignal.timeout(1000)); + } + + static async label(nip05: string, pubkey: string): Promise { + const label = await new AdminSigner().signEvent({ + kind: 1985, + tags: [ + ['L', 'nip05'], + ['l', nip05], + ['p', pubkey], + ], + content: '', + created_at: Math.floor(Date.now() / 1000), + }); + return pipeline.handleEvent(label, AbortSignal.timeout(1000)); + } + + static async result(event: NostrEvent, nip05: string): Promise { + const result = await new AdminSigner().signEvent({ + kind: 6950, + content: nip05, + tags: [ + ['request', JSON.stringify(event)], + ['i', nip05, 'text'], + ['e', event.id], + ['p', event.pubkey], + ], + created_at: Math.floor(Date.now() / 1000), + }); + return pipeline.handleEvent(result, AbortSignal.timeout(1000)); + } +}