Blog Archives

Node Routes with Functional Programming

Today’s post is a little short and a little late as I’m pretty busy at work!

I’m going to do a quick functional programming example that I do in my routing of my application, now there probably is an easier way, but as allways programming is a process.

Here’s the code:

_boolHandle = (_f) -> (req, res) ->
  _testExists req.params.ticketID, res, -></pre>
    _f req, res, (err, results) -> if err then res.status(500).json err else res.status(200).json results or true
app.post '/api/ticket/:ticketID/metadata', _boolHandle (req, res, cb) -> $tickets.metadata req.params.ticketID, req.body, cb

This is essentially a post handler in express 4 that calls a function that returns a function to call a function to call a standard response!

If we break it down, when we register the handler, normally this would be written as follows:


app.post '/api/ticket/:ticketID/metadata', (req, res) -> res.status(200).json true

My first step was figuring out that every call I made to the $ticket object calls it’s callback with (err, result) and returned the results, so my code then looks like this:


app.post '/api/ticket/:ticketID/metadata', (req, res) -> $ticket.metadata req.params.ticketID, (err, result) -> if err then res.status(500).json err else res.status(200).json result

Because I’m lazy I decided I didn’t want to write out the callback every time, it’s always the same so why bother? So my first functional programming block was this:

_boolHandle = (_f) -> (req, res) ->
  _f req, res, (err, results) -> if err then res.status(500).json err else res.status(200).json results or true
app.post '/api/ticket/:ticketID/metadata', _boolHandle (req, res, cb) -> $tickets.metadata req.params.ticketID, cb

As you can see I abstracted out the response by creating a wrapper around it. The other part I have in the code is the function that tests whether the ticketID actually exists (_testExists), if it exists it calls the callback else it returns a “ticket not found” error.

I hope this explanation helps someone out, if you have a better way of doing this – I’m all ears!!

Node.js As a Service on Windows

This week I am going to outline the difficulties I have in getting my app running as a service on windows.

Normally I would start up my server either by calling “coffee app.coffee” or “npm start”. If you look around at the blogs and posts about this you’ll find that all of them refer to running the service via “node app.js”. Which just plain won’t work for me.

Beforehand I’ve used nssm, so I decided to give it a go again, I settled for getting it to run “npm start”.

Steps!

  1. Figure out the location of your node.js installation (node.exe), for me it was “C:\Program Files\nodejs\node.exe”.
  2. Fire up nssm in the add service mode.
  3. Enter in your node installation for Application Path.
  4. Enter in the directory of your project in Startup directory.
  5. In Arguments put in the quoted location of the npm-cli.js file and then “start” (with quotes). This should be relative to your node installation, for me it’s “C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js”.
    In total the Arguments field should look like:

    "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "start"
  6. Hit save and your service should run as if you called “npm start”!

2014-08-06_1445

CRM Migration (Part 1)

Recently I’ve been able to start moving our internal Coldfusion based CRM onto Node.js, I’m going to start chronicling the difficulties and challenges this has produced and my solutions to these problems in this multi-part series CRM Migration. My aim is to get one of these up every wednesday.

Access

The first problem I came across is the nastiest one for a partial migration; How do I keep one login for both sites?

To solve this we need to solve a simpler question – How do I access legacy coldfusion pages that we aren’t migrating yet?

I tried using node-proxy, but that didn’t go so well after a while due to cookies making sessions do weird things, my eventual solution was as follows:

@get '/index.cfm*', (req,res) ->
	request
		uri: "#{security.proxyAddress}#{req.url.substring 1}"
		method: 'GET'
		jar: req.session.proxyCookie
	, (err, resp, data) => testCookie req, resp, -> res.send resp.statusCode, resp.body
@post '/index.cfm*', (req,res) ->
	request
		uri: "#{security.proxyAddress}#{req.url.substring 1}"
		method: 'POST'
		jar: req.session.proxyCookie
	, (err, resp, data) => testCookie req, resp, -> res.send resp.statusCode, resp.body

NOTE: I started off using zappajs, but then migrated to Express 4 so I replicated the helpers. The ‘@’ is essentially a reference to the express server variable.

I’ll start by explaining the reasoning behind the URL structure; ‘/index.cfm*’. The CRM in coldfusion runs on CFWheels, a MVC library, and I never got the url rewrites to work on IIS so an example format for Coldfusion URL’s is ‘/index.cfm/{controller}/{action}/{key}’. The two above handlers basically state that any request that starts with ‘/index.cfm’ is targeted to the coldfusion server, in case you haven’t guessed my approach is to field ALL http requests to the node.js server which will act as a proxy for the Coldfusion server if we haven’t migrated that across using node.js’s built in request library.

That’s basically it for access to the old Coldfusion pages, you may be curious about the ‘testCookie’ function and where on earth this ‘req.session.proxyCookie’ variable comes from, but that will be in Part 2.

Hint: It’s about authenticating the user for node.js and coldfusion!

See you all next week!

If you want to know about my basic setup for Node.js projects with express see my Nodejs Website Base.

Securing Express Routes with PassportJS

It’s been a while since I posted anything, but I finally found something worth blogging about! Besides my trip to India at the beginning of the year and not much work recently…

Recently I’ve been building a web app for my gaming clan to help them run their practices and also to help me learn more of Node.js and NOSQL (CouchDB in particular). My first big problem in building this app was that of user login, or authentication. After googling around a bit for some modules to help with this (I really like the modular nature of node.js!) I came across a unified login system called Auth0, which I have to say is really awesome. I decided to go with this as who hasn’t thought that letting people login using facebook or similar would be cool but it’s too hard to bother! After running through their node.js tutorial which makes use of PassportJS and their authentication strategy passport-auth0 I came up with the following basic login/authentication code. (This is stripped down a bit, for my full code see here)


http = require 'http'
express = require "express" # Note this is Express v3.5.x

app = module.exports = express()

httpServer = http.createServer app

passport = require 'passport'
Auth0Strategy = require 'passport-auth0'
security = require('./security')

strategy = new Auth0Strategy 
	domain:       security.auth0.domain
	clientID:     security.auth0.clientID
	clientSecret: security.auth0.clientSecret
	callbackURL:  '/callback'
, (accessToken, refreshToken, profile, done) ->
	console.log "Hit Auth0 strategy"
	done null, profile

passport.use strategy

# This is not a best practice, but we want to keep things simple for now
passport.serializeUser (user, done) -> done null, user

passport.deserializeUser (user, done) -> done null, user

helmet = require 'helmet'
	
app.configure ->
	app.use express.logger 'dev'
	app.set 'views', "#{__dirname}/views"
	app.engine 'jade', require('consolidate').jade
	app.set 'view engine', 'jade'
	
	app.use helmet.xframe(), helmet.iexss(), helmet.contentTypeOptions(), helmet.cacheControl()
	app.use express.json(), express.urlencoded()
	app.use express.methodOverride()
	app.use express.cookieParser()
	app.use express.session
		secret: security.cookieSecret
		#cookie:
			#httpOnly: true
			# secure: true # for HTTPS only
	app.use passport.initialize()
	app.use passport.session()
	app.use require('express-validator')()
	
app.all '/api/*', auth

auth = (req, res, next) -> if req.isAuthenticated() then next() else res.redirect '/login'

# Auth0 callback handler
app.get '/callback', passport.authenticate('auth0',
	failureRedirect: '/login'
), (req, res) ->
	if not req.user then throw new Error 'user null'
	if req.user._json.appid?
		req.session.dbconn = require('./../startup_security/nano').nano req.user._json.user_id, req.user._json.dbpass
		res.redirect "/#{req.user._json.appid}/manage"
	else res.redirect "/first-login"

# warning this would log you out of facebook if you logged in via the facebook button - don't use this in live!
app.get '/logout', (req, res) ->
	req.logout()
	delete req.session
	delete req.user
	res.redirect "https://simeonc.auth0.com/logout?returnTo=http://tawmanager.localhost:3000/"

app.get '/login', (req, res) -> res.render 'login.jade'
app.get '/first-login', auth, (req, res) -> res.render 'first-login.jade'

httpServer.listen 3000

console.log "Server Running on port 3000 via ExpressJS"
console.log "Authentication Via Passport.js and Auth0"

Now this is my final code after some help from the owner of passport-node0 here. Now I’ll detail some of the quirks I had to get through that are really, really poorly documented.

First; Authenticating individual routes. Initially from reading through what other people have written and the other information out there I tried this:

<pre>app.get '/first-login', passport.authenticate('auth0'), (req, res) -> res.render 'first-login.jade'</pre>

That is WRONG, and meant I spent many many hours looking at 302 redirects from that page back to the login page for no discernable reason…
Correct is:

auth = (req, res, next) -> if req.isAuthenticated() then next() else res.redirect '/login'</pre>
<pre>app.get '/first-login', auth, (req, res) -> res.render 'first-login.jade'</pre>
<pre>

Secondly; Authenticating all routes matching a particular prefix. From here and there around the web I thought you did this via:

app.use '/api', auth

Turns out that’s also wrong (this ones in the docs so I felt really stupid when I found it). Here’s the correct one:

app.all '/api/*', auth