commit
6d35b93d9b
@ -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…
Reference in new issue