Process nostr events included directly in the callback.

This commit is contained in:
mplorentz 2026-08-27 11:28:03 -04:00
parent 4e8918c1f3
commit d143a563ba

View file

@ -7,6 +7,7 @@ import { confirmSubscriptionAction, unsubscribeAction, registerSubscription, Act
import { getSubscriptionById, insertEvent, getSubscriptionByKey, getSubscriptionByPubkey } from './database.js'
import { load } from '@welshman/net'
import { getIdFilters } from '@welshman/util'
import { verifyEvent } from 'nostr-tools/pure'
// Endpoints
@ -147,7 +148,7 @@ addRoute('delete', '/subscription/:key', async (req: Request, res: Response) =>
// NIP-9a relay push callback
addRoute('post', '/notify/:id', async (req: Request, res: Response) => {
const { id, relay } = req.body
const { id, relay, event } = req.body
if (!id || !relay) {
return res.status(400).json({ error: 'id and relay are required' })
@ -164,19 +165,30 @@ addRoute('post', '/notify/:id', async (req: Request, res: Response) => {
return res.status(404).json({ error: 'Subscription not active' })
}
// Fetch the full event from the relay
try {
const [event] = await load({
relays: [relay],
filters: getIdFilters([id]),
})
let storedEvent = event
if (!event) {
// Event not found at relay — don't 404, just skip
return res.json({ ok: true, skipped: true })
if (storedEvent) {
// If the subscription requested include_event, verify and use it directly
if (storedEvent.id !== id || !validEvent(storedEvent)) {
return res.status(400).json({ error: 'Invalid event' })
}
} else {
// Otherwise fetch the full event from the relay
const [fetched] = await load({
relays: [relay],
filters: getIdFilters([id]),
})
storedEvent = fetched
if (!storedEvent) {
// Event not found at relay — don't 404, just skip
return res.json({ ok: true, skipped: true })
}
}
const stored = await insertEvent(id, sub.id, event, relay)
const stored = await insertEvent(id, sub.id, storedEvent, relay)
return res.json({ ok: true, stored })
} catch (error) {
@ -238,4 +250,11 @@ server.use((err: Error, req: Request, res: Response, next: NextFunction) => {
} else {
next()
}
})
})
// Validate an event's signature and that its id hash matches (defense against
// a malicious relay forwarding tampered content via include_event).
const validEvent = (event: any) => {
if (!event || typeof event !== 'object') return false
return verifyEvent(event)
}