From 704453794c21118a92244dc8bfc8ff9215b2401e Mon Sep 17 00:00:00 2001 From: AtHeartEngineer Date: Tue, 1 Aug 2023 14:22:50 -0400 Subject: [PATCH 01/11] schema change --- prisma/schema.prisma | 1 + 1 file changed, 1 insertion(+) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 0c42a1b..d679364 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -27,6 +27,7 @@ model Rooms { identities String[] @default([]) contractAddress String? // RLN_CONTRACT as "chainID:0xADDRESS" bandadaAddress String? // BANDADA as "url:groupID" + bandadaAPIKey String? // Bandada API Key epochs Epoch[] messages Messages[] claimCodes ClaimCodes[] @relation(fields: [claimCodeIds], references: [id]) From 0fd0a02969edef208a50271a6a2c64f95410edb7 Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Fri, 18 Aug 2023 11:58:48 -0500 Subject: [PATCH 02/11] chore(express) fixing eslint errors on routes --- src/crypto/verifier.ts | 4 +- src/data/db.ts | 15 ++++--- src/endpoints/index.ts | 90 ++++++++++++++++++++++++++++-------------- src/utils.ts | 2 +- tests/express.test.ts | 2 +- 5 files changed, 73 insertions(+), 40 deletions(-) diff --git a/src/crypto/verifier.ts b/src/crypto/verifier.ts index 1da92b3..82995f3 100644 --- a/src/crypto/verifier.ts +++ b/src/crypto/verifier.ts @@ -1,6 +1,6 @@ import type { MessageI, RoomI } from 'discreetly-interfaces'; import { str2BigInt } from 'discreetly-interfaces'; -import { RLNVerifier } from 'rlnjs'; +import { RLNFullProof, RLNVerifier } from 'rlnjs'; import vkey from './verification_key'; import { Group } from '@semaphore-protocol/group'; @@ -48,7 +48,7 @@ async function verifyProof(msg: MessageI, room: RoomI, epochErrorRange = 5): Pro } // Check that the proof is correct - return v.verifyProof(rlnIdentifier, msg.proof); + return v.verifyProof(rlnIdentifier, msg.proof as RLNFullProof); } export default verifyProof; diff --git a/src/data/db.ts b/src/data/db.ts index 9414e97..abf06cb 100644 --- a/src/data/db.ts +++ b/src/data/db.ts @@ -131,7 +131,7 @@ export function createSystemMessages(message: string, roomId?: string): Promise< return prisma.rooms.findMany(query) .then(rooms => { if (roomId && rooms.length === 0) { - Promise.reject('Room not found') + return Promise.reject('Room not found') } const createMessages = rooms.map(room => { return prisma.messages.create({ @@ -145,7 +145,10 @@ export function createSystemMessages(message: string, roomId?: string): Promise< }); return Promise.all(createMessages); - }); + }).catch(err => { + console.error(err); + return Promise.reject(err); + }) } @@ -163,18 +166,18 @@ export async function createRoom( userMessageLimit = 1, numClaimCodes = 0, approxNumMockUsers = 20, - type: string = 'PUBLIC' + type: string ): Promise { const claimCodes: { claimcode: string }[] = genClaimCodeArray(numClaimCodes); console.log(claimCodes); const mockUsers: string[] = genMockUsers(approxNumMockUsers); const roomData = { where: { - roomId: genId(serverConfig.id, name).toString() + roomId: genId(serverConfig.id as bigint, name).toString() }, update: {}, create: { - roomId: genId(serverConfig.id, name).toString(), + roomId: genId(serverConfig.id as bigint, name).toString(), name: name, rateLimit: rateLimit, userMessageLimit: userMessageLimit, @@ -184,7 +187,7 @@ export async function createRoom( create: claimCodes } } - }; + }; return await prisma.rooms .upsert(roomData) diff --git a/src/endpoints/index.ts b/src/endpoints/index.ts index 3b93f50..3f2a717 100644 --- a/src/endpoints/index.ts +++ b/src/endpoints/index.ts @@ -58,10 +58,22 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { } }); - app.get(['/rooms/:idc', '/api/rooms/:idc'], async (req, res) => { - pp(String('Express: fetching rooms by identityCommitment ' + req.params.idc)); - res.status(200).json(await getRoomsByIdentity(req.params.idc)); - }); + app.get( + ["/rooms/:idc", "/api/rooms/:idc"], + asyncHandler(async (req: Request, res: Response) => { + try { + pp( + String( + "Express: fetching rooms by identityCommitment " + req.params.idc + ) + ); + res.status(200).json(await getRoomsByIdentity(req.params.idc)); + } catch (error) { + console.error(error); + res.status(500).json({ error: "Internal Server Error" }); + } + }) + ); interface JoinData { code: string; @@ -123,10 +135,17 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { const roomName = roomMetadata.roomName; const rateLimit = roomMetadata.rateLimit; const userMessageLimit = roomMetadata.userMessageLimit; - const numClaimCodes = roomMetadata.numClaimCodes || 0; + const numClaimCodes = roomMetadata.numClaimCodes ?? 0; const approxNumMockUsers = roomMetadata.approxNumMockUsers; - const type = roomMetadata.roomType; - createRoom(roomName, rateLimit, userMessageLimit, numClaimCodes, approxNumMockUsers, type) + const type = roomMetadata.roomType as unknown as string; + createRoom( + roomName, + rateLimit, + userMessageLimit, + numClaimCodes, + approxNumMockUsers, + type + ) .then((result) => { console.log(result); if (result) { @@ -186,28 +205,39 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { }); }); - app.post("/admin/message", adminAuth, async (req, res) => { - const { message } = req.body; - pp(String("Express: sending system message: " + message)); - try { - await createSystemMessages(message); - res.status(200).json({ message: "Messages sent to all rooms" }); - } catch (err) { - console.error(err); - res.status(500).json({ error: "Internal Server Error" }); - } - }); + app.post( + "/admin/message", + adminAuth, + asyncHandler(async (req: Request, res: Response) => { + const { message } = req.body as { message: string }; + pp(String("Express: sending system message: " + message)); + try { + await createSystemMessages(message); + res.status(200).json({ message: "Messages sent to all rooms" }); + } catch (err) { + console.error(err); + res.status(500).json({ error: "Internal Server Error" }); + } + }) + ); + + app.post( + "/admin/message/:roomId", + adminAuth, + asyncHandler(async (req: Request, res: Response) => { + const { roomId } = req.params; + const { message } = req.body as { message: string }; + pp( + String("Express: sending system message: " + message + " to " + roomId) + ); + try { + await createSystemMessages(message, roomId); + res.status(200).json({ message: "Message sent to room " + roomId }); + } catch (err) { + console.error(err); + res.status(500).json({ error: "Internal Server Error" }); + } + }) + ); - app.post("/admin/message/:roomId", adminAuth, async (req, res) => { - const { roomId } = req.params; - const { message } = req.body; - pp(String("Express: sending system message: " + message + " to " + roomId)); - try { - await createSystemMessages(message, roomId); - res.status(200).json({ message: "Message sent to room " + roomId }); - } catch (err) { - console.error(err); - res.status(500).json({ error: "Internal Server Error" }); - } - }); } diff --git a/src/utils.ts b/src/utils.ts index 661cd8c..1a52dc7 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -20,7 +20,7 @@ export function genMockUsers(numMockUsers: number): string[] { for (let i = 0; i < newNumMockUsers; i++) { mockUsers.push( genId( - serverConfig.id, + serverConfig.id as bigint, // Generates a random string of length 10 Math.random() .toString(36) diff --git a/tests/express.test.ts b/tests/express.test.ts index 932d43e..0aac0b7 100644 --- a/tests/express.test.ts +++ b/tests/express.test.ts @@ -33,7 +33,7 @@ const room = { type: "PUBLIC" }; -const roomByIdTest = genId(serverConfig.id, room.roomName).toString(); +const roomByIdTest = genId(serverConfig.id as bigint, room.roomName).toString(); let testCode = ""; const testIdentity = randBigint(); const username = "admin"; From 4f6543b3649d537c87178e31723b310d267401bf Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Mon, 21 Aug 2023 17:15:54 -0500 Subject: [PATCH 03/11] feature(bandada) /join route now checks for membership types chore(crypto) changed some logic in the verifier that was throwing eslint errors --- package-lock.json | 8 +++--- package.json | 4 +-- prisma/seed.ts | 10 ++++---- src/crypto/verifier.ts | 14 ++++++++--- src/data/db.ts | 57 ++++++++++++++++++++++++++++++++++-------- src/endpoints/index.ts | 11 +++++++- 6 files changed, 79 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index 48c2bf0..5b39a28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "body-parser": "^1.20.2", "cors": "^2.8.5", "discreetly-claimcodes": "^1.1.5", - "discreetly-interfaces": "^0.1.29", + "discreetly-interfaces": "^0.1.34", "dotenv": "^16.3.1", "express": "^4.18.2", "express-basic-auth": "^1.2.1", @@ -3470,9 +3470,9 @@ "integrity": "sha512-pQueoGtBJk/FrTfGzepjqYfTLaymS+4t11byI4OcfjWQOagRsD7dtavGcowTVQ7Ib/vjKna5T+71WcgWZaAWuA==" }, "node_modules/discreetly-interfaces": { - "version": "0.1.29", - "resolved": "https://registry.npmjs.org/discreetly-interfaces/-/discreetly-interfaces-0.1.29.tgz", - "integrity": "sha512-3R63KkmB+wFKFFzD9DixX3VDoLCYkDuMQZucAItmXbjE+0tFgmrK683a1/WBI9VkBhARip6HsVNrjzaGqdR1Aw==", + "version": "0.1.34", + "resolved": "https://registry.npmjs.org/discreetly-interfaces/-/discreetly-interfaces-0.1.34.tgz", + "integrity": "sha512-7purPOWOowVH44ebdweBdZ4z2RsBQy5/H7xi6PdsHkaw1xwg8u3Ev2US5EdavP1igZ+SzebJdK8jT0ZTjzX8Kg==", "dependencies": { "poseidon-lite": "^0.2.0", "rlnjs": "^3.1.4" diff --git a/package.json b/package.json index 3881dc3..67848d3 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "body-parser": "^1.20.2", "cors": "^2.8.5", "discreetly-claimcodes": "^1.1.5", - "discreetly-interfaces": "^0.1.29", + "discreetly-interfaces": "^0.1.34", "dotenv": "^16.3.1", "express": "^4.18.2", "express-basic-auth": "^1.2.1", @@ -64,4 +64,4 @@ "ts-node": "^10.9.1", "typescript": "^5.1.6" } -} \ No newline at end of file +} diff --git a/prisma/seed.ts b/prisma/seed.ts index b29a0e9..90bbd47 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,9 +1,9 @@ import { createRoom } from '../src/data/db'; -function main() { - createRoom('1 Second Room', 1000, 1, 10); - createRoom('10 Second Room', 10000, 2, 10); - createRoom('100 Second Room', 100000, 10, 10); +async function main(){ + await createRoom('1 Second Room', 1000, 1, 10, 20, 'PUBLIC'); + await createRoom('10 Second Room', 10000, 2, 10, 20, 'PUBLIC'); + await createRoom('100 Second Room', 100000, 10, 10, 20, 'PUBLIC'); } -main(); +await main(); diff --git a/src/crypto/verifier.ts b/src/crypto/verifier.ts index 82995f3..db3b917 100644 --- a/src/crypto/verifier.ts +++ b/src/crypto/verifier.ts @@ -29,12 +29,20 @@ async function verifyProof(msg: MessageI, room: RoomI, epochErrorRange = 5): Pro // TODO! INTERNAL NULLIFIER (RLNjs cache) // Check that the message hash is correct - if (msgHash !== msg.proof.snarkProof.publicSignals.x) { + let proof: RLNFullProof; + + if (typeof msg.proof === 'string') { + proof = JSON.parse(msg.proof) as RLNFullProof; + } else { + proof = msg.proof; + } + + if (msgHash !== proof.snarkProof.publicSignals.x) { console.warn( 'Message hash incorrect:', msgHash, 'Hash in proof:', - msg.proof.snarkProof.publicSignals.x + proof.snarkProof.publicSignals.x ); return false; } @@ -42,7 +50,7 @@ async function verifyProof(msg: MessageI, room: RoomI, epochErrorRange = 5): Pro // Check that the merkle root is correct if (room.identities && Array.isArray(room.identities)) { const group = new Group(room.id, 20, room.identities as bigint[] | undefined); - if (group.root !== msg.proof.snarkProof.publicSignals.root) { + if (group.root !== proof.snarkProof.publicSignals.root) { return false; } } diff --git a/src/data/db.ts b/src/data/db.ts index abf06cb..1a67d43 100644 --- a/src/data/db.ts +++ b/src/data/db.ts @@ -92,28 +92,59 @@ export function updateClaimCode(code: string): Promise { }); } -export function updateRoomIdentities(idc: string, roomIds: string[]): Promise { +export async function updateRoomIdentities(idc: string, roomIds: string[]): Promise { return prisma.rooms .findMany({ where: { id: { in: roomIds } } }) .then((rooms) => { - const roomsToUpdate = rooms - .filter((room) => !room.identities.includes(idc)) + const identityListRooms = rooms + .filter((room) => room.membershipType === "IDENTITY_LIST" && !room.identities.includes(idc)) .map((room) => room.id); - if (roomsToUpdate) { + if (identityListRooms.length > 0) { return prisma.rooms.updateMany({ - where: { id: { in: roomsToUpdate } }, + where: { id: { in: identityListRooms } }, data: { identities: { push: idc } } }); } + const bandadaGroupRooms = rooms + .filter((room) => room.membershipType === "BANDADA_GROUP" && !room.identities.includes(idc)) + .map((room) => room); + + if (bandadaGroupRooms.length > 0) { + bandadaGroupRooms.forEach((room) => { + if (!room.bandadaAPIKey) { + console.error("API key is missing for room:", room); + return; + } + + const requestOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': room.bandadaAPIKey, + }, + }; + + const url = `https://api.bandada.pse.dev/groups/${room.bandadaAddress}/members/${idc}`; + + fetch(url, requestOptions) + .then((res) => { + if (res.status == 200) { + console.log(`Successfully added user to Bandada group ${room.bandadaAddress}`); + } + }) + .catch(console.error); + }); + } }) .catch((err) => { pp(err, 'error'); }); } + export async function findUpdatedRooms(roomIds: string[]): Promise { const rooms = await prisma.rooms.findMany({ where: { id: { in: roomIds } } @@ -161,28 +192,34 @@ export function createSystemMessages(message: string, roomId?: string): Promise< * @param {number} [approxNumMockUsers=20] - The approximate number of mock users to generate for the room. */ export async function createRoom( - name: string, + roomName: string, rateLimit = 1000, userMessageLimit = 1, numClaimCodes = 0, approxNumMockUsers = 20, - type: string + type: string, + bandadaAddress?: string, + bandadaAPIKey?: string, + membershipType?: string ): Promise { const claimCodes: { claimcode: string }[] = genClaimCodeArray(numClaimCodes); console.log(claimCodes); const mockUsers: string[] = genMockUsers(approxNumMockUsers); const roomData = { where: { - roomId: genId(serverConfig.id as bigint, name).toString() + roomId: genId(serverConfig.id as bigint, roomName).toString() }, update: {}, create: { - roomId: genId(serverConfig.id as bigint, name).toString(), - name: name, + roomId: genId(serverConfig.id as bigint, roomName).toString(), + name: roomName, rateLimit: rateLimit, userMessageLimit: userMessageLimit, identities: mockUsers, type, + bandadaAddress, + bandadaAPIKey, + membershipType, claimCodes: { create: claimCodes } diff --git a/src/endpoints/index.ts b/src/endpoints/index.ts index 3f2a717..33a3de7 100644 --- a/src/endpoints/index.ts +++ b/src/endpoints/index.ts @@ -125,6 +125,9 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { numClaimCodes?: number; approxNumMockUsers?: number; roomType?: string; + bandadaAddress?: string; + bandadaAPIKey?: string; + membershipType?: string; } /* ~~~~ ADMIN ENDPOINTS ~~~~ */ @@ -138,13 +141,19 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { const numClaimCodes = roomMetadata.numClaimCodes ?? 0; const approxNumMockUsers = roomMetadata.approxNumMockUsers; const type = roomMetadata.roomType as unknown as string; + const bandadaAddress = roomMetadata.bandadaAddress; + const bandadaAPIKey = roomMetadata.bandadaAPIKey; + const membershipType = roomMetadata.membershipType; createRoom( roomName, rateLimit, userMessageLimit, numClaimCodes, approxNumMockUsers, - type + type, + bandadaAddress, + bandadaAPIKey, + membershipType ) .then((result) => { console.log(result); From 1c5b90a21c37efaa66c0807bc332f912d0a8c786 Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Mon, 21 Aug 2023 18:20:21 -0500 Subject: [PATCH 04/11] refactor(bandada) refactored updateRoomIdentities into seperate functions for readability feature(db utils) added function to ensure an identityCommitment is a valid identityCommitment --- src/data/db.ts | 180 +++++++++++++++++++++++++++++-------------------- 1 file changed, 108 insertions(+), 72 deletions(-) diff --git a/src/data/db.ts b/src/data/db.ts index 1a67d43..4ce31cd 100644 --- a/src/data/db.ts +++ b/src/data/db.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-call */ -import { PrismaClient } from '@prisma/client'; -import { genId } from 'discreetly-interfaces'; -import type { RoomI } from 'discreetly-interfaces'; -import { serverConfig } from '../config/serverConfig'; -import { genMockUsers, genClaimCodeArray, pp } from '../utils'; +import { PrismaClient } from "@prisma/client"; +import { genId } from "discreetly-interfaces"; +import type { RoomI } from "discreetly-interfaces"; +import { serverConfig } from "../config/serverConfig"; +import { genMockUsers, genClaimCodeArray, pp } from "../utils"; const prisma = new PrismaClient(); @@ -22,7 +22,7 @@ export async function getRoomByID(id: string): Promise { const room = await prisma.rooms .findUnique({ where: { - roomId: id + roomId: id, }, select: { id: true, @@ -34,8 +34,8 @@ export async function getRoomByID(id: string): Promise { membershipType: true, contractAddress: true, bandadaAddress: true, - type: true - } + type: true, + }, }) .then((room) => { return room; @@ -48,7 +48,7 @@ export async function getRoomByID(id: string): Promise { if (room) { resolve(room as RoomI); } - reject('Room not found'); + reject("Room not found"); }); } @@ -64,9 +64,9 @@ export async function getRoomsByIdentity(identity: string): Promise { const rooms = await prisma.rooms.findMany({ where: { identities: { - has: identity - } - } + has: identity, + }, + }, }); rooms.forEach((room) => { r.push(room.roomId); @@ -81,90 +81,126 @@ export async function getRoomsByIdentity(identity: string): Promise { export function findClaimCode(code: string): Promise { return prisma.claimCodes.findUnique({ - where: { claimcode: code } + where: { claimcode: code }, }); } export function updateClaimCode(code: string): Promise { return prisma.claimCodes.update({ where: { claimcode: code }, - data: { claimed: true } + data: { claimed: true }, }); } -export async function updateRoomIdentities(idc: string, roomIds: string[]): Promise { +function sanitizeIDC(idc: string): string { + try { + const tempBigInt = BigInt(idc); + const tempString = tempBigInt.toString(); + if (idc === tempString) { + return idc; + } else { + throw new Error("Invalid IDC provided."); + } + } catch (error) { + throw new Error("Invalid IDC provided."); + } +} + +export async function updateRoomIdentities( + idc: string, + roomIds: string[] +): Promise { + const identityCommitment = sanitizeIDC(idc); return prisma.rooms .findMany({ - where: { id: { in: roomIds } } + where: { id: { in: roomIds } }, }) - .then((rooms) => { - const identityListRooms = rooms - .filter((room) => room.membershipType === "IDENTITY_LIST" && !room.identities.includes(idc)) - .map((room) => room.id); - - if (identityListRooms.length > 0) { - return prisma.rooms.updateMany({ - where: { id: { in: identityListRooms } }, - data: { identities: { push: idc } } - }); - } - const bandadaGroupRooms = rooms - .filter((room) => room.membershipType === "BANDADA_GROUP" && !room.identities.includes(idc)) - .map((room) => room); - - if (bandadaGroupRooms.length > 0) { - bandadaGroupRooms.forEach((room) => { - if (!room.bandadaAPIKey) { - console.error("API key is missing for room:", room); - return; - } - - const requestOptions = { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': room.bandadaAPIKey, - }, - }; - - const url = `https://api.bandada.pse.dev/groups/${room.bandadaAddress}/members/${idc}`; - - fetch(url, requestOptions) - .then((res) => { - if (res.status == 200) { - console.log(`Successfully added user to Bandada group ${room.bandadaAddress}`); - } - }) - .catch(console.error); - }); - } + .then(async (rooms) => { + await handleIdentityListRooms(rooms, identityCommitment); + await handleBandadaGroups(rooms, identityCommitment); }) .catch((err) => { - pp(err, 'error'); + pp(err, "error"); }); } +function handleIdentityListRooms(rooms, identityCommitment: string): any { + const identityListRooms = rooms + .filter( + (room) => + room.membershipType === "IDENTITY_LIST" && + !room.identities.includes(identityCommitment) + ) + .map((room) => room.id as string); + + if (identityListRooms.length > 0) { + return prisma.rooms.updateMany({ + where: { id: { in: identityListRooms } }, + data: { identities: { push: identityCommitment } }, + }); + } +} + +function handleBandadaGroups(rooms, identityCommitment: string): any { + const bandadaGroupRooms = rooms + .filter( + (room) => + room.membershipType === "BANDADA_GROUP" && + !room.identities.includes(identityCommitment) + ) + .map((room) => room as RoomI); + + if (bandadaGroupRooms.length > 0) { + bandadaGroupRooms.forEach((room) => { + if (!room.bandadaAPIKey) { + console.error("API key is missing for room:", room); + return; + } + const requestOptions = { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-api-key": room.bandadaAPIKey, + }, + }; + const url = `https://api.bandada.pse.dev/groups/${room.bandadaAddress}/members/${identityCommitment}`; + fetch(url, requestOptions) + .then((res) => { + if (res.status == 200) { + console.log( + `Successfully added user to Bandada group ${room.bandadaAddress}` + ); + } + }) + .catch(console.error); + }); + } +} export async function findUpdatedRooms(roomIds: string[]): Promise { const rooms = await prisma.rooms.findMany({ - where: { id: { in: roomIds } } + where: { id: { in: roomIds } }, }); return new Promise((resolve, reject) => { if (rooms) { resolve(rooms as RoomI[]); } - reject('No rooms found'); + reject("No rooms found"); }); } -export function createSystemMessages(message: string, roomId?: string): Promise { +export function createSystemMessages( + message: string, + roomId?: string +): Promise { const query = roomId ? { where: { roomId } } : undefined; - return prisma.rooms.findMany(query) - .then(rooms => { + return prisma.rooms + .findMany(query) + .then((rooms) => { if (roomId && rooms.length === 0) { - return Promise.reject('Room not found') + return Promise.reject("Room not found"); } - const createMessages = rooms.map(room => { + const createMessages = rooms.map((room) => { return prisma.messages.create({ data: { message, @@ -176,13 +212,13 @@ export function createSystemMessages(message: string, roomId?: string): Promise< }); return Promise.all(createMessages); - }).catch(err => { + }) + .catch((err) => { console.error(err); return Promise.reject(err); - }) + }); } - /** * Creates a new room with the given name and optional parameters. * @param {string} name - The name of the room. @@ -207,7 +243,7 @@ export async function createRoom( const mockUsers: string[] = genMockUsers(approxNumMockUsers); const roomData = { where: { - roomId: genId(serverConfig.id as bigint, roomName).toString() + roomId: genId(serverConfig.id as bigint, roomName).toString(), }, update: {}, create: { @@ -221,9 +257,9 @@ export async function createRoom( bandadaAPIKey, membershipType, claimCodes: { - create: claimCodes - } - } + create: claimCodes, + }, + }, }; return await prisma.rooms From 4634bcce7f106e710dde685ee1e52efbedbb6e8b Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Mon, 21 Aug 2023 19:05:13 -0500 Subject: [PATCH 05/11] refactor(bandada) identityCommitments are now also stored in room.identities --- src/data/db.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/data/db.ts b/src/data/db.ts index 4ce31cd..f2dfc5d 100644 --- a/src/data/db.ts +++ b/src/data/db.ts @@ -151,7 +151,7 @@ function handleBandadaGroups(rooms, identityCommitment: string): any { .map((room) => room as RoomI); if (bandadaGroupRooms.length > 0) { - bandadaGroupRooms.forEach((room) => { + bandadaGroupRooms.forEach(async (room) => { if (!room.bandadaAPIKey) { console.error("API key is missing for room:", room); return; @@ -163,6 +163,10 @@ function handleBandadaGroups(rooms, identityCommitment: string): any { "x-api-key": room.bandadaAPIKey, }, }; + await prisma.rooms.updateMany({ + where: { id: room.id }, + data: { identities: { push: identityCommitment } }, + }); const url = `https://api.bandada.pse.dev/groups/${room.bandadaAddress}/members/${identityCommitment}`; fetch(url, requestOptions) .then((res) => { From 52c1ebc9c767f751ea135dff0fcdd70e332c8f1f Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Tue, 22 Aug 2023 10:19:46 -0500 Subject: [PATCH 06/11] feature(bandada) fetch bandada group by identity commitment --- src/data/db.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/data/db.ts b/src/data/db.ts index f2dfc5d..f6a8f14 100644 --- a/src/data/db.ts +++ b/src/data/db.ts @@ -52,6 +52,7 @@ export async function getRoomByID(id: string): Promise { }); } + export async function getRoomsByIdentity(identity: string): Promise { /* TODO Need to create a system here where the client needs to provide a proof they know the secrets to some Identity Commitment with a unix epoch @@ -68,9 +69,18 @@ export async function getRoomsByIdentity(identity: string): Promise { }, }, }); - rooms.forEach((room) => { - r.push(room.roomId); - }); + for (const room of rooms) { + if (room.membershipType === "IDENTITY_LIST") { + r.push(room.roomId); + } + if (room.membershipType === "BANDADA_GROUP") { + const rooms = await fetch( + `https://api.bandada.pse.dev/groups/${room.bandadaAddress}` + ); + const roomData = await rooms.json() + r.push(roomData.id as string); + } + } console.log(r); return r; } catch (err) { From 4ddd6e3d7ffd637c369923d8542550f429d202a6 Mon Sep 17 00:00:00 2001 From: AtHeartEngineer Date: Tue, 22 Aug 2023 11:39:00 -0400 Subject: [PATCH 07/11] feat return more room info depending on membershiptype --- src/endpoints/index.ts | 138 +++++++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 60 deletions(-) diff --git a/src/endpoints/index.ts b/src/endpoints/index.ts index 33a3de7..20fada0 100644 --- a/src/endpoints/index.ts +++ b/src/endpoints/index.ts @@ -1,7 +1,7 @@ -import type { Express, RequestHandler, Request, Response } from "express"; -import { PrismaClient } from "@prisma/client"; -import { serverConfig } from "../config/serverConfig"; -import { pp } from "../utils"; +import type { Express, RequestHandler, Request, Response } from 'express'; +import { PrismaClient } from '@prisma/client'; +import { serverConfig } from '../config/serverConfig'; +import { pp } from '../utils'; import { getRoomByID, getRoomsByIdentity, @@ -10,9 +10,9 @@ import { updateRoomIdentities, findUpdatedRooms, createRoom, - createSystemMessages, -} from "../data/db"; -import { RoomI } from "discreetly-interfaces"; + createSystemMessages +} from '../data/db'; +import { RoomI } from 'discreetly-interfaces'; const prisma = new PrismaClient(); @@ -29,29 +29,56 @@ function asyncHandler(fn: { } export function initEndpoints(app: Express, adminAuth: RequestHandler) { - app.get(["/", "/api"], (req, res) => { - pp("Express: fetching server info"); + app.get(['/', '/api'], (req, res) => { + pp('Express: fetching server info'); res.status(200).json(serverConfig); }); - app.get(["/room/:id", "/api/room/:id"], (req, res) => { + app.get(['/room/:id', '/api/room/:id'], (req, res) => { if (!req.params.id) { - res.status(400).json({ error: "Bad Request" }); + res.status(400).json({ error: 'Bad Request' }); } else { - const requestRoomId = req.params.id ?? "0"; - pp(String("Express: fetching room info for " + req.params.id)); + const requestRoomId = req.params.id ?? '0'; + pp(String('Express: fetching room info for ' + req.params.id)); getRoomByID(requestRoomId) .then((room: RoomI) => { if (!room) { // This is set as a timeout to prevent someone from trying to brute force room ids - setTimeout( - () => res.status(500).json({ error: "Internal Server Error" }), - 1000 - ); + setTimeout(() => res.status(500).json({ error: 'Internal Server Error' }), 1000); } else { + const { + roomId, + name, + rateLimit, + userMessageLimit, + membershipType, + identities, + contractAddress, + bandadaAddress, + bandadaGroupId, + type + } = room || {}; + const id = String(roomId); + const roomResult: RoomI = { + id, + roomId, + name, + rateLimit, + userMessageLimit, + membershipType + }; // Add null check before accessing properties of room object - const { roomId, name, rateLimit, userMessageLimit } = room || {}; - res.status(200).json({ roomId, name, rateLimit, userMessageLimit }); + if (membershipType === 'BANDADA_GROUP') { + roomResult.bandadaAddress = bandadaAddress; + roomResult.bandadaGroupId = bandadaGroupId; + } + if (membershipType === 'IDENTITY_LIST') { + roomResult.identities = identities; + } + if (type === 'CONTRACT') { + roomResult.contractAddress = contractAddress; + } + res.status(200).json(roomResult); } }) .catch((err) => console.error(err)); @@ -59,18 +86,14 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { }); app.get( - ["/rooms/:idc", "/api/rooms/:idc"], + ['/rooms/:idc', '/api/rooms/:idc'], asyncHandler(async (req: Request, res: Response) => { try { - pp( - String( - "Express: fetching rooms by identityCommitment " + req.params.idc - ) - ); + pp(String('Express: fetching rooms by identityCommitment ' + req.params.idc)); res.status(200).json(await getRoomsByIdentity(req.params.idc)); } catch (error) { console.error(error); - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); } }) ); @@ -81,22 +104,20 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { } app.post( - ["/join", "/api/join"], + ['/join', '/api/join'], asyncHandler(async (req: Request, res: Response) => { const parsedBody: JoinData = req.body as JoinData; if (!parsedBody.code || !parsedBody.idc) { - res - .status(400) - .json({ message: "{code: string, idc: string} expected" }); + res.status(400).json({ message: '{code: string, idc: string} expected' }); } const { code, idc } = parsedBody; - console.log("Invite Code:", code); + console.log('Invite Code:', code); // Check if claim code is valid and not used before const codeStatus = await findClaimCode(code); if (!codeStatus || codeStatus.claimed) { - res.status(400).json({ message: "Claim code already used" }); + res.status(400).json({ message: 'Claim code already used' }); return; } @@ -112,8 +133,8 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { // Return the room ids of the updated rooms res.status(200).json({ - status: "valid", - roomIds: updatedRooms.map((room: RoomI) => room.roomId), + status: 'valid', + roomIds: updatedRooms.map((room: RoomI) => room.roomId) }); }) ); @@ -131,7 +152,7 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { } /* ~~~~ ADMIN ENDPOINTS ~~~~ */ - app.post(["/room/add", "/api/room/add"], adminAuth, (req, res) => { + app.post(['/room/add', '/api/room/add'], adminAuth, (req, res) => { console.log(req.body); const roomMetadata = req.body as addRoomData; console.log(roomMetadata); @@ -159,9 +180,9 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { console.log(result); if (result) { // TODO should return roomID and claim codes if they are generated - res.status(200).json({ message: "Room created successfully" }); + res.status(200).json({ message: 'Room created successfully' }); } else { - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); } }) .catch((err) => { @@ -170,26 +191,26 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { }); }); - app.get("/api/room/:id/messages", (req, res) => { + app.get('/api/room/:id/messages', (req, res) => { const { id } = req.params; prisma.messages .findMany({ where: { - roomId: id, - }, + roomId: id + } }) .then((messages) => { - pp("Express: fetching messages for room " + id); + pp('Express: fetching messages for room ' + id); res.status(200).json(messages); }) .catch((error: Error) => { - pp(error, "error"); - res.status(500).send("Error fetching messages"); + pp(error, 'error'); + res.status(500).send('Error fetching messages'); }); }); - app.get(["/logclaimcodes", "/api/logclaimcodes"], adminAuth, (req, res) => { - pp("Express: fetching claim codes"); + app.get(['/logclaimcodes', '/api/logclaimcodes'], adminAuth, (req, res) => { + pp('Express: fetching claim codes'); prisma.claimCodes .findMany() .then((claimCodes) => { @@ -197,12 +218,12 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { }) .catch((err) => { console.error(err); - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); }); }); - app.get(["/rooms", "/api/rooms"], adminAuth, (req, res) => { - pp(String("Express: fetching all rooms")); + app.get(['/rooms', '/api/rooms'], adminAuth, (req, res) => { + pp(String('Express: fetching all rooms')); prisma.rooms .findMany() .then((rooms) => { @@ -210,43 +231,40 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { }) .catch((err) => { console.error(err); - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); }); }); app.post( - "/admin/message", + '/admin/message', adminAuth, asyncHandler(async (req: Request, res: Response) => { const { message } = req.body as { message: string }; - pp(String("Express: sending system message: " + message)); + pp(String('Express: sending system message: ' + message)); try { await createSystemMessages(message); - res.status(200).json({ message: "Messages sent to all rooms" }); + res.status(200).json({ message: 'Messages sent to all rooms' }); } catch (err) { console.error(err); - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); } }) ); app.post( - "/admin/message/:roomId", + '/admin/message/:roomId', adminAuth, asyncHandler(async (req: Request, res: Response) => { const { roomId } = req.params; const { message } = req.body as { message: string }; - pp( - String("Express: sending system message: " + message + " to " + roomId) - ); + pp(String('Express: sending system message: ' + message + ' to ' + roomId)); try { await createSystemMessages(message, roomId); - res.status(200).json({ message: "Message sent to room " + roomId }); + res.status(200).json({ message: 'Message sent to room ' + roomId }); } catch (err) { console.error(err); - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); } }) ); - } From 452151b990cbab5bc1e536cf3fbf91d5ce7b5a16 Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Tue, 22 Aug 2023 11:16:17 -0500 Subject: [PATCH 08/11] refactor(bandada) refactored prisma schema to match RoomI interface and routes to match --- prisma/schema.prisma | 1 + src/data/db.ts | 87 ++++++++++++++++++++------------------ src/endpoints/index.ts | 96 +++++++++++++++++++++--------------------- 3 files changed, 96 insertions(+), 88 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 76e96da..dbd70ec 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -22,6 +22,7 @@ model Rooms { identities String[] @default([]) contractAddress String? // RLN_CONTRACT as "chainID:0xADDRESS" bandadaAddress String? // BANDADA as "url:groupID" + bandadaGroupId String? // Bandada Group ID bandadaAPIKey String? // Bandada API Key epochs Epoch[] messages Messages[] diff --git a/src/data/db.ts b/src/data/db.ts index f6a8f14..4a5808d 100644 --- a/src/data/db.ts +++ b/src/data/db.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-call */ -import { PrismaClient } from "@prisma/client"; -import { genId } from "discreetly-interfaces"; -import type { RoomI } from "discreetly-interfaces"; -import { serverConfig } from "../config/serverConfig"; -import { genMockUsers, genClaimCodeArray, pp } from "../utils"; +import { PrismaClient } from '@prisma/client'; +import { genId } from 'discreetly-interfaces'; +import type { RoomI } from 'discreetly-interfaces'; +import { serverConfig } from '../config/serverConfig'; +import { genMockUsers, genClaimCodeArray, pp } from '../utils'; const prisma = new PrismaClient(); @@ -48,47 +48,50 @@ export async function getRoomByID(id: string): Promise { if (room) { resolve(room as RoomI); } - reject("Room not found"); + reject('Room not found'); }); } +/* TODO Need to create a system here where the client needs to provide a +proof they know the secrets to some Identity Commitment with a unix epoch +time stamp to prevent replay attacks +https://github.com/Discreetly/IdentityCommitmentNullifierCircuit <- Circuit and JS to do this +*/ export async function getRoomsByIdentity(identity: string): Promise { - /* TODO Need to create a system here where the client needs to provide a - proof they know the secrets to some Identity Commitment with a unix epoch - time stamp to prevent replay attacks - - https://github.com/Discreetly/IdentityCommitmentNullifierCircuit <- Circuit and JS to do this - */ - const r: string[] = []; try { - const rooms = await prisma.rooms.findMany({ + const roomsFromDB = await prisma.rooms.findMany({ where: { identities: { has: identity, }, }, }); - for (const room of rooms) { - if (room.membershipType === "IDENTITY_LIST") { - r.push(room.roomId); - } - if (room.membershipType === "BANDADA_GROUP") { - const rooms = await fetch( - `https://api.bandada.pse.dev/groups/${room.bandadaAddress}` - ); - const roomData = await rooms.json() - r.push(roomData.id as string); - } - } - console.log(r); - return r; + + // Fetch all room IDs asynchronously + const roomIds = await Promise.all( + roomsFromDB.map(room => getRoomIdFromRoomData(room)) + ); + + return roomIds; } catch (err) { console.error(err); return []; } } +// Helper function to get the room ID based on its data +async function getRoomIdFromRoomData(room: any): Promise { + if (room.membershipType === 'IDENTITY_LIST') { + return room.roomId as string; + } else if (room.membershipType === 'BANDADA_GROUP') { + const response = await fetch(`https://${room.bandadaAddress}/groups/${room.bandadaGroupId}`); + const roomData = await response.json(); + return roomData.id as string; + } + return ''; +} + export function findClaimCode(code: string): Promise { return prisma.claimCodes.findUnique({ where: { claimcode: code }, @@ -109,10 +112,10 @@ function sanitizeIDC(idc: string): string { if (idc === tempString) { return idc; } else { - throw new Error("Invalid IDC provided."); + throw new Error('Invalid IDC provided.'); } } catch (error) { - throw new Error("Invalid IDC provided."); + throw new Error('Invalid IDC provided.'); } } @@ -130,7 +133,7 @@ export async function updateRoomIdentities( await handleBandadaGroups(rooms, identityCommitment); }) .catch((err) => { - pp(err, "error"); + pp(err, 'error'); }); } @@ -138,7 +141,7 @@ function handleIdentityListRooms(rooms, identityCommitment: string): any { const identityListRooms = rooms .filter( (room) => - room.membershipType === "IDENTITY_LIST" && + room.membershipType === 'IDENTITY_LIST' && !room.identities.includes(identityCommitment) ) .map((room) => room.id as string); @@ -155,7 +158,7 @@ function handleBandadaGroups(rooms, identityCommitment: string): any { const bandadaGroupRooms = rooms .filter( (room) => - room.membershipType === "BANDADA_GROUP" && + room.membershipType === 'BANDADA_GROUP' && !room.identities.includes(identityCommitment) ) .map((room) => room as RoomI); @@ -163,21 +166,21 @@ function handleBandadaGroups(rooms, identityCommitment: string): any { if (bandadaGroupRooms.length > 0) { bandadaGroupRooms.forEach(async (room) => { if (!room.bandadaAPIKey) { - console.error("API key is missing for room:", room); + console.error('API key is missing for room:', room); return; } const requestOptions = { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/json", - "x-api-key": room.bandadaAPIKey, + 'Content-Type': 'application/json', + 'x-api-key': room.bandadaAPIKey, }, }; await prisma.rooms.updateMany({ where: { id: room.id }, data: { identities: { push: identityCommitment } }, }); - const url = `https://api.bandada.pse.dev/groups/${room.bandadaAddress}/members/${identityCommitment}`; + const url = `https://${room.bandadaAddress}/groups/${room.bandadaGroupId}/members/${identityCommitment}`; fetch(url, requestOptions) .then((res) => { if (res.status == 200) { @@ -199,7 +202,7 @@ export async function findUpdatedRooms(roomIds: string[]): Promise { if (rooms) { resolve(rooms as RoomI[]); } - reject("No rooms found"); + reject('No rooms found'); }); } @@ -212,14 +215,14 @@ export function createSystemMessages( .findMany(query) .then((rooms) => { if (roomId && rooms.length === 0) { - return Promise.reject("Room not found"); + return Promise.reject('Room not found'); } const createMessages = rooms.map((room) => { return prisma.messages.create({ data: { message, roomId: room.roomId, - messageId: "0", + messageId: '0', proof: JSON.stringify({}), }, }); @@ -249,6 +252,7 @@ export async function createRoom( approxNumMockUsers = 20, type: string, bandadaAddress?: string, + bandadaGroupId?: string, bandadaAPIKey?: string, membershipType?: string ): Promise { @@ -268,6 +272,7 @@ export async function createRoom( identities: mockUsers, type, bandadaAddress, + bandadaGroupId, bandadaAPIKey, membershipType, claimCodes: { diff --git a/src/endpoints/index.ts b/src/endpoints/index.ts index 33a3de7..1546797 100644 --- a/src/endpoints/index.ts +++ b/src/endpoints/index.ts @@ -1,7 +1,7 @@ -import type { Express, RequestHandler, Request, Response } from "express"; -import { PrismaClient } from "@prisma/client"; -import { serverConfig } from "../config/serverConfig"; -import { pp } from "../utils"; +import type { Express, RequestHandler, Request, Response } from 'express'; +import { PrismaClient } from '@prisma/client'; +import { serverConfig } from '../config/serverConfig'; +import { pp } from '../utils'; import { getRoomByID, getRoomsByIdentity, @@ -10,9 +10,9 @@ import { updateRoomIdentities, findUpdatedRooms, createRoom, - createSystemMessages, -} from "../data/db"; -import { RoomI } from "discreetly-interfaces"; + createSystemMessages +} from '../data/db'; +import { RoomI } from 'discreetly-interfaces'; const prisma = new PrismaClient(); @@ -29,23 +29,23 @@ function asyncHandler(fn: { } export function initEndpoints(app: Express, adminAuth: RequestHandler) { - app.get(["/", "/api"], (req, res) => { - pp("Express: fetching server info"); + app.get(['/', '/api'], (req, res) => { + pp('Express: fetching server info'); res.status(200).json(serverConfig); }); - app.get(["/room/:id", "/api/room/:id"], (req, res) => { + app.get(['/room/:id', '/api/room/:id'], (req, res) => { if (!req.params.id) { - res.status(400).json({ error: "Bad Request" }); + res.status(400).json({ error: 'Bad Request' }); } else { - const requestRoomId = req.params.id ?? "0"; - pp(String("Express: fetching room info for " + req.params.id)); + const requestRoomId = req.params.id ?? '0'; + pp(String('Express: fetching room info for ' + req.params.id)); getRoomByID(requestRoomId) .then((room: RoomI) => { if (!room) { // This is set as a timeout to prevent someone from trying to brute force room ids setTimeout( - () => res.status(500).json({ error: "Internal Server Error" }), + () => res.status(500).json({ error: 'Internal Server Error' }), 1000 ); } else { @@ -59,18 +59,18 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { }); app.get( - ["/rooms/:idc", "/api/rooms/:idc"], + ['/rooms/:idc', '/api/rooms/:idc'], asyncHandler(async (req: Request, res: Response) => { try { pp( String( - "Express: fetching rooms by identityCommitment " + req.params.idc + 'Express: fetching rooms by identityCommitment ' + req.params.idc ) ); res.status(200).json(await getRoomsByIdentity(req.params.idc)); } catch (error) { console.error(error); - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); } }) ); @@ -81,22 +81,22 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { } app.post( - ["/join", "/api/join"], + ['/join', '/api/join'], asyncHandler(async (req: Request, res: Response) => { const parsedBody: JoinData = req.body as JoinData; if (!parsedBody.code || !parsedBody.idc) { res .status(400) - .json({ message: "{code: string, idc: string} expected" }); + .json({ message: '{code: string, idc: string} expected' }); } const { code, idc } = parsedBody; - console.log("Invite Code:", code); + console.log('Invite Code:', code); // Check if claim code is valid and not used before const codeStatus = await findClaimCode(code); if (!codeStatus || codeStatus.claimed) { - res.status(400).json({ message: "Claim code already used" }); + res.status(400).json({ message: 'Claim code already used' }); return; } @@ -112,8 +112,8 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { // Return the room ids of the updated rooms res.status(200).json({ - status: "valid", - roomIds: updatedRooms.map((room: RoomI) => room.roomId), + status: 'valid', + roomIds: updatedRooms.map((room: RoomI) => room.roomId) }); }) ); @@ -127,11 +127,12 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { roomType?: string; bandadaAddress?: string; bandadaAPIKey?: string; + bandadaGroupId?: string; membershipType?: string; } /* ~~~~ ADMIN ENDPOINTS ~~~~ */ - app.post(["/room/add", "/api/room/add"], adminAuth, (req, res) => { + app.post(['/room/add', '/api/room/add'], adminAuth, (req, res) => { console.log(req.body); const roomMetadata = req.body as addRoomData; console.log(roomMetadata); @@ -142,6 +143,7 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { const approxNumMockUsers = roomMetadata.approxNumMockUsers; const type = roomMetadata.roomType as unknown as string; const bandadaAddress = roomMetadata.bandadaAddress; + const bandadaGroupId = roomMetadata.bandadaGroupId; const bandadaAPIKey = roomMetadata.bandadaAPIKey; const membershipType = roomMetadata.membershipType; createRoom( @@ -152,6 +154,7 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { approxNumMockUsers, type, bandadaAddress, + bandadaGroupId, bandadaAPIKey, membershipType ) @@ -159,9 +162,9 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { console.log(result); if (result) { // TODO should return roomID and claim codes if they are generated - res.status(200).json({ message: "Room created successfully" }); + res.status(200).json({ message: 'Room created successfully' }); } else { - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); } }) .catch((err) => { @@ -170,26 +173,26 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { }); }); - app.get("/api/room/:id/messages", (req, res) => { + app.get('/api/room/:id/messages', (req, res) => { const { id } = req.params; prisma.messages .findMany({ where: { - roomId: id, - }, + roomId: id + } }) .then((messages) => { - pp("Express: fetching messages for room " + id); + pp('Express: fetching messages for room ' + id); res.status(200).json(messages); }) .catch((error: Error) => { - pp(error, "error"); - res.status(500).send("Error fetching messages"); + pp(error, 'error'); + res.status(500).send('Error fetching messages'); }); }); - app.get(["/logclaimcodes", "/api/logclaimcodes"], adminAuth, (req, res) => { - pp("Express: fetching claim codes"); + app.get(['/logclaimcodes', '/api/logclaimcodes'], adminAuth, (req, res) => { + pp('Express: fetching claim codes'); prisma.claimCodes .findMany() .then((claimCodes) => { @@ -197,12 +200,12 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { }) .catch((err) => { console.error(err); - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); }); }); - app.get(["/rooms", "/api/rooms"], adminAuth, (req, res) => { - pp(String("Express: fetching all rooms")); + app.get(['/rooms', '/api/rooms'], adminAuth, (req, res) => { + pp(String('Express: fetching all rooms')); prisma.rooms .findMany() .then((rooms) => { @@ -210,43 +213,42 @@ export function initEndpoints(app: Express, adminAuth: RequestHandler) { }) .catch((err) => { console.error(err); - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); }); }); app.post( - "/admin/message", + '/admin/message', adminAuth, asyncHandler(async (req: Request, res: Response) => { const { message } = req.body as { message: string }; - pp(String("Express: sending system message: " + message)); + pp(String('Express: sending system message: ' + message)); try { await createSystemMessages(message); - res.status(200).json({ message: "Messages sent to all rooms" }); + res.status(200).json({ message: 'Messages sent to all rooms' }); } catch (err) { console.error(err); - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); } }) ); app.post( - "/admin/message/:roomId", + '/admin/message/:roomId', adminAuth, asyncHandler(async (req: Request, res: Response) => { const { roomId } = req.params; const { message } = req.body as { message: string }; pp( - String("Express: sending system message: " + message + " to " + roomId) + String('Express: sending system message: ' + message + ' to ' + roomId) ); try { await createSystemMessages(message, roomId); - res.status(200).json({ message: "Message sent to room " + roomId }); + res.status(200).json({ message: 'Message sent to room ' + roomId }); } catch (err) { console.error(err); - res.status(500).json({ error: "Internal Server Error" }); + res.status(500).json({ error: 'Internal Server Error' }); } }) ); - } From e7a0754975bcb5541deea034c03cbb2a1b147204 Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Tue, 22 Aug 2023 12:08:37 -0500 Subject: [PATCH 09/11] refactor(bandada) removed unnessecary functionality --- src/data/db.ts | 45 ++++++++++++++++----------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/src/data/db.ts b/src/data/db.ts index 4a5808d..b21b30b 100644 --- a/src/data/db.ts +++ b/src/data/db.ts @@ -51,47 +51,34 @@ export async function getRoomByID(id: string): Promise { reject('Room not found'); }); } -/* TODO Need to create a system here where the client needs to provide a -proof they know the secrets to some Identity Commitment with a unix epoch -time stamp to prevent replay attacks - -https://github.com/Discreetly/IdentityCommitmentNullifierCircuit <- Circuit and JS to do this -*/ export async function getRoomsByIdentity(identity: string): Promise { + /* TODO Need to create a system here where the client needs to provide a + proof they know the secrets to some Identity Commitment with a unix epoch + time stamp to prevent replay attacks + + https://github.com/Discreetly/IdentityCommitmentNullifierCircuit <- Circuit and JS to do this + */ + const r: string[] = []; try { - const roomsFromDB = await prisma.rooms.findMany({ + const rooms = await prisma.rooms.findMany({ where: { identities: { - has: identity, - }, - }, + has: identity + } + } }); - - // Fetch all room IDs asynchronously - const roomIds = await Promise.all( - roomsFromDB.map(room => getRoomIdFromRoomData(room)) - ); - - return roomIds; + rooms.forEach((room) => { + r.push(room.roomId); + }); + console.log(r); + return r; } catch (err) { console.error(err); return []; } } -// Helper function to get the room ID based on its data -async function getRoomIdFromRoomData(room: any): Promise { - if (room.membershipType === 'IDENTITY_LIST') { - return room.roomId as string; - } else if (room.membershipType === 'BANDADA_GROUP') { - const response = await fetch(`https://${room.bandadaAddress}/groups/${room.bandadaGroupId}`); - const roomData = await response.json(); - return roomData.id as string; - } - return ''; -} - export function findClaimCode(code: string): Promise { return prisma.claimCodes.findUnique({ where: { claimcode: code }, From 9407b2cd9a183aaee22a7761768a7c56a8c0837c Mon Sep 17 00:00:00 2001 From: AtHeartEngineer Date: Tue, 22 Aug 2023 13:16:08 -0400 Subject: [PATCH 10/11] fix types and linting --- src/data/db.ts | 55 ++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/src/data/db.ts b/src/data/db.ts index 819dd3c..3b1ebd4 100644 --- a/src/data/db.ts +++ b/src/data/db.ts @@ -22,7 +22,7 @@ export async function getRoomByID(id: string): Promise { const room = await prisma.rooms .findUnique({ where: { - roomId: id, + roomId: id }, select: { id: true, @@ -82,14 +82,14 @@ export async function getRoomsByIdentity(identity: string): Promise { export function findClaimCode(code: string): Promise { return prisma.claimCodes.findUnique({ - where: { claimcode: code }, + where: { claimcode: code } }); } export function updateClaimCode(code: string): Promise { return prisma.claimCodes.update({ where: { claimcode: code }, - data: { claimed: true }, + data: { claimed: true } }); } @@ -107,47 +107,42 @@ function sanitizeIDC(idc: string): string { } } -export async function updateRoomIdentities( - idc: string, - roomIds: string[] -): Promise { +export async function updateRoomIdentities(idc: string, roomIds: string[]): Promise { const identityCommitment = sanitizeIDC(idc); return prisma.rooms .findMany({ - where: { id: { in: roomIds } }, + where: { id: { in: roomIds } } }) - .then(async (rooms) => { - await handleIdentityListRooms(rooms, identityCommitment); - await handleBandadaGroups(rooms, identityCommitment); + .then((rooms) => { + addIdentityToIdentityListRooms(rooms, identityCommitment); + addIdentityToBandadaRooms(rooms, identityCommitment); }) .catch((err) => { pp(err, 'error'); }); } -function handleIdentityListRooms(rooms, identityCommitment: string): any { +function addIdentityToIdentityListRooms(rooms, identityCommitment: string): unknown { const identityListRooms = rooms .filter( (room) => - room.membershipType === 'IDENTITY_LIST' && - !room.identities.includes(identityCommitment) + room.membershipType === 'IDENTITY_LIST' && !room.identities.includes(identityCommitment) ) .map((room) => room.id as string); if (identityListRooms.length > 0) { return prisma.rooms.updateMany({ where: { id: { in: identityListRooms } }, - data: { identities: { push: identityCommitment } }, + data: { identities: { push: identityCommitment } } }); } } -function handleBandadaGroups(rooms, identityCommitment: string): any { +function addIdentityToBandadaRooms(rooms, identityCommitment: string): void { const bandadaGroupRooms = rooms .filter( (room) => - room.membershipType === 'BANDADA_GROUP' && - !room.identities.includes(identityCommitment) + room.membershipType === 'BANDADA_GROUP' && !room.identities.includes(identityCommitment) ) .map((room) => room as RoomI); @@ -161,30 +156,30 @@ function handleBandadaGroups(rooms, identityCommitment: string): any { method: 'POST', headers: { 'Content-Type': 'application/json', - 'x-api-key': room.bandadaAPIKey, - }, + 'x-api-key': room.bandadaAPIKey + } }; await prisma.rooms.updateMany({ where: { id: room.id }, - data: { identities: { push: identityCommitment } }, + data: { identities: { push: identityCommitment } } }); const url = `https://${room.bandadaAddress}/groups/${room.bandadaGroupId}/members/${identityCommitment}`; fetch(url, requestOptions) .then((res) => { if (res.status == 200) { - console.log( - `Successfully added user to Bandada group ${room.bandadaAddress}` - ); + console.debug(`Successfully added user to Bandada group ${room.bandadaAddress}`); } }) - .catch(console.error); + .catch((err) => { + console.error(err); + }); }); } } export async function findUpdatedRooms(roomIds: string[]): Promise { const rooms = await prisma.rooms.findMany({ - where: { id: { in: roomIds } }, + where: { id: { in: roomIds } } }); return new Promise((resolve, reject) => { if (rooms) { @@ -194,10 +189,8 @@ export async function findUpdatedRooms(roomIds: string[]): Promise { }); } -export function createSystemMessages( - message: string, - roomId?: string -): Promise { +// TODO: Make interface for this return type; which is like a MessageI +export function createSystemMessages(message: string, roomId?: string): Promise { const query = roomId ? { where: { roomId } } : undefined; return prisma.rooms .findMany(query) @@ -266,7 +259,7 @@ export async function createRoom( const mockUsers: string[] = genMockUsers(approxNumMockUsers); const roomData = { where: { - roomId: genId(serverConfig.id as bigint, roomName).toString(), + roomId: genId(serverConfig.id as bigint, roomName).toString() }, update: {}, create: { From 0ce3ceb8f9e4a52f1e70fdf556e2adfad8440d5a Mon Sep 17 00:00:00 2001 From: AtHeartEngineer Date: Tue, 22 Aug 2023 13:18:34 -0400 Subject: [PATCH 11/11] fixed verifier --- src/crypto/verifier.ts | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/crypto/verifier.ts b/src/crypto/verifier.ts index 3135994..c3f633c 100644 --- a/src/crypto/verifier.ts +++ b/src/crypto/verifier.ts @@ -38,14 +38,6 @@ async function verifyProof(msg: MessageI, room: RoomI, epochErrorRange = 5): Pro // Check that the message hash is correct - let proof: RLNFullProof; - - if (typeof msg.proof === 'string') { - proof = JSON.parse(msg.proof) as RLNFullProof; - } else { - proof = msg.proof; - } - if (msgHash !== proof.snarkProof.publicSignals.x) { console.warn( 'Message hash incorrect:', @@ -65,7 +57,7 @@ async function verifyProof(msg: MessageI, room: RoomI, epochErrorRange = 5): Pro } // Check that the proof is correct - return v.verifyProof(rlnIdentifier, msg.proof as RLNFullProof); + return v.verifyProof(rlnIdentifier, proof); } export default verifyProof;