@@ -10,13 +10,17 @@ import { applySpaceEvent } from './handlers/applySpaceEvent.js';
1010import { createIdentity } from './handlers/createIdentity.js' ;
1111import { createSpace } from './handlers/createSpace.js' ;
1212import { createUpdate } from './handlers/createUpdate.js' ;
13- import { getIdentity } from './handlers/getIdentity.js' ;
13+ import { getIdentity , GetIdentityResult } from './handlers/getIdentity.js' ;
1414import { getSpace } from './handlers/getSpace.js' ;
1515import { listInvitations } from './handlers/listInvitations.js' ;
1616import { listSpaces } from './handlers/listSpaces.js' ;
1717import { createSessionNonce , getSessionNonce } from './handlers/sessionNonce.js' ;
1818import { createSessionToken , getAccountIdBySessionToken } from './handlers/sessionToken.js' ;
1919import { tmpInitAccount } from './handlers/tmpInitAccount.js' ;
20+ import { listPublicSpaceInboxes } from './handlers/listPublicSpaceInboxes.js' ;
21+ import { getSpaceInbox } from './handlers/getSpaceInbox.js' ;
22+ import { secp256k1 } from '@noble/curves/secp256k1' ;
23+ import { sha256 } from '@noble/hashes/sha256' ;
2024
2125interface CustomWebSocket extends WebSocket {
2226 accountId : string ;
@@ -271,6 +275,98 @@ app.get('/identity', async (req, res) => {
271275 }
272276} ) ;
273277
278+ app . get ( '/spaces/:spaceId/inboxes' , async ( req , res ) => {
279+ console . log ( 'GET spaces/:spaceId/inboxes' ) ;
280+ const spaceId = req . params . spaceId ;
281+ const inboxes = await listPublicSpaceInboxes ( { spaceId } ) ;
282+ const outgoingMessage : Messages . ResponseListSpaceInboxesPublic = {
283+ inboxes,
284+ } ;
285+ res . status ( 200 ) . send ( outgoingMessage ) ;
286+ } ) ;
287+
288+ app . get ( '/spaces/:spaceId/inboxes/:inboxId' , async ( req , res ) => {
289+ console . log ( 'GET spaces/:spaceId/inboxes/:inboxId' ) ;
290+ const spaceId = req . params . spaceId ;
291+ const inboxId = req . params . inboxId ;
292+ const inbox = await getSpaceInbox ( { spaceId, inboxId } ) ;
293+ const outgoingMessage : Messages . ResponseSpaceInboxPublic = {
294+ inbox,
295+ } ;
296+ res . status ( 200 ) . send ( outgoingMessage ) ;
297+ } ) ;
298+
299+ app . post ( '/spaces/:spaceId/inboxes/:inboxId/messages' , async ( req , res ) => {
300+ console . log ( 'POST spaces/:spaceId/inboxes/:inboxId/messages' ) ;
301+ const spaceId = req . params . spaceId ;
302+ const inboxId = req . params . inboxId ;
303+ const message = req . body ;
304+ let spaceInbox : Messages . SpaceInboxPublic ;
305+ try {
306+ spaceInbox = await getSpaceInbox ( { spaceId, inboxId } ) ;
307+ } catch ( error ) {
308+ res . status ( 404 ) . send ( { error : 'Inbox not found' } ) ;
309+ return ;
310+ }
311+
312+ if ( spaceInbox . authPolicy === 'auth_required' ) {
313+ if ( ! message . signature ) {
314+ res . status ( 400 ) . send ( { error : 'Signature required for auth_required inbox' } ) ;
315+ return ;
316+ }
317+
318+ // Recover the public key from the signature
319+ // TODO: move this to inboxes in the hypergraph package
320+ let signatureInstance = secp256k1 . Signature . fromCompact ( message . signature . hex ) ;
321+ signatureInstance = signatureInstance . addRecoveryBit ( message . signature . recovery ) ;
322+ const authorPublicKey = `0x${ signatureInstance . recoverPublicKey ( sha256 ( Utils . stringToUint8Array ( Utils . canonicalize ( message ) ) ) ) . toHex ( ) } ` ;
323+
324+ // Check if this public key corresponds to a member's identity
325+ let authorIdentity : GetIdentityResult ;
326+ try {
327+ authorIdentity = await getIdentity ( { signaturePublicKey : authorPublicKey } ) ;
328+ } catch ( error ) {
329+ res . status ( 403 ) . send ( { error : 'Not authorized to post to this inbox' } ) ;
330+ return ;
331+ }
332+ }
333+ await createSpaceInboxMessage ( { spaceId, inboxId, message } ) ;
334+ res . status ( 200 ) . send ( { } ) ;
335+ broadcastSpaceInboxMessage ( { spaceId, inboxId, message } ) ;
336+ } ) ;
337+
338+ // TODO same as above but for account inboxes
339+ app . get ( '/accounts/:accountId/inboxes' , async ( req , res ) => {
340+ console . log ( 'GET accounts/:accountId/inboxes' ) ;
341+ const accountId = req . params . accountId ;
342+ const inboxes = await listPublicAccountInboxes ( { accountId } ) ;
343+ const outgoingMessage : Messages . ResponseListAccountInboxesPublic = {
344+ inboxes,
345+ } ;
346+ res . status ( 200 ) . send ( outgoingMessage ) ;
347+ } ) ;
348+
349+ app . get ( '/accounts/:accountId/inboxes/:inboxId' , async ( req , res ) => {
350+ console . log ( 'GET accounts/:accountId/inboxes/:inboxId' ) ;
351+ const accountId = req . params . accountId ;
352+ const inboxId = req . params . inboxId ;
353+ const inbox = await getAccountInbox ( { accountId, inboxId } ) ;
354+ const outgoingMessage : Messages . ResponseAccountInboxPublic = {
355+ inbox,
356+ } ;
357+ res . status ( 200 ) . send ( outgoingMessage ) ;
358+ } ) ;
359+
360+ app . post ( '/accounts/:accountId/inboxes/:inboxId/messages' , async ( req , res ) => {
361+ console . log ( 'POST accounts/:accountId/inboxes/:inboxId/messages' ) ;
362+ const accountId = req . params . accountId ;
363+ const inboxId = req . params . inboxId ;
364+ const message = req . body ;
365+ await createAccountInboxMessage ( { accountId, inboxId, message } ) ;
366+ res . status ( 200 ) . send ( { } ) ;
367+ broadcastAccountInboxMessage ( { accountId, inboxId, message } ) ;
368+ } ) ;
369+
274370const server = app . listen ( PORT , ( ) => {
275371 console . log ( `Listening on port ${ PORT } ` ) ;
276372} ) ;
0 commit comments