From 44dea91cb38f5354bf5490c12545fdb8565f073e Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Thu, 26 Oct 2023 18:32:08 -0500 Subject: [PATCH 1/7] feature(jubmojis): created prisma models and endpoints for jubmoji groups and addresses --- prisma/schema.prisma | 67 ++++++--- src/data/db/remove.ts | 2 - src/data/db/update.ts | 1 - src/endpoints/gateways/ethereumGroup.ts | 1 + src/endpoints/gateways/jubmoji.ts | 177 ++++++++++++++++++++++++ 5 files changed, 224 insertions(+), 24 deletions(-) create mode 100644 src/endpoints/gateways/jubmoji.ts diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 83f513d..cc3edce 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -10,6 +10,8 @@ datasource db { url = env("DATABASE_URL") } +// Room Models +//----------------------------------------------------------------------------------------- model Rooms { id String @id @default(auto()) @map("_id") @db.ObjectId roomId String @unique @@ -31,12 +33,38 @@ model Rooms { type String @default("PUBLIC") ephemeral String @default("PERSISTENT") encrypted String @default("PLAINTEXT") + sessionIds Boolean @default(true) gatewayIds String[] @default([]) @db.ObjectId gateways GateWayIdentity[] @relation(fields: [gatewayIds], references: [id]) ethereumGroups EthereumGroup[] @relation(fields: [ethereumGroupIds], references: [id]) ethereumGroupIds String[] @db.ObjectId + jubmojiGroups JubmojiGroup[] @relation(fields: [jubmojiGroupIds], references: [id]) + jubmojiGroupIds String[] @db.ObjectId } +model Epoch { + id String @id @default(auto()) @map("_id") @db.ObjectId + epoch String + messages Messages[] + rooms Rooms? @relation(fields: [roomsId], references: [id]) + roomsId String? @db.ObjectId +} + +model Messages { + id String @id @default(auto()) @map("_id") @db.ObjectId + messageId String // Internal Nullifier + message String + timeStamp DateTime @default(now()) + roomId String + messageType String? @default("TEXT") + room Rooms @relation(fields: [roomId], references: [roomId]) + proof String + epoch Epoch? @relation(fields: [epochId], references: [id]) + epochId String? @db.ObjectId +} + +// Gateway Models +//----------------------------------------------------------------------------------------- model GateWayIdentity { id String @id @default(auto()) @map("_id") @db.ObjectId semaphoreIdentity String @unique @@ -48,6 +76,7 @@ model GateWayIdentity { usedClaimCodes String[] @default([]) @db.ObjectId claimCodes ClaimCodes[] @relation(fields: [usedClaimCodes], references: [id]) ethereumAddress EthereumAddress[] + jubmojiAddress JubmojiAddress[] } model EthereumGroup { @@ -65,6 +94,21 @@ model EthereumAddress { gatewayId String @db.ObjectId } +model JubmojiGroup { + id String @id @default(auto()) @map("_id") @db.ObjectId + name String @unique + jubmojiAddresses String[] @default([]) + rooms Rooms[] @relation(fields: [roomIds], references: [id]) + roomIds String[] @default([]) @db.ObjectId +} + +model JubmojiAddress { + id String @id @default(auto()) @map("_id") @db.ObjectId + jubmojiAddress String @unique + gateways GateWayIdentity @relation(fields: [gatewayId], references: [id]) + gatewayId String @db.ObjectId +} + model ClaimCodes { id String @id @default(auto()) @map("_id") @db.ObjectId claimcode String @unique @@ -77,27 +121,8 @@ model ClaimCodes { gateways GateWayIdentity[] @relation(fields: [gatewayIds], references: [id]) } -model Messages { - id String @id @default(auto()) @map("_id") @db.ObjectId - messageId String // Internal Nullifier - message String - timeStamp DateTime @default(now()) - roomId String - messageType String? @default("TEXT") - room Rooms @relation(fields: [roomId], references: [roomId]) - proof String - epoch Epoch? @relation(fields: [epochId], references: [id]) - epochId String? @db.ObjectId -} - -model Epoch { - id String @id @default(auto()) @map("_id") @db.ObjectId - epoch String - messages Messages[] - rooms Rooms? @relation(fields: [roomsId], references: [id]) - roomsId String? @db.ObjectId -} - +// Discord Bot Models +//----------------------------------------------------------------------------------------- model Discord { id String @id @default(auto()) @map("_id") @db.ObjectId discordServerId String @unique diff --git a/src/data/db/remove.ts b/src/data/db/remove.ts index 8aff204..0d1141d 100644 --- a/src/data/db/remove.ts +++ b/src/data/db/remove.ts @@ -49,7 +49,6 @@ export function removeIdentityFromRoom( * @param {string} roomId - The id of the room to remove * @returns {Promise} - A promise that resolves to true if the room was removed and false otherwise * */ - export function removeRoom(roomId: string): Promise { return prisma.messages .deleteMany({ @@ -82,7 +81,6 @@ export function removeRoom(roomId: string): Promise { * @param {string} messageId - The id of the message to remove * @returns {Promise} - A promise that resolves to true if the message was removed and false otherwise */ - export function removeMessage(roomId: string, messageId: string) { return prisma.messages .deleteMany({ diff --git a/src/data/db/update.ts b/src/data/db/update.ts index f192793..968d609 100644 --- a/src/data/db/update.ts +++ b/src/data/db/update.ts @@ -299,7 +299,6 @@ export async function addIdentityToBandadaRooms( * @param {string} roomId - The ID of the room * @param {string[]} ethAddresses - The list of Ethereum addresses to add to the group */ - export async function createEthGroup( name: string, roomId: string, diff --git a/src/endpoints/gateways/ethereumGroup.ts b/src/endpoints/gateways/ethereumGroup.ts index 85c5f96..9b9c2e6 100644 --- a/src/endpoints/gateways/ethereumGroup.ts +++ b/src/endpoints/gateways/ethereumGroup.ts @@ -95,6 +95,7 @@ router.post( name: string; roomIds: string[]; }; + if (!name) res.status(500).json({ error: 'No name provided' }) const ethereumGroup = await prisma.ethereumGroup.create({ data: { name: name, diff --git a/src/endpoints/gateways/jubmoji.ts b/src/endpoints/gateways/jubmoji.ts new file mode 100644 index 0000000..8c45a29 --- /dev/null +++ b/src/endpoints/gateways/jubmoji.ts @@ -0,0 +1,177 @@ +import express from 'express'; +import { Request, Response } from 'express'; +import { PrismaClient } from '@prisma/client'; +import { limiter } from '../middleware'; +import { generateRandomClaimCode } from 'discreetly-claimcodes'; +import basicAuth from 'express-basic-auth'; + +const router = express.Router(); +const prisma = new PrismaClient(); + +const adminPassword = process.env.PASSWORD + ? process.env.PASSWORD + : // eslint-disable-next-line @typescript-eslint/no-unsafe-call + (generateRandomClaimCode(4) as string); + +const adminAuth = basicAuth({ + users: { + admin: adminPassword + } +}); + +// Fetches all jubmoji groups that exist in the database +router.get('/groups/all', adminAuth, (req: Request, res: Response) => { + prisma.jubmojiGroup + .findMany({ + select: { + name: true + } + }) + .then((groups) => { + res.status(200).json(groups); + }) + .catch((err) => { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + }); +}); + +/** + * This code gets the Jubmoji group with the given address. + * @param {string} address - The address of the Jubmoji group to get + * @returns {void} + * @example { + * "address": "string" + * } + */ +router.get('/group/:address', limiter, (req: Request, res: Response) => { + const { address } = req.params as { address: string }; + prisma.jubmojiGroup + .findMany({ + where: { + jubmojiAddresses: { + has: address + } + }, + select: { + name: true + } + }) + .then((groups) => { + res.status(200).json(groups); + }) + .catch((err) => { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + }); +}) + + +/** + * This code creates a new Jubmoji group with the given name, and + * connects the group to the given rooms. It then sends back a JSON + * response with the newly created Jubmoji group. + * @param {string} name - The name of the Jubmoji group to create + * @param {string[]} roomIds - The ids of the rooms to connect to the group + * @returns {void} + * @example { + * "name": "string", + * "roomIds": string[] + * } + */ +router.post('/group/create', adminAuth, (req: Request, res: Response) => { + const { name, roomIds } = req.body as { name: string; roomIds: string[] }; + if (!name) res.status(500).json({ error: 'No name provided' }); + prisma.jubmojiGroup + .create({ + data: { + name, + rooms: { + connect: roomIds.map((id) => ({ id })) + } + } + }) + .then((group) => { + res.status(200).json(group); + }) + .catch((err) => { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + }); +}) + +/** Adds a list of jubmoji addresses to a list of groups in the database. + * @param {string[]} names - The names of the Jubmoji groups to add the address to + * @param {string[]} addresses - The addresses to add to the Jubmoji groups + */ +router.post('/group/add', adminAuth, (req: Request, res: Response) => { + const { names, addresses } = req.body as { names: string[]; addresses: string[] }; + + if (!names) res.status(500).json({ error: 'No name provided' }); + + prisma.jubmojiGroup + .updateMany({ + where: { + name: { + in: names + } + }, + data: { + jubmojiAddresses: { + push: addresses + } + } + }) + .then((group) => { + res.status(200).json(group); + }) + .catch((err) => { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + }); +}) + +/** Edits a jubmoji group in the database + * The body of the request contains the name of the group to edit and the room IDs to associate with the group. + * @param {string} name - The name of the Jubmoji group to edit + * @param {string[]} roomIds - The ids of the rooms to connect to the group + * @returns {void} + * @example { + * "name": "string", + * "roomIds": string[] + * } + */ +router.post('/group/edit', adminAuth, (req: Request, res: Response) => { + const { name, roomIds } = req.body as { name: string; roomIds: string[] }; + + if (!name) res.status(500).json({ error: 'No name provided' }); + prisma.jubmojiGroup.update({ + where: { + name: name + }, + data: { + rooms: { + connect: roomIds.map((id) => ({ id })) + } + } + }).then((group) => { + res.status(200).json(group); + }).catch((err) => { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + }) +}) + +router.post('/group/delete', adminAuth, (req: Request, res: Response) => { + const { name } = req.body as { name: string }; + prisma.jubmojiGroup.delete({ + where: { + name: name + } + }).then((group) => { + res.status(200).json(group); + }).catch((err) => { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + }) +}) From 42745ddd7f7a31ee89851ed86e12896d3f287a78 Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Fri, 27 Oct 2023 14:04:19 -0500 Subject: [PATCH 2/7] refactor(endpoints) refactoring eth endpoints --- prisma/seed.ts | 6 +- src/data/db/create.ts | 76 ++++++++++++- src/data/db/find.ts | 32 ++++++ src/data/db/remove.ts | 10 ++ src/data/db/update.ts | 34 +++++- src/data/utils.ts | 23 ++++ src/endpoints/gateways/ethereumGroup.ts | 141 ++++-------------------- src/types/index.ts | 6 + 8 files changed, 199 insertions(+), 129 deletions(-) diff --git a/prisma/seed.ts b/prisma/seed.ts index 6154574..f7f8e5b 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,5 +1,5 @@ import { createRoom } from '../src/data/db'; -import { createEthGroup } from '../src/data/db'; +import { createEthGroupForRoom } from '../src/data/db'; import addresses from './addresses'; async function main() { // @param name — The name of the room. @@ -17,8 +17,8 @@ async function main() { await createRoom('The Word', 10000, 12, 0, 0, 'PUBLIC', [], '007001'); const bcgd = await createRoom('Beacon Chain Genesis Depositors', 10000, 12, 0 ,20, 'PUBLIC'); const sgf = await createRoom('Stateful Genesis Funders', 10000, 12, 0, 20, 'PUBLIC'); - await createEthGroup('Beacon Chain Genesis Depositors', bcgd!.roomId, addresses.bcgd); - await createEthGroup('Stateful Genesis Funders', sgf!.roomId, addresses.sgf); + await createEthGroupForRoom('Beacon Chain Genesis Depositors', bcgd!.roomId, addresses.bcgd); + await createEthGroupForRoom('Stateful Genesis Funders', sgf!.roomId, addresses.sgf); } await main(); diff --git a/src/data/db/create.ts b/src/data/db/create.ts index 7252451..570554a 100644 --- a/src/data/db/create.ts +++ b/src/data/db/create.ts @@ -1,7 +1,12 @@ import { PrismaClient } from '@prisma/client'; -import { getRateCommitmentHash, MessageI, randomBigInt } from 'discreetly-interfaces'; +import { + getRateCommitmentHash, + MessageI, + randomBigInt +} from 'discreetly-interfaces'; import { genClaimCodeArray, genMockUsers } from '../../utils'; import type { Server as SocketIOServer } from 'socket.io'; +import { EthGroupI } from '../../types'; const prisma = new PrismaClient(); @@ -34,7 +39,9 @@ export async function createRoom( bandadaAPIKey?: string, membershipType?: string, roomId?: string -): Promise<{ roomId: string ; claimCodes: { claimcode: string }[] } | undefined | null> { +): Promise< + { roomId: string; claimCodes: { claimcode: string }[] } | undefined | null +> { const claimCodes: { claimcode: string }[] = genClaimCodeArray(numClaimCodes); const mockUsers: string[] = genMockUsers(approxNumMockUsers); const identityCommitments: string[] = mockUsers.map((user) => @@ -42,7 +49,7 @@ export async function createRoom( ); const _roomId = roomId ? roomId : randomBigInt().toString(); - const room = await prisma.rooms.findUnique({where: {roomId: _roomId}}) + const room = await prisma.rooms.findUnique({ where: { roomId: _roomId } }); if (room) return null; const roomData = { @@ -67,7 +74,7 @@ export async function createRoom( }, gateways: { create: mockUsers.map((user) => ({ - semaphoreIdentity: user, + semaphoreIdentity: user })) } } @@ -76,7 +83,7 @@ export async function createRoom( return await prisma.rooms .upsert(roomData) .then(() => { - return {roomId: _roomId, claimCodes}; + return { roomId: _roomId, claimCodes }; }) .catch((err) => { console.error(err); @@ -132,7 +139,10 @@ export function createSystemMessages( * @param {MessageI} message - The message to add to the room. * @returns {Promise} - A promise that resolves when the message has been added to the room. */ -export function createMessageInRoom(roomId: string, message: MessageI): Promise { +export function createMessageInRoom( + roomId: string, + message: MessageI +): Promise { if (!message.epoch) { throw new Error('Epoch not provided'); } @@ -158,3 +168,57 @@ export function createMessageInRoom(roomId: string, message: MessageI): Promise< } }); } + +export function createEthGroup( + name: string, + roomIds: string[] +): Promise { + return prisma.ethereumGroup.create({ + data: { + name: name, + rooms: { + connect: roomIds.map((roomId) => ({ roomId })) + } + } + }); +} + +export async function joinRoomsFromEthAddress( + recoveredAddress: string, + message: string +) { + const gatewayIdentity = await prisma.gateWayIdentity.upsert({ + where: { semaphoreIdentity: message }, + update: {}, + create: { + semaphoreIdentity: message + } + }); + await prisma.ethereumAddress.upsert({ + where: { ethereumAddress: recoveredAddress }, + update: {}, + create: { + ethereumAddress: recoveredAddress, + gatewayId: gatewayIdentity.id + } + }); + const roomsToJoin = await prisma.ethereumGroup.findMany({ + where: { + ethereumAddresses: { + has: recoveredAddress + } + }, + select: { + roomIds: true + } + }); + const roomIdsSet = new Set(roomsToJoin.map((room) => room.roomIds).flat()); + const roomIds = Array.from(roomIdsSet); + + await prisma.gateWayIdentity.update({ + where: { id: gatewayIdentity.id }, + data: { roomIds: { set: roomIds } } + }); + + return roomIds; +} diff --git a/src/data/db/find.ts b/src/data/db/find.ts index 6ba9cad..596f443 100644 --- a/src/data/db/find.ts +++ b/src/data/db/find.ts @@ -153,3 +153,35 @@ export async function findRoomWithMessageId( throw err; } } + +export function findManyEthGroups(address?: string): Promise<{ name: string }[]> { + if (address) { + return prisma.ethereumGroup.findMany({ + where: { + ethereumAddresses: { + has: address + } + }, + select: { + name: true + } + }) + } else { + return prisma.ethereumGroup.findMany({ + select: { + name: true + } + }) + } +} + +export function findUniqueEthGroup(name: string): Promise<{ ethereumAddresses: string[] } | null> { + return prisma.ethereumGroup.findUnique({ + where: { + name: name + }, + select: { + ethereumAddresses: true + } + }) +} diff --git a/src/data/db/remove.ts b/src/data/db/remove.ts index 0d1141d..b143191 100644 --- a/src/data/db/remove.ts +++ b/src/data/db/remove.ts @@ -97,3 +97,13 @@ export function removeMessage(roomId: string, messageId: string) { return false; }); } + + +export function removeEthGroup(name: string) { + return prisma.ethereumGroup + .delete({ + where: { + name: name + } + }) +} diff --git a/src/data/db/update.ts b/src/data/db/update.ts index 968d609..de21bc0 100644 --- a/src/data/db/update.ts +++ b/src/data/db/update.ts @@ -299,7 +299,7 @@ export async function addIdentityToBandadaRooms( * @param {string} roomId - The ID of the room * @param {string[]} ethAddresses - The list of Ethereum addresses to add to the group */ -export async function createEthGroup( +export async function createEthGroupForRoom( name: string, roomId: string, ethAddresses: string[] @@ -320,3 +320,35 @@ export async function createEthGroup( } }); } + +export function addAddressesToEthGroup(names: string[], ethAddresses: string[]) { + return prisma.ethereumGroup.updateMany({ + where: { + name: { + in: names + } + }, + data: { + ethereumAddresses: { + push: ethAddresses + } + } + }); +} + + +export function updateEthGroup(name: string, ethAddresses: string[], roomIds: string[]) { + return prisma.ethereumGroup.update({ + where: { + name: name + }, + data: { + ethereumAddresses: { + push: ethAddresses + }, + rooms: { + connect: roomIds.map((roomId) => ({ roomId })) + } + } + }); +} diff --git a/src/data/utils.ts b/src/data/utils.ts index 3080b8e..aa2463b 100644 --- a/src/data/utils.ts +++ b/src/data/utils.ts @@ -1,3 +1,12 @@ +import { + ecrecover, + pubToAddress, + bufferToHex, + fromRpcSig, + toBuffer, + hashPersonalMessage +} from 'ethereumjs-util'; + /** * The sanitizeIDC function takes a string and returns a string. * The string is converted to a BigInt and then back to a string. @@ -21,3 +30,17 @@ export function sanitizeIDC(idc: string): string { throw new Error('Invalid IDC provided.'); } } + +export function recoverPublicKey(message: string, signature: string): string { + const msgHex = bufferToHex(Buffer.from(message)); + const msgBuffer = toBuffer(msgHex); + const msgHash = hashPersonalMessage(msgBuffer); + + const { v, r, s } = fromRpcSig(signature); + const publicKey = ecrecover(msgHash, v, r, s); + const address = pubToAddress(publicKey); + + const recoveredAddress = bufferToHex(address); + + return recoveredAddress +} diff --git a/src/endpoints/gateways/ethereumGroup.ts b/src/endpoints/gateways/ethereumGroup.ts index 9b9c2e6..cd990bb 100644 --- a/src/endpoints/gateways/ethereumGroup.ts +++ b/src/endpoints/gateways/ethereumGroup.ts @@ -1,18 +1,11 @@ import asyncHandler from 'express-async-handler'; import type { Request, Response } from 'express'; import express from 'express'; -import { PrismaClient } from '@prisma/client'; import { limiter } from '../middleware'; import { generateRandomClaimCode } from 'discreetly-claimcodes'; -import { - ecrecover, - pubToAddress, - bufferToHex, - fromRpcSig, - toBuffer, - hashPersonalMessage -} from 'ethereumjs-util'; import basicAuth from 'express-basic-auth'; +import { addAddressesToEthGroup, updateEthGroup, createEthGroup, findManyEthGroups, findUniqueEthGroup, removeEthGroup, joinRoomsFromEthAddress } from '../../data/db'; +import { recoverPublicKey } from '../../data/utils'; const adminPassword = process.env.PASSWORD ? process.env.PASSWORD @@ -26,16 +19,10 @@ const adminAuth = basicAuth({ }); const router = express.Router(); -const prisma = new PrismaClient(); // Fetches all ethereum groups that exist in the database router.get('/groups/all', adminAuth, (req: Request, res: Response) => { - prisma.ethereumGroup - .findMany({ - select: { - name: true - } - }) + findManyEthGroups() .then((groups) => { res.status(200).json(groups); }) @@ -55,17 +42,7 @@ router.get('/groups/all', adminAuth, (req: Request, res: Response) => { */ router.get('/group/:address', limiter, (req, res) => { const { address } = req.params as { address: string }; - prisma.ethereumGroup - .findMany({ - where: { - ethereumAddresses: { - has: address - } - }, - select: { - name: true - } - }) + findManyEthGroups(address) .then((groups) => { res.status(200).json(groups); }) @@ -96,14 +73,7 @@ router.post( roomIds: string[]; }; if (!name) res.status(500).json({ error: 'No name provided' }) - const ethereumGroup = await prisma.ethereumGroup.create({ - data: { - name: name, - rooms: { - connect: roomIds.map((roomId) => ({ roomId })) - } - } - }); + const ethereumGroup = await createEthGroup(name, roomIds) res.json({ success: true, ethereumGroup }); }) ); @@ -120,20 +90,17 @@ router.post( names: string[]; ethAddresses: string[]; }; - if (!names) return; - const groups = await prisma.ethereumGroup.updateMany({ - where: { - name: { - in: names - } - }, - data: { - ethereumAddresses: { - push: ethAddresses - } + if (!names) res.status(500).json({ error: 'No names provided' }); + try { + const groups = await addAddressesToEthGroup(names, ethAddresses); + if (groups.count === 0) { + res.status(500).json({ error: 'No groups found' }); + return; } - }); - res.json({ success: true, groups }); + res.json({ success: true, groups }); + } catch (err) { + res.status(500).json({ error: 'Internal Server Error' }); + } }) ); @@ -160,33 +127,16 @@ router.post( roomIds: []; }; try { - const foundGroup = await prisma.ethereumGroup.findUnique({ - where: { - name: name - }, - select: { - ethereumAddresses: true - } - }); + const foundGroup = await findUniqueEthGroup(name) let addresses: string[] = []; + if (foundGroup?.ethereumAddresses) { addresses = ethAddresses.filter((address) => { return !foundGroup.ethereumAddresses.includes(address); }); } - const updatedGroup = await prisma.ethereumGroup.update({ - where: { - name: name - }, - data: { - ethereumAddresses: { - push: addresses - }, - rooms: { - connect: roomIds.map((roomId) => ({ roomId })) - } - } - }); + + const updatedGroup = await updateEthGroup(name, addresses, roomIds); res.json({ success: true, updatedGroup }); } catch (err) { console.error(err); @@ -204,12 +154,7 @@ router.post( */ router.post('/group/delete', adminAuth, (req, res) => { const { name } = req.body as { name: string }; - prisma.ethereumGroup - .delete({ - where: { - name: name - } - }) + removeEthGroup(name) .then((group) => { res.status(200).json(group); }) @@ -241,51 +186,9 @@ router.post( }; try { - const msgHex = bufferToHex(Buffer.from(message)); - const msgBuffer = toBuffer(msgHex); - const msgHash = hashPersonalMessage(msgBuffer); - - const { v, r, s } = fromRpcSig(signature); - const publicKey = ecrecover(msgHash, v, r, s); - const address = pubToAddress(publicKey); - - const recoveredAddress = bufferToHex(address); - const gatewayIdentity = await prisma.gateWayIdentity.upsert({ - where: { semaphoreIdentity: message }, - update: {}, - create: { - semaphoreIdentity: message - } - }); - - await prisma.ethereumAddress.upsert({ - where: { ethereumAddress: recoveredAddress }, - update: {}, - create: { - ethereumAddress: recoveredAddress, - gatewayId: gatewayIdentity.id - } - }); - - const roomsToJoin = await prisma.ethereumGroup.findMany({ - where: { - ethereumAddresses: { - has: recoveredAddress - } - }, - select: { - roomIds: true - } - }); - - const roomIdsSet = new Set(roomsToJoin.map((room) => room.roomIds).flat()); - const roomIds = Array.from(roomIdsSet); - - await prisma.gateWayIdentity.update({ - where: { id: gatewayIdentity.id }, - data: { roomIds: { set: roomIds } } - }); + const recoveredAddress = recoverPublicKey(message, signature); + const roomIds = await joinRoomsFromEthAddress(recoveredAddress, message); res.json({ status: 'valid', roomIds: roomIds }); } catch (err) { console.error(err); diff --git a/src/types/index.ts b/src/types/index.ts index 7c096c3..0530102 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -67,3 +67,9 @@ export interface addRoomData { admin?: boolean; discordIds?: string[]; } + +export interface EthGroupI { + name: string; + roomIds: string[]; + ethereumAddresses: string[]; +} From 2b2d1cc6cfaf64cb97ecd8c4a0fb388f9916b421 Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Fri, 27 Oct 2023 15:11:02 -0500 Subject: [PATCH 3/7] refactor(endpoints) find groups refactor --- src/data/db/find.ts | 69 ++++++++++++++++++------- src/endpoints/gateways/ethereumGroup.ts | 6 +-- src/endpoints/gateways/jubmoji.ts | 24 +++------ src/endpoints/index.ts | 3 ++ 4 files changed, 62 insertions(+), 40 deletions(-) diff --git a/src/data/db/find.ts b/src/data/db/find.ts index 596f443..4a38f31 100644 --- a/src/data/db/find.ts +++ b/src/data/db/find.ts @@ -93,7 +93,9 @@ export async function findClaimCode(code: string): Promise { }); } -export async function findGatewayByIdentity(identity: string): Promise { +export async function findGatewayByIdentity( + identity: string +): Promise { return await prisma.gateWayIdentity.findFirst({ where: { semaphoreIdentity: identity @@ -154,28 +156,57 @@ export async function findRoomWithMessageId( } } -export function findManyEthGroups(address?: string): Promise<{ name: string }[]> { - if (address) { - return prisma.ethereumGroup.findMany({ - where: { - ethereumAddresses: { - has: address - } - }, - select: { - name: true +export function findManyGroups( + group: string, + address?: string +) { + switch (group) { + case 'ethereum': + if (address) { + return prisma.ethereumGroup.findMany({ + where: { + ethereumAddresses: { + has: address + } + }, + select: { + name: true + } + }); + } else { + return prisma.ethereumGroup.findMany({ + select: { + name: true + } + }); } - }) - } else { - return prisma.ethereumGroup.findMany({ - select: { - name: true + case 'jubmoji': + if (address) { + return prisma.jubmojiGroup.findMany({ + where: { + jubmojiAddresses: { + has: address + } + }, + select: { + name: true + } + }); + } else { + return prisma.jubmojiGroup.findMany({ + select: { + name: true + } + }); } - }) + default: + throw new Error('Invalid group'); } } -export function findUniqueEthGroup(name: string): Promise<{ ethereumAddresses: string[] } | null> { +export function findUniqueEthGroup( + name: string +): Promise<{ ethereumAddresses: string[] } | null> { return prisma.ethereumGroup.findUnique({ where: { name: name @@ -183,5 +214,5 @@ export function findUniqueEthGroup(name: string): Promise<{ ethereumAddresses: s select: { ethereumAddresses: true } - }) + }); } diff --git a/src/endpoints/gateways/ethereumGroup.ts b/src/endpoints/gateways/ethereumGroup.ts index cd990bb..c936e4a 100644 --- a/src/endpoints/gateways/ethereumGroup.ts +++ b/src/endpoints/gateways/ethereumGroup.ts @@ -4,7 +4,7 @@ import express from 'express'; import { limiter } from '../middleware'; import { generateRandomClaimCode } from 'discreetly-claimcodes'; import basicAuth from 'express-basic-auth'; -import { addAddressesToEthGroup, updateEthGroup, createEthGroup, findManyEthGroups, findUniqueEthGroup, removeEthGroup, joinRoomsFromEthAddress } from '../../data/db'; +import { addAddressesToEthGroup, updateEthGroup, createEthGroup, findManyGroups, findUniqueEthGroup, removeEthGroup, joinRoomsFromEthAddress } from '../../data/db'; import { recoverPublicKey } from '../../data/utils'; const adminPassword = process.env.PASSWORD @@ -22,7 +22,7 @@ const router = express.Router(); // Fetches all ethereum groups that exist in the database router.get('/groups/all', adminAuth, (req: Request, res: Response) => { - findManyEthGroups() + findManyGroups('ethereum') .then((groups) => { res.status(200).json(groups); }) @@ -42,7 +42,7 @@ router.get('/groups/all', adminAuth, (req: Request, res: Response) => { */ router.get('/group/:address', limiter, (req, res) => { const { address } = req.params as { address: string }; - findManyEthGroups(address) + findManyGroups('ethereum', address) .then((groups) => { res.status(200).json(groups); }) diff --git a/src/endpoints/gateways/jubmoji.ts b/src/endpoints/gateways/jubmoji.ts index 8c45a29..e6259af 100644 --- a/src/endpoints/gateways/jubmoji.ts +++ b/src/endpoints/gateways/jubmoji.ts @@ -4,6 +4,7 @@ import { PrismaClient } from '@prisma/client'; import { limiter } from '../middleware'; import { generateRandomClaimCode } from 'discreetly-claimcodes'; import basicAuth from 'express-basic-auth'; +import { findManyGroups } from '../../data/db'; const router = express.Router(); const prisma = new PrismaClient(); @@ -21,12 +22,7 @@ const adminAuth = basicAuth({ // Fetches all jubmoji groups that exist in the database router.get('/groups/all', adminAuth, (req: Request, res: Response) => { - prisma.jubmojiGroup - .findMany({ - select: { - name: true - } - }) + findManyGroups('jubmoji') .then((groups) => { res.status(200).json(groups); }) @@ -46,17 +42,7 @@ router.get('/groups/all', adminAuth, (req: Request, res: Response) => { */ router.get('/group/:address', limiter, (req: Request, res: Response) => { const { address } = req.params as { address: string }; - prisma.jubmojiGroup - .findMany({ - where: { - jubmojiAddresses: { - has: address - } - }, - select: { - name: true - } - }) + findManyGroups('jubmoji', address) .then((groups) => { res.status(200).json(groups); }) @@ -87,7 +73,7 @@ router.post('/group/create', adminAuth, (req: Request, res: Response) => { data: { name, rooms: { - connect: roomIds.map((id) => ({ id })) + connect: roomIds.map((roomId) => ({ roomId })) } } }) @@ -175,3 +161,5 @@ router.post('/group/delete', adminAuth, (req: Request, res: Response) => { res.status(500).json({ error: 'Internal Server Error' }); }) }) + +export default router; diff --git a/src/endpoints/index.ts b/src/endpoints/index.ts index c48b34c..bb48e56 100644 --- a/src/endpoints/index.ts +++ b/src/endpoints/index.ts @@ -6,10 +6,12 @@ import discordRouter from './gateways/discord'; import ethRouter from './gateways/ethereumGroup'; import theWordRouter from './gateways/theWord'; import codeRouter from './gateways/inviteCode'; +import jubmojiRouter from './gateways/jubmoji'; import roomRouter from './rooms/rooms'; import identityRouter from './identity/idc'; import adminRouter from './admin/admin'; + export function initEndpoints(app: Express) { // This code is used to fetch the server info from the api // This is used to display the server info on the client side @@ -17,6 +19,7 @@ export function initEndpoints(app: Express) { app.use('/gateway/eth', ethRouter); app.use('/gateway/theword', theWordRouter); app.use('/gateway/code', codeRouter); + app.use('/gateway/jubmoji', jubmojiRouter) app.use('/room', roomRouter); app.use('/identity', identityRouter); app.use('/admin', adminRouter); From b4593e39bc1f690f8cde7d020dfc75d0076b1c24 Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Mon, 30 Oct 2023 12:37:06 -0500 Subject: [PATCH 4/7] refactor(endpoints): further refactoring endpoints --- src/data/db/find.ts | 21 +++++++++++++++ src/data/db/remove.ts | 36 ++++++++++++++++++++++--- src/data/db/update.ts | 2 ++ src/endpoints/gateways/ethereumGroup.ts | 2 +- src/endpoints/gateways/inviteCode.ts | 9 +++---- src/endpoints/gateways/jubmoji.ts | 9 +++---- src/endpoints/gateways/theWord.ts | 4 +-- src/endpoints/rooms/rooms.ts | 28 +++---------------- 8 files changed, 68 insertions(+), 43 deletions(-) diff --git a/src/data/db/find.ts b/src/data/db/find.ts index 4a38f31..951b005 100644 --- a/src/data/db/find.ts +++ b/src/data/db/find.ts @@ -216,3 +216,24 @@ export function findUniqueEthGroup( } }); } + +export function findMessages(roomId : string) { + return prisma.messages + .findMany({ + take: 500, + orderBy: { + timeStamp: 'desc' + }, + where: { + roomId: roomId + }, + select: { + id: false, + message: true, + messageId: true, + proof: true, + roomId: true, + timeStamp: true + } + }) +} diff --git a/src/data/db/remove.ts b/src/data/db/remove.ts index b143191..13ecdb2 100644 --- a/src/data/db/remove.ts +++ b/src/data/db/remove.ts @@ -98,12 +98,42 @@ export function removeMessage(roomId: string, messageId: string) { }); } +/** + * This function deletes an ethereum group from the database. + * @param name - The name of the Ethereum group to delete + * @returns {void} + */ +export function removeEthGroup(group: string, name: string) { + switch(group) { + case 'ethereum': + return prisma.ethereumGroup + .delete({ + where: { + name: name + } + }) + case 'jubmoji': + return prisma.jubmojiGroup + .delete({ + where: { + name: name + } + }) + default: + throw new Error('No group found') + } +} -export function removeEthGroup(name: string) { - return prisma.ethereumGroup +/** + * This function removes a claim code from the database. + * @param {string} code - The claim code to find + * @returns {void} + */ +export function removeClaimCode(code: string) { + return prisma.claimCodes .delete({ where: { - name: name + claimcode: code } }) } diff --git a/src/data/db/update.ts b/src/data/db/update.ts index de21bc0..078ed27 100644 --- a/src/data/db/update.ts +++ b/src/data/db/update.ts @@ -352,3 +352,5 @@ export function updateEthGroup(name: string, ethAddresses: string[], roomIds: st } }); } + + diff --git a/src/endpoints/gateways/ethereumGroup.ts b/src/endpoints/gateways/ethereumGroup.ts index c936e4a..ef6951b 100644 --- a/src/endpoints/gateways/ethereumGroup.ts +++ b/src/endpoints/gateways/ethereumGroup.ts @@ -154,7 +154,7 @@ router.post( */ router.post('/group/delete', adminAuth, (req, res) => { const { name } = req.body as { name: string }; - removeEthGroup(name) + removeEthGroup('ethereum', name) .then((group) => { res.status(200).json(group); }) diff --git a/src/endpoints/gateways/inviteCode.ts b/src/endpoints/gateways/inviteCode.ts index abd672e..20685ec 100644 --- a/src/endpoints/gateways/inviteCode.ts +++ b/src/endpoints/gateways/inviteCode.ts @@ -7,7 +7,8 @@ import { findClaimCode, updateClaimCode, updateRoomIdentities, - findUpdatedRooms + findUpdatedRooms, + removeClaimCode } from '../../data/db/'; import { GatewayInviteDataI } from '../../types'; import { RoomI } from 'discreetly-interfaces'; @@ -52,11 +53,7 @@ router.post( if (foundCode && (foundCode.usesLeft >= 0 || foundCode.usesLeft === -1)) { const updatedCode = await updateClaimCode(code, idc); if (updatedCode && updatedCode.usesLeft === 0) { - await prisma.claimCodes.delete({ - where: { - claimcode: code - } - }); + await removeClaimCode(code); } } else { res.status(400).json({ message: 'Invalid Claim Code' }); diff --git a/src/endpoints/gateways/jubmoji.ts b/src/endpoints/gateways/jubmoji.ts index e6259af..392a5df 100644 --- a/src/endpoints/gateways/jubmoji.ts +++ b/src/endpoints/gateways/jubmoji.ts @@ -4,7 +4,7 @@ import { PrismaClient } from '@prisma/client'; import { limiter } from '../middleware'; import { generateRandomClaimCode } from 'discreetly-claimcodes'; import basicAuth from 'express-basic-auth'; -import { findManyGroups } from '../../data/db'; +import { findManyGroups, removeEthGroup } from '../../data/db'; const router = express.Router(); const prisma = new PrismaClient(); @@ -150,11 +150,8 @@ router.post('/group/edit', adminAuth, (req: Request, res: Response) => { router.post('/group/delete', adminAuth, (req: Request, res: Response) => { const { name } = req.body as { name: string }; - prisma.jubmojiGroup.delete({ - where: { - name: name - } - }).then((group) => { + removeEthGroup('jubmoji', name) + .then((group) => { res.status(200).json(group); }).catch((err) => { console.error(err); diff --git a/src/endpoints/gateways/theWord.ts b/src/endpoints/gateways/theWord.ts index db5e842..63c9c0e 100644 --- a/src/endpoints/gateways/theWord.ts +++ b/src/endpoints/gateways/theWord.ts @@ -27,11 +27,11 @@ router.post( const isValid = await verifyTheWordProof(proof); if (isValid) { - const room = (await prisma.rooms.findUnique({ + const room = await prisma.rooms.findUnique({ where: { roomId: '007' + process.env.THEWORD_ITERATION } - })) as RoomI; + }) as RoomI; const addedRoom = await addIdentityToIdentityListRooms([room], idc); if (addedRoom.length === 0) { res.status(500).json({ diff --git a/src/endpoints/rooms/rooms.ts b/src/endpoints/rooms/rooms.ts index aba8b2e..27c2a34 100644 --- a/src/endpoints/rooms/rooms.ts +++ b/src/endpoints/rooms/rooms.ts @@ -1,25 +1,20 @@ import express from 'express'; import type { Request, Response } from 'express'; import { limiter } from '../middleware'; -import asyncHandler from 'express-async-handler'; -import { PrismaClient } from '@prisma/client'; -import { verifyIdentityProof } from '../../crypto/idcVerifier/verifier'; import { pp } from '../../utils'; -import { IDCProof } from 'idc-nullifier/dist/types/types'; import { addRoomData } from '../../types'; import { findRoomById, - findRoomsByIdentity, createRoom, removeRoom, - removeMessage + removeMessage, + findMessages } from '../../data/db/'; import { MessageI, RoomI } from 'discreetly-interfaces'; import { RLNFullProof } from 'rlnjs'; import basicAuth from 'express-basic-auth'; import { generateRandomClaimCode } from 'discreetly-claimcodes'; const router = express.Router(); -const prisma = new PrismaClient(); const adminPassword = process.env.PASSWORD ? process.env.PASSWORD @@ -224,24 +219,7 @@ router.post('/:roomId/message/delete', adminAuth, (req, res) => { */ router.get('/:id/messages', limiter, (req, res) => { const { id } = req.params; - prisma.messages - .findMany({ - take: 500, - orderBy: { - timeStamp: 'desc' - }, - where: { - roomId: id - }, - select: { - id: false, - message: true, - messageId: true, - proof: true, - roomId: true, - timeStamp: true - } - }) + findMessages(id) .then((messages) => { messages.map((message: MessageI) => { message.timeStamp = new Date(message.timeStamp as Date).getTime(); From c0062ff9ca5911d70dd9667abc2b340bf62ec47f Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Mon, 30 Oct 2023 14:51:22 -0500 Subject: [PATCH 5/7] feat(endpoints) adding js docs to endpoint functions --- src/data/db/find.ts | 30 +++++++++++++++++++++++++++++- src/data/db/update.ts | 17 ++++++++++++++--- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/data/db/find.ts b/src/data/db/find.ts index 951b005..200eb67 100644 --- a/src/data/db/find.ts +++ b/src/data/db/find.ts @@ -52,9 +52,10 @@ time stamp to prevent replay attacks https://github.com/Discreetly/IdentityCommitmentNullifierCircuit <- Circuit and JS to do this */ + /** * This function takes in an identity and returns the rooms the identity is in. - * @param identity - the identity of a user + * @param {string[]} identity - the identity of a user * @returns an array of roomIds */ export async function findRoomsByIdentity(identity: string): Promise { @@ -93,6 +94,11 @@ export async function findClaimCode(code: string): Promise { }); } +/** + * Finds a gateway identity in the database. + * @param {string} identity - The identity to find + * @returns + */ export async function findGatewayByIdentity( identity: string ): Promise { @@ -122,6 +128,12 @@ export async function findUpdatedRooms(roomIds: string[]): Promise { }); } +/** + * This function is used to find a room in the database using a message and the roomId and returns the room + * @param {string} roomId - The id of the room to find + * @param {MessageI} message - The id of message to find + * @returns + */ export async function findRoomWithMessageId( roomId: string, message: MessageI @@ -156,6 +168,12 @@ export async function findRoomWithMessageId( } } +/** + * This function is used to find groups in the database that the ethereum address is in + * @param {string} group - The type of the group to find + * @param {string} group - The address of the group to find + * @returns + */ export function findManyGroups( group: string, address?: string @@ -204,6 +222,11 @@ export function findManyGroups( } } +/** + * This function is used to find a group in the database and returns the groups ethereum addresses + * @param {string} name - The name of the group to find + * @returns {Promise<{ ethereumAddresses: string[] } | null>} - A promise that resolves to the group + */ export function findUniqueEthGroup( name: string ): Promise<{ ethereumAddresses: string[] } | null> { @@ -217,6 +240,11 @@ export function findUniqueEthGroup( }); } +/** + * This function is used to find messages in a room + * @param {string} roomId - The id of the room to find messages in + * @returns {void} + */ export function findMessages(roomId : string) { return prisma.messages .findMany({ diff --git a/src/data/db/update.ts b/src/data/db/update.ts index 078ed27..9c24731 100644 --- a/src/data/db/update.ts +++ b/src/data/db/update.ts @@ -321,6 +321,13 @@ export async function createEthGroupForRoom( }); } + +/** + * + * @param {string[]} names - The names of the ethereum groups to add the addresses to + * @param {string[]} ethAddresses - An array of ethereum addresses to add to the groups + * @returns + */ export function addAddressesToEthGroup(names: string[], ethAddresses: string[]) { return prisma.ethereumGroup.updateMany({ where: { @@ -336,7 +343,13 @@ export function addAddressesToEthGroup(names: string[], ethAddresses: string[]) }); } - +/** + * This function updates an ethereum group in the database. + * @param {string} name - The name of the ethereum group to update + * @param {string[]} ethAddresses - An array of ethereum addresses to add to the group + * @param {string[]} roomIds - The ids of the rooms to connect to the group + * @returns + */ export function updateEthGroup(name: string, ethAddresses: string[], roomIds: string[]) { return prisma.ethereumGroup.update({ where: { @@ -352,5 +365,3 @@ export function updateEthGroup(name: string, ethAddresses: string[], roomIds: st } }); } - - From 9ceac9e93a533c408dae01cd766a89caabe2898c Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Wed, 1 Nov 2023 16:59:11 -0500 Subject: [PATCH 6/7] refactor(endpoints) further refactoring endpoints --- src/data/db/create.ts | 37 +++++++++++++++++ src/data/db/find.ts | 16 ++++++++ src/data/db/update.ts | 38 ++++++++++++++++++ src/endpoints/admin/admin.ts | 77 ++++++------------------------------ src/types/index.ts | 1 + 5 files changed, 104 insertions(+), 65 deletions(-) diff --git a/src/data/db/create.ts b/src/data/db/create.ts index 570554a..45f983e 100644 --- a/src/data/db/create.ts +++ b/src/data/db/create.ts @@ -183,6 +183,43 @@ export function createEthGroup( }); } +export function createClaimCode( + claimCode: string, + roomIds: string[], + expiresAt: number, + usesLeft: number, + discordId: string, + roomId?: string + ) { + if (!roomId) { + return prisma.claimCodes.create({ + data: { + claimcode: claimCode, + roomIds: roomIds, + expiresAt: expiresAt, + usesLeft: usesLeft, + discordId: discordId + } + }); + } else { + return prisma.claimCodes.create({ + data: { + claimcode: claimCode, + roomIds: roomIds, + expiresAt: expiresAt, + usesLeft: usesLeft, + discordId: discordId, + rooms: { + connect: { + roomId: roomId + } + } + } + }); + } +} + + export async function joinRoomsFromEthAddress( recoveredAddress: string, message: string diff --git a/src/data/db/find.ts b/src/data/db/find.ts index 200eb67..de1472f 100644 --- a/src/data/db/find.ts +++ b/src/data/db/find.ts @@ -46,6 +46,22 @@ export async function findRoomById(id: string): Promise { }); } +export function findRoomClaimCodes(roomId: string) { + return prisma.rooms + .findUnique({ + where: { roomId: roomId }, + include: { claimCodes: true } + }) +} + +export function findAllClaimCodes() { + return prisma.claimCodes.findMany() +} + +export async function findAllRooms(all?: boolean, rooms?: string[] | undefined) { + const query = all ? undefined : { where: { roomId: { in: rooms } } } + return await prisma.rooms.findMany(query); +} /* 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 diff --git a/src/data/db/update.ts b/src/data/db/update.ts index 9c24731..5f9ba20 100644 --- a/src/data/db/update.ts +++ b/src/data/db/update.ts @@ -5,6 +5,7 @@ import { RoomI } from 'discreetly-interfaces'; import { getRateCommitmentHash } from '../../crypto'; import { pp } from '../../utils'; import { RoomWithSecretsI, ClaimCodeI } from '../../types/'; +import { IDCProof } from 'idc-nullifier'; const prisma = new PrismaClient(); @@ -365,3 +366,40 @@ export function updateEthGroup(name: string, ethAddresses: string[], roomIds: st } }); } + +export function updateRoomClaimCodes(roomId: string, claimCodeId: string) { + return prisma.rooms.update({ + where: { + roomId: roomId + }, + data: { + claimCodeIds: { + push: claimCodeId + } + } + }); +} + +export async function updateIdentites(generatedProof: IDCProof) { + return await prisma.gateWayIdentity.update({ + where: { + semaphoreIdentity: String(generatedProof.publicSignals.identityCommitment) + }, + data: { + semaphoreIdentity: String(generatedProof.publicSignals.externalNullifier), + } + }) +} + +export async function addAdminToRoom(roomId: string, idc: string) { + return await prisma.rooms.update({ + where: { + roomId: roomId + }, + data: { + adminIdentities: { + push: idc + } + } + }); +} diff --git a/src/endpoints/admin/admin.ts b/src/endpoints/admin/admin.ts index 020387a..6c1915a 100644 --- a/src/endpoints/admin/admin.ts +++ b/src/endpoints/admin/admin.ts @@ -2,14 +2,12 @@ import express from 'express'; import type { Request, Response } from 'express'; import asyncHandler from 'express-async-handler'; import basicAuth from 'express-basic-auth'; -import { PrismaClient } from '@prisma/client'; import { genClaimCodeArray, pp } from '../../utils'; import { IDCProof } from 'idc-nullifier/dist/types/types'; import { verifyIdentityProof } from '../../crypto/idcVerifier/verifier'; import { limiter } from '../middleware'; -import { createSystemMessages } from '../../data/db'; +import { addAdminToRoom, createClaimCode, createSystemMessages, findAllClaimCodes, findAllRooms, findRoomClaimCodes, updateIdentites, updateRoomClaimCodes } from '../../data/db'; -const prisma = new PrismaClient(); const router = express.Router(); const adminPassword = process.env.PASSWORD ? process.env.PASSWORD : 'password'; @@ -61,34 +59,17 @@ router.post( const threeMonthsLater = new Date(currentDate).setMonth(currentDate.getMonth() + 3); const codeExpires = expiresAt ? expiresAt : threeMonthsLater; - const query = all ? undefined : { where: { roomId: { in: rooms } } }; + // const query = all ? undefined : { where: { roomId: { in: rooms } } }; const codes = genClaimCodeArray(numCodes); - return await prisma.rooms.findMany(query).then((rooms) => { + return findAllRooms(all, rooms).then((rooms) => { + console.log(rooms); const roomIds = rooms.map((room) => room.id); const createCodes = codes.map((code) => { - return prisma.claimCodes - .create({ - data: { - claimcode: code.claimcode, - roomIds: roomIds, - expiresAt: codeExpires, - usesLeft: usesLeft, - discordId: discordId - } - }) + return createClaimCode(code.claimcode, roomIds, codeExpires, usesLeft, discordId) .then((newCode) => { const updatePromises = rooms.map((room) => { - return prisma.rooms.update({ - where: { - roomId: room.roomId - }, - data: { - claimCodeIds: { - push: newCode.id - } - } - }); + return updateRoomClaimCodes(room.roomId, newCode.id) }); return Promise.all(updatePromises); }) @@ -136,11 +117,7 @@ router.post('/:roomId/addcode', adminAuth, (req, res) => { const codeExpires = expires ? expires : threeMonthsLater; - prisma.rooms - .findUnique({ - where: { roomId: roomId }, - include: { claimCodes: true } - }) + findRoomClaimCodes(roomId) .then((room) => { if (!room) { res.status(404).json({ error: 'Room not found' }); @@ -148,20 +125,8 @@ router.post('/:roomId/addcode', adminAuth, (req, res) => { } // Map over the codes array and create a claim code for each code const createCodes = codes.map((code) => { - return prisma.claimCodes.create({ - data: { - claimcode: code.claimcode, - expiresAt: codeExpires, - usesLeft: usesLeft, - rooms: { - connect: { - roomId: roomId - } - } - } - }); + return createClaimCode(code.claimcode, [], codeExpires, usesLeft, '', roomId) }); - return Promise.all(createCodes); }) .then(() => { @@ -176,8 +141,7 @@ router.post('/:roomId/addcode', adminAuth, (req, res) => { // This fetches the claim/invite codes from the database and returns them as JSON router.get('/logclaimcodes', adminAuth, (req, res) => { pp('Express: fetching claim codes'); - prisma.claimCodes - .findMany() + findAllClaimCodes() .then((claimCodes) => { res.status(401).json(claimCodes); }) @@ -190,8 +154,7 @@ router.get('/logclaimcodes', adminAuth, (req, res) => { // GET all rooms from the database and return them as JSON router.get('/rooms', adminAuth, (req, res) => { pp(String('Express: fetching all rooms')); - prisma.rooms - .findMany() + findAllRooms() .then((rooms) => { res.status(200).json(rooms); }) @@ -215,14 +178,7 @@ router.post( const isValid = await verifyIdentityProof(generatedProof); if (isValid) { - const updatedIdentity = await prisma.gateWayIdentity.update({ - where: { - semaphoreIdentity: String(generatedProof.publicSignals.identityCommitment) - }, - data: { - semaphoreIdentity: String(generatedProof.publicSignals.externalNullifier) - } - }); + const updatedIdentity = await updateIdentites(generatedProof) res.status(200).json({ message: 'Identity updated successfully', updatedIdentity }); } else { res.status(500).json({ error: 'Internal Server Error' }); @@ -286,16 +242,7 @@ router.post( const { roomId } = req.params; const { idc } = req.body as { idc: string }; try { - await prisma.rooms.update({ - where: { - roomId: roomId - }, - data: { - adminIdentities: { - push: idc - } - } - }); + await addAdminToRoom(roomId, idc); res.status(200).json({ message: `Admin added to room ${roomId}` }); } catch (err) { res.status(500).json({ error: 'Internal Server Error' }); diff --git a/src/types/index.ts b/src/types/index.ts index 0530102..3379917 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -21,6 +21,7 @@ export interface ClaimCodeI { discordId: string | null; } + export interface GateWayIdentityI { semaphoreIdentity: string | null; roomIds: string[]; From 1dbbfffff9f7ce70bdb94d9a619e83ba0914cadf Mon Sep 17 00:00:00 2001 From: Tanner Shaw Date: Wed, 1 Nov 2023 17:07:37 -0500 Subject: [PATCH 7/7] feat(docs) adding jsdocs for new endpoint functions --- src/data/db/find.ts | 7 +++++++ src/data/db/update.ts | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/data/db/find.ts b/src/data/db/find.ts index de1472f..d3f8fb2 100644 --- a/src/data/db/find.ts +++ b/src/data/db/find.ts @@ -54,10 +54,17 @@ export function findRoomClaimCodes(roomId: string) { }) } +// Fetches all claim codes from the database export function findAllClaimCodes() { return prisma.claimCodes.findMany() } +/** + * This function is used to find all rooms in the database + * @param {boolean} all - True or false to query all rooms + * @param {string[]} rooms - An array of roomIds to query + * @returns + */ export async function findAllRooms(all?: boolean, rooms?: string[] | undefined) { const query = all ? undefined : { where: { roomId: { in: rooms } } } return await prisma.rooms.findMany(query); diff --git a/src/data/db/update.ts b/src/data/db/update.ts index 5f9ba20..12cdee5 100644 --- a/src/data/db/update.ts +++ b/src/data/db/update.ts @@ -367,6 +367,12 @@ export function updateEthGroup(name: string, ethAddresses: string[], roomIds: st }); } +/** + * Updates a room's claim code list. + * @param {string} roomId - The id of the room to update + * @param {string} claimCodeId - The id of the claim code to add to the room + * @returns + */ export function updateRoomClaimCodes(roomId: string, claimCodeId: string) { return prisma.rooms.update({ where: { @@ -380,6 +386,11 @@ export function updateRoomClaimCodes(roomId: string, claimCodeId: string) { }); } +/** + * Updates a users identity commitment in the database. + * @param {IDCProof} generatedProof - Proof generated by the user + * @returns + */ export async function updateIdentites(generatedProof: IDCProof) { return await prisma.gateWayIdentity.update({ where: { @@ -391,6 +402,12 @@ export async function updateIdentites(generatedProof: IDCProof) { }) } +/** + * Adds an admin to a room. + * @param {string} roomId - The id of the room to add the admin to + * @param {string} idc - The identity of the admin + * @returns + */ export async function addAdminToRoom(roomId: string, idc: string) { return await prisma.rooms.update({ where: {