/* steve jansen */

// another day in paradise hacking code and more

Running Yeoman in a Shell Script

| Comments

I had a niche need to automate yeoman, and spent a few hours trying to overcome yeoman’s insistance on interactive prompts. As far as I can tell the prompting library, Inquirer.js, has no way to read a response file, or at least be commanded to run in non-interactive mode.

Enter an old-school POSIX friend in core-utils… yes

The yes utility continuously outputs ‘Y’ followed by a newline as long as another process is reading the stdout stream. Very convenient for piping to another program.

Here’s how I automated Yeoman to generate a new AngularJS app:

1
2
3
4
5
6
7
8
# yeoman has a number of interactive prompts, and sadly doesn't support a batch mode
# so we use the coreutils `yes` utility to accept all the default answers in yeoman;
# yes is not part of msysgit, so skip this when running on windows without cygwin
which yes > /dev/null
if [ $? -eq 0 ]
then
  yes | yo angular
fi

Wiring Together Express, Passport OAuth, and Swagger in NodeJS

| Comments

I spent a couple of hours tonight sorting out how to wire a NodeJS Express app to use both the Passport authentication strategy for GitHub OAuth with Swagger for Express. Normally, this would be fairly straightforward. A wrinkle with other examples is I needed to disallow all anonymous access for an intranet app.

I’m a big fan of Swagger UI – it’s a great, DRY way to auto-document your REST APIs. I expected Swagger to be a natural fit with NodeJS. Suprisingly, I found the Swagger.Net implmentation for .Net’s WebAPI to be considerably easier to use compared to the NodeJS implementation. Swagger.Net easily drops into an existing WebAPI project. Not so with NodeJS.

In Node, you really have to write your REST APIs from the ground up using the Swagger packge. The other wacky part for me was you need two Express apps side-by-side to handle requests for both REST APIs and static content.

1
2
3
4
var express = require('express'),
    app     = express(),
    subapp  = express(),;
    swagger = require('./lib/swagger/swagger');

As we’ll see below, the subapp sandboxes the Swagger package to the /api/* route.

(I use a local copy of the swagger-node-express package downloaded to my source tree because I found that the npm package was considerably outdated compared to the master branch of the swagger-node-express repo.)

Next, we configure PassportJS to use GitHub OAuth. GitHub will POST back to the route /auth/github/callback upon successful authentication.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var passport       = require('passport'),
    GitHubStrategy = require('passport-github').Strategy;

passport.use(new GitHubStrategy({
    clientID: config['OAUTH_ID'],
    clientSecret: config['OAUTH_TOKEN'],
    callbackURL: '/auth/github/callback'
  },
  function(accessToken, refreshToken, profile, done) {
    var user = {
      id: profile.username,
      email: (profile.emails.length) ? profile.emails[0].value : null,
      gravatar: profile._json.gravatar_id
    };
    return done(null, user);
  }
));

For my needs, I got away with serializing the 3 user properties I need to a session cookie:

1
2
3
4
5
6
7
passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
  done(null, user);
});

A critical piece of wiring is a reusable function to verify authentication:

1
2
3
4
5
6
7
8
9
10
11
// middleware to ensure user is authenticated
function authenticate(req, res, next) {
  if (req.isAuthenticated()) {
    return next();
  }
  if (req.headers['x-requested-with'] === 'XMLHttpRequest') {
    res.send("Authentication required", 401);
  } else {
    res.redirect('/login');
  }
}

The next key wiring is to configure both Express apps to use Passport as well as our authenticate function. This approach prevents infinite OAuth HTTP 302 redirects:

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
// configure express to use swagger for the `/api` route
subpath.configure(function() {
  subpath.use(express.cookieParser());
  subpath.use(express.bodyParser());
  subpath.use(express.methodOverride());
  subpath.use(express.session({ secret: config['SESSION_TOKEN'] }));
  subpath.use(passport.initialize());
  subpath.use(passport.session());
  subpath.use(authenticate);
  swagger.setAppHandler(subpath);
});

// configure express for the static content on the `/` route
app.configure(function() {
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.session({ secret: config['SESSION_TOKEN'] }));
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);
  app.use(authenticate);
  app.use('/api', subpath); /* mount `/api` using the subapp */
  // default document middleware for swagger/index.html
  app.use('/swagger', function(req, res, next) {
    if (req.url === '/swagger') {
      res.redirect('/swagger/');
    }
    next();
  });
  app.use('/swagger', express.static(path.join(__dirname, 'public/swagger')));
  app.use(express.static(path.join(__dirname, 'public/client')));
});

Finally, we define routes to handle OAuth logins and callbacks, then configure Swagger using the route /api/doc, and finally start the server.

1
2
3
4
5
6
7
8
9
10
11
// GitHub OAuth routes
app.get('/login', passport.authenticate('github'));
app.get('/auth/github/callback',  passport.authenticate('github', { successReturnToOrRedirect: '/', failureRedirect: '/login' }));

// Swagger configuration
swagger.addModels(require('./models'));
swagger.addGet(require('./controllers/user').get);
swagger.configureSwaggerPaths('', '/doc', '');
swagger.configure('', require('../package.json').version);

app.listen(8080);

For All UI Devs Out there…json-proxy v0.10.0

| Comments

To all my UI devs out there, I finally had some time to rework json-proxy into a lean and meaner machine.

If you haven’t seen the proxy before, it enables a UI dev to proxy localhost URLs to a remote server.

Why do this? Say you are doing an AngularJS front end, and want to wire some data to a REST API call like $http.get('/api/foo/1'). Before, you had to mock out the JSON result, run the entire server stack locally, or just cross your fingers and hope it works on the integration server.

Well, the proxy lets you transparently reroute http://localhost/api/foo/1 from your local laptop to an integration server like http://integration-server/api/foo/1. No CORS. No JSONP. No nonsense.

Grunt

With v0.1.0, the big change is the proxy now works right inside the Grunt server. Here’s an example config from the scaffold project:

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
connect: {
  options: {
    port: 9000,
    // Change this to '0.0.0.0' to access the server from outside.
    hostname: 'localhost'
  },
  livereload: {
    options: {
      middleware: function (connect) {
        return [
          require('json-proxy').initialize({
            proxy: {
              forward: {
                '/api/': 'http://integration-server:4040',
                '/swagger/': 'http://integration-server:4040',
              },
              headers: {
                'X-Forwarded-User': 'John Doe',
                'X-Forwarded-User-Email': 'john.doe@example.com'
              }
            }
          }),
          lrSnippet,
          mountFolder(connect, '.tmp'),
          mountFolder(connect, yeomanConfig.app)
        ];
      }
    }
  },

Auth Headers

Even better, you can inject headers into proxied request. So if you remote server requires an Authorization header with an OAuth-style token, or sits behind an Enterprise SSO appliance, you can add the headers to deal with bypassing the remote server authentication.

CLI

The CLI utility is also improved. The CLI properly supports global installation. If you install using sudo npm install -g json-proxy, you can invoke the proxy simply as json-proxy with whatever args you want.

CLI usage info:

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
json-proxy [-c configFile] [-p port] [-f proxy forwarding rule]
             [-h header rule] [-html5mode [defaultFile]] [directory]

Examples:
   json-proxy -p 8080 -f "/api=http://server" -f "/=http://localhost:9000" .
   json-proxy -h "X-Forwarded-User=johndoe" /tmp/folder
   json-proxy -c "/tmp/config.json"

By default, looks for a config file at ./json-proxy.json

Environmental variables:
  JSON_PROXY_PORT         see --port
  JSON_PROXY_WEBROOT      directory
  JSON_PROXY_GATEWAY      --gateway
  JSON_PROXY_GATEWAY_AUTH "username:password" credentials for --gateway)

Options:
  -p, --port     The TCP port for the proxy server
  -f, --forward  a forwarding rule (ex. /foo=server/foo)
  -h, --header   a custom request header (ex. iv-user=johndoel)
  -c, --config   a config file
  -g, --gateway  URL for a LAN HTTP proxy to use for forwarding requests
  --html5mode    support AngularJS HTML5 mode by catching 404s
  -?, --help     about this utility
  --version      version info

More info @ https://github.com/steve-jansen/json-proxy and https://npmjs.org/package/json-proxy

Enjoy!

Passport-reverseproxy

| Comments

Just released a new “API” provider for the NodeJS authentication middelware Passport. The ReverseProxy API provider enables NodeJS apps to authenticate users via HTTP Request Proxies injected by a reverse HTTP proxy server. Reverse Proxy authentication is a technique seen in enterprise Single Sign On (SSO) where an authentication server sits in front of the web server/app server. The proxy server authenticates users against some enterprise store (e.g., LDAP Directory).

After successful authentication, the proxy will forward the original request to the target web server/app server. Typically, the proxy will inject identifying information about the user (e.g., username, email address, display name) into custom HTTP request headers. IBM’s WebSeal application for SSO does exactly this.

Suprisingly, no one had written a passport strategy that uses custom HTTP headers yet. So, I coded up an implementation, inspired by Passport’s passport-http strategy for HTTP basic authentication.

Installing the provider is as simple as:

1
2
3
npm install express
npm install passport
npm install passport-reverseproxy

I’ve also included a sample Express app using the reverse proxy stategy in passport-reverseproxy/examples/app.js

Overall, I think Passport is a great library – both easy to use and easy to implement custom strategies.

Update to the Cordova Email Plugin for iOS

| Comments

I put some serious TLC against the Cordova/PhoneGap plugin for creating email messages on iOS devices — v2.0 of the plugin now lives @ https://github.com/steve-jansen/cordova-ios-emailcomposer

You can give it a test drive with:

1
2
3
4
5
6
7
8
sudo npm install -g cordova
cordova create ~/MyApp MyApp
cd ~/MyApp
cordova platform add ios
cordova plugin add emailcomposer # using the http://plugins.cordova.io registry
cordova build
# manually update the www/index.html file to link to www/examples/EmailComposer.html
# run the app in the iOS 5.x+ simulator via Xcode

Major changes to the plugin include:

  • Support for file attachments using files paths, or file contents as encoded strings
  • Simpler JavaScript API
  • Support for cordova.require to load the plugin in JavaScript which means less global namespace pollution
  • Cordova 2.0+ plugin spec implemented (i.e., - (void) show:(CDVInvokedUrlCommand*)command)
  • ARC support
  • Ran git subtree to extract the history into a standalone repo, per the new Cordova plugin respository guidelines
  • Backwards compatibility with the JS API for the 1.x plugin
  • Backwards compatibility with the iOS/EmailComposerWithAttachments plugin
  • Jasmine unit tests for the JS part of the plugin
  • Xcode unit tests for the obj-c part of the plugin

I have a pull request to repoint phonegap-plugins/iOS/EmailCompser and phonegap-plugins/iOS/EmailCompserWithAttachments to this new repo. As a courtesy, I’ve asked the original contributors to these two plugins to give their blessing.

I’ve also published this plugin to the cordova npm-like repository. And, trust me, don’t call plugman publish with the --plugin argument.

How to Modify the TCP/IP Port Binding for the Microsoft Web Deployment Agent Service

| Comments

I love shell scripting, which is probably why I seem to somehow get organically involved in “DevOps” on most of my project work. I’m drafting up a series of posts on tips and tricks for shell scripts (with love for both Windows and *nix) – it seems to be a fading art among recent comp sci grads. Until I finish those posts, I wanted to share a quick script I wrote to reassign the TCP/IP port binding for Microsoft’s Web Deployment Agent service.

This is my attempt to refine a very good answer posted a couple years ago asking if web deploy can run on a port other than 80. Why, yes it can…

A Ghost No More

| Comments

Blogging has long been on my todo list — quite frankly too long. A colleague shared a great piece by Troy Hunt named “The ghost who codes: how anonymity is killing your career”. Troy inspired me that I need to make the time to just get it done. So this is where I start giving back whatever small knowledge bits I may have.

I am fortunate enough to be with a company now that encourages professional writing, which hasn’t always been the case. Troy’s article really resonated with me that developers have an insatiatable appetite for consuming knowledge. We take information all the time, and there’s a duty on all our parts to give back and not just take. Thanks to both Troy any my colleague Alex for pushing me to do more!

Many years ago I learned an metaphor from a very accomplished veteran of the US military that is quite applicable to coding: “you have to either be tough or smart to succeed”. Say you want to navigate from point A to point B, and there just happens to be a tall mountain between the two points. The tough guy takes a straight line route, ardously ascending and descending the mountain. The smart guy circumnavigates the mountain, saving time and energy.

I know developers like to be the smartest person in the room, but, I am self-aware enough to admit I often fall into the “tough” camp – hacking into the late hours until the job is done. I suppose this blog will be a true measure of how many (or how few) smart/clever ideas I have up my sleeve!