diff --git a/api/ani/v1/routes/stats.js b/api/ani/v1/routes/stats.js new file mode 100644 index 0000000..32db483 --- /dev/null +++ b/api/ani/v1/routes/stats.js @@ -0,0 +1,5 @@ +module.exports = (app, router) => { + router.get('/stats', (req, res) => res.json({ + users: Object.keys(app.cache.users).length + })); +}; \ No newline at end of file diff --git a/api/ani/v1/routes/user.js b/api/ani/v1/routes/user.js index 9ef0506..3a659c2 100644 --- a/api/ani/v1/routes/user.js +++ b/api/ani/v1/routes/user.js @@ -4,8 +4,9 @@ const {sign} = require('jsonwebtoken'); module.exports = (app, router) => { const Users = app.db.models.ani.users; - router.get('/user', (req, res) => res.send("/user: /user/:id required.")); - //router.use(app.util.list(router, '/user')); //list users + //router.get('/user', (req, res) => res.send("/user: /user/:id required.")); + router.use('/users', (req, res, next) => {req.listData = Object.keys(app.cache.users); next()}, app.util.list(router, '/users')); //list users + router.use('/user', (req, res, next) => {req.listData = Object.keys(app.cache.users); next()}, app.util.list(router, '/user')); router.route('/user/:id') .get(async (req, res) => { @@ -34,14 +35,17 @@ module.exports = (app, router) => { password: hashSync(req.body.password, 8) }); return newUser.save() - .then(() => res.json({ - message: "Successfully added user.", - name: newUser.name, - discord: newUser.discord, - id: newUser.id, - permissions: newUser.permissions, - accessToken: sign({id: newUser.id}, app.auth.jwt_secret, {expiresIn: "15d"}) - })) + .then(() => { + app.cache.users[newUser.id] = {id: newUser.id, discord: newUser.discord}; + return res.json({ + message: "Successfully added user.", + name: newUser.name, + discord: newUser.discord, + id: newUser.id, + permissions: newUser.permissions, + accessToken: sign({id: newUser.id}, app.auth.jwt_secret, {expiresIn: "15d"}) + }); + }) .catch(e => {console.error("Error trying to add new user", e); res.status(500).send("Something went wrong.");}); } catch (e) {console.error("Error trying to add new user", e); res.status(500).send("Something went wrong.");} @@ -66,17 +70,17 @@ module.exports = (app, router) => { }); }) .get(app.auth.token, (req, res) => { - if (!req.user) {return res.status(401).send("You have not been authenticated, and will not be able to access any sensitive routes.");} + if (!req.authenticatedUser) {return res.status(401).send("You have not been authenticated, and will not be able to access any sensitive routes.");} return res.json({ message: "You are authenticated, and your token is valid.", - name: req.user.name, - discord: req.user.discord, - id: req.user.id, - permissions: req.user.permissions + name: req.authenticatedUser.name, + discord: req.authenticatedUser.discord, + id: req.authenticatedUser.id, + permissions: req.authenticatedUser.permissions }); }); - router.use('/user/:id/permissions', async (req, res, next) => { + router.use('/user/:id/permissions', app.auth.tokenPass, async (req, res, next) => { if (!req.params.id) {return res.status(400).send("Missing ID!");} const user = await Users.findOne({id: req.params.id.toLowerCase()}); if (!user) {return res.status(404).send("That user doesn't exist!");} @@ -89,5 +93,5 @@ module.exports = (app, router) => { req.user.permissions = permissions; req.user.markModified('permissions'); await req.user.save(); - })); + }, (req, res, next) => {if (!req.authenticatedUser) {return res.status(401).send("You must be authenticated before you do that!");} next();})); }; \ No newline at end of file diff --git a/api/index.js b/api/index.js index 7f5785d..96adabe 100644 --- a/api/index.js +++ b/api/index.js @@ -40,6 +40,8 @@ server = app.listen(4062, async () => { app.util = {}; app.util.list = require('./util/list'); + await require('./util/startup/cache')(app); + require('./v1/index')(app); //initialize bot API branch require('./ani/index')(app); //initialize ani API branch diff --git a/api/util/baseAuthorize.js b/api/util/baseAuthorize.js index d70cf7d..7fb5872 100644 --- a/api/util/baseAuthorize.js +++ b/api/util/baseAuthorize.js @@ -5,13 +5,13 @@ module.exports = (app, passAuth) => { return (req, res, next) => { if (req.headers && req.headers.authorization && req.headers.authorization.split(" ")[0] === "JWT") { verify(req.headers.authorization.split(' ')[1], app.auth.jwt_secret, (e, d) => { - if (e) {req.user = undefined; return passAuth ? next() : res.status(401).send("You are not authenticated!");} + if (e) {req.authenticatedUser = undefined; return passAuth ? next() : res.status(401).send("You are not authenticated!");} Users.findOne({id: d.id}) .exec((err, user) => { if (err) {res.status(500).send("Something went trying to authorize you!");} - else {req.user = user; next();} + else {req.authenticatedUser = user; next();} }); }); - } + } else {req.authenticatedUser = undefined; return passAuth ? next() : res.status(401).send("You are not authenticated; you did not send your request with any authentication headers.");} }; }; \ No newline at end of file diff --git a/api/util/list.js b/api/util/list.js index 3e37b30..4c7958e 100644 --- a/api/util/list.js +++ b/api/util/list.js @@ -1,6 +1,6 @@ const {Router} = require("express"); -module.exports = (parentRouter, path, modifiable, bodyName, save) => { +module.exports = (parentRouter, path, modifiable, bodyName, save, authHandler) => { const router = Router(); router.get("/", (req, res) => res.json(req.listData)); @@ -14,18 +14,21 @@ module.exports = (parentRouter, path, modifiable, bodyName, save) => { req.listData.push(req.body[bodyName]); return await save(req, res, req.listData, req.body[bodyName]) || res.json(req.listData); } - router.post('/add', add); - router.post('/', add); - router.post('/clear', async (req, res) => { + router.post('/add', authHandler, add); + router.post('/', authHandler, add); + router.post('/clear', authHandler, async (req, res) => { req.listData = []; return await save(req, res, req.listData) || res.json(req.listData); }); - router.delete('/remove', async (req, res) => { + router.delete('/remove', authHandler, async (req, res) => { if (!req.body[bodyName]) {return res.status(400).send(`Missing body param "${bodyName}".`);} let index = req.listData.indexOf(req.body[bodyName]); if (index === -1) {return res.status(400).send("The server was unable to find an item matching the specified criteria.");} let length = req.listData.length; - req.listData = req.listData.length === 1 && req.listData[0] === req.body[bodyName] ? [] : req.listData.splice(req.listData.indexOf(req.body[bodyName]), 1); + + if (req.listData.length === 1 && req.listData[0] === req.body[bodyName]) {req.listData = [];} + else {req.listData.splice(req.listData.indexOf(req.body[bodyName]), 1);} + return req.listData.length === length ? res.status(500).send("For some reason, that couldn't be removed.") : await save(req, res, req.listData) || res.json(req.listData); }); } diff --git a/api/util/startup/cache.js b/api/util/startup/cache.js new file mode 100644 index 0000000..a0ef987 --- /dev/null +++ b/api/util/startup/cache.js @@ -0,0 +1,21 @@ +const gs = require('gradient-string'); +const spinnies = require('dreidels'); +const chalk = require('chalk'); + +module.exports = async app => { + app.cache = { + users: {} + }; + + return new Promise(async resolve => { + const loaders = []; + const spin = new spinnies(); + + let userCache = spin.add("ar", {text: "Caching Users..."}); + loaders.push(require('./cache/users')(app, userCache)); + + await Promise.all(loaders); + console.log(''); + resolve(0); + }); +}; //robbery is cool :) \ No newline at end of file diff --git a/api/util/startup/cache/users.js b/api/util/startup/cache/users.js new file mode 100644 index 0000000..c937a55 --- /dev/null +++ b/api/util/startup/cache/users.js @@ -0,0 +1,24 @@ +const chalk = require('chalk'); + +module.exports = async (app, spinner) => { + const Users = app.db.models.ani.users; + + return new Promise(async resolve => { + const st = new Date().getTime(); + + let amount = 1; + + for await (const user of Users.find()) { + app.cache.users[user.id] = {id: user.id, discord: user.discord}; + spinner.update({text: `${chalk.gray('[PROC]')} >> ${chalk.blueBright(`Cached`)} ${chalk.white(`${amount}`)} ${chalk.blueBright(`ani DB users.`)}`}); + amount++; + } + + const cacheTime = new Date().getTime() - st; + spinner.update({text: `${spinner.options.text.slice(0, 19).trim()} ${chalk.gray(`${cacheTime}ms >>`.padStart(8, '0').padStart(7, '0'))} ${spinner.options.text.slice(19).trim()}`}); + spinner.status('non-spinnable'); + + resolve(0); + }); +} //robbery is like, the best +// ...it's my own code don't @ me \ No newline at end of file diff --git a/db/ani/users.js b/db/ani/users.js index 33d11dc..ab01e9e 100644 --- a/db/ani/users.js +++ b/db/ani/users.js @@ -6,5 +6,5 @@ module.exports = (connection) => connection.model('users', new Schema({ discord: {type: String, unique: true}, permissions: [String], password: String, - apiToken: {type: String, unique: true} + apiToken: String })); \ No newline at end of file diff --git a/package.json b/package.json index 4db2813..65c4feb 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,13 @@ "dependencies": { "bcrypt": "^5.1.0", "body-parser": "^1.20.1", + "chalk": "^4.1.0", "cors": "^2.8.5", "discord.js": "^14.7.1", + "dreidels": "^0.5.2", "express": "^4.18.2", + "fuzzysort": "^2.0.4", + "gradient-string": "^2.0.2", "helmet": "^6.0.1", "jsonwebtoken": "^9.0.0", "mongoose": "^6.8.4"