161 lines
4.6 KiB
TypeScript
161 lines
4.6 KiB
TypeScript
import { nostrService } from './nostr'
|
|
import { getPrimaryRelaySync } from './config'
|
|
import type { Event } from 'nostr-tools'
|
|
import { createSubscription } from '@/types/nostr-tools-extended'
|
|
|
|
export function createMessageVerificationFilters(messageEventId: string, authorPubkey: string, recipientPubkey: string, articleId: string): Array<{
|
|
kinds: number[]
|
|
ids: string[]
|
|
authors: string[]
|
|
'#p': string[]
|
|
'#e': string[]
|
|
limit: number
|
|
}> {
|
|
return [
|
|
{
|
|
kinds: [4],
|
|
ids: [messageEventId],
|
|
authors: [authorPubkey],
|
|
'#p': [recipientPubkey],
|
|
'#e': [articleId],
|
|
limit: 1,
|
|
},
|
|
]
|
|
}
|
|
|
|
interface MessageVerificationContext {
|
|
messageEventId: string
|
|
articleId: string
|
|
recipientPubkey: string
|
|
authorPubkey: string
|
|
}
|
|
|
|
export function handleMessageVerificationEvent(
|
|
event: import('nostr-tools').Event,
|
|
ctx: MessageVerificationContext,
|
|
finalize: (value: boolean) => void
|
|
): void {
|
|
console.warn('Private message verified on relay', {
|
|
messageEventId: event.id,
|
|
articleId: ctx.articleId,
|
|
recipientPubkey: ctx.recipientPubkey,
|
|
authorPubkey: ctx.authorPubkey,
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
finalize(true)
|
|
}
|
|
|
|
export function setupMessageVerificationHandlers(
|
|
params: {
|
|
sub: import('@/types/nostr-tools-extended').Subscription
|
|
ctx: MessageVerificationContext
|
|
finalize: (value: boolean) => void
|
|
isResolved: () => boolean
|
|
}
|
|
): void {
|
|
params.sub.on('event', (event: Event): void => {
|
|
handleMessageVerificationEvent(event, params.ctx, params.finalize)
|
|
})
|
|
|
|
params.sub.on('eose', (): void => {
|
|
console.warn('Private message not found on relay after EOSE', {
|
|
messageEventId: params.ctx.messageEventId,
|
|
articleId: params.ctx.articleId,
|
|
recipientPubkey: params.ctx.recipientPubkey,
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
params.finalize(false)
|
|
})
|
|
|
|
setTimeout(() => {
|
|
if (!params.isResolved()) {
|
|
console.warn('Timeout verifying private message on relay', {
|
|
messageEventId: params.ctx.messageEventId,
|
|
articleId: params.ctx.articleId,
|
|
recipientPubkey: params.ctx.recipientPubkey,
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
params.finalize(false)
|
|
}
|
|
}, 5000)
|
|
}
|
|
|
|
function createMessageVerificationSubscription(
|
|
params: { pool: import('nostr-tools').SimplePool; ctx: MessageVerificationContext }
|
|
): ReturnType<typeof createSubscription> {
|
|
const filters = createMessageVerificationFilters(
|
|
params.ctx.messageEventId,
|
|
params.ctx.authorPubkey,
|
|
params.ctx.recipientPubkey,
|
|
params.ctx.articleId
|
|
)
|
|
const relayUrl = getPrimaryRelaySync()
|
|
return createSubscription(params.pool, [relayUrl], filters)
|
|
}
|
|
|
|
function createVerificationPromise(
|
|
params: { sub: import('@/types/nostr-tools-extended').Subscription; ctx: MessageVerificationContext }
|
|
): Promise<boolean> {
|
|
return new Promise<boolean>((resolve) => {
|
|
let resolved = false
|
|
|
|
const finalize = (value: boolean): void => {
|
|
if (resolved) {
|
|
return
|
|
}
|
|
resolved = true
|
|
params.sub.unsub()
|
|
resolve(value)
|
|
}
|
|
|
|
setupMessageVerificationHandlers({ sub: params.sub, ctx: params.ctx, finalize, isResolved: () => resolved })
|
|
})
|
|
}
|
|
|
|
export function verifyPrivateMessagePublished(
|
|
messageEventId: string,
|
|
authorPubkey: string,
|
|
recipientPubkey: string,
|
|
articleId: string
|
|
): Promise<boolean> {
|
|
try {
|
|
const pool = nostrService.getPool()
|
|
if (!pool) {
|
|
console.error('Pool not initialized for message verification', {
|
|
messageEventId,
|
|
articleId,
|
|
recipientPubkey,
|
|
})
|
|
return Promise.resolve(false)
|
|
}
|
|
|
|
const ctx: MessageVerificationContext = { messageEventId, articleId, recipientPubkey, authorPubkey }
|
|
const sub = createMessageVerificationSubscription({ pool, ctx })
|
|
return createVerificationPromise({ sub, ctx })
|
|
} catch (error) {
|
|
console.error('Error verifying private message', {
|
|
messageEventId,
|
|
articleId,
|
|
recipientPubkey,
|
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
timestamp: new Date().toISOString(),
|
|
})
|
|
return Promise.resolve(false)
|
|
}
|
|
}
|
|
|
|
export async function publishAndVerifyMessage(
|
|
articleId: string,
|
|
recipientPubkey: string,
|
|
authorPubkey: string,
|
|
messageEventId: string
|
|
): Promise<boolean> {
|
|
const verified = await verifyPrivateMessagePublished(messageEventId, authorPubkey, recipientPubkey, articleId)
|
|
if (verified) {
|
|
console.warn('Private message verified on relay', { messageEventId, articleId, recipientPubkey })
|
|
} else {
|
|
console.warn('Private message published but not yet verified on relay', { messageEventId, articleId, recipientPubkey })
|
|
}
|
|
return verified
|
|
}
|