From 8d9bbc18937d752d02f2b2d423f28809e545680f Mon Sep 17 00:00:00 2001 From: Declan Chidlow Date: Sat, 13 Jul 2024 20:58:10 +0800 Subject: [PATCH] De monk-ify --- api/bun.lockb | Bin 48707 -> 43174 bytes api/package.json | 3 +- api/src/db.ts | 36 +++++---- api/src/middlewares/updateTokenExpiry.ts | 28 +++++-- api/src/routes/dash/server-automod.ts | 90 ++++++++++++----------- api/src/routes/login.ts | 31 ++++---- api/src/utils.ts | 19 +++-- 7 files changed, 125 insertions(+), 82 deletions(-) diff --git a/api/bun.lockb b/api/bun.lockb index 33876fcd393ca1b983a2ff4e3bfe95b43bdee836..816e2d134228210350684e32b719c187b9bdf600 100755 GIT binary patch delta 9368 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 M-Kk;yzD?r)0$Kus1poj5 delta 12564 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 D<9=r= diff --git a/api/package.json b/api/package.json index 341c960..58b0d3b 100644 --- a/api/package.json +++ b/api/package.json @@ -10,13 +10,12 @@ }, "dependencies": { "@types/express": "^4.17.21", - "@types/monk": "^6.0.0", "@types/ws": "^8.5.11", "automod": "^0.1.0", "dotenv": "^14.3.2", "express": "^4.19.2", "log75": "^2.2.0", - "monk": "^7.3.4", + "mongodb": "^6.8.0", "redis": "^4.6.15", "ulid": "^2.3.0", "ws": "^8.18.0" diff --git a/api/src/db.ts b/api/src/db.ts index c8b38bd..0a7ff14 100644 --- a/api/src/db.ts +++ b/api/src/db.ts @@ -1,34 +1,44 @@ -import Monk, { IMonkManager } from 'monk'; +import { MongoClient, Db } from 'mongodb'; import Redis from 'redis'; import { logger } from '.'; -export default (): IMonkManager => { - let dburl = getDBUrl(); - let db = Monk(dburl); - return db; -}; +let db: Db; + +export default async function buildDBClient(): Promise { + if (db) return db; + const url = getDBUrl(); + const client = new MongoClient(url); + try { + await client.connect(); + db = client.db(); + logger.info('Connected successfully to MongoDB'); + return db; + } catch (error) { + logger.error('Failed to connect to MongoDB', error); + throw error; + } +} const redis = Redis.createClient({ url: process.env.REDIS_URL }); -export { redis } +export { redis }; // Checks if all required env vars were supplied, and returns the mongo db URL -function getDBUrl() { - let env = process.env; +function getDBUrl(): string { + const env = process.env; if (env['DB_URL']) return env['DB_URL']; - + if (!env['DB_HOST']) { logger.error(`Environment variable 'DB_HOST' not set, unable to connect to database`); logger.error(`Specify either 'DB_URL' or 'DB_HOST', 'DB_USERNAME', 'DB_PASS' and 'DB_NAME'`); - throw 'Missing environment variables'; + throw new Error('Missing environment variables'); } // mongodb://username:password@hostname:port/dbname let dburl = 'mongodb://'; if (env['DB_USERNAME']) dburl += env['DB_USERNAME']; if (env['DB_PASS']) dburl += `:${env['DB_PASS']}`; - dburl += `${process.env['DB_USERNAME'] ? '@' : ''}${env['DB_HOST']}`; // DB_HOST is assumed to contain the port + dburl += `${env['DB_USERNAME'] ? '@' : ''}${env['DB_HOST']}`; // DB_HOST is assumed to contain the port dburl += `/${env['DB_NAME'] ?? 'automod'}`; - return dburl; } diff --git a/api/src/middlewares/updateTokenExpiry.ts b/api/src/middlewares/updateTokenExpiry.ts index 35fe74f..6895f8d 100644 --- a/api/src/middlewares/updateTokenExpiry.ts +++ b/api/src/middlewares/updateTokenExpiry.ts @@ -1,19 +1,33 @@ import { Request, Response } from "express"; -import { FindOneResult } from "monk"; -import { app, db, SESSION_LIFETIME } from ".."; +import { Collection, Db } from "mongodb"; +import { app, SESSION_LIFETIME } from ".."; + +let sessionsCollection: Collection; + +export function initializeSessionsMiddleware(db: Db) { + sessionsCollection = db.collection('sessions'); +} app.use('*', async (req: Request, res: Response, next: () => void) => { next(); - const user = req.header('x-auth-user'); const token = req.header('x-auth-token'); - if (!user || !token) return; try { - const session: FindOneResult = await db.get('sessions').findOne({ user, token, expires: { $gt: Date.now() } }); + const session = await sessionsCollection.findOne({ + user, + token, + expires: { $gt: new Date() } + }); + if (session) { - await db.get('sessions').update({ _id: session._id }, { $set: { expires: Date.now() + SESSION_LIFETIME } }); + await sessionsCollection.updateOne( + { _id: session._id }, + { $set: { expires: new Date(Date.now() + SESSION_LIFETIME) } } + ); } - } catch(e) { console.error(e) } + } catch(e) { + console.error(e); + } }); diff --git a/api/src/routes/dash/server-automod.ts b/api/src/routes/dash/server-automod.ts index ff8bc83..acfbd66 100644 --- a/api/src/routes/dash/server-automod.ts +++ b/api/src/routes/dash/server-automod.ts @@ -2,9 +2,15 @@ import { app, db } from '../..'; import { Request, Response } from 'express'; import { badRequest, ensureObjectStructure, isAuthenticated, requireAuth, unauthorized } from '../../utils'; import { botReq } from '../internal/ws'; -import { FindOneResult } from 'monk'; +import { Collection, Db, ObjectId } from 'mongodb'; import { ulid } from 'ulid'; +let serversCollection: Collection; + +export function initializeAutomodAPI(database: Db) { + serversCollection = database.collection('servers'); +} + type AntispamRule = { id: string; max_msg: number; @@ -14,7 +20,7 @@ type AntispamRule = { message: string | null; } -app.get('/dash/server/:server/automod',requireAuth({ permission: 2 }) , async (req: Request, res: Response) => { +app.get('/dash/server/:server/automod', requireAuth({ permission: 2 }), async (req: Request, res: Response) => { const user = await isAuthenticated(req, res, true); if (!user) return; @@ -31,11 +37,11 @@ app.get('/dash/server/:server/automod',requireAuth({ permission: 2 }) , async (r const permissionLevel: 0|1|2|3 = response.perms; if (permissionLevel < 1) return unauthorized(res, `Only moderators and bot managers may view this.`); - const serverConfig: FindOneResult = await db.get('servers').findOne({ id: server }); + const serverConfig = await serversCollection.findOne({ id: server }); const result = { antispam: (serverConfig?.automodSettings?.spam as AntispamRule[]|undefined) - ?.map(r => ({ // Removing unwanted fields from response + ?.map(r => ({ action: r.action, channels: r.channels, id: r.id, @@ -57,28 +63,29 @@ app.patch('/dash/server/:server/automod/:ruleid', requireAuth({ permission: 2 }) const body = req.body; if (!server || !ruleid) return badRequest(res); - const serverConfig: FindOneResult = await db.get('servers').findOne({ id: server }); - const antiSpamRules: AntispamRule[] = serverConfig.automodSettings?.spam ?? []; + const serverConfig = await serversCollection.findOne({ id: server }); + const antiSpamRules: AntispamRule[] = serverConfig?.automodSettings?.spam ?? []; const rule = antiSpamRules.find(r => r.id == ruleid); if (!rule) return res.status(404).send({ error: 'No rule with this ID could be found.' }); - await db.get('servers').update({ - id: server - }, { - $set: { - "automodSettings.spam.$[rulefilter]": { - ...rule, - action: Number(body.action ?? rule.action), - channels: body.channels ?? rule.channels, - message: body.message ?? rule.message, - max_msg: body.max_msg ?? rule.max_msg, - timeframe: body.timeframe ?? rule.timeframe, - } as AntispamRule + const result = await serversCollection.updateOne( + { id: server, "automodSettings.spam.id": ruleid }, + { + $set: { + "automodSettings.spam.$": { + ...rule, + action: Number(body.action ?? rule.action), + channels: body.channels ?? rule.channels, + message: body.message ?? rule.message, + max_msg: body.max_msg ?? rule.max_msg, + timeframe: body.timeframe ?? rule.timeframe, + } + } } - }, { arrayFilters: [ { "rulefilter.id": ruleid } ] }); + ); - return res.send({ success: true }); + return res.send({ success: result.modifiedCount > 0 }); }); app.post('/dash/server/:server/automod', requireAuth({ permission: 2 }), async (req, res) => { @@ -109,21 +116,22 @@ app.post('/dash/server/:server/automod', requireAuth({ permission: 2 }), async ( const id = ulid(); - await db.get('servers').update({ - id: server, - }, { - $push: { - "automodSettings.spam": { - id: id, - max_msg: rule.max_msg ?? 5, - timeframe: rule.timeframe ?? 3, - action: rule.action ?? 0, - message: rule.message ?? null, + const result = await serversCollection.updateOne( + { id: server }, + { + $push: { + "automodSettings.spam": { + id: id, + max_msg: rule.max_msg ?? 5, + timeframe: rule.timeframe ?? 3, + action: rule.action ?? 0, + message: rule.message ?? null, + } } } - }); + ); - res.status(200).send({ success: true, id: id }); + res.status(200).send({ success: result.modifiedCount > 0, id: id }); }); app.delete('/dash/server/:server/automod/:ruleid', requireAuth({ permission: 2 }), async (req, res) => { @@ -140,22 +148,22 @@ app.delete('/dash/server/:server/automod/:ruleid', requireAuth({ permission: 2 } if (!response.server) return res.status(404).send({ error: 'Server not found' }); - // todo: fix this shit idk if it works - let queryRes; + let result; try { - queryRes = await db.get('servers').update({ - id: server - }, { - $pull: { - "automodSettings.spam": { id: ruleid } + result = await serversCollection.updateOne( + { id: server }, + { + $pull: { + "automodSettings.spam": { id: ruleid } + } } - }); + ); } catch(e) { console.error(e); res.status(500).send({ error: e }); return; } - if (queryRes.nModified > 0) res.status(200).send({ success: true }); + if (result.modifiedCount > 0) res.status(200).send({ success: true }); else res.status(404).send({ success: false, error: 'Rule not found' }); }); diff --git a/api/src/routes/login.ts b/api/src/routes/login.ts index ee7a68a..a943b40 100644 --- a/api/src/routes/login.ts +++ b/api/src/routes/login.ts @@ -2,14 +2,22 @@ import crypto from 'crypto'; import { app, SESSION_LIFETIME } from '..'; import { Request, Response } from 'express'; import { botReq } from './internal/ws'; -import { db } from '..'; -import { FindOneResult } from 'monk'; +import { Collection, Db } from 'mongodb'; import { badRequest, isAuthenticated, requireAuth } from '../utils'; import { RateLimiter } from '../middlewares/ratelimit'; +let pendingLoginsCollection: Collection; +let sessionsCollection: Collection; + +export function initializeAuthAPI(database: Db) { + pendingLoginsCollection = database.collection('pending_logins'); + sessionsCollection = database.collection('sessions'); +} + class BeginReqBody { user: string; } + class CompleteReqBody { user: string; nonce: string; @@ -24,14 +32,10 @@ app.post('/login/begin', requireAuth({ noAuthOnly: true }), async (req: Request, res: Response) => { if (typeof await isAuthenticated(req) == 'string') return res.status(403).send({ error: 'You are already authenticated' }); - const body = req.body as BeginReqBody; if (!body.user || typeof body.user != 'string') return badRequest(res); - const r = await botReq('requestLogin', { user: body.user.toLowerCase() }); - if (!r.success) return res.status(r.statusCode ?? 500).send(JSON.stringify({ error: r.error }, null, 4)); - res.status(200).send({ success: true, nonce: r.nonce, code: r.code, uid: r.uid }); }); @@ -43,8 +47,8 @@ app.post('/login/complete', if ((!body.user || typeof body.user != 'string') || (!body.nonce || typeof body.nonce != 'string') || (!body.code || typeof body.code != 'string')) return badRequest(res); - - const loginAttempt: FindOneResult = await db.get('pending_logins').findOne({ + + const loginAttempt = await pendingLoginsCollection.findOne({ code: body.code, user: body.user, nonce: body.nonce, @@ -52,24 +56,25 @@ app.post('/login/complete', invalid: false, }); - if (!loginAttempt) return res.status(404).send({ error: 'The provided login info could not be found.' }); - + if (!loginAttempt) return res.status(404).send({ error: 'The provided login info could not be found.' }); if (!loginAttempt.confirmed) { return res.status(400).send({ error: "This code is not yet valid." }); } const sessionToken = crypto.randomBytes(48).toString('base64').replace(/=/g, ''); - await Promise.all([ - db.get('sessions').insert({ + sessionsCollection.insertOne({ user: body.user.toUpperCase(), token: sessionToken, nonce: body.nonce, invalid: false, expires: Date.now() + SESSION_LIFETIME, }), - db.get('pending_logins').update({ _id: loginAttempt._id }, { $set: { exchanged: true } }), + pendingLoginsCollection.updateOne( + { _id: loginAttempt._id }, + { $set: { exchanged: true } } + ), ]); res.status(200).send({ success: true, user: body.user.toUpperCase(), token: sessionToken }); diff --git a/api/src/utils.ts b/api/src/utils.ts index 1199a28..ef1a28c 100644 --- a/api/src/utils.ts +++ b/api/src/utils.ts @@ -1,8 +1,13 @@ import { Request, Response } from "express"; -import { FindOneResult } from "monk"; -import { db } from "."; +import { Collection, Db } from "mongodb"; import { botReq } from "./routes/internal/ws"; +let sessionsCollection: Collection; + +export function initializeSessionAuthentication(db: Db) { + sessionsCollection = db.collection('sessions'); +} + class Session { user: string; token: string; @@ -19,9 +24,7 @@ class Session { async function isAuthenticated(req: Request, res?: Response, send401?: boolean): Promise { const user = req.header('x-auth-user'); const token = req.header('x-auth-token'); - if (!user || !token) return false; - const info = await getSessionInfo(user, token); if (res && send401 && !info.valid) { res.status(401).send({ error: 'Unauthorized' }); @@ -32,9 +35,13 @@ async function isAuthenticated(req: Request, res?: Response, send401?: boolean): type SessionInfo = { exists: boolean, valid: boolean, nonce?: string } async function getSessionInfo(user: string, token: string): Promise { - const session: FindOneResult = await db.get('sessions').findOne({ user, token }); + const session = await sessionsCollection.findOne({ user, token }); - return { exists: !!session, valid: !!(session && !session.invalid && session.expires > Date.now()), nonce: session?.nonce } + return { + exists: !!session, + valid: !!(session && !session.invalid && session.expires > Date.now()), + nonce: session?.nonce + } } function badRequest(res: Response, infoText?: string) {