banana
/
definma-api
Archived
2
Fork 0
This repository has been archived on 2023-03-02. You can view files and clone it, but cannot push or open issues or pull requests.
definma-api/src/helpers/authorize.ts

120 lines
3.2 KiB
TypeScript

import basicAuth from 'basic-auth';
import bcrypt from 'bcryptjs';
import UserModel from '../models/user';
import globals from '../globals';
// appends req.auth(res, ['levels'], method = 'all')
// which returns sends error message and returns false if unauthorized, otherwise true
// req.authDetails returns eg. {methods: ['basic'], username: 'johndoe', level: 'write'}
module.exports = async (req, res, next) => {
let givenMethod = ''; // authorization method given by client, basic taken preferred
let user = {name: '', level: '', id: '', location: '', models: []}; // user object
// test authentications
const userBasic = await basic(req, next);
if (userBasic) { // basic available
givenMethod = 'basic';
user = userBasic;
}
else { // if basic not available, test key
const userKey = await key(req, next);
if (userKey) {
givenMethod = 'key';
user = userKey;
}
}
req.auth = (res, levels, method = 'all') => {
if (givenMethod === method || (method === 'all' && givenMethod !== '')) { // method is available
if (levels.indexOf(user.level) > -1) { // level is available
return true;
}
else {
res.status(403).json({status: 'Forbidden'});
return false;
}
}
else {
res.status(401).json({status: 'Unauthorized'});
return false;
}
}
req.authDetails = {
method: givenMethod,
username: user.name,
level: user.level,
id: user.id,
location: user.location,
models: user.models
};
next();
}
function basic (req, next): any { // checks basic auth and returns changed user object
return new Promise(resolve => {
const auth = basicAuth(req);
if (auth !== undefined) { // basic auth available
UserModel.find({name: auth.name, status: globals.status.new}).lean().exec( (err, data: any) => { // find user
if (err) return next(err);
if (data.length === 1) { // one user found
bcrypt.compare(auth.pass, data[0].pass, (err, res) => { // check password
if (err) return next(err);
if (res === true) { // password correct
resolve({
level: Object.entries(globals.levels).find(e => e[1] === data[0].level)[0],
name: data[0].name,
id: data[0]._id.toString(),
location: data[0].location,
models: data[0].models
});
}
else {
resolve(null);
}
});
}
else {
resolve(null);
}
});
}
else {
resolve(null);
}
});
}
function key (req, next): any { // checks API key and returns changed user object
return new Promise(resolve => {
if (req.query.key !== undefined) { // key available
UserModel.find({key: req.query.key, status: globals.status.new}).lean().exec( (err, data: any) => { // find user
if (err) return next(err);
if (data.length === 1) { // one user found
resolve({
level: Object.entries(globals.levels).find(e => e[1] === data[0].level)[0],
name: data[0].name,
id: data[0]._id.toString(),
location: data[0].location,
models: data[0].models
});
if (!/^\/api/m.test(req.url)){
delete req.query.key; // delete query parameter to avoid interference with later validation
}
}
else {
resolve(null);
}
});
}
else {
resolve(null);
}
});
}