UNPKG

@syngrisi/syngrisi

Version:
224 lines (203 loc) 6.99 kB
/** * Ensure that a user is logged in before proceeding to next route middleware. * * This middleware ensures that a user is logged in. If a request is received * that is unauthenticated, the request will be redirected to a login page (by * default to `/login`). * * Additionally, `returnTo` will be be set in the session to the URL of the * current request. After authentication, this value can be used to redirect * the user to the page that was originally requested. * * Options: * - `redirectTo` URL to redirect to for login, defaults to _/login_ * - `setReturnTo` set redirectTo in session, defaults to _true_ * * Examples: * * app.get('/profile', * ensureLoggedIn(), * function(req, res) { ... }); * * app.get('/profile', * ensureLoggedIn('/signin'), * function(req, res) { ... }); * * app.get('/profile', * ensureLoggedIn({ redirectTo: '/session/new', setReturnTo: false }), * function(req, res) { ... }); * * @param {Object} options * @return {Function} * @api public */ const { User } = require('../../models'); const $this = this; $this.logMeta = { scope: 'Authentication', msgType: 'LOGIN', }; // eslint-disable-next-line consistent-return const handleBasicAuth = async (req) => { const logOpts = { scope: 'handleBasicAuth', msgType: 'AUTH_API', }; if (req.isAuthenticated()) { return { type: 'success', status: 200 }; } if (!(await global.AppSettings.isAuthEnabled())) { const guest = await User.findOne({ username: 'Guest' }); // noinspection UnnecessaryLocalVariableJS const result = new Promise((resolve) => { req.logIn(guest, (err) => { if (err) { log.error(`cannot find quest user: '${err}'`, $this, logOpts); resolve({ type: 'redirect', status: 301, value: `/auth?=Error: cannot find quest user: ${err}`, user: null, }); } else { resolve({ type: 'success', status: 200, value: '', user: guest, }); } }); }); return result; } const result = { type: 'error', status: 400, value: '', user: null, }; if ((await global.AppSettings.isAuthEnabled()) && ((await global.AppSettings.isFirstRun())) && process.env.SYNGRISI_DISABLE_FIRST_RUN !== '1' ) { log.info('first run, set admin password', $this, logOpts); result.type = 'redirect'; result.status = 301; result.value = '/auth/change?first_run=true'; return result; } if (await global.AppSettings.isAuthEnabled()) { log.info(`user is not authenticated - ${req.originalUrl}`, $this, logOpts); result.type = 'redirect'; result.status = 301; if (req?.originalUrl !== '/') { result.value = `/auth?origin=${encodeURIComponent(req.originalUrl)}`; return result; } result.value = '/auth'; return result; } }; exports.ensureLoggedIn = function ensureLoggedIn() { // eslint-disable-next-line consistent-return return async (req, res, next) => { const result = await handleBasicAuth(req); // log.silly(result, { // scope: 'ensureLoggedIn', // msgType: 'AUTH_API', // }, $this); req.user = result.user || req.user; if (result.type === 'success') { return next(); } res.status(result.status) .redirect(result.value); return next('redirect'); }; }; const handleAPIAuth = async (hashedApiKey) => { const logOpts = { scope: 'handleAPIAuth', msgType: 'AUTH_API', }; const result = { status: 400, type: 'error', value: '', user: null, }; if (!(await global.AppSettings.isAuthEnabled())) { const guest = await User.findOne({ username: 'Guest' }); if (!guest) { log.error('cannot find Guest user'); result.type = 'error'; result.value = 'cannot find Guest user'; return result; } log.debug('authentication disabled', logOpts, { user: 'Guest' }); result.type = 'success'; result.user = guest; result.status = 200; return result; } if (!hashedApiKey) { log.debug('API key missing', logOpts); result.type = 'error'; result.status = 401; result.value = 'API key missing'; return result; } const user = await User.findOne({ apiKey: hashedApiKey }); if (!user) { log.error(`wrong API key: ${hashedApiKey}`, logOpts); result.type = 'error'; result.status = 401; result.value = 'wrong API key'; return result; } log.debug('authenticated', $this, { ...logOpts, ...{ user: user?.username } }); result.type = 'success'; result.status = 200; result.user = user; return result; }; exports.ensureApiKey = function ensureApiKey() { const logOpts = { scope: 'ensureApiKey', msgType: 'AUTH_API', }; // eslint-disable-next-line consistent-return return async (req, res, next) => { log.silly(`headers: ${JSON.stringify(req.headers, null, '..')}`, logOpts); log.silly(`SYNGRISI_AUTH: '${process.env.SYNGRISI_AUTH}'`); const hashedApiKey = req.headers.apikey || req.query.apikey; const result = await handleAPIAuth(hashedApiKey); req.user = req.user || result.user; req.headers.apikey = result?.user?.apiKey || req?.headers?.apikey; if (result.type !== 'success') { log.info(`${result.value} - ${req.originalUrl}`, $this, logOpts); res.status(result.status) .json({ error: result.value }); return next(new Error(result.value)); } return next(); }; }; exports.ensureLoggedInOrApiKey = () => async (req, res, next) => { const basicAuthResult = await handleBasicAuth(req); const hashedApiKey = req.headers.apikey || req.query.apikey; const apiKeyResult = await handleAPIAuth(hashedApiKey); req.user = req.user || apiKeyResult.user; if ( (basicAuthResult.type !== 'success') && (apiKeyResult.type !== 'success') ) { log.info(`Unauthorized - ${req.originalUrl}`); // res.status(401).json({ error: `${`${apiKeyResult.value} ${basicAuthResult.value}`} - ${req.originalUrl}` }); res.status(401) .json({ error: `Unauthorized - ${req.originalUrl}` }); return next(new Error(`Unauthorized - ${req.originalUrl}`)); } return next(); };