From 1521166b26ecb7dd0e021328361891f3564f0b49 Mon Sep 17 00:00:00 2001 From: Raven Date: Sat, 12 Sep 2026 08:58:16 -0700 Subject: [PATCH 1/5] NPM: Install jsonc-parser. --- package-lock.json | 11 +++++++++++ package.json | 1 + 2 files changed, 12 insertions(+) diff --git a/package-lock.json b/package-lock.json index 536b588..01c3826 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "firebase": "^9.21.0", "firebase-admin": "^11.8.0", "fuse.js": "^6.5.3", + "jsonc-parser": "^3.3.1", "jsonwebtoken": "^9.0.0", "mongodb": "^5.5.0", "node-cache": "^5.1.2", @@ -3352,6 +3353,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==" + }, "node_modules/jsonwebtoken": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", @@ -7588,6 +7594,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==" + }, "jsonwebtoken": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", diff --git a/package.json b/package.json index 84189dd..abe1465 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "firebase": "^9.21.0", "firebase-admin": "^11.8.0", "fuse.js": "^6.5.3", + "jsonc-parser": "^3.3.1", "jsonwebtoken": "^9.0.0", "mongodb": "^5.5.0", "node-cache": "^5.1.2", From f0f1af0f900ec08271e40a6b96e7c5de57c807d7 Mon Sep 17 00:00:00 2001 From: Raven Date: Sat, 12 Sep 2026 09:40:30 -0700 Subject: [PATCH 2/5] Config: Refactor out config.json into config.jsonc and add example. --- .gitignore | 3 +- example.config.jsonc | 51 +++++++++++++++++++++++++++++++++ helpers.js | 60 +++++++++++++++++++++++---------------- index.js | 8 +++--- routers/analytics.js | 5 ++-- routers/auth.js | 64 ------------------------------------------ routers/dev.js | 3 +- routers/img.js | 20 ++++++------- routers/matchmaking.js | 3 +- 9 files changed, 107 insertions(+), 110 deletions(-) create mode 100644 example.config.jsonc diff --git a/.gitignore b/.gitignore index bee723d..a7c15f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,8 @@ node_modules .env config.json -src +config.jsonc env.js -nginx.conf data/audit.json admin.json keys/ diff --git a/example.config.jsonc b/example.config.jsonc new file mode 100644 index 0000000..d50bada --- /dev/null +++ b/example.config.jsonc @@ -0,0 +1,51 @@ +{ + // What port should the API listen on? + // Default: 8080 + "port": 8080, + + // All options relating to the image / photo system. + "images": { + // Completely disables image fetching, will return an error status. + // Default: false + "disable_fetch": false, + // Disables the in-memory cache. Useful on memory-constrained systems. + // Default: false + "disable_caching": false, + // Prevents users from uploading images entirely. + // Default: false + "disable_upload": false, + // The maximum size of uploaded images. + // Default: "10mb" + "max_size": "10mb", + + // Replace this with your Firebase bucket URL. + "firebase_bucket_url": "YOUR-BUCKET-HERE.appspot.com" + }, + + // Settings for debugging / developing the API itself. + "debug": { + // Logs the level of server load to the audit log very frequently. + // Default: false + "enable_load_logging": false, + // Prints a tabulated display of all live matchmaking instances + // every few minutes. + // Default: false + "trace_instances": false + }, + + // Used to configure the Automatic Error Reporting (AER) system. + "error_reporting": { + // An absolute or relative path to a public key for encrypting + // all received error reports. + "public_key_path": "./keys/YOUR_EXCEPTION_KEY.key.pub", + // The format of the public key. + "public_key_format": "openssh-public" + }, + + // Settings related to in-game moderation. + "moderation": { + // After how many reports should we automatically time out a player? + // Default: 3 + "timeout_after_reports": 3 + } +} \ No newline at end of file diff --git a/helpers.js b/helpers.js index 41931f2..0b71f8a 100644 --- a/helpers.js +++ b/helpers.js @@ -1,6 +1,5 @@ require('dotenv').config(); const fs = require('fs'); -const config = require('./config.json'); const notificationTemplates = { invite: "invite", @@ -8,27 +7,40 @@ const notificationTemplates = { messageRecieved: "messageRecieved" }; +const jsonc = require('jsonc-parser'); +let parseErrors = []; +const config = jsonc.parse( + require('node:fs').readFileSync("config.jsonc", "ascii"), + parseErrors, + { + allowEmptyContent: true, + allowTrailingComma: true, + disallowComments: false, + } +); + module.exports = { - PullPlayerData: PullPlayerData, - PushPlayerData: PushPlayerData, - NotifyPlayer: NotifyPlayer, - ArePlayersAnyFriendType: ArePlayersAnyFriendType, - ArePlayersAcquantances: ArePlayersAcquantances, - ArePlayersFriends: ArePlayersFriends, - ArePlayersFavoriteFriends: ArePlayersFavoriteFriends, - RemoveAcquaintance: RemoveAcquaintance, - RemoveFriend: RemoveFriend, - RemoveFavoriteFriend: RemoveFavoriteFriend, - AddFriend: AddFriend, - AddFavoriteFriend: AddFavoriteFriend, - AddAcquaintance: AddAcquaintance, - getUserID: getUserID, - getAccountCount: getAccountCount, - auditLog: auditLog, - MergeArraysWithoutDuplication: MergeArraysWithoutDuplication, - BanPlayer: BanPlayer, - onPlayerReportedCallback: onPlayerReportedCallback, - check: check + PullPlayerData, + PushPlayerData, + NotifyPlayer, + ArePlayersAnyFriendType, + ArePlayersAcquantances, + ArePlayersFriends, + ArePlayersFavoriteFriends, + RemoveAcquaintance, + RemoveFriend, + RemoveFavoriteFriend, + AddFriend, + AddFavoriteFriend, + AddAcquaintance, + getUserID, + getAccountCount, + auditLog, + MergeArraysWithoutDuplication, + BanPlayer, + onPlayerReportedCallback, + check, + config, }; /** @@ -354,9 +366,9 @@ async function onPlayerReportedCallback(reportData) { reportingData.auth.reportedUsers.splice(index); await PushPlayerData(reportData.reportingUser, reportingData); } - } else if (reportedData.auth.recievedReports.length >= config.timeout_at_report_count) { - await BanPlayer(reportData.reportedUser, `Automated timeout for recieving ${config.timeout_at_report_count} or more reports. This timeout will not affect your moderation history unless it is found to be 100% justified.`, 6, reportData.reportingUser); - auditLog(`!! MODERATION ACTION !! User ${reportingData.nickname} (@${reportedData.username}) was timed out for 6 hours for recieving ${config.timeout_at_report_count} reports. Please investigate!`); + } else if (reportedData.auth.recievedReports.length >= config.moderation?.timeout_after_reports ?? 3) { + await BanPlayer(reportData.reportedUser, `Automated timeout for recieving ${config.moderation?.timeout_after_reports ?? 3} or more reports. This timeout will not affect your moderation history unless it is found to be 100% justified.`, 6, reportData.reportingUser); + auditLog(`!! MODERATION ACTION !! User "${reportingData.nickname}" (@${reportedData.username}) was timed out for 6 hours for recieving ${config.moderation?.timeout_after_reports ?? 3} reports. Please investigate!`); } } diff --git a/index.js b/index.js index 19c6128..1bb37e4 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,10 @@ require('dotenv').config(); + const express = require('express'); const fileUpload = require('express-fileupload'); const RateLimit = require('express-rate-limit'); const helpers = require('./helpers'); +const config = helpers.config; const firebaseAuth = require('firebase/auth'); const WebSocketV2_MessageTemplate = { @@ -31,8 +33,6 @@ app.use(fileUpload({ limit: '50mb' })); -const config = require('./config.json'); - //#region routers // /api/accounts/* @@ -114,7 +114,7 @@ app.get("/api/dingus", async(req, res) => { //#endregion -const server = app.listen(config.PORT, '0.0.0.0'); +const server = app.listen(config.port ?? 8080, '0.0.0.0'); const { MongoClient } = require('mongodb'); @@ -178,7 +178,7 @@ client.connect().then(async (client) => { exports.MessagingGatewayServerV1 = MessagingGatewayServerV1; exports.WebSocketServerV2 = WebSocketServerV2; - helpers.auditLog(`Server Init, API is ready at http://127.0.0.1:${config.PORT}/ \n:D`, false); + helpers.auditLog(`Server Init, API is ready at http://127.0.0.1:${config.port ?? 8080}/ \n:D`, false); process.on('beforeExit', () => { helpers.auditLog("Server exit.", false); diff --git a/routers/analytics.js b/routers/analytics.js index 5b49120..5b3cc61 100644 --- a/routers/analytics.js +++ b/routers/analytics.js @@ -1,12 +1,11 @@ const router = require('express').Router(); -const { PullPlayerData } = require('../helpers'); +const { PullPlayerData, config } = require('../helpers'); const { authenticateToken } = require('../middleware'); const { GetInstances } = require('./matchmaking'); const { readFileSync } = require('node:fs'); const RSA = require('node-rsa'); -const cfg = require('../config.json'); -const EXCEPTION_LOGGING_PUBLIC_KEY = new RSA().importKey(readFileSync(cfg.exception_logging_publickey_path).toString('utf-8'), cfg.exception_logging_publickey_format); +const EXCEPTION_LOGGING_PUBLIC_KEY = new RSA().importKey(readFileSync(config.error_reporting.public_key_path).toString('utf-8'), config.error_reporting.public_key_format); router.get("/account-count", async (req, res) => { const {mongoClient} = require('../index'); diff --git a/routers/auth.js b/routers/auth.js index 56cc3dc..91bb53b 100644 --- a/routers/auth.js +++ b/routers/auth.js @@ -5,8 +5,6 @@ const middleware = require('../middleware'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const { PullPlayerData, check, PushPlayerData} = require('../helpers'); -const config = require('../config.json'); - const {default: rateLimit} = require('express-rate-limit'); const accountSid = process.env.TWILIO_ACCOUNT_SID; @@ -122,18 +120,6 @@ router.post("/login", async (req, res) => { const passwordMatches = bcrypt.compareSync(password, HASHED_PASSWORD); if(!passwordMatches) { - if(typeof data.auth.logins != 'object') data.auth.logins = []; - const attempt = { - SUCCESS: false, - IP: req.ip, - TIME: Date.now(), - HWID: hwid, - TWO_FACTOR_CODE: two_factor_code - }; - if(data.auth.logins.length < config.max_logged_logins) { - data.auth.logins.push(attempt); - await helpers.PushPlayerData(userID, data); - } return res.status(403).send({message: "Incorrect password!", failureCode: "6"}); } @@ -141,19 +127,6 @@ router.post("/login", async (req, res) => { const element = data.auth.bans[index]; if(element.endTS > Date.now()) { - if(typeof data.auth.logins != 'object') data.auth.logins = []; - const attempt = { - SUCCESS: false, - IP: req.ip, - TIME: Date.now(), - HWID: hwid, - TWO_FACTOR_CODE: two_factor_code - }; - if(data.auth.logins.length < config.max_logged_logins) { - data.auth.logins.push(attempt); - // eslint-disable-next-line no-await-in-loop - await helpers.PushPlayerData(userID, data); - } return res.status(403).send({ message: "USER IS BANNED", endTimeStamp: element.endTS, @@ -172,18 +145,6 @@ router.post("/login", async (req, res) => { const accessToken = jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, { expiresIn: "30m" }); if(typeof data.auth.mfa_enabled == 'boolean' && !data.auth.mfa_enabled) { - const attempt = { - SUCCESS: true, - IP: req.ip, - TIME: Date.now(), - HWID: hwid, - TWO_FACTOR_CODE: two_factor_code - }; - if(data.auth.logins.length < config.max_logged_logins) { - data.auth.logins.push(attempt); - await helpers.PushPlayerData(userID, data); - } - const mongo = require('../index').mongoClient; const coll = mongo.db(process.env.MONGOOSE_DATABASE_NAME).collection("analytics"); coll.insertOne({ @@ -194,19 +155,6 @@ router.post("/login", async (req, res) => { } if(typeof data.auth.mfa_enabled == 'string' && data.auth.mfa_enabled === 'unverified') { - if(typeof data.auth.logins != 'object') data.auth.logins = []; - const attempt = { - SUCCESS: true, - IP: req.ip, - TIME: Date.now(), - HWID: hwid, - TWO_FACTOR_CODE: two_factor_code - }; - if(data.auth.logins.length < config.max_logged_logins) { - data.auth.logins.push(attempt); - await helpers.PushPlayerData(userID, data); - } - const mongo = require('../index').mongoClient; const coll = mongo.db(process.env.MONGOOSE_DATABASE_NAME).collection("analytics"); coll.insertOne({ @@ -219,18 +167,6 @@ router.post("/login", async (req, res) => { } if(typeof two_factor_code != 'string') { - if(typeof data.auth.logins != 'object') data.auth.logins = []; - const attempt = { - SUCCESS: false, - IP: req.ip, - TIME: Date.now(), - HWID: hwid, - TWO_FACTOR_CODE: two_factor_code - }; - if(data.auth.logins.length < config.max_logged_logins) { - data.auth.logins.push(attempt); - await helpers.PushPlayerData(userID, data); - } if(typeof hwid != 'string') return res.status(400).send({message: "You have 2FA enabled on your account but you did not specify a valid 2 Factor Authentication token.", failureCode: "1"}); if(data.auth.multi_factor_authenticated_logins.length < 1) return res.status(400).send({message: "You have 2FA enabled on your account but you did not specify a valid 2 Factor Authentication token.", failureCode: "1"}); diff --git a/routers/dev.js b/routers/dev.js index 8903c68..1be6dbb 100644 --- a/routers/dev.js +++ b/routers/dev.js @@ -1,7 +1,6 @@ const router = require('express').Router(); const { PullPlayerData, PushPlayerData } = require('../helpers'); const middleware = require('../middleware'); -const config = require('../config.json'); const { execSync } = require('node:child_process'); const { authenticateTokenAndTag } = require('../middleware'); const { v1 } = require('uuid'); @@ -56,7 +55,7 @@ router.post("/accounts/:id/inventory-item", middleware.authenticateDeveloperToke router.post("/pull-origin", async (req, res) => { try { let Authentication = req.headers.authorization.split(' ')[1]; - let key = config.development_mode ? process.env.DEV_PULL_SECRET : process.env.PRODUCTION_PULL_SECRET; + let key = process.env.PRODUCTION_PULL_SECRET; // fixme change to PULL_SECRET if(Authentication?.length != key?.length || Authentication != key) return res.status(403).json({ code: "invalid_secret", diff --git a/routers/img.js b/routers/img.js index 035b90f..abb1b38 100644 --- a/routers/img.js +++ b/routers/img.js @@ -9,16 +9,16 @@ const serviceAccount = require('../admin.json'); const NodeCache = require('node-cache'); -const config = require('../config.json'); +const config = helpers.config; const { default: rateLimit } = require('express-rate-limit'); -router.use(express.text({limit: config.max_image_size})); +router.use(express.text({limit: config.images.max_size ?? "10mb"})); router.use(express.urlencoded({extended: false})); const app = initializeApp({ credential: cert(serviceAccount), - storageBucket: config.firebase_bucket_url + storageBucket: config.images.firebase_bucket_url }); const imageMetadataTemplate = { @@ -73,7 +73,7 @@ const imgCache = new NodeCache({ }); router.post("/upload", uploadRateLimit, middleware.authenticateToken, async (req, res) => { - if(config.disable_image_upload && !req.user.developer) return res.status(409).send({"message": "Access denied - image uploads have been disabled by the system administrator.", "code": "uploads_disabled"}); + if((config.images.disable_upload ?? false) && !req.user.developer) return res.status(409).send({"message": "Access denied - image uploads have been disabled by the system administrator.", "code": "uploads_disabled"}); try { var {others, room_id, tags} = req.query; if(req.headers['content-type'] !== 'text/plain' || typeof req.body == 'undefined') return res.status(400).send("You did not send encoded photo data."); @@ -200,7 +200,7 @@ router.get('/:id/embed', (req, res) => { }); router.get("/:id/info", async (req, res) => { - if(config.disable_image_fetch && !req.user.developer) return res.status(500).send({"message": "Access denied - image fetching is disabled."}); + if((config.images.disable_fetch ?? false) && !req.user.developer) return res.status(500).send({"message": "Access denied - image fetching is disabled."}); var {id} = req.params; if(typeof id != 'string') return res.status(400).send("You did not specify an image ID."); try { @@ -225,7 +225,7 @@ router.get("/:id/info", async (req, res) => { router.get("/:id", fetch_rate_limit, async (req, res) => { try { - if(config.disable_image_fetch && !req.user.developer) return res.status(500).send("Image fetching has been disabled by the system administrator."); + if((config.images.disable_fetch ?? false) && !req.user.developer) return res.status(500).send("Image fetching has been disabled by the system administrator."); // Setup of parameters var {id} = req.params; var {base64} = req.query; @@ -259,7 +259,7 @@ router.get("/:id", fetch_rate_limit, async (req, res) => { if (typeof base64 == 'undefined' || base64 !== 'true') { var ImageBuffer; - if(!imgCache.has(id) || config.disable_image_caching) { + if(!imgCache.has(id) || (config.images.disable_caching ?? false)) { const storage = new Storage(app); storage.maxOperationRetryTime = 5 * 1000; storage.maxUploadRetryTime = 10 * 1000; @@ -285,14 +285,14 @@ router.get("/:id", fetch_rate_limit, async (req, res) => { }); res.end(ImageBuffer); - if(!imgCache.has(id) && !config.disable_image_caching) { + if(!imgCache.has(id) && !(config.images.disable_caching ?? false)) { imgCache.set(id, ImageBuffer); console.log(`Request submitted for uncached image ${id}, cached.`); } else console.log(`Request submitted for cached image ${id}.`); } else { // eslint-disable-next-line no-redeclare var ImageBuffer; - if(!imgCache.has(id) || config.disable_image_caching) { + if(!imgCache.has(id) || (config.images.disable_caching ?? false)) { const storage = new Storage(app); storage.maxOperationRetryTime = 5 * 1000; storage.maxUploadRetryTime = 10 * 1000; @@ -312,7 +312,7 @@ router.get("/:id", fetch_rate_limit, async (req, res) => { var ImageBase64String = Buffer.from(ImageBuffer).toString('base64'); res.status(200).contentType('text/plain').send(ImageBase64String); - if(!imgCache.has(id) && !config.disable_image_caching) { + if(!imgCache.has(id) && !(config.images.disable_caching ?? false)) { imgCache.set(id, ImageBuffer); console.log(`Request submitted for uncached image ${id}, cached.`); } else console.log(`Request submitted for cached image ${id}.`); diff --git a/routers/matchmaking.js b/routers/matchmaking.js index 1a4109c..5e80c82 100644 --- a/routers/matchmaking.js +++ b/routers/matchmaking.js @@ -1,6 +1,7 @@ const router = require('express').Router(); const uuid = require('uuid'); const middleware = require('../middleware'); +const { config } = require('../helpers'); router.get("/:room_id/:subroom_id/public-instances", middleware.authenticateToken, async (req, res) => { try { @@ -274,7 +275,7 @@ var GlobalRoomInstances = Object.create(null); setInterval(CleanupInstances, 300 * 1000); -if (require('../config.json').debug_trace_instances) { +if (config.debug.trace_instances ?? false) { setInterval(LogInstanceTable, 30 * 1000); } From 5d4bb47a3217ca1e05eddb15fd03fbb4ba9b26ae Mon Sep 17 00:00:00 2001 From: Raven Date: Sat, 12 Sep 2026 09:44:57 -0700 Subject: [PATCH 3/5] Config: Refactor out env.js. --- example.config.jsonc | 12 +++++++++++- index.js | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/example.config.jsonc b/example.config.jsonc index d50bada..e8ae44d 100644 --- a/example.config.jsonc +++ b/example.config.jsonc @@ -19,7 +19,17 @@ "max_size": "10mb", // Replace this with your Firebase bucket URL. - "firebase_bucket_url": "YOUR-BUCKET-HERE.appspot.com" + "firebase_bucket_url": "YOUR-BUCKET-HERE.appspot.com", + + // Replace this with your Firebase client config object. + "firebase_client_config": { + "apiKey": "YOUR-API-KEY", + "authDomain": "YOUR-PROJECT-ID.firebaseapp.com", + "projectId": "YOUR-PROJECT-ID", + "storageBucket": "YOUR-PROJECT-ID.appspot.com", + "messagingSenderId": "YOUR-SENDER-ID", + "appId": "YOUR-APP-ID" + } }, // Settings for debugging / developing the API itself. diff --git a/index.js b/index.js index 1bb37e4..259c1db 100644 --- a/index.js +++ b/index.js @@ -133,7 +133,7 @@ client.connect().then(async (client) => { console.log("MongoDB Connection Established."); - require('firebase/app').initializeApp(require('./env').firebaseConfig); + require('firebase/app').initializeApp(config.images.firebase_client_config); const auth = firebaseAuth.getAuth(); From 5d5ffc76f575c96d0b6864d6d69e4e0ac4b67b3b Mon Sep 17 00:00:00 2001 From: Raven Date: Sat, 12 Sep 2026 09:47:37 -0700 Subject: [PATCH 4/5] Config: Refactor out admin.json. --- example.config.jsonc | 5 +++++ routers/img.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/example.config.jsonc b/example.config.jsonc index e8ae44d..8383752 100644 --- a/example.config.jsonc +++ b/example.config.jsonc @@ -29,6 +29,11 @@ "storageBucket": "YOUR-PROJECT-ID.appspot.com", "messagingSenderId": "YOUR-SENDER-ID", "appId": "YOUR-APP-ID" + }, + + // Replace this with your Firebase admin config object. + "firebase_admin_config": { + // Insert your firebase admin config object instead of this blank one. } }, diff --git a/routers/img.js b/routers/img.js index abb1b38..1c64c88 100644 --- a/routers/img.js +++ b/routers/img.js @@ -5,11 +5,11 @@ const express = require('express'); // const firebaseStorage = require('firebase/storage'); const { initializeApp, cert } = require('firebase-admin/app'); const { Storage } = require('firebase-admin/storage'); -const serviceAccount = require('../admin.json'); const NodeCache = require('node-cache'); const config = helpers.config; +const serviceAccount = config.images.firebase_admin_config; const { default: rateLimit } = require('express-rate-limit'); router.use(express.text({limit: config.images.max_size ?? "10mb"})); From 8de30cf463d8f13243777c76b16da930eea31502 Mon Sep 17 00:00:00 2001 From: Raven Date: Sat, 12 Sep 2026 10:16:44 -0700 Subject: [PATCH 5/5] Config: Refactor out .env! --- .gitignore | 4 -- example.config.jsonc | 51 ++++++++++++++++----- helpers.js | 16 +++---- index.js | 6 +-- middleware.js | 9 ++-- routers/accounts.js | 6 +-- routers/analytics.js | 4 +- routers/auth.js | 30 ++++++------- routers/dev.js | 14 +++--- routers/econ.js | 11 ++--- routers/global.js | 5 ++- routers/img.js | 8 ++-- routers/messages.js | 23 +++++----- routers/rooms.js | 62 +++++++++++++------------- routers/social.js | 7 +-- routers/ws/MessagingGatewayServerV1.js | 3 +- routers/ws/WebSocketServerV2.js | 18 ++++---- 17 files changed, 154 insertions(+), 123 deletions(-) diff --git a/.gitignore b/.gitignore index a7c15f5..118afa9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,6 @@ node_modules -.env -config.json config.jsonc -env.js data/audit.json -admin.json keys/ # IDE stuff diff --git a/example.config.jsonc b/example.config.jsonc index 8383752..f9bfc88 100644 --- a/example.config.jsonc +++ b/example.config.jsonc @@ -3,6 +3,15 @@ // Default: 8080 "port": 8080, + // Configuration for the database used by the API. + // Right now, only MongoDB is supported. Sorry. + "database": { + // The URL used to connect to the MongoDB instance. + "mongodb_connection_string": "mongodb+srv://YOUR-CONNECTION-STRING-HERE", + // The database in MongoDB that should be used. + "mongodb_database_name": "YOUR-DATABASE-NAME" + }, + // All options relating to the image / photo system. "images": { // Completely disables image fetching, will return an error status. @@ -19,22 +28,21 @@ "max_size": "10mb", // Replace this with your Firebase bucket URL. - "firebase_bucket_url": "YOUR-BUCKET-HERE.appspot.com", + "firebase_bucket_url": "YOUR-BUCKET-URL.appspot.com", // Replace this with your Firebase client config object. "firebase_client_config": { - "apiKey": "YOUR-API-KEY", - "authDomain": "YOUR-PROJECT-ID.firebaseapp.com", - "projectId": "YOUR-PROJECT-ID", - "storageBucket": "YOUR-PROJECT-ID.appspot.com", - "messagingSenderId": "YOUR-SENDER-ID", - "appId": "YOUR-APP-ID" + // YOUR CLIENT CONFIG }, // Replace this with your Firebase admin config object. "firebase_admin_config": { - // Insert your firebase admin config object instead of this blank one. - } + // YOUR ADMIN CONFIG + }, + + // The email and password used to sign in with Firebase. + "firebase_email": "YOUR-FIREBASE-DUMMY-ACCOUNT-EMAIL", + "firebase_password": "YOUR-FIREBASE-DUMMY-ACCOUNT-PASSWORD" }, // Settings for debugging / developing the API itself. @@ -45,14 +53,23 @@ // Prints a tabulated display of all live matchmaking instances // every few minutes. // Default: false - "trace_instances": false + "trace_instances": false, + // The identifier for this specific CVR server instance, used in the + // Discord webhook on audit logs. Leave blank, and the webhook won't + // be invoked. + "discord_webhook_id": "My CVR Server :)", + // The URL that should be called to send a Discord webhook. Leave blank + // to prevent the webhook from being called. + "discord_webhook_url": "https://discord.com/YOUR-WEBHOOK-URL-HERE", + // The secret that should be used to verify Git webhooks. + "webhook_git_pull_secret": "YOUR-GIT-PULL-SECRET" }, // Used to configure the Automatic Error Reporting (AER) system. "error_reporting": { // An absolute or relative path to a public key for encrypting // all received error reports. - "public_key_path": "./keys/YOUR_EXCEPTION_KEY.key.pub", + "public_key_path": "/PATH/TO/YOUR/KEY.pub", // The format of the public key. "public_key_format": "openssh-public" }, @@ -62,5 +79,17 @@ // After how many reports should we automatically time out a player? // Default: 3 "timeout_after_reports": 3 + }, + + // Config related to the authentication process (login, 2FA, etc) + "authentication": { + // The secret used to sign all JWTs. + "token_secret": "YOUR-TOKEN-SIGNING-SECRET-HERE", + // Twilio account SID, used for 2FA. + "twilio_account_sid": "YOUR-TWILIO-ACCOUNT-SID-HERE", + // Twilio auth token, used for 2FA. + "twilio_auth_token": "YOUR-TWILIO-AUTH-TOKEN-HERE", + // Twilio service SID, used for 2FA. + "twilio_service_sid": "YOUR-TWILIO-SERVICE-SID-HERE" } } \ No newline at end of file diff --git a/helpers.js b/helpers.js index 0b71f8a..3ea112a 100644 --- a/helpers.js +++ b/helpers.js @@ -49,7 +49,7 @@ module.exports = { * @returns {Object} The player's account data. */ async function PullPlayerData(id) { - const db = require('./index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('./index').mongoClient.db(config.database.mongodb_database_name); const account = await db.collection('accounts').findOne({_id: {$eq: id, $exists: true}}); return account; } @@ -60,7 +60,7 @@ async function PullPlayerData(id) { * @param {Object} data The full data of the specified player's account */ async function PushPlayerData(id, data) { - const db = require('./index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('./index').mongoClient.db(config.database.mongodb_database_name); await db.collection('accounts').replaceOne({_id: {$eq: id, $exists: true}}, data, {upsert: true}); } @@ -271,7 +271,7 @@ async function AddFavoriteFriend(player1, player2, both) { * @returns {String|null} The ID of the account associated with that username. */ async function getUserID(username) { - const db = require('./index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('./index').mongoClient.db(config.database.mongodb_database_name); const all = await db.collection('accounts').find({}).toArray(); username = username.toLowerCase(); for(const item of all) { @@ -285,7 +285,7 @@ async function getUserID(username) { * @returns {Number} The total number of accounts in the database. */ async function getAccountCount() { - const db = require('./index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('./index').mongoClient.db(config.database.mongodb_database_name); const count = await db.collection('accounts').countDocuments(); return count - 1; } @@ -309,14 +309,14 @@ function auditLog(message, isRaw) { console.log(log); - if (!process.env.AUDIT_SERVER_ID || !process.env.AUDIT_WEBHOOK_URI) return; + if (!config.debug.discord_webhook_url || !config.debug.discord_webhook_id) return; const globalAuditMessage = isRaw ? - `API audit log from server.\nID: \`${process.env.AUDIT_SERVER_ID}\`\nMessage:\n${message}` : - `API audit log from server.\nID: \`${process.env.AUDIT_SERVER_ID}\`\nMessage:\`${message}\``; + `API audit log from server.\nID: \`${config.debug.discord_webhook_id}\`\nMessage:\n${message}` : + `API audit log from server.\nID: \`${config.debug.discord_webhook_id}\`\nMessage:\`${message}\``; fetch( - process.env.AUDIT_WEBHOOK_URI, + config.debug.discord_webhook_url, { 'method': 'POST', 'headers': { diff --git a/index.js b/index.js index 259c1db..53b6c54 100644 --- a/index.js +++ b/index.js @@ -80,7 +80,7 @@ app.get("/", async (req, res) => { app.get("/api/versioncheck/:platform/:version_id", async (req, res) => { let {platform, version_id} = req.params; - let conf = await client.db(process.env.MONGOOSE_DATABASE_NAME).collection('global').findOne({_id: {$eq: "VersionCheckConfig", $exists: true}}); + let conf = await client.db(config.database.mongodb_database_name).collection('global').findOne({_id: {$eq: "VersionCheckConfig", $exists: true}}); if(conf == null) { res.status(500).json({ "code": "internal_error", @@ -118,7 +118,7 @@ const server = app.listen(config.port ?? 8080, '0.0.0.0'); const { MongoClient } = require('mongodb'); -const uri = process.env.MONGOOSE_CONNECTION_STRING; +const uri = config.database.mongodb_connection_string; const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true @@ -137,7 +137,7 @@ client.connect().then(async (client) => { const auth = firebaseAuth.getAuth(); - const firebaseAuthUser = await firebaseAuth.signInWithEmailAndPassword(auth, process.env.FIREBASE_EMAIL, process.env.FIREBASE_API_SECRET); + const firebaseAuthUser = await firebaseAuth.signInWithEmailAndPassword(auth, config.images.firebase_email, config.images.firebase_password); if (typeof firebaseAuthUser.user.uid == 'undefined') { helpers.auditLog('Failed to connect to Firebase - fatal'); diff --git a/middleware.js b/middleware.js index 281e67a..d6c3c7c 100644 --- a/middleware.js +++ b/middleware.js @@ -1,4 +1,5 @@ const helpers = require('./helpers'); +const config = helpers.config; const jwt = require('jsonwebtoken'); module.exports = { @@ -18,7 +19,7 @@ async function authenticateToken(req, res, next) { //then we need to authenticate that token in this middleware and return a user try { - const tokenData = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET); + const tokenData = jwt.verify(token, config.authentication.token_secret); req.user = tokenData; const data = await helpers.PullPlayerData(tokenData.id); @@ -56,7 +57,7 @@ async function authenticateDeveloperToken(req, res, next) { //then we need to authenticate that token in this middleware and return a user try { - const tokenData = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET); + const tokenData = jwt.verify(token, config.authentication.token_secret); req.user = tokenData; const data = await helpers.PullPlayerData(tokenData.id); @@ -90,7 +91,7 @@ function authenticateTokenAndTag(tag) { if (typeof token != 'string') return res.sendStatus(401); try { - const tokenData = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET); + const tokenData = jwt.verify(token, config.authentication.token_secret); req.user = tokenData; const data = await helpers.PullPlayerData(tokenData.id); @@ -123,7 +124,7 @@ async function authenticateToken_internal(token) { //then we need to authenticate that token in this middleware and return a user try { - const tokenData = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET); + const tokenData = jwt.verify(token, config.authentication.token_secret); const playerData = await helpers.PullPlayerData(tokenData.id); if(playerData === null) return {success: false, tokenData: tokenData, playerData: null, reason: "player_not_found"}; diff --git a/routers/accounts.js b/routers/accounts.js index b0e5b31..6048656 100644 --- a/routers/accounts.js +++ b/routers/accounts.js @@ -3,7 +3,7 @@ const helpers = require('../helpers'); const middleware = require('../middleware'); const regex = require('../data/badwords/regexp'); const { authenticateDeveloperToken, authenticateToken_optional } = require('../middleware'); -const { PullPlayerData, PushPlayerData, check } = require('../helpers'); +const { PullPlayerData, PushPlayerData, check, config } = require('../helpers'); const express = require('express'); const Fuse = require('fuse.js'); const { WebSocketV2_MessageTemplate } = require('../index'); @@ -300,7 +300,7 @@ router.get("/search", async (req, res) => { if(typeof case_sensitive != 'string') case_sensitive = false; else case_sensitive = case_sensitive === 'true' ? true : false; - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const all = await db.collection('accounts').find({}).toArray(); switch (type) { @@ -439,7 +439,7 @@ router.post('/set-pfp/:id', middleware.authenticateToken, async (req, res) => { var { id } = req.params; - var image_meta = await client.db(process.env.MONGOOSE_DATABASE_NAME).collection("images").findOne({ _id: { $eq: parseInt(id), $exists: true } }); + var image_meta = await client.db(config.database.mongodb_database_name).collection("images").findOne({ _id: { $eq: parseInt(id), $exists: true } }); if (image_meta == null) return res.status(404).json({ code: "image_not_found", diff --git a/routers/analytics.js b/routers/analytics.js index 5b3cc61..8a4a00f 100644 --- a/routers/analytics.js +++ b/routers/analytics.js @@ -9,7 +9,7 @@ const EXCEPTION_LOGGING_PUBLIC_KEY = new RSA().importKey(readFileSync(config.err router.get("/account-count", async (req, res) => { const {mongoClient} = require('../index'); - const db = mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = mongoClient.db(config.database.mongodb_database_name); const size = await db.collection("accounts").countDocuments({}); res.status(200).send(`${size}`); }); @@ -51,7 +51,7 @@ router.put("/exception-report", authenticateToken, async (req, res) => { const client = require('../index').mongoClient; await client - .db(process.env.MONGOOSE_DATABASE_NAME) + .db(config.database.mongodb_database_name) .collection('exception_reports') .insertOne({ data: encrypted diff --git a/routers/auth.js b/routers/auth.js index 91bb53b..bde176d 100644 --- a/routers/auth.js +++ b/routers/auth.js @@ -1,14 +1,14 @@ require('dotenv').config(); const router = require('express').Router(); -const helpers = require('../helpers'); const middleware = require('../middleware'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); -const { PullPlayerData, check, PushPlayerData} = require('../helpers'); +const helpers = require('../helpers'); +const { PullPlayerData, check, PushPlayerData, config} = helpers; const {default: rateLimit} = require('express-rate-limit'); -const accountSid = process.env.TWILIO_ACCOUNT_SID; -const authToken = process.env.TWILIO_AUTH_TOKEN; +const accountSid = config.authentication.twilio_account_sid; +const authToken = config.authentication.twilio_auth_token; const client = require('twilio')(accountSid, authToken); // Users can now only create 1 account per day. @@ -21,7 +21,7 @@ const accountCreationLimit = rateLimit({ router.get('/photon-info', async (req, res) => { try { - const coll = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME).collection("configuration"); + const coll = require('../index').mongoClient.db(config.database.mongodb_database_name).collection("configuration"); const data = await coll.findOne( { @@ -50,7 +50,7 @@ router.post('/enable-2fa', middleware.authenticateToken, async (req, res) => { const data = await helpers.PullPlayerData(req.user.id); if(data.auth.mfa_enabled || data.auth.mfa_enabled === "unverified") return res.status(400).send("Two factor authentication is already enabled on this account!"); - client.verify.services(process.env.TWILIO_SERVICE_SID) + client.verify.services(config.authentication.twilio_service_sid) .entities(`COMPENSATION-VR-ACCOUNT-ID-${req.user.id}`) .newFactors .create({ @@ -142,11 +142,11 @@ router.post("/login", async (req, res) => { const user = {username: username, id: userID, developer: developer}; - const accessToken = jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, { expiresIn: "30m" }); + const accessToken = jwt.sign(user, config.authentication.token_secret, { expiresIn: "30m" }); if(typeof data.auth.mfa_enabled == 'boolean' && !data.auth.mfa_enabled) { const mongo = require('../index').mongoClient; - const coll = mongo.db(process.env.MONGOOSE_DATABASE_NAME).collection("analytics"); + const coll = mongo.db(config.database.mongodb_database_name).collection("analytics"); coll.insertOne({ date_time: new Date(), type: "LOGIN" @@ -156,7 +156,7 @@ router.post("/login", async (req, res) => { if(typeof data.auth.mfa_enabled == 'string' && data.auth.mfa_enabled === 'unverified') { const mongo = require('../index').mongoClient; - const coll = mongo.db(process.env.MONGOOSE_DATABASE_NAME).collection("analytics"); + const coll = mongo.db(config.database.mongodb_database_name).collection("analytics"); coll.insertOne({ date_time: new Date(), type: "LOGIN" @@ -179,7 +179,7 @@ router.post("/login", async (req, res) => { if (MatchingLogins.length > 0) { const mongo = require('../index').mongoClient; - const coll = mongo.db(process.env.MONGOOSE_DATABASE_NAME).collection("analytics"); + const coll = mongo.db(config.database.mongodb_database_name).collection("analytics"); coll.insertOne({ date_time: new Date(), type: "LOGIN" @@ -203,7 +203,7 @@ router.post("/login", async (req, res) => { await helpers.PushPlayerData(userID, data); var mongo = require('../index').mongoClient; - var coll = mongo.db(process.env.MONGOOSE_DATABASE_NAME).collection("analytics"); + var coll = mongo.db(config.database.mongodb_database_name).collection("analytics"); coll.insertOne({ date_time: new Date(), type: "LOGIN" @@ -237,7 +237,7 @@ router.post("/refresh", middleware.authenticateToken, async (req, res) => { const user = {username: data.public.username, id: req.user.id, developer: developer}; - const accessToken = jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, { expiresIn: "30m" }); + const accessToken = jwt.sign(user, config.authentication.token_secret, { expiresIn: "30m" }); return res.status(200).json({ userID: req.user.id, username: data.public.username, accessToken: accessToken}); }); @@ -277,7 +277,7 @@ router.post("/create", accountCreationLimit, async (req, res) => { res.sendStatus(200); const client = require('../index').mongoClient; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); const collection = db.collection("servers"); var server = await collection.findOne({_id: {$eq: "a8ec2c20-a4c7-11ec-896d-419328454766", $exists: true}}); @@ -353,7 +353,7 @@ router.get("/password-update", middleware.authenticateDeveloperToken, async (req async function Verify2faUser(user_id, code, callback) { var data = await helpers.PullPlayerData(user_id); - client.verify.services(process.env.TWILIO_SERVICE_SID) + client.verify.services(config.authentication.twilio_service_sid) .entities(`COMPENSATION-VR-ACCOUNT-ID-${user_id}`) .factors(data.auth.mfa_factor_sid) .update({authPayload: code}) @@ -364,7 +364,7 @@ async function Verify2faUser(user_id, code, callback) { async function Verify2faCode(user_id, code, callback) { var data = await helpers.PullPlayerData(user_id); - client.verify.services(process.env.TWILIO_SERVICE_SID) + client.verify.services(config.authentication.twilio_service_sid) .entities(`COMPENSATION-VR-ACCOUNT-ID-${user_id}`) .challenges .create({authPayload: code, factorSid: data.auth.mfa_factor_sid}) diff --git a/routers/dev.js b/routers/dev.js index 1be6dbb..1b7f8f7 100644 --- a/routers/dev.js +++ b/routers/dev.js @@ -1,5 +1,5 @@ const router = require('express').Router(); -const { PullPlayerData, PushPlayerData } = require('../helpers'); +const { PullPlayerData, PushPlayerData, config } = require('../helpers'); const middleware = require('../middleware'); const { execSync } = require('node:child_process'); const { authenticateTokenAndTag } = require('../middleware'); @@ -55,7 +55,7 @@ router.post("/accounts/:id/inventory-item", middleware.authenticateDeveloperToke router.post("/pull-origin", async (req, res) => { try { let Authentication = req.headers.authorization.split(' ')[1]; - let key = process.env.PRODUCTION_PULL_SECRET; // fixme change to PULL_SECRET + let key = config.debug.webhook_git_pull_secret; if(Authentication?.length != key?.length || Authentication != key) return res.status(403).json({ code: "invalid_secret", @@ -88,7 +88,7 @@ router.get("/quality-control/test-cases", authenticateTokenAndTag("QA Tester"), const client = require('../index').mongoClient; - const cases = client.db(process.env.MONGOOSE_DATABASE_NAME).collection("test_cases"); + const cases = client.db(config.database.mongodb_database_name).collection("test_cases"); const filters = filter.split("|"); @@ -120,7 +120,7 @@ router.post("/quality-control/test-case/:_id/relinquish", authenticateTokenAndTa const client = require('../index').mongoClient; - const cases = client.db(process.env.MONGOOSE_DATABASE_NAME).collection("test_cases"); + const cases = client.db(config.database.mongodb_database_name).collection("test_cases"); var result = await cases.findOne( { @@ -168,7 +168,7 @@ router.post("/quality-control/test-case/:_id/assign-self", authenticateTokenAndT const client = require('../index').mongoClient; - const cases = client.db(process.env.MONGOOSE_DATABASE_NAME).collection("test_cases"); + const cases = client.db(config.database.mongodb_database_name).collection("test_cases"); var result = await cases.findOne( { @@ -216,7 +216,7 @@ router.post("/quality-control/test-case/:_id/set-status/:active", authenticateTo const client = require('../index').mongoClient; - const cases = client.db(process.env.MONGOOSE_DATABASE_NAME).collection("test_cases"); + const cases = client.db(config.database.mongodb_database_name).collection("test_cases"); var result = await cases.findOne( { @@ -262,7 +262,7 @@ router.put("/quality-control/submit-test-case", authenticateTokenAndTag("QA Test const client = require('../index').mongoClient; - const cases = client.db(process.env.MONGOOSE_DATABASE_NAME).collection("test_cases"); + const cases = client.db(config.database.mongodb_database_name).collection("test_cases"); if (typeof header != 'string' || typeof description != 'string') return res.status(400).json({ code: "invalid_input", diff --git a/routers/econ.js b/routers/econ.js index 1aa61d5..44a4e49 100644 --- a/routers/econ.js +++ b/routers/econ.js @@ -1,5 +1,6 @@ const router = require('express').Router(); const helpers = require('../helpers'); +const config = helpers.config; const middleware = require('../middleware'); router.route("/item/:id/info") @@ -26,7 +27,7 @@ router.route("/item/:id/info") .put(middleware.authenticateDeveloperToken, async (req, res) => { var id = await require('../index') .mongoClient - .db(process.env.MONGOOSE_DATABASE_NAME) + .db(config.database.mongodb_database_name) .collection('items') .countDocuments({}); await PushItem(id.toString(), req.body); @@ -157,7 +158,7 @@ router.post("/currency/transfer", middleware.authenticateToken, async (req, res) router.get("/item/all", async (req, res) => { const client = require('../index.js').mongoClient; const list = - await client.db(process.env.MONGOOSE_DATABASE_NAME) + await client.db(config.database.mongodb_database_name) .collection("items") .find({}) .toArray(); @@ -203,7 +204,7 @@ router.post("/item/equip", middleware.authenticateToken, async (req, res) => { router.get("/items/featured", async (req, res) => { try { - let db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + let db = require('../index').mongoClient.db(config.database.mongodb_database_name); let data = await db.collection('global').findOne({ _id: { $eq: "featured_items", $exists: true } }); if (data == null || !Array.isArray(data?.data)) @@ -225,13 +226,13 @@ router.get("/items/featured", async (req, res) => { //#region functions async function PullItem(id) { - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const item = db.collection('items').findOne({_id: {$eq: id, $exists: true}}); return item; } async function PushItem(id, data) { - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const collection = db.collection('items'); // replace the old item with the inputted data. diff --git a/routers/global.js b/routers/global.js index e379e3a..d7ba7d9 100644 --- a/routers/global.js +++ b/routers/global.js @@ -1,5 +1,6 @@ const router = require('express').Router(); const middleware = require('../middleware'); +const { config } = require('../helpers'); router.route("/:key") @@ -8,7 +9,7 @@ router.route("/:key") try { const { key } = req.params; - const collection = mongoClient.db(process.env.MONGOOSE_DATABASE_NAME).collection("global"); + const collection = mongoClient.db(config.database.mongodb_database_name).collection("global"); const doc = await collection.findOne({_id: {$eq: key, $exists: true}}); @@ -25,7 +26,7 @@ router.route("/:key") const { key } = req.params; const { value } = req.body; - const collection = mongoClient.db(process.env.MONGOOSE_DATABASE_NAME).collection("global"); + const collection = mongoClient.db(config.database.mongodb_database_name).collection("global"); await collection.updateOne( { diff --git a/routers/img.js b/routers/img.js index 1c64c88..869873c 100644 --- a/routers/img.js +++ b/routers/img.js @@ -84,7 +84,7 @@ router.post("/upload", uploadRateLimit, middleware.authenticateToken, async (req var timestamp = Date.now(); var TakenByData = await helpers.PullPlayerData(req.user.id); - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); var collection = db.collection("configuration"); var doc = await collection.findOne({_id: 'ImageCount'}); @@ -168,7 +168,7 @@ router.get('/:id/embed', (req, res) => { `; - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); var collection = db.collection("images"); collection.findOne({_id: id}).then(doc => { @@ -211,7 +211,7 @@ router.get("/:id/info", async (req, res) => { return res.status(400).send("Failed to parse image ID to integer, please try again with a valid URL-Encoded int."); } - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); var collection = db.collection("images"); try { @@ -242,7 +242,7 @@ router.get("/:id", fetch_rate_limit, async (req, res) => { } // Open database - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); // Validate collection var collection = db.collection("configuration"); diff --git a/routers/messages.js b/routers/messages.js index f6d5e09..aec9d49 100644 --- a/routers/messages.js +++ b/routers/messages.js @@ -1,5 +1,6 @@ const router = require('express').Router(); const helpers = require('../helpers'); +const { config } = helpers; const middleware = require('../middleware'); const uuid = require('uuid'); @@ -25,7 +26,7 @@ router.route("/channels/:channel_id/messages") const {channel_id} = req.params; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); var collection = db.collection("channels"); const channel = await collection.findOne({'_id': {$exists: true, $eq: channel_id}}); @@ -80,7 +81,7 @@ router.route("/channels/:channel_id/messages") if(typeof content != 'string') return res.status(400).send({message: "invalid_message_content"}); const {channel_id} = req.params; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); var collection = db.collection("channels"); const channel = await collection.findOne({'_id': {$exists: true, $eq: channel_id}}); @@ -133,7 +134,7 @@ router.route("/channels/:channel_id/info") const {channel_id} = req.params; const client = require('../index').mongoClient; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); var collection = db.collection("channels"); const channel = await collection.findOne({'_id': {$exists: true, $eq: channel_id}}); @@ -171,7 +172,7 @@ router.route("/messages/:message_id") const {message_id} = req.params; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); var collection = db.collection("messages"); const message = await collection.findOne({'_id': {$exists: true, $eq: message_id}}); @@ -207,7 +208,7 @@ router.route("/messages/:message_id") const {message_id} = req.params; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); var collection = db.collection("messages"); const message = await collection.findOne({'_id': {$exists: true, $eq: message_id}}); @@ -252,7 +253,7 @@ router.route("/messages/:message_id") const {message_id} = req.params; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); var collection = db.collection("messages"); const message = await collection.findOne({'_id': {$exists: true, $eq: message_id}}); @@ -300,7 +301,7 @@ router.route("/servers/:server_id/channels") const client = require('../index').mongoClient; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); const server_collection = db.collection("servers"); @@ -327,7 +328,7 @@ router.route("/servers/:server_id/name") const {server_id} = req.params; const client = require('../index').mongoClient; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); const server_collection = db.collection("servers"); @@ -345,7 +346,7 @@ router.route("/servers/:server_id/description") const {server_id} = req.params; const client = require('../index').mongoClient; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); const server_collection = db.collection("servers"); @@ -363,7 +364,7 @@ router.route("/servers/:server_id/users") const {server_id} = req.params; const client = require('../index').mongoClient; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); const server_collection = db.collection("servers"); const server_data = await server_collection.findOne({_id: {$eq: server_id, $exists: true}}); @@ -380,7 +381,7 @@ router.route("/servers/:server_id/icon_id") const {server_id} = req.params; const client = require('../index').mongoClient; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); const server_collection = db.collection("servers"); const server_data = await server_collection.findOne({_id: {$eq: server_id, $exists: true}}); diff --git a/routers/rooms.js b/routers/rooms.js index e90c683..67c0888 100644 --- a/routers/rooms.js +++ b/routers/rooms.js @@ -4,7 +4,7 @@ const Fuse = require('fuse.js'); const express = require('express'); const { getStorage } = require('firebase-admin/storage'); const { v1 } = require('uuid'); -const { auditLog, PullPlayerData } = require('../helpers'); +const { auditLog, PullPlayerData, config } = require('../helpers'); const { default: rateLimit } = require('express-rate-limit'); const { WebSocketV2_MessageTemplate } = require('../index'); @@ -83,7 +83,7 @@ router.route("/room/:room_id/info") const {room_id} = req.params; const {mongoClient} = require('../index'); - const db = mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = mongoClient.db(config.database.mongodb_database_name); const room_collection = db.collection("rooms"); @@ -124,7 +124,7 @@ router.route("/room/:room_id/subrooms/:subroom_id/versions/:version_id/download" var {room_id, subroom_id, version_id} = req.params; const {mongoClient: client} = require('../index'); - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); const room_collection = db.collection("rooms"); @@ -164,7 +164,7 @@ router.get("/search", authenticateToken_optional, async (req, res) => { const {mode, query} = req.query; const {mongoClient: client} = require('../index'); - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); const rooms_collection = db.collection("rooms"); var all = await rooms_collection.find({}, {sort: {visits: 1}}).toArray(); @@ -283,7 +283,7 @@ router.put('/room/:id/subrooms/:subroom_id/versions/new', authenticateToken, req "message": "The `collaborators` parameter of your version metadata is not specified or is invalid." }); - const collection = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME).collection('rooms'); + const collection = require('../index').mongoClient.db(config.database.mongodb_database_name).collection('rooms'); const room = await collection.findOne({_id: {$eq: id, $exists: true}}); if(!Object.keys(room.subrooms).includes(subroom_id)) return res.status(404).json({ @@ -326,7 +326,7 @@ router.post('/room/:id/subrooms/:subroom_id/versions/:version_id/associate-data' const collection = require('../index') .mongoClient - .db(process.env.MONGOOSE_DATABASE_NAME) + .db(config.database.mongodb_database_name) .collection('rooms'); const room = await collection.findOne({_id: {$eq: id, $exists: true}}); @@ -394,7 +394,7 @@ router.post('/room/:id/subrooms/:subroom_id/versions/public', authenticateToken, }); const client = require('../index').mongoClient; - const room = await client.db(process.env.MONGOOSE_DATABASE_NAME).collection('rooms').findOne({_id: {$eq: id, $exists: true}}); + const room = await client.db(config.database.mongodb_database_name).collection('rooms').findOne({_id: {$eq: id, $exists: true}}); if(room == null) return res.status(404).json({ "code": "room_not_found", "message": "That room does not exist." @@ -414,7 +414,7 @@ router.post('/room/:id/subrooms/:subroom_id/versions/public', authenticateToken, setFilter[str] = version_id; - await client.db(process.env.MONGOOSE_DATABASE_NAME) + await client.db(config.database.mongodb_database_name) .collection('rooms') .updateOne( {_id: {$eq: id, $exists: true}}, @@ -457,7 +457,7 @@ router.post('/room/:id/tags', authenticateToken, requiresRoomPermission("manageT }); } - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); await db.collection('rooms') .updateOne( @@ -504,7 +504,7 @@ router.post('/room/:id/content_flags', authenticateToken, requiresRoomPermission }); } - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); await roomAuditLog( id, @@ -559,7 +559,7 @@ router.post('/room/:id/moderation-suspend', authenticateDeveloperToken, async (r message: "Note must be either unspecified or a string." }); - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const collection = db.collection('rooms'); const room = await collection.findOne({ @@ -661,7 +661,7 @@ router.post("/room/:id/moderation-terminate", authenticateDeveloperToken, async message: "Note must be either unspecified or a string." }); - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const collection = db.collection('rooms'); const room = await collection.findOne({ @@ -788,7 +788,7 @@ router.post('/room/:id/description', authenticateToken, requiresRoomPermission(" message: "Cannot set description of room to anything other than a string." }); - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); await db.collection('rooms') .updateOne( @@ -835,7 +835,7 @@ router.get('/room/:id/subrooms/list', authenticateToken, requiresRoomPermission( try { const { id } = req.params; - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const subrooms = (await db.collection('rooms') .find( @@ -936,7 +936,7 @@ router.post('/room/:id/report', ReportRateLimit, authenticateToken, async (req, message: "One or more parameters of your request are invalid." }); - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const collection = db.collection('rooms'); await collection.updateOne( @@ -1038,7 +1038,7 @@ router.post('/new', authenticateToken, async (req, res) => { try { const { name } = req.body; - const coll = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME).collection("rooms"); + const coll = require('../index').mongoClient.db(config.database.mongodb_database_name).collection("rooms"); if(typeof name != 'string') return res.status(400).json({ @@ -1165,7 +1165,7 @@ router.put('/room/:id/roles/new', authenticateToken, requiresRoomPermission("man message: "Body field 'name' must be a string." }); - const collection = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME).collection('rooms'); + const collection = require('../index').mongoClient.db(config.database.mongodb_database_name).collection('rooms'); if (["owner", "everyone"].includes(name)) return res.status(400).json({ code: "invalid_input", @@ -1223,7 +1223,7 @@ router.get('/room/:id/permissions', authenticateToken, requiresRoomPermission("v try { const { id } = req.params; - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const room = await db.collection('rooms').findOne({ _id: { @@ -1273,7 +1273,7 @@ router.post("/room/:id/roles/:role_name/update", authenticateToken, requiresRoom message: "You cannot edit the permissions of the 'owner' role." }); - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const collection = db.collection('rooms'); const room = await collection.findOne( @@ -1362,7 +1362,7 @@ router.post("/room/:id/roles/:role_name/delete", authenticateToken, requiresRoom message: "You cannot delete a reserved role. (i.e 'owner' or 'everyone')" }); - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const collection = db.collection('rooms'); var $unset = {}; @@ -1443,7 +1443,7 @@ router.post("/room/:id/user/:user_id/set-role/:role_name", authenticateToken, re message: "You cannot set your own role." }); - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const room = await db.collection('rooms').findOne({ _id: { @@ -1513,7 +1513,7 @@ router.post("/room/:id/cover-image/set/:image_id", authenticateToken, requiresRo image_id } = req.params; - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const image_collection = db.collection('images'); const image = await image_collection.findOne( @@ -1568,7 +1568,7 @@ router.get("/room/:id/verify-subroom-link/:to", authenticateToken, canViewRoom, const room = await require('../index') .mongoClient - .db(process.env.MONGOOSE_DATABASE_NAME) + .db(config.database.mongodb_database_name) .collection('rooms') .findOne({ _id: { @@ -1652,7 +1652,7 @@ router.post("/room/:id/subrooms/:name/create", authenticateToken, requiresRoomPe message: "A subroom with that name already exists." }); - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); const $set = Object.create(null); @@ -1733,7 +1733,7 @@ router.post("/room/:id/subrooms/:name/delete", authenticateToken, requiresRoomPe var $unset = {}; $unset[`subrooms.${name}`] = true; - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); await db.collection('rooms').updateOne( { @@ -1785,7 +1785,7 @@ router.post("/room/:id/subrooms/:name/set-max-players/:count", authenticateToken $set[`subrooms.${name}.maxPlayers`] = parseInt(count); - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); await db.collection('rooms').updateOne( { @@ -1828,7 +1828,7 @@ router.post("/room/:id/set-home-subroom/:name", authenticateToken, requiresRoomP message: "No subroom with that name exists on this room." }); - const db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../index').mongoClient.db(config.database.mongodb_database_name); await db.collection('rooms').updateOne( { @@ -1895,7 +1895,7 @@ async function canViewRoom(req, res, next) { // Fetch room var room = await client - .db(process.env.MONGOOSE_DATABASE_NAME) + .db(config.database.mongodb_database_name) .collection('rooms') .findOne({_id: {$eq: id, $exists: true}}); if(room == null) return res.status(404).json({ @@ -1934,7 +1934,7 @@ function requiresRoomPermission(permission) { // Fetch room var room = await client - .db(process.env.MONGOOSE_DATABASE_NAME) + .db(config.database.mongodb_database_name) .collection('rooms') .findOne({_id: {$eq: id, $exists: true}}); if(room == null) return res.status(404).json({ @@ -1967,7 +1967,7 @@ function requiresRoomPermission(permission) { async function hasPermission(user_id, room_id, permission) { const client = require('../index').mongoClient; var room = await client - .db(process.env.MONGOOSE_DATABASE_NAME) + .db(config.database.mongodb_database_name) .collection('rooms') .findOne({ _id: { $eq: room_id, $exists: true } }); @@ -1996,7 +1996,7 @@ async function hasPermission(user_id, room_id, permission) { */ async function roomAuditLog(room_id, user_id, event) { const client = require('../index').mongoClient; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); const collection = db.collection("room_audit"); var event = { diff --git a/routers/social.js b/routers/social.js index bc98036..11f683c 100644 --- a/routers/social.js +++ b/routers/social.js @@ -1,5 +1,6 @@ const router = require('express').Router(); const helpers = require('../helpers'); +const { config } = helpers; const middleware = require('../middleware'); const notificationTemplates = { invite: "invite", @@ -13,7 +14,7 @@ router.get("/imgfeed", middleware.authenticateToken_optional, async (req, res) = var { count, reverse, offset, filter } = req.query; const client = require('../index').mongoClient; - const db = client.db(process.env.MONGOOSE_DATABASE_NAME); + const db = client.db(config.database.mongodb_database_name); const image_collection = db.collection("images"); if (filter == "mine" && !req.user) return res.status(400).json({ @@ -98,7 +99,7 @@ router.get("/takenby", async (req, res) => { // True if any value present, otherwise false. - var db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + var db = require('../index').mongoClient.db(config.database.mongodb_database_name); var collection = db.collection("images"); var filtered_images = await collection.find({'takenBy.id': target}).toArray(); @@ -149,7 +150,7 @@ router.get("/takenwith", async (req, res) => { offset = 0; } - var db = require('../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + var db = require('../index').mongoClient.db(config.database.mongodb_database_name); var collection = db.collection("images"); var filtered_images = await collection.find({others: {$all: [target]}}).toArray(); diff --git a/routers/ws/MessagingGatewayServerV1.js b/routers/ws/MessagingGatewayServerV1.js index 56bf1ea..c532e00 100644 --- a/routers/ws/MessagingGatewayServerV1.js +++ b/routers/ws/MessagingGatewayServerV1.js @@ -1,6 +1,7 @@ const middleware = require('../../middleware'); const WebSocket = require('ws'); const { mongoClient, WebSocketV2_MessageTemplate } = require("../../index"); +const { config } = require('../../helpers'); const MessagingGatewayServerV1 = new WebSocket.Server({ noServer: true }); exports.MessagingGatewayServerV1 = MessagingGatewayServerV1; @@ -14,7 +15,7 @@ MessagingGatewayServerV1.on('connection', async (stream) => { isDeveloper: false, isCreativeToolsBetaProgramMember: false }; - const db = mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = mongoClient.db(config.database.mongodb_database_name); const server_collection = db.collection("servers"); const message_collection = db.collection("messages"); diff --git a/routers/ws/WebSocketServerV2.js b/routers/ws/WebSocketServerV2.js index ff37d1a..cbc7557 100644 --- a/routers/ws/WebSocketServerV2.js +++ b/routers/ws/WebSocketServerV2.js @@ -4,7 +4,7 @@ const middleware = require('../../middleware'); const WebSocket = require('ws'); const { MatchmakingModes } = require('../matchmaking'); const { WebSocketV2_MessageTemplate } = require("../../index"); -const { auditLog } = require('../../helpers'); +const { auditLog, config } = require('../../helpers'); /** * @typedef Connection @@ -154,7 +154,7 @@ WebSocketServerV2.on('connection', (Socket) => { if (typeof ParsedContent.data.roomId != 'string' || typeof ParsedContent.data.subroomId != 'string') return; - var db = require('../../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + var db = require('../../index').mongoClient.db(config.database.mongodb_database_name); var collection = db.collection("rooms"); var room = await collection.findOne({ _id: { $eq: ParsedContent.data.roomId, $exists: true } }); @@ -288,7 +288,7 @@ WebSocketServerV2.on('connection', (Socket) => { return; // eslint-disable-next-line no-redeclare - var db = require('../../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + var db = require('../../index').mongoClient.db(config.database.mongodb_database_name); // eslint-disable-next-line no-redeclare var collection = db.collection("rooms"); @@ -359,7 +359,7 @@ WebSocketServerV2.on('connection', (Socket) => { return; // eslint-disable-next-line no-redeclare - var db = require('../../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + var db = require('../../index').mongoClient.db(config.database.mongodb_database_name); // eslint-disable-next-line no-redeclare var collection = db.collection("rooms"); @@ -512,7 +512,7 @@ WebSocketServerV2.on('connection', (Socket) => { ws_connected_clients[ConnectedUserData.uid].joinCode = instance.JoinCode; // eslint-disable-next-line no-redeclare - var collection = require('../../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME).collection("rooms"); + var collection = require('../../index').mongoClient.db(config.database.mongodb_database_name).collection("rooms"); var room = await collection.findOne({ _id: { $eq: ConnectedUserData.matchmaking_RoomId, $exists: true } }); // eslint-disable-next-line no-redeclare @@ -586,7 +586,7 @@ WebSocketServerV2.on('connection', (Socket) => { ws_connected_clients[ConnectedUserData.uid].joinCode = instance.JoinCode; // eslint-disable-next-line no-redeclare - var collection = require('../../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME).collection("rooms"); + var collection = require('../../index').mongoClient.db(config.database.mongodb_database_name).collection("rooms"); var room = await collection.findOne({ _id: { $eq: ConnectedUserData.matchmaking_RoomId, $exists: true } }); // eslint-disable-next-line no-redeclare @@ -656,7 +656,7 @@ WebSocketServerV2.on('connection', (Socket) => { var instance = (await MatchmakingAPI.GetInstances(roomId)).filter(x => x.JoinCode == joinCode)[0]; var roomData = await require('../../index') .mongoClient - .db(process.env.MONGOOSE_DATABASE_NAME) + .db(config.database.mongodb_database_name) .collection('rooms') .findOne({ _id: { $eq: roomId, $exists: true } }); instance.AddPlayer(ConnectedUserData.uid); @@ -672,7 +672,7 @@ WebSocketServerV2.on('connection', (Socket) => { ws_connected_clients[ConnectedUserData.uid].globalInstanceId = instance.GlobalInstanceId; ws_connected_clients[ConnectedUserData.uid].joinCode = instance.JoinCode; - var room = await require('../../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME) + var room = await require('../../index').mongoClient.db(config.database.mongodb_database_name) .collection('rooms') .findOne({_id: {$exists: true, $eq: instance.RoomId}}); @@ -700,7 +700,7 @@ WebSocketServerV2.on('connection', (Socket) => { Socket.on('permission-update', async (roomId) => { if (roomId != ConnectedUserData.matchmaking_RoomId) return; - const db = require('../../index').mongoClient.db(process.env.MONGOOSE_DATABASE_NAME); + const db = require('../../index').mongoClient.db(config.database.mongodb_database_name); const room = await db.collection('rooms').findOne( { _id: {