pis #12

Merged
fred.boniface merged 95 commits from pis into main 2023-05-06 21:54:51 +01:00
10 changed files with 58 additions and 38 deletions
Showing only changes of commit 096ce154da - Show all commits

9
app.js
View File

@ -12,6 +12,7 @@ const app = express();
// Middleware // Middleware
const compression = require('compression') const compression = require('compression')
const rateLimit = require('express-rate-limit')
const authenticate= require('./src/middlewares/auth.middlewares') const authenticate= require('./src/middlewares/auth.middlewares')
// Internal Requires // Internal Requires
@ -29,6 +30,13 @@ const regRtr = require('./src/routes/registration.routes'); // /auth end
const srvListen = process.env.OWL_SRV_LISTEN || "0.0.0.0" const srvListen = process.env.OWL_SRV_LISTEN || "0.0.0.0"
const srvPort = process.env.OWL_SRV_PORT || 8460 const srvPort = process.env.OWL_SRV_PORT || 8460
const limiter = rateLimit({
windowMs: 15 * (60 * 1000), // 15 minutes
max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: true, // Disable the `X-RateLimit-*` headers
})
// Print version number: // Print version number:
log.out(`app: Starting OwlBoard - Backend Version: ${version.app} - API versions: ${version.api}`, "init"); log.out(`app: Starting OwlBoard - Backend Version: ${version.app} - API versions: ${version.api}`, "init");
@ -52,6 +60,7 @@ app.use((err, req, res, next) => {
// Global Middleware: // Global Middleware:
app.use(express.json()); //JSON Parsing for POST Requests app.use(express.json()); //JSON Parsing for POST Requests
app.use(compression()) // Compress API Data if supported by client app.use(compression()) // Compress API Data if supported by client
app.use(limiter)
// Unauthenticated Routes // Unauthenticated Routes
app.use('/api/v1/list', listRtr); app.use('/api/v1/list', listRtr);

12
package-lock.json generated
View File

@ -12,6 +12,7 @@
"axios": "^1.2.1", "axios": "^1.2.1",
"compression": "^1.7.4", "compression": "^1.7.4",
"express": "^4.18.2", "express": "^4.18.2",
"express-rate-limit": "^6.7.0",
"ldbs-json": "^1.2.1", "ldbs-json": "^1.2.1",
"mongodb": "^4.13.0", "mongodb": "^4.13.0",
"nodemailer": "^6.9.1", "nodemailer": "^6.9.1",
@ -1426,6 +1427,17 @@
"node": ">= 0.10.0" "node": ">= 0.10.0"
} }
}, },
"node_modules/express-rate-limit": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz",
"integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA==",
"engines": {
"node": ">= 12.9.0"
},
"peerDependencies": {
"express": "^4 || ^5"
}
},
"node_modules/express/node_modules/safe-buffer": { "node_modules/express/node_modules/safe-buffer": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",

View File

@ -3,6 +3,7 @@
"axios": "^1.2.1", "axios": "^1.2.1",
"compression": "^1.7.4", "compression": "^1.7.4",
"express": "^4.18.2", "express": "^4.18.2",
"express-rate-limit": "^6.7.0",
"ldbs-json": "^1.2.1", "ldbs-json": "^1.2.1",
"mongodb": "^4.13.0", "mongodb": "^4.13.0",
"nodemailer": "^6.9.1", "nodemailer": "^6.9.1",

View File

@ -11,7 +11,7 @@ module.exports = async function authCheck(req, res, next) {
return next(err) return next(err)
} }
try { try {
var result = await utils.isAuthed(uuid) | false var result = await utils.isAuthed(uuid) || false
if (!result) { if (!result) {
const err = new Error("Unauthorised"); const err = new Error("Unauthorised");
err.status = 401 err.status = 401

View File

@ -23,7 +23,7 @@ async function send(message){ // message is an object containing strings for: *t
try { try {
var res = await transporter.sendMail(message) var res = await transporter.sendMail(message)
} catch(err) { } catch(err) {
log.out(`mailServices.send: Message send failed`, "err") log.out(`mailServices.send: Message send failed: ${err}`, "err")
return false; return false;
} }
log.out(`mailServices.send: SMTP Response: ${res.response}`) log.out(`mailServices.send: SMTP Response: ${res.response}`)

View File

@ -7,15 +7,14 @@ const domains = require('../configs/domains.configs')
async function createRegKey(body) { async function createRegKey(body) {
log.out(`registerServices.createRegKey: Incoming request`, "INFO") log.out(`registerServices.createRegKey: Incoming request`, "INFO")
log.out(`registerServices.createRegKey: ${JSON.stringify(domains)}`) const domain = await clean.getDomainFromEmail(body.email) // The function should validate the email
const domain = await clean.splitDomain(body.email)
log.out(`registerServices: New registration request from domain: ${domain}`, "info") log.out(`registerServices: New registration request from domain: ${domain}`, "info")
if (domains.includes(domain)) { // Needs testing if (domains.includes(domain)) {
log.out(`registerServices.createRegKey: Key from valid domain: ${domain}`) log.out(`registerServices.createRegKey: Key from valid domain: ${domain}`)
const uuid = auth.generateKey(); const uuid = await auth.generateKey();
db.addRegReq(await uuid, domain) db.addRegReq(uuid, domain)
const message = auth.generateConfirmationEmail(body.email, uuid) const message = await auth.generateConfirmationEmail(body.email, uuid)
if (await message == false) { // This error should be handled in the upstream function if (!message) {
const err = new Error("Message generation error"); const err = new Error("Message generation error");
log.out(`registerServices.createRegKey: Error generating registration email`, "err") log.out(`registerServices.createRegKey: Error generating registration email`, "err")
return 500; return 500;
@ -28,19 +27,19 @@ async function createRegKey(body){
return {status: 403, message: "forbidden, domain is not on whitelist"} return {status: 403, message: "forbidden, domain is not on whitelist"}
} }
async function regUser(req) { async function regUser(req) { // Add input validation
log.out(`registrationServices.regUser: Checking validity of : ${req.uuid}`) log.out(`registrationServices.regUser: Checking validity of : ${req.uuid}`, "info")
let res = await auth.checkRequest(req.uuid) const res = await auth.checkRequest(req.uuid)
log.out(`registrationServices.regUser: checkRequest returned: ${JSON.stringify(res)}`) log.out(`registrationServices.regUser: checkRequest returned: ${JSON.stringify(res)}`, "info")
if (res.result) { if (res.result) {
let uuid = await auth.generateKey() const uuid = await auth.generateKey()
let apiKey = await db.addUser(uuid, res.domain) const apiKey = await db.addUser(uuid, res.domain)
if (apiKey) { if (apiKey) {
db.delRegReq(req.uuid) db.delRegReq(req.uuid)
return {status: 201, message: "User added", api_key: uuid} return {status: 201, message: "User added", api_key: uuid}
} }
} }
return {status: 401, message: "Unautorised"} return {status: 401, message: "Unauthorised"}
} }
module.exports = { module.exports = {

View File

@ -5,27 +5,24 @@ const fs = require('fs/promises')
// Checks users registration key against issued keys // Checks users registration key against issued keys
async function isAuthed(uuid) { // Needs testing async function isAuthed(uuid) { // Needs testing
q = {uuid: uuid}; const q = {uuid: uuid}
res = await db.query("users", q); const res = await db.query("users", q)
log.out(`authUtils.checkUser: DB Query answer: ${JSON.stringify(res[0])}`) log.out(`authUtils.checkUser: DB Query answer: ${JSON.stringify(res[0])}`, "dbug")
// Do something here to determine if authorised or not and simply return a BOOL const authorized = res && res[0] && res[0].domain;
if (res[0].domain) { if (authorized) db.userAtime(uuid)
db.userAtime(uuid) return authorized
return true
}
return false
} }
// Checks whether a registration request key is valid // Checks whether a registration request key is valid
async function checkRequest(key) { async function checkRequest(key) {
let collection = "registrations" const collection = "registrations"
let query = {uuid: key} const query = {uuid: key}
const res = await db.query(collection, query) const res = await db.query(collection, query)
log.out(`authUtils.checkRequest: DB Query result: ${JSON.stringify(res)}`, "info") log.out(`authUtils.checkRequest: DB Query result: ${JSON.stringify(res)}`, "dbug")
if (res[0].time) { const result = res.length > 0 && res[0].time
return {result: true, domain: res[0].domain} ? { result: true, domain: res[0].domain }
} : { result: false };
return {result: false} return result;
} }
// Creates an API key for a user // Creates an API key for a user

View File

@ -4,10 +4,10 @@ const san = require('../utils/sanitizer.utils') // Sanitiser
async function checkCrs(input){ async function checkCrs(input){
var INPUT = input.toUpperCase() var INPUT = input.toUpperCase()
log.out(`ldbUtils.checkCrs: Building database query to find: '${INPUT}'`, "info") log.out(`ldbUtils.checkCrs: Building database query to find: '${INPUT}'`, "dbug")
var query = {'$or':[{'3ALPHA':INPUT},{'TIPLOC':INPUT},{'STANOX':INPUT}]}; var query = {'$or':[{'3ALPHA':INPUT},{'TIPLOC':INPUT},{'STANOX':INPUT}]};
var result = await db.query("stations", query) var result = await db.query("stations", query)
log.out(`ldbUtils.checkCrs: Query results: ${JSON.stringify(result)}`, "info") log.out(`ldbUtils.checkCrs: Query results: ${JSON.stringify(result)}`, "dbug")
return result return result
} }

View File

@ -1,7 +1,9 @@
const environment = process.env.NODE_ENV; const environment = process.env.NODE_ENV;
const hideInProduction = ["info", "dbug"]
async function out(msg, level = 'othr') { async function out(msg, level = 'othr') {
if (environment === "production" && level === "info") { if (environment === "production" && hideInProduction.includes(level)) {
return; return;
} else { } else {
const time = new Date().toISOString(); const time = new Date().toISOString();

View File

@ -38,7 +38,7 @@ function cleanNrcc(input) {
return rmPara; return rmPara;
} }
async function splitDomain(mail) { // Needs testing async function getDomainFromEmail(mail) { // Needs testing
split = mail.split("@") split = mail.split("@")
return split[1] return split[1]
} }
@ -47,5 +47,5 @@ module.exports = {
cleanApiEndpointTxt, cleanApiEndpointTxt,
cleanApiEndpointNum, cleanApiEndpointNum,
cleanNrcc, cleanNrcc,
splitDomain getDomainFromEmail
} }