Merge branch 'dvm' into 'main'
Add DVM module, process domain name requests See merge request soapbox-pub/ditto!118
This commit is contained in:
commit
1e73f55c8c
|
@ -85,6 +85,7 @@ function connectStream(socket: WebSocket) {
|
||||||
send(['OK', event.id, false, e.message]);
|
send(['OK', event.id, false, e.message]);
|
||||||
} else {
|
} else {
|
||||||
send(['OK', event.id, false, 'error: something went wrong']);
|
send(['OK', event.id, false, 'error: something went wrong']);
|
||||||
|
console.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { deleteAttachedMedia } from '@/db/unattached-media.ts';
|
||||||
import { Debug, LNURL, type NostrEvent } from '@/deps.ts';
|
import { Debug, LNURL, type NostrEvent } from '@/deps.ts';
|
||||||
import { DittoEvent } from '@/interfaces/DittoEvent.ts';
|
import { DittoEvent } from '@/interfaces/DittoEvent.ts';
|
||||||
import { isEphemeralKind } from '@/kinds.ts';
|
import { isEphemeralKind } from '@/kinds.ts';
|
||||||
|
import { DVM } from '@/pipeline/DVM.ts';
|
||||||
import { getAuthor } from '@/queries.ts';
|
import { getAuthor } from '@/queries.ts';
|
||||||
import { updateStats } from '@/stats.ts';
|
import { updateStats } from '@/stats.ts';
|
||||||
import { purifyEvent } from '@/storages/hydrate.ts';
|
import { purifyEvent } from '@/storages/hydrate.ts';
|
||||||
|
@ -36,6 +37,7 @@ async function handleEvent(event: DittoEvent, signal: AbortSignal): Promise<void
|
||||||
storeEvent(event, signal),
|
storeEvent(event, signal),
|
||||||
parseMetadata(event, signal),
|
parseMetadata(event, signal),
|
||||||
processDeletions(event, signal),
|
processDeletions(event, signal),
|
||||||
|
DVM.event(event),
|
||||||
trackRelays(event),
|
trackRelays(event),
|
||||||
trackHashtags(event),
|
trackHashtags(event),
|
||||||
fetchRelatedEvents(event, signal),
|
fetchRelatedEvents(event, signal),
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { NIP05, NostrEvent } from '@soapbox/nspec';
|
||||||
|
|
||||||
|
import { Conf } from '@/config.ts';
|
||||||
|
import * as pipeline from '@/pipeline.ts';
|
||||||
|
import { AdminSigner } from '@/signers/AdminSigner.ts';
|
||||||
|
import { eventsDB } from '@/storages.ts';
|
||||||
|
|
||||||
|
export class DVM {
|
||||||
|
static async event(event: NostrEvent): Promise<void> {
|
||||||
|
switch (event.kind) {
|
||||||
|
case 5950:
|
||||||
|
await DVM.nameRegistration(event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async nameRegistration(event: NostrEvent): Promise<void> {
|
||||||
|
const admin = await new AdminSigner().getPublicKey();
|
||||||
|
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<void> {
|
||||||
|
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<void> {
|
||||||
|
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<void> {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -181,13 +181,15 @@ class EventsDB implements NStore {
|
||||||
query = query.limit(filter.limit!);
|
query = query.limit(filter.limit!);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (key.startsWith('#')) {
|
const joinedQuery = query.leftJoin('tags', 'tags.event_id', 'events.id');
|
||||||
const tag = key.replace(/^#/, '');
|
|
||||||
const value = filter[key as `#${string}`] as string[];
|
for (const [key, value] of Object.entries(filter)) {
|
||||||
query = query
|
if (key.startsWith('#') && Array.isArray(value)) {
|
||||||
.leftJoin('tags', 'tags.event_id', 'events.id')
|
const name = key.replace(/^#/, '');
|
||||||
.where('tags.tag', '=', tag)
|
query = joinedQuery
|
||||||
|
.where('tags.tag', '=', name)
|
||||||
.where('tags.value', 'in', value);
|
.where('tags.value', 'in', value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue