all files / express-stormpath/lib/ stormpath.js

95.69% Statements 111/116
78.26% Branches 36/46
100% Functions 18/18
95.69% Lines 111/116
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278                                63×   63×   63× 61×                   63×   63×   63×     63× 61× 61×     63×                         63×   63× 63×     63×                 142× 142× 142×   142×       142×   142×     142× 141×           13×       63× 61× 61×     61×       142×     142× 142×   142×     245×     302×     61×     61×   61×     61× 61×   60× 60×       61× 61×   60× 60× 60×         61× 244×   244×               61× 61×     61× 59×   58× 58×       61× 59× 59×     61×     61× 61×     61× 60×     61× 61×         61× 61×   61× 61× 61×       63×   63×   63×     10×                                                                    
'use strict';
 
var cookieParser = require('cookie-parser');
var express = require('express');
var winston = require('winston');
 
var controllers = require('./controllers');
var helpers = require('./helpers');
var middleware = require('./middleware');
var bodyParser = helpers.bodyParser;
 
var version = require('../package.json').version;
var expressVersion = helpers.getAppModuleVersion('express') || 'unknown';
var userAgent = 'stormpath-express/' + version + ' ' + 'express/' + expressVersion;
 
/**
 * Initialize the Stormpath client.
 *
 * @method
 * @private
 *
 * @param {Object} app - The express application.
 * @param {object} opts - A JSON hash of user supplied options.
 *
 * @return {Function} A function which accepts a callback.
 */
function initClient(app, opts) {
  opts.userAgent = userAgent;
 
  var logger = opts.logger;
 
  if (!logger) {
    logger = new winston.Logger({
      transports: [
        new winston.transports.Console({
          colorize: true,
          level: opts.debug || 'error'
        })
      ]
    });
  }
 
  app.set('stormpathLogger', logger);
 
  var client = require('./client')(opts);
 
  client.on('error', function (err) {
    logger.error(err);
    app.emit('stormpath.error', err);
  });
 
  client.on('ready', function () {
    app.set('stormpathClient', client);
    app.set('stormpathConfig', client.config);
  });
 
  return client;
}
 
/**
 * Initialize the Stormpath middleware.
 *
 * @method
 *
 * @param {Object} app - The express application.
 * @param {object} opts - A JSON hash of user supplied options.
 *
 * @return {Function} An express middleware.
 */
module.exports.init = function (app, opts) {
  opts = opts || {};
 
  var router = express.Router();
  var client = initClient(app, opts);
 
  // Indicates whether or not the client is ready.
  var isClientReady = false;
 
  // Handle the X-Stormpath-Agent header.
  // Important: This might not report 100% accurately since the
  // user agent might be overwritten by a subsequent request with a
  // different header (race condition). But this is "good enough" for
  // now until we've solved this issue in the Node SDK (since creating
  // new clients for each request is too expensive it would be
  // better if we could just scope it).
  function stormpathUserAgentMiddleware(req, res, next) {
    var newUserAgent = userAgent;
    var config = req.app.get('stormpathConfig');
    var stormpathAgent = req.headers['x-stormpath-agent'];
 
    Iif (stormpathAgent) {
      newUserAgent = stormpathAgent + ' ' + userAgent;
    }
 
    config.userAgent = newUserAgent;
 
    next();
  }
 
  function awaitClientReadyMiddleware(req, res, next) {
    if (isClientReady) {
      next();
    } else {
      app.on('stormpath.ready', function () {
        next();
      });
    }
  }
 
  function stormpathMiddleware(req, res, next) {
    middleware.getUser(req, res, next);
  }
 
  // Build routes.
  client.on('ready', function () {
    var config = app.get('stormpathConfig');
    var web = config.web;
 
    // Expand customData by default, unless explicitly disabled.
    if (config.expand && config.expand.customData !== false) {
      config.expand.customData = true;
    }
 
    function localsMiddleware(req, res, next) {
      // Helper for getting the current URL.
      res.locals.url = req.protocol + '://' + helpers.getHost(req);
 
      // Make the app object available for access in all templates.
      res.locals.app = req.app;
      res.locals.stormpathConfig = config;
 
      next();
    }
 
    function addGetRoute(path, controller) {
      router.get(path, bodyParser.forceDefaultBody(), controller);
    }
 
    function addPostRoute(path, controller, options) {
      router.post(path, bodyParser.formOrJson(options), controller);
    }
 
    router.use(localsMiddleware);
 
    // Sign cookies with the API-key secret.
    router.use(cookieParser());
 
    if (web.idSite.enabled) {
      addGetRoute(web.idSite.uri, controllers.idSiteVerify);
    }
 
    Eif (web.register.enabled) {
      if (web.idSite.enabled) {
        addGetRoute(web.register.uri, controllers.idSiteRedirect({ path: web.idSite.registerUri }));
      } else {
        addGetRoute(web.register.uri, controllers.register);
        addPostRoute(web.register.uri, controllers.register, { limit: '11mb' });
      }
    }
 
    Eif (web.login.enabled) {
      if (web.idSite.enabled) {
        addGetRoute(web.login.uri, controllers.idSiteRedirect({ path: web.idSite.loginUri }));
      } else {
        router.use(web.login.uri, middleware.getUser);
        addGetRoute(web.login.uri, controllers.login);
        addPostRoute(web.login.uri, controllers.login);
      }
    }
 
    // Iterate all social providers and set-up controller routes for them.
    for (var providerName in config.web.social) {
      var provider = config.web.social[providerName];
 
      Iif (provider.enabled) {
        var controllerName = providerName + 'Login';
        if (controllerName in controllers) {
          addGetRoute(provider.uri, controllers[controllerName]);
        }
      }
    }
 
    Eif (web.logout.enabled) {
      addPostRoute(web.logout.uri, controllers.logout);
    }
 
    if (web.forgotPassword.enabled) {
      if (web.idSite.enabled) {
        addGetRoute(web.forgotPassword.uri, controllers.idSiteRedirect({ path: web.idSite.forgotUri }));
      } else {
        addGetRoute(web.forgotPassword.uri, controllers.forgotPassword);
        addPostRoute(web.forgotPassword.uri, controllers.forgotPassword);
      }
    }
 
    if (web.changePassword.enabled) {
      addGetRoute(web.changePassword.uri, controllers.changePassword);
      addPostRoute(web.changePassword.uri, controllers.changePassword);
    }
 
    if (web.verifyEmail.enabled) {
      addGetRoute(web.verifyEmail.uri, controllers.verifyEmail);
      addPostRoute(web.verifyEmail.uri, controllers.verifyEmail);
    }
 
    Eif (web.me.enabled) {
      router.get(web.me.uri, stormpathMiddleware, middleware.loginRequired, controllers.currentUser);
    }
 
    if (web.oauth2.enabled) {
      router.all(web.oauth2.uri, bodyParser.form(), stormpathMiddleware, controllers.getToken);
    }
 
    client.getApplication(config.application.href, function (err, application) {
      Iif (err) {
        throw new Error('Cannot fetch application ' + config.application.href);
      }
 
      // Warm the view model cache
      helpers.getFormViewModel('login', config, function () {});
      helpers.getFormViewModel('register', config, function () {});
 
      app.set('stormpathApplication', application);
      isClientReady = true;
      app.emit('stormpath.ready');
    });
  });
 
  router.use(stormpathUserAgentMiddleware);
 
  app.use(awaitClientReadyMiddleware);
 
  return router;
};
 
function getUserMiddlewareProxy(nextMiddleware) {
  return function (req, res, next) {
    middleware.getUser(req, res, nextMiddleware.bind(null, req, res, next));
  };
}
 
/**
 * Expose the `loginRequired` middleware.
 *
 * @property loginRequired
 */
module.exports.loginRequired = getUserMiddlewareProxy(middleware.loginRequired);
 
/**
 * Expose the `getUser` middleware.
 *
 * @property getUser
 */
module.exports.getUser = middleware.getUser;
 
/**
 * Expose the `groupsRequired` middleware.
 *
 * @property groupsRequired
 */
module.exports.groupsRequired = function groupsRequiredProxy() {
  return getUserMiddlewareProxy(middleware.groupsRequired.apply(null, arguments));
};
 
/**
 * Expose the `apiAuthenticationRequired` middleware.
 *
 * @property apiAuthenticationRequired
 */
module.exports.apiAuthenticationRequired = middleware.apiAuthenticationRequired;
 
/**
 * Expose the `authenticationRequired` middleware.
 *
 * @property authenticationRequired
 */
module.exports.authenticationRequired = getUserMiddlewareProxy(middleware.authenticationRequired);