119 lines
3.5 KiB
TypeScript
119 lines
3.5 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);
|
|
}
|
|
});
|
|
} |