import basicAuth from 'basic-auth'; import bcrypt from 'bcryptjs'; import UserModel from '../models/user'; // 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: ''}; // 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 }; 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}).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: data[0].level, name: data[0].name, id: data[0]._id.toString(), location: data[0].location}); } 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}).lean().exec( (err, data: any) => { // find user if (err) return next(err); if (data.length === 1) { // one user found resolve({level: data[0].level, name: data[0].name, id: data[0]._id.toString(), location: data[0].location}); } else { resolve(null); } }); } else { resolve(null); } }); }