diff --git a/src/controllers/api/streaming.ts b/src/controllers/api/streaming.ts index d3c3b8a2..5f54ba05 100644 --- a/src/controllers/api/streaming.ts +++ b/src/controllers/api/streaming.ts @@ -1,5 +1,6 @@ import { AppController } from '@/app.ts'; import { nip21 } from '@/deps.ts'; +import { signStreams } from '@/sign.ts'; const streamingController: AppController = (c) => { const upgrade = c.req.headers.get('upgrade'); @@ -23,6 +24,8 @@ const streamingController: AppController = (c) => { socket.addEventListener('close', () => console.log('websocket: connection closed')); socket.addEventListener('message', (e) => console.log('websocket message: ', e.data)); + signStreams.set(token, socket); + return response; }; diff --git a/src/sign.ts b/src/sign.ts index 4b339e83..1dc6baa6 100644 --- a/src/sign.ts +++ b/src/sign.ts @@ -3,10 +3,38 @@ import { getEventHash, getPublicKey, getSignature, HTTPException } from '@/deps. import type { Event, EventTemplate, SignedEvent } from '@/event.ts'; +/** Map of OAuth tokens to WebSocket signing streams. */ +export const signStreams = new Map(); + +/** Get signing WebSocket from app context. */ +function getSignStream(c: AppContext): WebSocket | undefined { + const token = c.req.headers.get('authorization')?.replace(/^Bearer /, ''); + return token ? signStreams.get(token) : undefined; +} + /** Sign Nostr event using the app context. */ -// deno-lint-ignore require-await async function signEvent(event: EventTemplate, c: AppContext): Promise> { const seckey = c.get('seckey'); + const stream = getSignStream(c); + + if (stream) { + try { + return await new Promise>((resolve, reject) => { + stream.addEventListener('message', (e) => { + const data = JSON.parse(e.data); + if (data.event === 'nostr.sign') { + resolve(JSON.parse(data.payload)); + } + }); + stream.send(JSON.stringify({ event: 'nostr.sign', payload: JSON.stringify(event) })); + setTimeout(reject, 30000); + }); + } catch (_e) { + throw new HTTPException(504, { + res: c.json({ id: 'ditto.timeout', error: 'Signing timeout' }, 504), + }); + } + } // Ditto only supports publishing events with a private key (for now). // TODO: Let the client sign events through a websocket.