ravel
Version:
Ravel Rapid Application Development Framework
126 lines (116 loc) • 6.34 kB
JavaScript
;function _asyncToGenerator(fn) {return function () {var gen = fn.apply(this, arguments);return new Promise(function (resolve, reject) {function step(key, arg) {try {var info = gen[key](arg);var value = info.value;} catch (error) {reject(error);return;}if (info.done) {resolve(value);} else {return Promise.resolve(value).then(function (value) {step("next", value);}, function (err) {step("throw", err);});}}return step("next");});};}
const httpCodes = require('../util/http_codes');
const symbols = require('./symbols');
const sRavelInstance = Symbol.for('_ravelInstance');
const sShouldRedirect = Symbol.for('_shouldRedirect');
const sAllowMobileRegistration = Symbol.for('_allowMobileRegistration');
const sTokenAuth = Symbol.for('_tokenAuth');
/**
* Factory for Koa-style middleware which authenticates a request to a route, using
* either a web-based user's session, or a mobile-based user's authentication token
* (the latter being supplied via the x-auth-token header).
*
* Non-web clients must also identify their type using an x-auth-client header
* such as:
* - 'google-oauth2-ios' (for an iOS device)
* - 'google-oauth2-web' (for a web browser)
* See specific authentication provider for more details.
* @private
*/let
AuthenticationMiddleware = class AuthenticationMiddleware {
/**
* @private
* @param {Object} ravelInstance - An instance of a Ravel app.
* @param {boolean} shouldRedirect - True iff this middleware should redirect to the login page when a
* user is not authenticated.
* @param {boolean} allowMobileRegistration - True iff this middleware should automatically register mobile clients
* the first time they are seen.
*/
constructor(ravelInstance, shouldRedirect, allowMobileRegistration) {
this[sRavelInstance] = ravelInstance;
this[sShouldRedirect] = shouldRedirect;
this[sAllowMobileRegistration] = allowMobileRegistration;
this[sTokenAuth] = require('./authenticate_token')(ravelInstance);
}
/**
* @returns {Ravel} The Ravel app associated with this AuthenticationMiddleware. Useful for subclasses.
* @private
*/
get ravelInstance() {
return this[sRavelInstance];
}
/**
* @returns {boolean} The value of shouldRedirect, as passed into the constructor. Useful for subclasses.
* @private
*/
get shouldRedirect() {
return this[sShouldRedirect];
}
/**
* @returns {boolean} The value of allowMobileRegistration, as passed into the constructor. Useful for subclasses.
* @private
*/
get allowMobileRegistration() {
return this[sAllowMobileRegistration];
}
/**
* @returns {AsyncFunction} Koa-compatible middleware which validates a web session or mobile auth token,
* potentially redirecting if the user is not authenticated, or registering an
* unknown mobile client automatically.
* @private
*/
middleware() {
const self = this;
return (() => {var _ref = _asyncToGenerator(function* (ctx, next) {
let promise;
if (ctx.headers['x-auth-token'] && ctx.headers['x-auth-client']) {
promise = self[sTokenAuth].credentialToProfile(ctx.headers['x-auth-token'], ctx.headers['x-auth-client']).
then(function (profile) {
if (self[sAllowMobileRegistration]) {
return self[sRavelInstance][symbols.authConfigModule].deserializeOrCreateUser(profile);
} else {
return self[sRavelInstance][symbols.authConfigModule].deserializeUser(profile.id);
}
}).
then(function (user) {
// set ctx.user for mobile users
ctx.user = user;
});
} else if (!ctx.isAuthenticated || !ctx.isAuthenticated()) {
// Web user isn't authenticated
promise = Promise.reject(
new self[sRavelInstance].ApplicationError.Authentication(
`User with session id=${ctx.cookies.get('koa.sid')} is not authenticated`));
} else {
// Web user is authenticated and ctx.user has been set by passport.
promise = Promise.resolve();
}
// try out the promise, and then try to await next
// catch all errors, regardless of client type, and behave appropriately
let errorFromNext = false;
try {
yield promise;
errorFromNext = true;
yield next();
} catch (err) {
if (!errorFromNext && self[sShouldRedirect]) {
self[sRavelInstance].log.error(err);
ctx.redirect(self[sRavelInstance].get('login route'));
} else if (!errorFromNext) {
// if the error didn't come from the next middleware, then
// we should throw an auth error instead.
self[sRavelInstance].log.error(err);
ctx.status = httpCodes.UNAUTHORIZED;
throw new self[sRavelInstance].ApplicationError.Authentication(
`User with session id=${ctx.cookies.get('koa.sid')} is not authenticated`);
} else {
// throw errors which don't come from auth
throw err;
}
}
});return function (_x, _x2) {return _ref.apply(this, arguments);};})();
}};
/*!
* Export AuthenticationMiddleware
*/
module.exports = AuthenticationMiddleware;