From 5f9c95ed69768dbd8de915af06cfcdacf3b22767 Mon Sep 17 00:00:00 2001
From: Lloyd Hilaiel <lloyd@hilaiel.com>
Date: Tue, 2 Aug 2011 06:19:46 -0600
Subject: [PATCH] erect a simple mechanism for deployment environment specific
 configuration

---
 browserid/app.js    | 25 ++++++++-----
 browserid/run.js    |  1 +
 libs/environment.js | 85 ++++++++++++++++++++++++++++++++++++++++++
 run.js              | 91 +++++++++++++++++++++------------------------
 4 files changed, 144 insertions(+), 58 deletions(-)
 create mode 100644 libs/environment.js

diff --git a/browserid/app.js b/browserid/app.js
index 6224de3f4..bef67d256 100644
--- a/browserid/app.js
+++ b/browserid/app.js
@@ -15,11 +15,12 @@ webfinger = require('./lib/webfinger.js'),
 sessions = require('cookie-sessions'),
 express = require('express'),
 secrets = require('./lib/secrets.js'),
-db = require('./lib/db.js')
+db = require('./lib/db.js'),
+environment = require('../libs/environment.js'),
+substitution = require('../libs/substitute.js');
 
 // looks unused, see run.js
 // const STATIC_DIR = path.join(path.dirname(__dirname), "static");
-
 const COOKIE_SECRET = secrets.hydrateSecret('cookie_secret', VAR_DIR);
 const COOKIE_KEY = 'browserid_state';
 
@@ -33,7 +34,9 @@ function internal_redirector(new_url) {
 function router(app) {
   app.set("views", __dirname + '/views'); 
 
-  app.set('view options', { production: exports.production });
+  app.set('view options', {
+    production: app.enabled('use_minified_resources')
+  });
 
   // this should probably be an internal redirect
   // as soon as relative paths are figured out.
@@ -41,7 +44,7 @@ function router(app) {
     res.render('dialog.ejs', {
       title: 'A Better Way to Sign In',
       layout: false,
-      production: exports.production 
+      production: app.enabled('use_minified_resources')
     });
   });
 
@@ -109,9 +112,6 @@ function router(app) {
 };
 
 exports.varDir = VAR_DIR;
-exports.production = true;
-
-
 
 exports.setup = function(server) {
   server.use(express.cookieParser());
@@ -144,7 +144,7 @@ exports.setup = function(server) {
       // not awesome, but probably sufficient for now.
       req.session.csrf = crypto.createHash('md5').update('' + new Date().getTime()).digest('hex');
     }
-    
+
     next();
   });
 
@@ -172,8 +172,15 @@ exports.setup = function(server) {
       }
     }
 
-    next();        
+    next();
   });
+
+  // configure environment variables based on the deployment target ('NODE_ENV');
+  environment.configure(server);
+
+  // add middleware to re-write urls if needed
+  environment.performSubstitution(server);
+
   // add the actual URL handlers other than static
   router(server);
 }
diff --git a/browserid/run.js b/browserid/run.js
index 94f0583de..ed8b03dbe 100755
--- a/browserid/run.js
+++ b/browserid/run.js
@@ -42,3 +42,4 @@ exports.stopServer = function(cb) {
 
 // when directly invoked from the command line, we'll start the server
 if (amMain) exports.runServer();
+
diff --git a/libs/environment.js b/libs/environment.js
new file mode 100644
index 000000000..3bbfec25b
--- /dev/null
+++ b/libs/environment.js
@@ -0,0 +1,85 @@
+/*
+ * An abstraction which contains various pre-set deployment
+ * environments and adjusts runtime configuration appropriate for
+ * the current environmnet (specified via the NODE_ENV env var)..
+ *
+ * usage is
+ *   exports.configure(app);
+ */
+
+const substitution = require('./substitute.js');
+
+if (undefined === process.env['NODE_ENV']) {
+  process.env['NODE_ENV'] = 'local';
+}
+
+exports.configure = function(app) {
+  if (!app) throw "configure requires express app as argument"; 
+
+  var known = false;
+
+  app.enable('use_minified_resources');
+
+  app.configure('production', function() {
+    app.set('hostname', 'browserid.org');
+    app.set('port', '443');
+    app.set('scheme', 'https');
+    known = true;
+  });
+
+  app.configure('development', function() {
+    app.set('hostname', 'dev.diresworb.org');
+    app.set('port', '443');
+    app.set('scheme', 'https');
+    known = true;
+  });
+
+  app.configure('beta', function() {
+    app.set('hostname', 'diresworb.org');
+    app.set('port', '443');
+    app.set('scheme', 'https');
+    known = true;
+  });
+
+  app.configure('local', function() {
+    app.set('hostname', '127.0.0.1');
+    app.set('port', '10001');
+    app.set('scheme', 'http');
+    app.disable('use_minified_resources');
+    known = true;
+  });
+
+  if (!known) throw "unknown environment: " + process.env('NODE_ENV');
+
+  function getPortForURL() {
+    if (app.set('scheme') === 'https' && app.set('port') === '443') return "";
+    if (app.set('scheme') === 'http' && app.set('port') === '80') return "";
+    return ":" + app.set('port');
+  }
+
+  app.set('URL',
+          app.set('scheme') +
+          '://' +
+          app.set('hostname') +
+          getPortForURL());
+};
+
+/*
+ * Install middleware that will perform textual replacement on served output
+ * to re-write urls as needed for this particular environment.
+ *
+ * Note, for a 'local' environment, no re-write is needed because this is
+ * handled at a higher level.  For a 'production' env no rewrite is necc cause
+ * all source files are written for that environment.
+ */
+exports.performSubstitution = function(app) {
+  if (process.env['NODE_ENV'] !== 'production' &&
+      process.env['NODE_ENV'] !== 'local') {
+    app.use(substitution.substitute({
+      'https://browserid.org': app.set('URL'),
+      'browserid.org:443': app.set('hostname') + ':' + app.set('port'),
+      'browserid.org': app.set('hostname')
+    }));
+  }
+};
+
diff --git a/run.js b/run.js
index 7f7654451..95046e55d 100755
--- a/run.js
+++ b/run.js
@@ -8,7 +8,8 @@ var      sys = require("sys"),
         path = require("path"),
           fs = require("fs"),
      express = require("express"),
-substitution = require('./libs/substitute.js');
+substitution = require('./libs/substitute.js'),
+ environment = require('./libs/environment.js');
 
 var PRIMARY_HOST = "127.0.0.1";
 
@@ -58,58 +59,54 @@ function substitutionMiddleware(req, resp, next) {
   (substitution.substitute(subs))(req, resp, next);
 }
 
-
 function createServer(obj) {
-    var app = express.createServer();
-    app.use(express.logger());
+  var app = express.createServer();
+
+  // configure the server based on the environment (NODE_ENV).
+  environment.configure(app);
+
+  app.use(express.logger());
 
-    // this file is a *test* harness, to make it go, we'll insert a little handler that
-    // substitutes output, changing production URLs to developement URLs.
-    app.use(substitutionMiddleware);
+  // this file is a *test* harness, to make it go, we'll insert a little
+  // handler that substitutes output, changing production URLs to
+  // developement URLs.
+  app.use(substitutionMiddleware);
 
-    // let the specific server interact directly with the express server to register their middleware,
-    // routes, etc...
-    if (obj.setup) obj.setup(app);
+  // let the specific server interact directly with the express server to
+  // register their middleware, routes, etc...
+  if (obj.setup) obj.setup(app);
 
-    // now set up the static resource servin'
-    var p = obj.path, ps = path.join(p, "static");
-    try { if (fs.statSync(ps).isDirectory()) p = ps; } catch(e) { }
-    app.use(express.static(p));
+  // now set up the static resource servin'
+  var p = obj.path, ps = path.join(p, "static");
+  try { if (fs.statSync(ps).isDirectory()) p = ps; } catch(e) { }
+  app.use(express.static(p));
 
-    // and listen!
-    app.listen(obj.port, PRIMARY_HOST);
-    return app;
+  // and listen!
+  app.listen(obj.port, PRIMARY_HOST);
+  return app;
 };
 
 // start up webservers on ephemeral ports for each subdirectory here.
 var dirs = [
-    // the reference verification server.  A version is hosted at
-    // browserid.org and may be used, or the RP may perform their
-    // own verification.
-    {
-        name: "https://browserid.org/verify",
-        subPath: "/",
-        path: path.join(__dirname, "verifier")
-    },
-    // An example relying party.
-    {
-        name: "http://rp.eyedee.me",
-        path: path.join(__dirname, "rp")
-    },
-
-    // disabled primary for now since it's not in working
-    // order.
-    /*    // A reference primary identity provider.
-    {
-        name: "https://eyedee.me",
-        path: path.join(__dirname, "primary")
-        }, */
-
-    // BrowserID: the secondary + ip + more.
-    {
-        name: "https://browserid.org",
-        path: path.join(__dirname, "browserid")
-    }
+  // the reference verification server.  A version is hosted at
+  // browserid.org and may be used, or the RP may perform their
+  // own verification.
+  {
+    name: "https://browserid.org/verify",
+    subPath: "/",
+    path: path.join(__dirname, "verifier")
+  },
+  // An example relying party.
+  {
+    name: "http://rp.eyedee.me",
+    path: path.join(__dirname, "rp")
+  },
+
+  // BrowserID: the secondary + ip + more.
+  {
+    name: "https://browserid.org",
+    path: path.join(__dirname, "browserid")
+  }
 ];
 
 function formatLink(server, extraPath) {
@@ -132,11 +129,7 @@ dirs.forEach(function(dirObj) {
   try {
     var runJSExists = false;
     try { runJSExists = fs.statSync(handlerPath).isFile() } catch(e) {};
-    if (runJSExists) {
-      var runJS = require(handlerPath);
-      // set to development mode
-      runJS.production = false;
-    }
+    if (runJSExists) runJS = require(handlerPath);
   } catch(e) {
     console.log("Error loading " + handlerPath + ": " + e);
     process.exit(1);
-- 
GitLab