mirror of
https://github.com/Discreetly/server.git
synced 2026-01-10 05:18:00 -05:00
292 lines
7.8 KiB
TypeScript
292 lines
7.8 KiB
TypeScript
/* 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';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
interface CodeStatus {
|
|
claimed: boolean;
|
|
roomIds: string[];
|
|
}
|
|
|
|
interface RoomsFromClaimCode {
|
|
roomIds: string[];
|
|
}
|
|
|
|
export async function getRoomByID(id: string): Promise<RoomI | null> {
|
|
const room = await prisma.rooms
|
|
.findUnique({
|
|
where: {
|
|
roomId: id
|
|
},
|
|
select: {
|
|
id: true,
|
|
roomId: true,
|
|
name: true,
|
|
identities: true,
|
|
rateLimit: true,
|
|
userMessageLimit: true,
|
|
membershipType: true,
|
|
contractAddress: true,
|
|
bandadaAddress: true,
|
|
bandadaGroupId: true,
|
|
type: true
|
|
}
|
|
})
|
|
.then((room) => {
|
|
return room;
|
|
})
|
|
.catch((err) => {
|
|
console.error(err);
|
|
throw err; // Add this line to throw the error
|
|
});
|
|
return new Promise((resolve, reject) => {
|
|
if (room) {
|
|
resolve(room as RoomI);
|
|
}
|
|
reject('Room not found');
|
|
});
|
|
}
|
|
|
|
export async function getRoomsByIdentity(identity: string): Promise<string[]> {
|
|
/* 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({
|
|
where: {
|
|
identities: {
|
|
has: identity
|
|
}
|
|
}
|
|
});
|
|
rooms.forEach((room) => {
|
|
r.push(room.roomId);
|
|
});
|
|
console.log(r);
|
|
return r;
|
|
} catch (err) {
|
|
console.error(err);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export function findClaimCode(code: string): Promise<CodeStatus | null> {
|
|
return prisma.claimCodes.findUnique({
|
|
where: { claimcode: code }
|
|
});
|
|
}
|
|
|
|
export function updateClaimCode(code: string): Promise<RoomsFromClaimCode> {
|
|
return prisma.claimCodes.update({
|
|
where: { claimcode: code },
|
|
data: { claimed: true }
|
|
});
|
|
}
|
|
|
|
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<void> {
|
|
const identityCommitment = sanitizeIDC(idc);
|
|
return prisma.rooms
|
|
.findMany({
|
|
where: { id: { in: roomIds } }
|
|
})
|
|
.then((rooms) => {
|
|
addIdentityToIdentityListRooms(rooms, identityCommitment);
|
|
addIdentityToBandadaRooms(rooms, identityCommitment);
|
|
})
|
|
.catch((err) => {
|
|
pp(err, 'error');
|
|
});
|
|
}
|
|
|
|
function addIdentityToIdentityListRooms(rooms, identityCommitment: string): unknown {
|
|
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 addIdentityToBandadaRooms(rooms, identityCommitment: string): void {
|
|
const bandadaGroupRooms = rooms
|
|
.filter(
|
|
(room) =>
|
|
room.membershipType === 'BANDADA_GROUP' && !room.identities.includes(identityCommitment)
|
|
)
|
|
.map((room) => room as RoomI);
|
|
|
|
if (bandadaGroupRooms.length > 0) {
|
|
bandadaGroupRooms.forEach(async (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
|
|
}
|
|
};
|
|
await prisma.rooms.updateMany({
|
|
where: { id: room.id },
|
|
data: { identities: { push: identityCommitment } }
|
|
});
|
|
const url = `https://${room.bandadaAddress}/groups/${room.bandadaGroupId}/members/${identityCommitment}`;
|
|
fetch(url, requestOptions)
|
|
.then((res) => {
|
|
if (res.status == 200) {
|
|
console.debug(`Successfully added user to Bandada group ${room.bandadaAddress}`);
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
console.error(err);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
export async function findUpdatedRooms(roomIds: string[]): Promise<RoomI[]> {
|
|
const rooms = await prisma.rooms.findMany({
|
|
where: { id: { in: roomIds } }
|
|
});
|
|
return new Promise((resolve, reject) => {
|
|
if (rooms) {
|
|
resolve(rooms as RoomI[]);
|
|
}
|
|
reject('No rooms found');
|
|
});
|
|
}
|
|
|
|
// TODO: Make interface for this return type; which is like a MessageI
|
|
export function createSystemMessages(message: string, roomId?: string): Promise<unknown> {
|
|
const query = roomId ? { where: { roomId } } : undefined;
|
|
return prisma.rooms
|
|
.findMany(query)
|
|
.then((rooms) => {
|
|
if (roomId && rooms.length === 0) {
|
|
return Promise.reject('Room not found');
|
|
}
|
|
const createMessages = rooms.map((room) => {
|
|
return prisma.messages.create({
|
|
data: {
|
|
message,
|
|
roomId: room.roomId,
|
|
messageId: '0',
|
|
proof: JSON.stringify({})
|
|
}
|
|
});
|
|
});
|
|
|
|
return Promise.all(createMessages);
|
|
})
|
|
.catch((err) => {
|
|
console.error(err);
|
|
return Promise.reject(err);
|
|
});
|
|
}
|
|
|
|
export function removeIdentityFromRoom(idc: string, room: RoomI): Promise<void | RoomI> {
|
|
const updateIdentities = room.identities?.map((identity) =>
|
|
identity === idc ? '0n' : identity
|
|
) as string[];
|
|
return prisma.rooms
|
|
.update({
|
|
where: { id: room.id },
|
|
data: { identities: updateIdentities }
|
|
})
|
|
.then((room) => {
|
|
return room as RoomI;
|
|
})
|
|
.catch((err) => {
|
|
console.error(err);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates a new room with the given name and optional parameters.
|
|
* @param {string} name - The name of the room.
|
|
* @param {number} [rateLimit=1000] - The length of an epoch in milliseconds
|
|
* @param {number} [userMessageLimit=1] - The message limit per user per epoch
|
|
* @param {number} [numClaimCodes=0] - The number of claim codes to generate for the room.
|
|
* @param {number} [approxNumMockUsers=20] - The approximate number of mock users to generate for the room.
|
|
*/
|
|
export async function createRoom(
|
|
roomName: string,
|
|
rateLimit = 1000,
|
|
userMessageLimit = 1,
|
|
numClaimCodes = 0,
|
|
approxNumMockUsers = 20,
|
|
type: string,
|
|
bandadaAddress?: string,
|
|
bandadaGroupId?: string,
|
|
bandadaAPIKey?: string,
|
|
membershipType?: string
|
|
): Promise<boolean> {
|
|
const claimCodes: { claimcode: string }[] = genClaimCodeArray(numClaimCodes);
|
|
console.log(claimCodes);
|
|
const mockUsers: string[] = genMockUsers(approxNumMockUsers);
|
|
const roomData = {
|
|
where: {
|
|
roomId: genId(serverConfig.id as bigint, roomName).toString()
|
|
},
|
|
update: {},
|
|
create: {
|
|
roomId: genId(serverConfig.id as bigint, roomName).toString(),
|
|
name: roomName,
|
|
rateLimit: rateLimit,
|
|
userMessageLimit: userMessageLimit,
|
|
identities: mockUsers,
|
|
type,
|
|
bandadaAddress,
|
|
bandadaGroupId,
|
|
bandadaAPIKey,
|
|
membershipType,
|
|
claimCodes: {
|
|
create: claimCodes
|
|
}
|
|
}
|
|
};
|
|
|
|
return await prisma.rooms
|
|
.upsert(roomData)
|
|
.then(() => {
|
|
return true;
|
|
})
|
|
.catch((err) => {
|
|
console.error(err);
|
|
return false;
|
|
});
|
|
}
|