api user routes and auth setup

master
Kit Kasune 2 years ago
commit 6d35b93d9b
  1. 5
      api/ani/index.js
  2. 3
      api/ani/v1/index.js
  3. 15
      api/ani/v1/router.js
  4. 77
      api/ani/v1/routes/user.js
  5. 17
      api/baseAuthorize.js
  6. 41
      api/index.js
  7. 3
      api/v1/index.js

@ -0,0 +1,5 @@
module.exports = app => {
app.get('/ani', (req, res) => res.send("This is the Natsuki Anime Database API! We're currently at v1, so direct your queries to /ani/v1/."));
require('./v1/index')(app);
};

@ -0,0 +1,3 @@
module.exports = app => {
app.use('/ani/v1', require('./router')(app));
};

@ -0,0 +1,15 @@
const fs = require('fs');
const {Router} = require("express");
const router = Router();
module.exports = app => {
router
.use((req, res, next) => {console.log(`[ANI/v1] ${req.path} | [${req.method}]`); next()})
.get('/', (req, res) => res.send("This is the Natsuki Anime DB API v1 head."))
fs.readdirSync('./ani/v1/routes').filter(file => file.endsWith('.js'))
.forEach(route => require(`./routes/${route}`)(app, router)); //execute all router functions
return router;
};

@ -0,0 +1,77 @@
const {hashSync, compareSync} = require('bcrypt');
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.route('/user/:id')
.get(async (req, res) => {
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!");}
return res.json({name: user.name, discord: user.discord, id: user.id, permissions: user.permissions});
})
.post(async (req, res) => { //TODO validate Discord ID
try {
if (!req.params.id) {return res.status(400).send("Missing ID!");}
if (await Users.findOne({id: req.params.id.toLowerCase()})) {return res.status(400).send("That user already exists!");}
if (!req.body) {return res.status(400).send("Missing body!");}
if (
!req.body.name || !req.body.discord || !req.body.permissions || !Array.isArray(req.body.permissions)
|| !req.body.name.match(/^[\w_ ]+$/gm) || req.body.name.length > 20
|| !req.params.id.toLowerCase().match(/^[\w_]+$/gm) || req.params.id.toLowerCase().length > 15
|| !req.body.password || req.body.password.length > 30
) {return res.status(400).send("Malformed body or missing body data. Make sure you have all the required parameters, and you don't have illegal characters present.");}
const newUser = new Users({
id: req.params.id.toLowerCase(),
name: req.body.name,
permissions: req.body.permissions,
discord: req.body.discord,
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"})
}))
.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.");}
})
.put(app.auth.token, async (req, res) => {
});
router.route('/user/:id/auth')
.post(async (req, res) => {
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!");}
if (!req.body.password || !compareSync(req.body.password, user.password)) {return res.status(401).json({accessToken: null, message: "Invalid or missing password!"});}
return res.json({
message: "Successfully authenticated.",
name: user.name,
discord: user.discord,
id: user.id,
permissions: user.permissions,
accessToken: sign({id: user.id}, app.auth.jwt_secret, {expiresIn: "15d"})
});
})
.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.");}
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
});
});
};

@ -0,0 +1,17 @@
const {verify} = require("jsonwebtoken");
module.exports = app => {
const Users = app.db.models.ani.users
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 next();}
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();}
});
});
}
};
};

@ -0,0 +1,41 @@
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const helmet = require('helmet');
const {set, createConnection} = require('mongoose');
const app = express();
set('strictQuery', false);
app.use(helmet());
app.use(bodyParser.json());
app.use(cors());
app.use(express.urlencoded({extended: true}));
app.get('/', (req, res) => res.send("You've reached the Natsuki API! This 200 status indicates we're online, and currently on v1. Natsuki bot-related queries live at /v1/, ani database queries live at /ani/v1/."));
app.auth = {};
app.auth.jwt_secret = require('../auth.json').jwt_secret;
let server;
const anidb = createConnection(`mongodb://127.0.0.1:27017/natsuki-anime-api`, {
useNewUrlParser: true, dbName: 'natsuki-anime-api', useUnifiedTopology: true
});
const botdb = createConnection(`mongodb://127.0.0.1:27017/natsuki-api`, {
useNewUrlParser: true, dbName: 'natsuki-api', useUnifiedTopology: true
});
console.log("Connected to Mongo Databases");
server = app.listen(4062, async () => {
console.log(`API online at port ${server.address().port}`);
app.db = {}; //set db connections into app object
app.db.ani = anidb;
app.db.bot = botdb;
require('../db/build')(app); //place all models in memory to prevent double-compiling
app.auth.token = require('./baseAuthorize')(app); //jwt token validation
require('./v1/index')(app); //initialize bot API branch
require('./ani/index')(app); //initialize ani API branch
});

@ -0,0 +1,3 @@
module.exports = (app) => {
app.get('/v1', (req, res) => res.send("This is the Natsuki API v1 head."));
};
Loading…
Cancel
Save