refactor: move functions
fix: locked accounts was not implemented lol
This commit is contained in:
parent
eabc1bfba9
commit
0036d4448c
8 changed files with 350 additions and 299 deletions
125
index.js
125
index.js
|
@ -6,8 +6,7 @@ const express = require("express"),
|
||||||
passport = require("passport"),
|
passport = require("passport"),
|
||||||
SteamStrategy = require("passport-steam").Strategy;
|
SteamStrategy = require("passport-steam").Strategy;
|
||||||
|
|
||||||
const { JsonDB, Config } = require("node-json-db"),
|
const { JsonDB, Config } = require("node-json-db");
|
||||||
{ generateRandomString, log } = require("./utils/functions");
|
|
||||||
|
|
||||||
const config = require("./config");
|
const config = require("./config");
|
||||||
const db = new JsonDB(new Config(`data/${config.production ? "main" : "test"}_db`, true, true, "/"));
|
const db = new JsonDB(new Config(`data/${config.production ? "main" : "test"}_db`, true, true, "/"));
|
||||||
|
@ -110,130 +109,8 @@ db.getData("/admins").then(data => {
|
||||||
app.locals = {
|
app.locals = {
|
||||||
config: config,
|
config: config,
|
||||||
db: db,
|
db: db,
|
||||||
getKey: getKey,
|
|
||||||
isRatelimited: isRatelimited,
|
|
||||||
isMultiAccount: isMultiAccount,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a user's key from the database.
|
|
||||||
*
|
|
||||||
* Checks if the user already has a key, and returns it if so.
|
|
||||||
* Otherwise generates a new one.
|
|
||||||
*
|
|
||||||
* @param {Object | string} user The user object or SteamID64.
|
|
||||||
* @returns {Promise<String>} The user's key.
|
|
||||||
*/
|
|
||||||
async function getKey(user) {
|
|
||||||
user = typeof user === "string" ? user : user.steamid;
|
|
||||||
|
|
||||||
const keys = await db.getData("/keys");
|
|
||||||
const key = keys[user];
|
|
||||||
|
|
||||||
if (key) {
|
|
||||||
await log(
|
|
||||||
`[KEY] User logged in (SteamID: ${user}, Key ${key}).`,
|
|
||||||
`[KEY] User logged in (SteamID: \`${user}\`, Key \`${key}\`).`,
|
|
||||||
);
|
|
||||||
return key;
|
|
||||||
} else return await _createKey(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new unique key for the given user and saves it to the database.
|
|
||||||
*
|
|
||||||
* @param {Object | string} user The OpenID Steam user object or SteamID64.
|
|
||||||
* @returns {Promise<String>} The new unique key generated for the user.
|
|
||||||
*/
|
|
||||||
async function _createKey(user) {
|
|
||||||
user = typeof user === "string" ? user : user.steamid;
|
|
||||||
|
|
||||||
const keys = await db.getData("/keys");
|
|
||||||
const key = generateRandomString();
|
|
||||||
const isFound = keys[key];
|
|
||||||
|
|
||||||
if (!isFound) {
|
|
||||||
keys[user] = key;
|
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
|
|
||||||
await log(
|
|
||||||
`[KEY] New user (SteamID: ${user}, Key: ${key}, TimeCreated: ${new Date(now).toLocaleString("ru-RU")}).`,
|
|
||||||
`[KEY] New user (SteamID: \`${user}\`, Key: \`${key}\`, TimeCreated: <t:${Math.floor(now / 1000)}:f>).`,
|
|
||||||
);
|
|
||||||
await db.push("/keys", keys);
|
|
||||||
|
|
||||||
return key;
|
|
||||||
} else return await _createKey(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if an IP address is currently rate limited.
|
|
||||||
*
|
|
||||||
* Gets the current rate limits from the database.
|
|
||||||
* If the IP already has a recent rate limit, returns true.
|
|
||||||
* Otherwise, saves a new rate limit for the IP and returns false.
|
|
||||||
*
|
|
||||||
* @param {string} ip The IP address to check
|
|
||||||
* @returns {Promise<boolean>} Whether the IP is currently rate limited
|
|
||||||
*/
|
|
||||||
async function isRatelimited(ip) {
|
|
||||||
const rateLimits = await db.getData("/ratelimits");
|
|
||||||
|
|
||||||
if (rateLimits[ip] && Date.now() - rateLimits[ip] <= config.rateLimitTime) return true;
|
|
||||||
|
|
||||||
rateLimits[ip] = Date.now();
|
|
||||||
|
|
||||||
await db.push("/ratelimits", rateLimits);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a user is using multiple accounts based on their IP address and Steam ID.
|
|
||||||
*
|
|
||||||
* Retrieves the locked accounts and user records from the database. If the user's account is locked, returns true.
|
|
||||||
* Otherwise, checks if the user has changed their IP address more than the configured `ipChangeTime`. If so, clears the
|
|
||||||
* user's IP address history and locks the account if the user has changed their IP more than 3 times. Updates the
|
|
||||||
* database with the new account status and returns the result.
|
|
||||||
*
|
|
||||||
* @param {string} ip The IP address of the user.
|
|
||||||
* @param {string} steamid The Steam ID of the user.
|
|
||||||
* @returns {Promise<boolean>} Whether the user is using multiple accounts.
|
|
||||||
*/
|
|
||||||
async function isMultiAccount(ip, steamid) {
|
|
||||||
const locked = await db.getData("/locked");
|
|
||||||
const records = await db.getData("/records");
|
|
||||||
|
|
||||||
if (locked[steamid]) return true;
|
|
||||||
|
|
||||||
if (!records[steamid])
|
|
||||||
records[steamid] = {
|
|
||||||
ips: {
|
|
||||||
[ip]: true,
|
|
||||||
},
|
|
||||||
lastchanged: Date.now(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clear IPs if the user has changed their ip more than ipChangeTime
|
|
||||||
if (Date.now() - records[steamid]["lastchanged"] > config.ipChangeTime) {
|
|
||||||
records[steamid]["ips"] = [];
|
|
||||||
records[steamid]["lastchanged"] = Date.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lock account if the user changed their IP more than 3 time in ipChangeTime
|
|
||||||
if (Object.keys(records[steamid]["ips"]).length > 2) {
|
|
||||||
locked[steamid] = true;
|
|
||||||
|
|
||||||
await db.push("/locked", locked);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
await db.push("/records", records);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTP server
|
// HTTP server
|
||||||
const http = require("http");
|
const http = require("http");
|
||||||
|
|
||||||
|
|
12
package.json
12
package.json
|
@ -7,16 +7,16 @@
|
||||||
"start": "node ."
|
"start": "node ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"daisyui": "^4.11.1",
|
"daisyui": "^4.12.23",
|
||||||
"ejs": "^2.6.1",
|
"ejs": "^2.6.1",
|
||||||
"express": "^4.16.1",
|
"express": "^4.21.2",
|
||||||
"express-session": "^1.18.0",
|
"express-session": "^1.18.1",
|
||||||
"formidable": "^2.1.2",
|
"formidable": "^2.1.2",
|
||||||
"lzma": "^2.3.2",
|
"lzma": "^2.3.2",
|
||||||
"mongoose": "^8.9.0",
|
"mongoose": "^8.9.5",
|
||||||
"morgan": "^1.9.1",
|
"morgan": "^1.10.0",
|
||||||
"node-fetch": "^2.7.0",
|
"node-fetch": "^2.7.0",
|
||||||
"node-json-db": "^2.3.0",
|
"node-json-db": "^2.3.1",
|
||||||
"open-graph-scraper": "^6.5.0",
|
"open-graph-scraper": "^6.5.0",
|
||||||
"passport": "^0.7.0",
|
"passport": "^0.7.0",
|
||||||
"passport-steam": "^1.0.18"
|
"passport-steam": "^1.0.18"
|
||||||
|
|
307
pnpm-lock.yaml
307
pnpm-lock.yaml
|
@ -9,17 +9,17 @@ importers:
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
daisyui:
|
daisyui:
|
||||||
specifier: ^4.11.1
|
specifier: ^4.12.23
|
||||||
version: 4.11.1(postcss@8.4.36)
|
version: 4.12.23(postcss@8.4.36)
|
||||||
ejs:
|
ejs:
|
||||||
specifier: ^2.6.1
|
specifier: ^2.6.1
|
||||||
version: 2.6.2
|
version: 2.6.2
|
||||||
express:
|
express:
|
||||||
specifier: ^4.16.1
|
specifier: ^4.21.2
|
||||||
version: 4.16.4
|
version: 4.21.2
|
||||||
express-session:
|
express-session:
|
||||||
specifier: ^1.18.0
|
specifier: ^1.18.1
|
||||||
version: 1.18.0
|
version: 1.18.1
|
||||||
formidable:
|
formidable:
|
||||||
specifier: ^2.1.2
|
specifier: ^2.1.2
|
||||||
version: 2.1.2
|
version: 2.1.2
|
||||||
|
@ -27,17 +27,17 @@ importers:
|
||||||
specifier: ^2.3.2
|
specifier: ^2.3.2
|
||||||
version: 2.3.2
|
version: 2.3.2
|
||||||
mongoose:
|
mongoose:
|
||||||
specifier: ^8.9.0
|
specifier: ^8.9.5
|
||||||
version: 8.9.0
|
version: 8.9.5
|
||||||
morgan:
|
morgan:
|
||||||
specifier: ^1.9.1
|
specifier: ^1.10.0
|
||||||
version: 1.9.1
|
version: 1.10.0
|
||||||
node-fetch:
|
node-fetch:
|
||||||
specifier: ^2.7.0
|
specifier: ^2.7.0
|
||||||
version: 2.7.0
|
version: 2.7.0
|
||||||
node-json-db:
|
node-json-db:
|
||||||
specifier: ^2.3.0
|
specifier: ^2.3.1
|
||||||
version: 2.3.0
|
version: 2.3.1
|
||||||
open-graph-scraper:
|
open-graph-scraper:
|
||||||
specifier: ^6.5.0
|
specifier: ^6.5.0
|
||||||
version: 6.5.0
|
version: 6.5.0
|
||||||
|
@ -224,9 +224,9 @@ packages:
|
||||||
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
body-parser@1.18.3:
|
body-parser@1.20.3:
|
||||||
resolution: {integrity: sha512-YQyoqQG3sO8iCmf8+hyVpgHHOv0/hCEFiS4zTGUwTA1HjAFX66wRcNQrVCeJq9pgESMRvUAOvSil5MJlmccuKQ==}
|
resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
|
||||||
|
|
||||||
boolbase@1.0.0:
|
boolbase@1.0.0:
|
||||||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||||
|
@ -245,8 +245,8 @@ packages:
|
||||||
resolution: {integrity: sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==}
|
resolution: {integrity: sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==}
|
||||||
engines: {node: '>=16.20.1'}
|
engines: {node: '>=16.20.1'}
|
||||||
|
|
||||||
bytes@3.0.0:
|
bytes@3.1.2:
|
||||||
resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
|
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
call-bind@1.0.7:
|
call-bind@1.0.7:
|
||||||
|
@ -297,8 +297,8 @@ packages:
|
||||||
concat-map@0.0.1:
|
concat-map@0.0.1:
|
||||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||||
|
|
||||||
content-disposition@0.5.2:
|
content-disposition@0.5.4:
|
||||||
resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==}
|
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
content-type@1.0.5:
|
content-type@1.0.5:
|
||||||
|
@ -311,12 +311,12 @@ packages:
|
||||||
cookie-signature@1.0.7:
|
cookie-signature@1.0.7:
|
||||||
resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==}
|
resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==}
|
||||||
|
|
||||||
cookie@0.3.1:
|
cookie@0.7.1:
|
||||||
resolution: {integrity: sha512-+IJOX0OqlHCszo2mBUq+SrEbCj6w7Kpffqx60zYbPTFaO4+yYgRjHwcZNpWvaTylDHaV7PPmBHzSecZiMhtPgw==}
|
resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
cookie@0.6.0:
|
cookie@0.7.2:
|
||||||
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
cross-spawn@7.0.3:
|
cross-spawn@7.0.3:
|
||||||
|
@ -342,8 +342,8 @@ packages:
|
||||||
resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==}
|
resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==}
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
|
||||||
daisyui@4.11.1:
|
daisyui@4.12.23:
|
||||||
resolution: {integrity: sha512-obT9CUbQdW6eoHwSeT5VwaRrWlwrM4OT5qlfdJ0oQlSIEYhwnEl2+L2fwu5PioLbitwuMdYC2X8I1cyy8Pf6LQ==}
|
resolution: {integrity: sha512-EM38duvxutJ5PD65lO/AFMpcw+9qEy6XAZrTpzp7WyaPeO/l+F/Qiq0ECHHmFNcFXh5aVoALY4MGrrxtCiaQCQ==}
|
||||||
engines: {node: '>=16.9.0'}
|
engines: {node: '>=16.9.0'}
|
||||||
|
|
||||||
debug@2.6.9:
|
debug@2.6.9:
|
||||||
|
@ -374,16 +374,13 @@ packages:
|
||||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
|
|
||||||
depd@1.1.2:
|
|
||||||
resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}
|
|
||||||
engines: {node: '>= 0.6'}
|
|
||||||
|
|
||||||
depd@2.0.0:
|
depd@2.0.0:
|
||||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
destroy@1.0.4:
|
destroy@1.2.0:
|
||||||
resolution: {integrity: sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==}
|
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
|
||||||
|
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
|
||||||
|
|
||||||
dezalgo@1.0.4:
|
dezalgo@1.0.4:
|
||||||
resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==}
|
resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==}
|
||||||
|
@ -431,6 +428,10 @@ packages:
|
||||||
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
|
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
encodeurl@2.0.0:
|
||||||
|
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
entities@4.5.0:
|
entities@4.5.0:
|
||||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||||
engines: {node: '>=0.12'}
|
engines: {node: '>=0.12'}
|
||||||
|
@ -487,12 +488,12 @@ packages:
|
||||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
express-session@1.18.0:
|
express-session@1.18.1:
|
||||||
resolution: {integrity: sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==}
|
resolution: {integrity: sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
express@4.16.4:
|
express@4.21.2:
|
||||||
resolution: {integrity: sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==}
|
resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==}
|
||||||
engines: {node: '>= 0.10.0'}
|
engines: {node: '>= 0.10.0'}
|
||||||
|
|
||||||
fast-deep-equal@3.1.3:
|
fast-deep-equal@3.1.3:
|
||||||
|
@ -522,8 +523,8 @@ packages:
|
||||||
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
|
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
finalhandler@1.1.1:
|
finalhandler@1.3.1:
|
||||||
resolution: {integrity: sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==}
|
resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
find-up@5.0.0:
|
find-up@5.0.0:
|
||||||
|
@ -632,12 +633,12 @@ packages:
|
||||||
htmlparser2@8.0.2:
|
htmlparser2@8.0.2:
|
||||||
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
||||||
|
|
||||||
http-errors@1.6.3:
|
http-errors@2.0.0:
|
||||||
resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==}
|
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
iconv-lite@0.4.23:
|
iconv-lite@0.4.24:
|
||||||
resolution: {integrity: sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==}
|
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
iconv-lite@0.6.3:
|
iconv-lite@0.6.3:
|
||||||
|
@ -662,6 +663,9 @@ packages:
|
||||||
inherits@2.0.3:
|
inherits@2.0.3:
|
||||||
resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==}
|
resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==}
|
||||||
|
|
||||||
|
inherits@2.0.4:
|
||||||
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
@ -761,8 +765,8 @@ packages:
|
||||||
memory-pager@1.5.0:
|
memory-pager@1.5.0:
|
||||||
resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
|
resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
|
||||||
|
|
||||||
merge-descriptors@1.0.1:
|
merge-descriptors@1.0.3:
|
||||||
resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
|
resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}
|
||||||
|
|
||||||
merge2@1.4.1:
|
merge2@1.4.1:
|
||||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||||
|
@ -784,8 +788,9 @@ packages:
|
||||||
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
mime@1.4.1:
|
mime@1.6.0:
|
||||||
resolution: {integrity: sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==}
|
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
minimatch@3.1.2:
|
minimatch@3.1.2:
|
||||||
|
@ -829,12 +834,12 @@ packages:
|
||||||
socks:
|
socks:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
mongoose@8.9.0:
|
mongoose@8.9.5:
|
||||||
resolution: {integrity: sha512-b58zY3PLNBcoz6ZXFckr0leJcVVBMAOBvD+7Bj2ZjghAwntXmNnqwlDixTKQU3UYoQIGTv+AQx/0ThsvaeVrCA==}
|
resolution: {integrity: sha512-SPhOrgBm0nKV3b+IIHGqpUTOmgVL5Z3OO9AwkFEmvOZznXTvplbomstCnPOGAyungtRXE5pJTgKpKcZTdjeESg==}
|
||||||
engines: {node: '>=16.20.1'}
|
engines: {node: '>=16.20.1'}
|
||||||
|
|
||||||
morgan@1.9.1:
|
morgan@1.10.0:
|
||||||
resolution: {integrity: sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==}
|
resolution: {integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
mpath@0.9.0:
|
mpath@0.9.0:
|
||||||
|
@ -878,8 +883,8 @@ packages:
|
||||||
encoding:
|
encoding:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
node-json-db@2.3.0:
|
node-json-db@2.3.1:
|
||||||
resolution: {integrity: sha512-B8T+w4q6zXZ20YcfQINLSjMGgImRKzkvR0ShYYoNRdLxtMhVvbzaMBzNdEaRcCjilW/lKS+g9CwVXNoK5uTncw==}
|
resolution: {integrity: sha512-cZ0HGQuMUhMg9iGLgS7eOGK5gGYfAyEsPXMD16mcHvUNhMMtOxgUAMuiCED7qh+c2IOeN/6l9FXUCgnGtXvLIA==}
|
||||||
|
|
||||||
normalize-path@3.0.0:
|
normalize-path@3.0.0:
|
||||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||||
|
@ -903,6 +908,10 @@ packages:
|
||||||
resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
|
resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
on-finished@2.4.1:
|
||||||
|
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
on-headers@1.0.2:
|
on-headers@1.0.2:
|
||||||
resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
|
resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
@ -975,8 +984,8 @@ packages:
|
||||||
resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
|
resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
|
||||||
engines: {node: '>=16 || 14 >=14.17'}
|
engines: {node: '>=16 || 14 >=14.17'}
|
||||||
|
|
||||||
path-to-regexp@0.1.7:
|
path-to-regexp@0.1.12:
|
||||||
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
|
resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==}
|
||||||
|
|
||||||
pause@0.0.1:
|
pause@0.0.1:
|
||||||
resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==}
|
resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==}
|
||||||
|
@ -1061,6 +1070,10 @@ packages:
|
||||||
resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==}
|
resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
|
|
||||||
|
qs@6.13.0:
|
||||||
|
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
|
||||||
|
engines: {node: '>=0.6'}
|
||||||
|
|
||||||
qs@6.5.2:
|
qs@6.5.2:
|
||||||
resolution: {integrity: sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==}
|
resolution: {integrity: sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
|
@ -1076,8 +1089,8 @@ packages:
|
||||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
raw-body@2.3.3:
|
raw-body@2.5.2:
|
||||||
resolution: {integrity: sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==}
|
resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
read-cache@1.0.0:
|
read-cache@1.0.0:
|
||||||
|
@ -1118,20 +1131,20 @@ packages:
|
||||||
safer-buffer@2.1.2:
|
safer-buffer@2.1.2:
|
||||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||||
|
|
||||||
send@0.16.2:
|
send@0.19.0:
|
||||||
resolution: {integrity: sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==}
|
resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
serve-static@1.13.2:
|
serve-static@1.16.2:
|
||||||
resolution: {integrity: sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==}
|
resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
set-function-length@1.2.2:
|
set-function-length@1.2.2:
|
||||||
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
|
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
setprototypeof@1.1.0:
|
setprototypeof@1.2.0:
|
||||||
resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==}
|
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||||
|
@ -1159,13 +1172,9 @@ packages:
|
||||||
sparse-bitfield@3.0.3:
|
sparse-bitfield@3.0.3:
|
||||||
resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
|
resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
|
||||||
|
|
||||||
statuses@1.4.0:
|
statuses@2.0.1:
|
||||||
resolution: {integrity: sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==}
|
resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
statuses@1.5.0:
|
|
||||||
resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
|
|
||||||
engines: {node: '>= 0.6'}
|
|
||||||
|
|
||||||
steam-web@0.4.0:
|
steam-web@0.4.0:
|
||||||
resolution: {integrity: sha512-FgSYhL7GaP4Va5JKT09yZ+WrTZttFtLwenIPuZd7GUA1z3W7vu7qqPT/qTC76Pd9+sf85txMgIPr/y0+3gNlUA==}
|
resolution: {integrity: sha512-FgSYhL7GaP4Va5JKT09yZ+WrTZttFtLwenIPuZd7GUA1z3W7vu7qqPT/qTC76Pd9+sf85txMgIPr/y0+3gNlUA==}
|
||||||
|
@ -1223,6 +1232,10 @@ packages:
|
||||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||||
engines: {node: '>=8.0'}
|
engines: {node: '>=8.0'}
|
||||||
|
|
||||||
|
toidentifier@1.0.1:
|
||||||
|
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||||
|
engines: {node: '>=0.6'}
|
||||||
|
|
||||||
tr46@0.0.3:
|
tr46@0.0.3:
|
||||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||||
|
|
||||||
|
@ -1478,18 +1491,20 @@ snapshots:
|
||||||
|
|
||||||
binary-extensions@2.3.0: {}
|
binary-extensions@2.3.0: {}
|
||||||
|
|
||||||
body-parser@1.18.3:
|
body-parser@1.20.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
bytes: 3.0.0
|
bytes: 3.1.2
|
||||||
content-type: 1.0.5
|
content-type: 1.0.5
|
||||||
debug: 2.6.9
|
debug: 2.6.9
|
||||||
depd: 1.1.2
|
depd: 2.0.0
|
||||||
http-errors: 1.6.3
|
destroy: 1.2.0
|
||||||
iconv-lite: 0.4.23
|
http-errors: 2.0.0
|
||||||
on-finished: 2.3.0
|
iconv-lite: 0.4.24
|
||||||
qs: 6.5.2
|
on-finished: 2.4.1
|
||||||
raw-body: 2.3.3
|
qs: 6.13.0
|
||||||
|
raw-body: 2.5.2
|
||||||
type-is: 1.6.18
|
type-is: 1.6.18
|
||||||
|
unpipe: 1.0.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
@ -1510,7 +1525,7 @@ snapshots:
|
||||||
|
|
||||||
bson@6.10.1: {}
|
bson@6.10.1: {}
|
||||||
|
|
||||||
bytes@3.0.0: {}
|
bytes@3.1.2: {}
|
||||||
|
|
||||||
call-bind@1.0.7:
|
call-bind@1.0.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1576,7 +1591,9 @@ snapshots:
|
||||||
|
|
||||||
concat-map@0.0.1: {}
|
concat-map@0.0.1: {}
|
||||||
|
|
||||||
content-disposition@0.5.2: {}
|
content-disposition@0.5.4:
|
||||||
|
dependencies:
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
content-type@1.0.5: {}
|
content-type@1.0.5: {}
|
||||||
|
|
||||||
|
@ -1584,9 +1601,9 @@ snapshots:
|
||||||
|
|
||||||
cookie-signature@1.0.7: {}
|
cookie-signature@1.0.7: {}
|
||||||
|
|
||||||
cookie@0.3.1: {}
|
cookie@0.7.1: {}
|
||||||
|
|
||||||
cookie@0.6.0: {}
|
cookie@0.7.2: {}
|
||||||
|
|
||||||
cross-spawn@7.0.3:
|
cross-spawn@7.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1613,7 +1630,7 @@ snapshots:
|
||||||
|
|
||||||
culori@3.3.0: {}
|
culori@3.3.0: {}
|
||||||
|
|
||||||
daisyui@4.11.1(postcss@8.4.36):
|
daisyui@4.12.23(postcss@8.4.36):
|
||||||
dependencies:
|
dependencies:
|
||||||
css-selector-tokenizer: 0.8.0
|
css-selector-tokenizer: 0.8.0
|
||||||
culori: 3.3.0
|
culori: 3.3.0
|
||||||
|
@ -1640,11 +1657,9 @@ snapshots:
|
||||||
|
|
||||||
delayed-stream@1.0.0: {}
|
delayed-stream@1.0.0: {}
|
||||||
|
|
||||||
depd@1.1.2: {}
|
|
||||||
|
|
||||||
depd@2.0.0: {}
|
depd@2.0.0: {}
|
||||||
|
|
||||||
destroy@1.0.4: {}
|
destroy@1.2.0: {}
|
||||||
|
|
||||||
dezalgo@1.0.4:
|
dezalgo@1.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1689,6 +1704,8 @@ snapshots:
|
||||||
|
|
||||||
encodeurl@1.0.2: {}
|
encodeurl@1.0.2: {}
|
||||||
|
|
||||||
|
encodeurl@2.0.0: {}
|
||||||
|
|
||||||
entities@4.5.0: {}
|
entities@4.5.0: {}
|
||||||
|
|
||||||
es-define-property@1.0.0:
|
es-define-property@1.0.0:
|
||||||
|
@ -1771,9 +1788,9 @@ snapshots:
|
||||||
|
|
||||||
etag@1.8.1: {}
|
etag@1.8.1: {}
|
||||||
|
|
||||||
express-session@1.18.0:
|
express-session@1.18.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
cookie: 0.6.0
|
cookie: 0.7.2
|
||||||
cookie-signature: 1.0.7
|
cookie-signature: 1.0.7
|
||||||
debug: 2.6.9
|
debug: 2.6.9
|
||||||
depd: 2.0.0
|
depd: 2.0.0
|
||||||
|
@ -1784,35 +1801,36 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
express@4.16.4:
|
express@4.21.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
accepts: 1.3.8
|
accepts: 1.3.8
|
||||||
array-flatten: 1.1.1
|
array-flatten: 1.1.1
|
||||||
body-parser: 1.18.3
|
body-parser: 1.20.3
|
||||||
content-disposition: 0.5.2
|
content-disposition: 0.5.4
|
||||||
content-type: 1.0.5
|
content-type: 1.0.5
|
||||||
cookie: 0.3.1
|
cookie: 0.7.1
|
||||||
cookie-signature: 1.0.6
|
cookie-signature: 1.0.6
|
||||||
debug: 2.6.9
|
debug: 2.6.9
|
||||||
depd: 1.1.2
|
depd: 2.0.0
|
||||||
encodeurl: 1.0.2
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
etag: 1.8.1
|
etag: 1.8.1
|
||||||
finalhandler: 1.1.1
|
finalhandler: 1.3.1
|
||||||
fresh: 0.5.2
|
fresh: 0.5.2
|
||||||
merge-descriptors: 1.0.1
|
http-errors: 2.0.0
|
||||||
|
merge-descriptors: 1.0.3
|
||||||
methods: 1.1.2
|
methods: 1.1.2
|
||||||
on-finished: 2.3.0
|
on-finished: 2.4.1
|
||||||
parseurl: 1.3.3
|
parseurl: 1.3.3
|
||||||
path-to-regexp: 0.1.7
|
path-to-regexp: 0.1.12
|
||||||
proxy-addr: 2.0.7
|
proxy-addr: 2.0.7
|
||||||
qs: 6.5.2
|
qs: 6.13.0
|
||||||
range-parser: 1.2.1
|
range-parser: 1.2.1
|
||||||
safe-buffer: 5.1.2
|
safe-buffer: 5.2.1
|
||||||
send: 0.16.2
|
send: 0.19.0
|
||||||
serve-static: 1.13.2
|
serve-static: 1.16.2
|
||||||
setprototypeof: 1.1.0
|
setprototypeof: 1.2.0
|
||||||
statuses: 1.4.0
|
statuses: 2.0.1
|
||||||
type-is: 1.6.18
|
type-is: 1.6.18
|
||||||
utils-merge: 1.0.1
|
utils-merge: 1.0.1
|
||||||
vary: 1.1.2
|
vary: 1.1.2
|
||||||
|
@ -1847,14 +1865,14 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
|
|
||||||
finalhandler@1.1.1:
|
finalhandler@1.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 2.6.9
|
debug: 2.6.9
|
||||||
encodeurl: 1.0.2
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
on-finished: 2.3.0
|
on-finished: 2.4.1
|
||||||
parseurl: 1.3.3
|
parseurl: 1.3.3
|
||||||
statuses: 1.4.0
|
statuses: 2.0.1
|
||||||
unpipe: 1.0.0
|
unpipe: 1.0.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -1969,14 +1987,15 @@ snapshots:
|
||||||
domutils: 3.1.0
|
domutils: 3.1.0
|
||||||
entities: 4.5.0
|
entities: 4.5.0
|
||||||
|
|
||||||
http-errors@1.6.3:
|
http-errors@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
depd: 1.1.2
|
depd: 2.0.0
|
||||||
inherits: 2.0.3
|
inherits: 2.0.4
|
||||||
setprototypeof: 1.1.0
|
setprototypeof: 1.2.0
|
||||||
statuses: 1.5.0
|
statuses: 2.0.1
|
||||||
|
toidentifier: 1.0.1
|
||||||
|
|
||||||
iconv-lite@0.4.23:
|
iconv-lite@0.4.24:
|
||||||
dependencies:
|
dependencies:
|
||||||
safer-buffer: 2.1.2
|
safer-buffer: 2.1.2
|
||||||
|
|
||||||
|
@ -2000,6 +2019,8 @@ snapshots:
|
||||||
|
|
||||||
inherits@2.0.3: {}
|
inherits@2.0.3: {}
|
||||||
|
|
||||||
|
inherits@2.0.4: {}
|
||||||
|
|
||||||
ipaddr.js@1.9.1: {}
|
ipaddr.js@1.9.1: {}
|
||||||
|
|
||||||
is-binary-path@2.1.0:
|
is-binary-path@2.1.0:
|
||||||
|
@ -2073,7 +2094,7 @@ snapshots:
|
||||||
|
|
||||||
memory-pager@1.5.0: {}
|
memory-pager@1.5.0: {}
|
||||||
|
|
||||||
merge-descriptors@1.0.1: {}
|
merge-descriptors@1.0.3: {}
|
||||||
|
|
||||||
merge2@1.4.1: {}
|
merge2@1.4.1: {}
|
||||||
|
|
||||||
|
@ -2090,7 +2111,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
mime-db: 1.52.0
|
mime-db: 1.52.0
|
||||||
|
|
||||||
mime@1.4.1: {}
|
mime@1.6.0: {}
|
||||||
|
|
||||||
minimatch@3.1.2:
|
minimatch@3.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2113,7 +2134,7 @@ snapshots:
|
||||||
bson: 6.10.1
|
bson: 6.10.1
|
||||||
mongodb-connection-string-url: 3.0.1
|
mongodb-connection-string-url: 3.0.1
|
||||||
|
|
||||||
mongoose@8.9.0:
|
mongoose@8.9.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
bson: 6.10.1
|
bson: 6.10.1
|
||||||
kareem: 2.6.3
|
kareem: 2.6.3
|
||||||
|
@ -2132,11 +2153,11 @@ snapshots:
|
||||||
- socks
|
- socks
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
morgan@1.9.1:
|
morgan@1.10.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
basic-auth: 2.0.1
|
basic-auth: 2.0.1
|
||||||
debug: 2.6.9
|
debug: 2.6.9
|
||||||
depd: 1.1.2
|
depd: 2.0.0
|
||||||
on-finished: 2.3.0
|
on-finished: 2.3.0
|
||||||
on-headers: 1.0.2
|
on-headers: 1.0.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -2172,7 +2193,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-url: 5.0.0
|
whatwg-url: 5.0.0
|
||||||
|
|
||||||
node-json-db@2.3.0:
|
node-json-db@2.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
rwlock: 5.0.0
|
rwlock: 5.0.0
|
||||||
|
|
||||||
|
@ -2192,6 +2213,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
ee-first: 1.1.1
|
ee-first: 1.1.1
|
||||||
|
|
||||||
|
on-finished@2.4.1:
|
||||||
|
dependencies:
|
||||||
|
ee-first: 1.1.1
|
||||||
|
|
||||||
on-headers@1.0.2: {}
|
on-headers@1.0.2: {}
|
||||||
|
|
||||||
once@1.4.0:
|
once@1.4.0:
|
||||||
|
@ -2273,7 +2298,7 @@ snapshots:
|
||||||
lru-cache: 10.2.0
|
lru-cache: 10.2.0
|
||||||
minipass: 7.0.4
|
minipass: 7.0.4
|
||||||
|
|
||||||
path-to-regexp@0.1.7: {}
|
path-to-regexp@0.1.12: {}
|
||||||
|
|
||||||
pause@0.0.1: {}
|
pause@0.0.1: {}
|
||||||
|
|
||||||
|
@ -2339,6 +2364,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
side-channel: 1.0.6
|
side-channel: 1.0.6
|
||||||
|
|
||||||
|
qs@6.13.0:
|
||||||
|
dependencies:
|
||||||
|
side-channel: 1.0.6
|
||||||
|
|
||||||
qs@6.5.2: {}
|
qs@6.5.2: {}
|
||||||
|
|
||||||
queue-microtask@1.2.3: {}
|
queue-microtask@1.2.3: {}
|
||||||
|
@ -2347,11 +2376,11 @@ snapshots:
|
||||||
|
|
||||||
range-parser@1.2.1: {}
|
range-parser@1.2.1: {}
|
||||||
|
|
||||||
raw-body@2.3.3:
|
raw-body@2.5.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
bytes: 3.0.0
|
bytes: 3.1.2
|
||||||
http-errors: 1.6.3
|
http-errors: 2.0.0
|
||||||
iconv-lite: 0.4.23
|
iconv-lite: 0.4.24
|
||||||
unpipe: 1.0.0
|
unpipe: 1.0.0
|
||||||
|
|
||||||
read-cache@1.0.0:
|
read-cache@1.0.0:
|
||||||
|
@ -2388,30 +2417,30 @@ snapshots:
|
||||||
|
|
||||||
safer-buffer@2.1.2: {}
|
safer-buffer@2.1.2: {}
|
||||||
|
|
||||||
send@0.16.2:
|
send@0.19.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 2.6.9
|
debug: 2.6.9
|
||||||
depd: 1.1.2
|
depd: 2.0.0
|
||||||
destroy: 1.0.4
|
destroy: 1.2.0
|
||||||
encodeurl: 1.0.2
|
encodeurl: 1.0.2
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
etag: 1.8.1
|
etag: 1.8.1
|
||||||
fresh: 0.5.2
|
fresh: 0.5.2
|
||||||
http-errors: 1.6.3
|
http-errors: 2.0.0
|
||||||
mime: 1.4.1
|
mime: 1.6.0
|
||||||
ms: 2.0.0
|
ms: 2.1.3
|
||||||
on-finished: 2.3.0
|
on-finished: 2.4.1
|
||||||
range-parser: 1.2.1
|
range-parser: 1.2.1
|
||||||
statuses: 1.4.0
|
statuses: 2.0.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
serve-static@1.13.2:
|
serve-static@1.16.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
encodeurl: 1.0.2
|
encodeurl: 2.0.0
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
parseurl: 1.3.3
|
parseurl: 1.3.3
|
||||||
send: 0.16.2
|
send: 0.19.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
@ -2424,7 +2453,7 @@ snapshots:
|
||||||
gopd: 1.0.1
|
gopd: 1.0.1
|
||||||
has-property-descriptors: 1.0.2
|
has-property-descriptors: 1.0.2
|
||||||
|
|
||||||
setprototypeof@1.1.0: {}
|
setprototypeof@1.2.0: {}
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2449,9 +2478,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
memory-pager: 1.5.0
|
memory-pager: 1.5.0
|
||||||
|
|
||||||
statuses@1.4.0: {}
|
statuses@2.0.1: {}
|
||||||
|
|
||||||
statuses@1.5.0: {}
|
|
||||||
|
|
||||||
steam-web@0.4.0:
|
steam-web@0.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2536,6 +2563,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-number: 7.0.0
|
is-number: 7.0.0
|
||||||
|
|
||||||
|
toidentifier@1.0.1: {}
|
||||||
|
|
||||||
tr46@0.0.3: {}
|
tr46@0.0.3: {}
|
||||||
|
|
||||||
tr46@4.1.1:
|
tr46@4.1.1:
|
||||||
|
|
|
@ -4,7 +4,7 @@ const express = require("express"),
|
||||||
openGraphScraper = require("open-graph-scraper"),
|
openGraphScraper = require("open-graph-scraper"),
|
||||||
lzma = require("lzma");
|
lzma = require("lzma");
|
||||||
|
|
||||||
const { isAdmin, isUser, isUserGame, generateCode, isCourseFileValid, log } = require("../utils/functions"),
|
const { isAdmin, isUser, isUserGame, isRatelimited, isMultiAccount, isLocked, getKey, generateCode, isCourseFileValid, log } = require("../utils/functions"),
|
||||||
{ formidable } = require("formidable");
|
{ formidable } = require("formidable");
|
||||||
|
|
||||||
router.post("/", isUser, async (req, res) => {
|
router.post("/", isUser, async (req, res) => {
|
||||||
|
@ -21,19 +21,21 @@ router.get("/download", isUserGame, async (req, res) => {
|
||||||
if (!headers.map) return res.status(401).json({ res: res.statusCode, message: "No map provided. Please provide a valid map." });
|
if (!headers.map) return res.status(401).json({ res: res.statusCode, message: "No map provided. Please provide a valid map." });
|
||||||
|
|
||||||
const ip = headers["cf-connecting-ip"] || "Unknown";
|
const ip = headers["cf-connecting-ip"] || "Unknown";
|
||||||
|
const db = req.app.locals.db;
|
||||||
const key = headers.authorization;
|
const key = headers.authorization;
|
||||||
const keys = await req.app.locals.db.getData("/keys");
|
const keys = await db.getData("/keys");
|
||||||
const steamIds = Object.fromEntries(Object.entries(keys).map(([k, v]) => [v, k]));
|
const steamIds = Object.fromEntries(Object.entries(keys).map(([k, v]) => [v, k]));
|
||||||
const steamid = steamIds[key];
|
const steamid = steamIds[key];
|
||||||
|
|
||||||
if (ip !== "Unknown" && (await req.app.locals.isRatelimited(ip))) return res.status(401).json({ res: res.statusCode, message: "Too many requests. Please try again later." });
|
if (ip !== "Unknown" && (await isRatelimited(db, ip))) return res.status(401).json({ res: res.statusCode, message: "Too many requests. Please try again later." });
|
||||||
if (ip !== "Unknown" && (await req.app.locals.isMultiAccount(ip, steamid))) return res.status(401).json({ res: res.statusCode, message: "Your account was detected as multiaccount. Please open a ticket on our Discord server." });
|
if (ip !== "Unknown" && (await isMultiAccount(db, ip, steamid))) return res.status(401).json({ res: res.statusCode, message: "Your account was detected as multiaccount. Please open a ticket on our Discord server." });
|
||||||
|
if (await isLocked(db, steamid)) return res.status(401).json({ res: res.statusCode, message: "Your account is locked. Please open a ticket on our Discord server." });
|
||||||
|
|
||||||
let courseData;
|
let courseData;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
courseData = await req.app.locals.db.getData(`/courses/${headers.code.toUpperCase()}`);
|
courseData = await db.getData(`/courses/${headers.code.toUpperCase()}`);
|
||||||
} catch (e) {
|
} catch {
|
||||||
return res.status(401).json({ res: res.statusCode, message: "Invalid course code provided." });
|
return res.status(401).json({ res: res.statusCode, message: "Invalid course code provided." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +51,7 @@ router.get("/download", isUserGame, async (req, res) => {
|
||||||
if (!courseData.plays) courseData.plays = 1;
|
if (!courseData.plays) courseData.plays = 1;
|
||||||
else courseData.plays++;
|
else courseData.plays++;
|
||||||
|
|
||||||
await req.app.locals.db.push(`/courses/${headers.code.toUpperCase()}`, courseData);
|
await db.push(`/courses/${headers.code.toUpperCase()}`, courseData);
|
||||||
|
|
||||||
res.send({ res: res.statusCode, file: file });
|
res.send({ res: res.statusCode, file: file });
|
||||||
});
|
});
|
||||||
|
@ -61,18 +63,20 @@ router.post("/upload", isUserGame, async (req, res) => {
|
||||||
if (headers.mapid === null || headers.mapid === undefined) return res.status(401).json({ res: res.statusCode, message: "No map id provided. Please provide a valid map id." });
|
if (headers.mapid === null || headers.mapid === undefined) return res.status(401).json({ res: res.statusCode, message: "No map id provided. Please provide a valid map id." });
|
||||||
|
|
||||||
const ip = headers["cf-connecting-ip"] || "Unknown";
|
const ip = headers["cf-connecting-ip"] || "Unknown";
|
||||||
|
const db = req.app.locals.db;
|
||||||
const key = headers.authorization;
|
const key = headers.authorization;
|
||||||
const keys = await req.app.locals.db.getData("/keys");
|
const keys = await db.getData("/keys");
|
||||||
const steamIds = Object.fromEntries(Object.entries(keys).map(([k, v]) => [v, k]));
|
const steamIds = Object.fromEntries(Object.entries(keys).map(([k, v]) => [v, k]));
|
||||||
const steamid = steamIds[key];
|
const steamid = steamIds[key];
|
||||||
|
|
||||||
if (ip !== "Unknown" && (await req.app.locals.isRatelimited(ip))) return res.status(401).json({ res: res.statusCode, message: "Too many requests. Please try again later." });
|
if (ip !== "Unknown" && (await isRatelimited(db, ip))) return res.status(401).json({ res: res.statusCode, message: "Too many requests. Please try again later." });
|
||||||
if (ip !== "Unknown" && (await req.app.locals.isMultiAccount(ip, steamid))) return res.status(401).json({ res: res.statusCode, message: "Your account was detected as multiaccount. Please open a ticket on our Discord server." });
|
if (ip !== "Unknown" && (await isMultiAccount(db, ip, steamid))) return res.status(401).json({ res: res.statusCode, message: "Your account was detected as multiaccount. Please open a ticket on our Discord server." });
|
||||||
|
if (await isLocked(db, steamid)) return res.status(401).json({ res: res.statusCode, message: "Your account is locked. Please open a ticket on our Discord server." });
|
||||||
|
|
||||||
let course = "";
|
let course = "";
|
||||||
try {
|
try {
|
||||||
course = lzma.decompress(Buffer.from(headers.course, "base64"));
|
course = lzma.decompress(Buffer.from(headers.course, "base64"));
|
||||||
} catch (e) {
|
} catch {
|
||||||
course = Buffer.from(headers.course, "base64").toString("utf-8");
|
course = Buffer.from(headers.course, "base64").toString("utf-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +94,7 @@ router.post("/upload", isUserGame, async (req, res) => {
|
||||||
|
|
||||||
const mapImage = headers.mapid === "0" || headers.mapid === "no_map_id" ? "" : await openGraphScraper({ url: `https://steamcommunity.com/sharedfiles/filedetails/?id=${headers.mapid}` }).then(data => data.result.ogImage[0].url);
|
const mapImage = headers.mapid === "0" || headers.mapid === "no_map_id" ? "" : await openGraphScraper({ url: `https://steamcommunity.com/sharedfiles/filedetails/?id=${headers.mapid}` }).then(data => data.result.ogImage[0].url);
|
||||||
|
|
||||||
await req.app.locals.db.push("/courses", {
|
await db.push("/courses", {
|
||||||
[code]: {
|
[code]: {
|
||||||
map: headers.map,
|
map: headers.map,
|
||||||
uploader: {
|
uploader: {
|
||||||
|
@ -115,9 +119,11 @@ router.post("/upload", isUserGame, async (req, res) => {
|
||||||
router.post("/upload_site", isUser, async (req, res) => {
|
router.post("/upload_site", isUser, async (req, res) => {
|
||||||
const { headers, user } = req;
|
const { headers, user } = req;
|
||||||
const ip = headers["cf-connecting-ip"] || "Unknown";
|
const ip = headers["cf-connecting-ip"] || "Unknown";
|
||||||
|
const db = req.app.locals.db;
|
||||||
|
|
||||||
if (ip !== "Unknown" && (await req.app.locals.isRatelimited(ip))) return res.status(401).json({ res: res.statusCode, message: "Too many requests. Please try again later." });
|
if (ip !== "Unknown" && (await isRatelimited(db, ip))) return res.status(401).json({ res: res.statusCode, message: "Too many requests. Please try again later." });
|
||||||
if (ip !== "Unknown" && (await req.app.locals.isMultiAccount(ip, user.steamid))) return res.status(401).json({ res: res.statusCode, message: "Your account was detected as multiaccount. Please open a ticket on our Discord server." });
|
if (ip !== "Unknown" && (await isMultiAccount(db, ip, user.steamid))) return res.status(401).json({ res: res.statusCode, message: "Your account was detected as multiaccount. Please open a ticket on our Discord server." });
|
||||||
|
if (await isLocked(db, user.steamid)) return res.status(401).json({ res: res.statusCode, message: "Your account is locked. Please open a ticket on our Discord server." });
|
||||||
|
|
||||||
const form = formidable({ maxFileSize: 10 * 1024 * 1024 });
|
const form = formidable({ maxFileSize: 10 * 1024 * 1024 });
|
||||||
|
|
||||||
|
@ -129,7 +135,7 @@ router.post("/upload_site", isUser, async (req, res) => {
|
||||||
let course = "";
|
let course = "";
|
||||||
try {
|
try {
|
||||||
course = lzma.decompress(uploaded);
|
course = lzma.decompress(uploaded);
|
||||||
} catch (e) {
|
} catch {
|
||||||
course = uploaded;
|
course = uploaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +154,7 @@ router.post("/upload_site", isUser, async (req, res) => {
|
||||||
const mapid = fields.link.match(/id=(\d+)/)[1];
|
const mapid = fields.link.match(/id=(\d+)/)[1];
|
||||||
const mapImage = await openGraphScraper({ url: `https://steamcommunity.com/sharedfiles/filedetails/?id=${mapid}` }).then(data => data.result.ogImage[0].url);
|
const mapImage = await openGraphScraper({ url: `https://steamcommunity.com/sharedfiles/filedetails/?id=${mapid}` }).then(data => data.result.ogImage[0].url);
|
||||||
|
|
||||||
await req.app.locals.db.push("/courses", {
|
await db.push("/courses", {
|
||||||
[code]: {
|
[code]: {
|
||||||
map: fields.map,
|
map: fields.map,
|
||||||
uploader: {
|
uploader: {
|
||||||
|
@ -178,15 +184,17 @@ router.post("/update", isUserGame, async (req, res) => {
|
||||||
if (!headers.code) return res.status(401).json({ res: res.statusCode, message: "No code provided. Please provide a valid course code." });
|
if (!headers.code) return res.status(401).json({ res: res.statusCode, message: "No code provided. Please provide a valid course code." });
|
||||||
|
|
||||||
const ip = headers["cf-connecting-ip"] || "Unknown";
|
const ip = headers["cf-connecting-ip"] || "Unknown";
|
||||||
|
const db = req.app.locals.db;
|
||||||
const key = headers.authorization;
|
const key = headers.authorization;
|
||||||
const keys = await req.app.locals.db.getData("/keys");
|
const keys = await db.getData("/keys");
|
||||||
const steamIds = Object.fromEntries(Object.entries(keys).map(([k, v]) => [v, k]));
|
const steamIds = Object.fromEntries(Object.entries(keys).map(([k, v]) => [v, k]));
|
||||||
const steamid = steamIds[key];
|
const steamid = steamIds[key];
|
||||||
|
|
||||||
if (ip !== "Unknown" && (await req.app.locals.isRatelimited(ip))) return res.status(401).json({ message: "Too many requests. Please try again later." });
|
if (ip !== "Unknown" && (await isRatelimited(db, ip))) return res.status(401).json({ message: "Too many requests. Please try again later." });
|
||||||
if (ip !== "Unknown" && (await req.app.locals.isMultiAccount(ip, steamid))) return res.status(401).json({ message: "Your account was detected as multiaccount. Please open a ticket on our Discord server." });
|
if (ip !== "Unknown" && (await isMultiAccount(db, ip, steamid))) return res.status(401).json({ message: "Your account was detected as multiaccount. Please open a ticket on our Discord server." });
|
||||||
|
if (await isLocked(db, steamid)) return res.status(401).json({ res: res.statusCode, message: "Your account is locked. Please open a ticket on our Discord server." });
|
||||||
|
|
||||||
const courseData = await req.app.locals.db.getData(`/courses/${headers.code.toUpperCase()}`);
|
const courseData = await db.getData(`/courses/${headers.code.toUpperCase()}`);
|
||||||
|
|
||||||
if (courseData.map !== headers.map) return res.status(401).json({ res: res.statusCode, message: "Invalid map. You should provide the same map as before." });
|
if (courseData.map !== headers.map) return res.status(401).json({ res: res.statusCode, message: "Invalid map. You should provide the same map as before." });
|
||||||
if (courseData.uploader.userid !== steamIds[key]) return res.status(401).json({ res: res.statusCode, message: "Invalid key. You are not the uploader of this course. Only the uploader can update their course." });
|
if (courseData.uploader.userid !== steamIds[key]) return res.status(401).json({ res: res.statusCode, message: "Invalid key. You are not the uploader of this course. Only the uploader can update their course." });
|
||||||
|
@ -194,7 +202,7 @@ router.post("/update", isUserGame, async (req, res) => {
|
||||||
let course = "";
|
let course = "";
|
||||||
try {
|
try {
|
||||||
course = lzma.decompress(Buffer.from(headers.course, "base64"));
|
course = lzma.decompress(Buffer.from(headers.course, "base64"));
|
||||||
} catch (e) {
|
} catch {
|
||||||
course = Buffer.from(headers.course, "base64").toString("utf-8");
|
course = Buffer.from(headers.course, "base64").toString("utf-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +212,7 @@ router.post("/update", isUserGame, async (req, res) => {
|
||||||
|
|
||||||
courseData.time = Date.now();
|
courseData.time = Date.now();
|
||||||
|
|
||||||
await req.app.locals.db.push(`/courses/${headers.code.toUpperCase()}`, courseData);
|
await db.push(`/courses/${headers.code.toUpperCase()}`, courseData);
|
||||||
|
|
||||||
await log(
|
await log(
|
||||||
`[UPDATE] User updated a course (Course: ${headers.code.toUpperCase()}, SteamID: ${steamIds[key]}, Key ${key}).`,
|
`[UPDATE] User updated a course (Course: ${headers.code.toUpperCase()}, SteamID: ${steamIds[key]}, Key ${key}).`,
|
||||||
|
@ -242,7 +250,7 @@ router.post("/admin", isAdmin, async (req, res) => {
|
||||||
if (action === "addKey") {
|
if (action === "addKey") {
|
||||||
if (!target) return res.send({ success: false, message: "Target not provided. Please provide a target." });
|
if (!target) return res.send({ success: false, message: "Target not provided. Please provide a target." });
|
||||||
|
|
||||||
const key = await req.app.locals.getKey(target);
|
const key = await getKey(req.app.locals.db, target);
|
||||||
|
|
||||||
if (!key) return res.send({ success: false, message: "Internal error. Contact the developer." });
|
if (!key) return res.send({ success: false, message: "Internal error. Contact the developer." });
|
||||||
|
|
||||||
|
@ -364,7 +372,7 @@ router.get("/info/:code", async (req, res) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
course = await req.app.locals.db.getData(`/courses/${req.params.code.toUpperCase()}`);
|
course = await req.app.locals.db.getData(`/courses/${req.params.code.toUpperCase()}`);
|
||||||
} catch (e) {
|
} catch {
|
||||||
return res.status(401).json({ res: res.statusCode, message: "Invalid course code provided." });
|
return res.status(401).json({ res: res.statusCode, message: "Invalid course code provided." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ router.get("/", async (req, res) => {
|
||||||
let codeFile = "";
|
let codeFile = "";
|
||||||
try {
|
try {
|
||||||
codeFile = fs.readFileSync(`public/${codeData.path}`, "utf-8");
|
codeFile = fs.readFileSync(`public/${codeData.path}`, "utf-8");
|
||||||
} catch (e) {
|
} catch {
|
||||||
return console.log(`[WARNING] Not found file for: ${code}`);
|
return console.log(`[WARNING] Not found file for: ${code}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ const express = require("express"),
|
||||||
router = express.Router(),
|
router = express.Router(),
|
||||||
fetch = require("node-fetch");
|
fetch = require("node-fetch");
|
||||||
|
|
||||||
const { sanitize } = require("../utils/functions");
|
const { getKey, sanitize } = require("../utils/functions");
|
||||||
|
|
||||||
router.get("/", async (req, res) => {
|
router.get("/", async (req, res) => {
|
||||||
if (req.user) {
|
if (req.user) {
|
||||||
|
@ -55,7 +55,7 @@ async function registerUser(locals, user) {
|
||||||
if (!hasGame(locals, user)) return "Account doesn't have Garry's mod. Make sure your game details are public.";
|
if (!hasGame(locals, user)) return "Account doesn't have Garry's mod. Make sure your game details are public.";
|
||||||
|
|
||||||
const usernames = await locals.db.getData("/usernames");
|
const usernames = await locals.db.getData("/usernames");
|
||||||
const key = await locals.getKey(user);
|
const key = await getKey(locals.db, user);
|
||||||
const username = sanitize(user.personaname, false, true);
|
const username = sanitize(user.personaname, false, true);
|
||||||
|
|
||||||
usernames[user.steamid] = username || "Unknown";
|
usernames[user.steamid] = username || "Unknown";
|
||||||
|
|
|
@ -7,7 +7,7 @@ router.get("/:code", async (req, res) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
course = await req.app.locals.db.getData(`/courses/${req.params.code.toUpperCase()}`);
|
course = await req.app.locals.db.getData(`/courses/${req.params.code.toUpperCase()}`);
|
||||||
} catch (e) {
|
} catch {
|
||||||
return res.status(401).json({ res: res.statusCode, message: "Invalid course code provided." });
|
return res.status(401).json({ res: res.statusCode, message: "Invalid course code provided." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,35 @@ const fs = require("fs"),
|
||||||
config = require("../config"),
|
config = require("../config"),
|
||||||
fetch = require("node-fetch");
|
fetch = require("node-fetch");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new unique key for the given user and saves it to the database.
|
||||||
|
*
|
||||||
|
* @param {Object} db The database
|
||||||
|
* @param {Object | string} user The OpenID Steam user object or SteamID64.
|
||||||
|
* @returns {Promise<String>} The new unique key generated for the user.
|
||||||
|
*/
|
||||||
|
async function createKey(db, user) {
|
||||||
|
user = typeof user === "string" ? user : user.steamid;
|
||||||
|
|
||||||
|
const keys = await db.getData("/keys");
|
||||||
|
const key = generateRandomString();
|
||||||
|
const isFound = keys[key];
|
||||||
|
|
||||||
|
if (!isFound) {
|
||||||
|
keys[user] = key;
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
await log(
|
||||||
|
`[KEY] New user (SteamID: ${user}, Key: ${key}, TimeCreated: ${new Date(now).toLocaleString("ru-RU")}).`,
|
||||||
|
`[KEY] New user (SteamID: \`${user}\`, Key: \`${key}\`, TimeCreated: <t:${Math.floor(now / 1000)}:f>).`,
|
||||||
|
);
|
||||||
|
await db.push("/keys", keys);
|
||||||
|
|
||||||
|
return key;
|
||||||
|
} else return await createKey(db, user);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Middleware function that checks if the current user is an admin.
|
* Middleware function that checks if the current user is an admin.
|
||||||
* If the user is not an admin, it redirects them to the "/key" route.
|
* If the user is not an admin, it redirects them to the "/key" route.
|
||||||
|
@ -65,6 +94,115 @@ async function isUserGame(req, res, next) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an IP address is currently rate limited.
|
||||||
|
*
|
||||||
|
* Gets the current rate limits from the database.
|
||||||
|
* If the IP already has a recent rate limit, returns true.
|
||||||
|
* Otherwise, saves a new rate limit for the IP and returns false.
|
||||||
|
*
|
||||||
|
* @param {Object} db The database
|
||||||
|
* @param {string} ip The IP address to check
|
||||||
|
* @returns {Promise<boolean>} Whether the IP is currently rate limited
|
||||||
|
*/
|
||||||
|
async function isRatelimited(db, ip) {
|
||||||
|
const rateLimits = await db.getData("/ratelimits");
|
||||||
|
|
||||||
|
if (rateLimits[ip] && Date.now() - rateLimits[ip] <= config.rateLimitTime) return true;
|
||||||
|
|
||||||
|
rateLimits[ip] = Date.now();
|
||||||
|
|
||||||
|
await db.push("/ratelimits", rateLimits);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a user is using multiple accounts based on their IP address and Steam ID.
|
||||||
|
*
|
||||||
|
* Retrieves the locked accounts and user records from the database. If the user's account is locked, returns true.
|
||||||
|
* Otherwise, checks if the user has changed their IP address more than the configured `ipChangeTime`. If so, clears the
|
||||||
|
* user's IP address history and locks the account if the user has changed their IP more than 3 times. Updates the
|
||||||
|
* database with the new account status and returns the result.
|
||||||
|
*
|
||||||
|
* @param {Object} db The database
|
||||||
|
* @param {string} ip The IP address of the user.
|
||||||
|
* @param {string} steamid The Steam ID of the user.
|
||||||
|
* @returns {Promise<boolean>} Whether the user is using multiple accounts.
|
||||||
|
*/
|
||||||
|
async function isMultiAccount(db, ip, steamid) {
|
||||||
|
const locked = await db.getData("/locked");
|
||||||
|
const records = await db.getData("/records");
|
||||||
|
|
||||||
|
if (!records[steamid])
|
||||||
|
records[steamid] = {
|
||||||
|
ips: {
|
||||||
|
[ip]: true,
|
||||||
|
},
|
||||||
|
lastchanged: Date.now(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Clear IPs if the user has changed their ip more than ipChangeTime
|
||||||
|
if (Date.now() - records[steamid]["lastchanged"] > config.ipChangeTime) {
|
||||||
|
records[steamid] = {
|
||||||
|
ips: {},
|
||||||
|
lastchanged: Date.now(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock account if the user changed their IP more than 3 time in ipChangeTime
|
||||||
|
if (Object.keys(records[steamid]["ips"]).length > 2) {
|
||||||
|
locked[steamid] = true;
|
||||||
|
await db.push("/locked", locked);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.push("/records", records);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if user is locked from using the app.
|
||||||
|
*
|
||||||
|
* @param {Object} db The database
|
||||||
|
* @param {string} steamid The Steam ID of the user.
|
||||||
|
* @returns {Promise<boolean>} Whether the user is locked.
|
||||||
|
*/
|
||||||
|
async function isLocked(db, steamid) {
|
||||||
|
const locks = await db.getData("/locked");
|
||||||
|
|
||||||
|
if (locks[steamid]) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a user's key from the database.
|
||||||
|
*
|
||||||
|
* Checks if the user already has a key, and returns it if so.
|
||||||
|
* Otherwise generates a new one.
|
||||||
|
*
|
||||||
|
* @param {Object} db The database
|
||||||
|
* @param {Object | string} user The user object or SteamID64.
|
||||||
|
* @returns {Promise<String>} The user's key.
|
||||||
|
*/
|
||||||
|
async function getKey(db, user) {
|
||||||
|
user = typeof user === "string" ? user : user.steamid;
|
||||||
|
|
||||||
|
const keys = await db.getData("/keys");
|
||||||
|
const key = keys[user];
|
||||||
|
|
||||||
|
if (key) {
|
||||||
|
await log(
|
||||||
|
`[KEY] User logged in (SteamID: ${user}, Key ${key}).`,
|
||||||
|
`[KEY] User logged in (SteamID: \`${user}\`, Key \`${key}\`).`,
|
||||||
|
);
|
||||||
|
return key;
|
||||||
|
} else return await createKey(db, user);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a random string of the given length.
|
* Generates a random string of the given length.
|
||||||
*
|
*
|
||||||
|
@ -134,7 +272,6 @@ function isCourseFileValid(content) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs a message to a log file and optionally sends it to a Discord webhook.
|
* Logs a message to a log file and optionally sends it to a Discord webhook.
|
||||||
*
|
*
|
||||||
|
@ -162,4 +299,4 @@ async function log(logs_message, discord_message) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { isAdmin, isUser, isUserGame, generateRandomString, generateCode, sanitize, isCourseFileValid, log };
|
module.exports = { isAdmin, isUser, isUserGame, isRatelimited, isMultiAccount, isLocked, getKey, generateRandomString, generateCode, sanitize, isCourseFileValid, log };
|
||||||
|
|
Loading…
Reference in a new issue