From 286e20067942235d509e8614cd8efe583645cb56 Mon Sep 17 00:00:00 2001
From: kushal Likhi
Date: Thu, 9 Jan 2014 19:51:08 +0530
Subject: [PATCH 1/7] added idea files to gitignore
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 8a7a5499..77b66660 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ node_modules/*
config.json
logs/*
pids/*
+.idea/
From ce06b17cb794e6d5acb1d94a0118d90a169edcfe Mon Sep 17 00:00:00 2001
From: kushal Likhi
Date: Thu, 9 Jan 2014 21:58:47 +0530
Subject: [PATCH 2/7] Added the JWT bearer auth token providing support.
---
app.js | 70 ++++++++++++++++++++++++++++++++++----
config.json.sample | 18 ----------
package.json | 4 ++-
public/data/apiconfig.json | 14 ++++++++
public/data/jwttest.json | 25 ++++++++++++++
5 files changed, 105 insertions(+), 26 deletions(-)
delete mode 100644 config.json.sample
create mode 100644 public/data/jwttest.json
diff --git a/app.js b/app.js
index 84f431ad..0535c2f6 100755
--- a/app.js
+++ b/app.js
@@ -36,6 +36,8 @@ var express = require('express'),
https = require('https'),
crypto = require('crypto'),
redis = require('redis'),
+ jwt = require('jwt-simple'),
+ request = require('request'),
RedisStore = require('connect-redis')(express);
// Configuration
@@ -207,13 +209,67 @@ function oauth2(req, res, next){
var apiName = req.body.apiName,
apiConfig = apisConfig[apiName];
- if (apiConfig.oauth2) {
- var apiKey = req.body.apiKey || req.body.key,
- apiSecret = req.body.apiSecret || req.body.secret,
- refererURL = url.parse(req.headers.referer),
- callbackURL = refererURL.protocol + '//' + refererURL.host + '/oauth2Success/' + apiName,
- key = req.sessionID + ':' + apiName,
- oa = new OAuth2(apiKey,
+ if(!apiConfig.oauth2) {
+ next();
+ return;
+ }
+
+ var apiKey = req.body.apiKey || req.body.key,
+ apiSecret = req.body.apiSecret || req.body.secret,
+ refererURL = url.parse(req.headers.referer),
+ callbackURL = refererURL.protocol + '//' + refererURL.host + '/oauth2Success/' + apiName,
+ key = req.sessionID + ':' + apiName;
+
+ if(apiConfig.oauth2.type == 'bearer-jwt'){
+ console.log("Starting the JWT Bearer OAUTH, v2.0");
+
+ //API url
+ var accessTokenAPIUrl = apiConfig.protocol + "://" + apiConfig.baseURL + apiConfig.oauth2.accessTokenURL;
+
+ var claimSet = {
+ id: apiKey,
+ scope: "all", //For now only all scope is supported
+ exp: (1000*60*60*24) //24 hours
+ };
+
+ var jwtToken = jwt.encode(claimSet, apiSecret);
+
+ request.post(accessTokenAPIUrl, {
+ form: {
+ "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", //Only this grant type is supported, i.e. Bearer. Pass this string as it is.
+ "assertion": jwtToken //pass the token
+ }
+ }, function (err, resp, body) {
+ if (err) {
+ res.send("Error getting OAuth access token : " + util.inspect(err), 500);
+ }
+ var bodyObj = JSON.parse(body);
+ var token = bodyObj[apiConfig.oauth2.tokenName];
+ console.log("Access Token:", token);
+ if(!token){
+ req.session[apiName] = null;
+ db.del(key + ':access_token',function(){
+ db.del(key + ':refresh_token',function(){
+ res.send(body);
+ });
+ });
+ } else {
+ db.mset([key + ':access_token', token,
+ key + ':refresh_token', token
+ ], function(err, results2) {
+ req.session[apiName] = {};
+ req.session[apiName].authed = true;
+ if (config.debug) {
+ console.log('session[apiName].authed: ' + util.inspect(req.session));
+ }
+ res.end(body);
+ });
+ }
+ }
+ );
+
+ } else {
+ var oa = new OAuth2(apiKey,
apiSecret,
apiConfig.oauth2.baseSite,
apiConfig.oauth2.authorizeURL,
diff --git a/config.json.sample b/config.json.sample
deleted file mode 100644
index 1983fc97..00000000
--- a/config.json.sample
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "title" : "I/O Docs - http://github.com/mashery/iodocs",
- "address": "0.0.0.0",
- "port" : 3000,
- "apiConfigDir" : "./public/data/",
- "debug" : false,
- "sessionSecret" : "12345",
- "basicAuth" : {
- "username" : "",
- "password" : ""
- },
- "redis" : {
- "host" : "localhost",
- "port" : 6379,
- "password" : "",
- "database" : "0"
- }
-}
diff --git a/package.json b/package.json
index d549df0e..03bf0f04 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,9 @@
"oauth": "0.9.10",
"redis": "0.8.3",
"querystring": "0.1.0",
- "supervisor": ">= 0.5.x"
+ "supervisor": ">= 0.5.x",
+ "jwt-simple":"*",
+ "request":"*"
},
"devDependencies": {},
"main": "index",
diff --git a/public/data/apiconfig.json b/public/data/apiconfig.json
index 16cbffba..f4ec895e 100644
--- a/public/data/apiconfig.json
+++ b/public/data/apiconfig.json
@@ -50,6 +50,20 @@
},
"keyParam":""
},
+ "jwttest": {
+ "name": "JWT BASED (OAuth 2.0 Auth Code)",
+ "protocol": "http",
+ "baseURL": "localhost:9091",
+ "publicPath": "",
+ "auth": "oauth2",
+ "oauth2": {
+ "type": "bearer-jwt",
+ "baseSite": "localhost:9091",
+ "accessTokenURL": "/oauth/v2/token",
+ "tokenName": "access_token"
+ },
+ "keyParam": ""
+ },
"rdio": {
"name": "Rdio Beta (OAuth 2.0 Client Credentials)",
"protocol": "https",
diff --git a/public/data/jwttest.json b/public/data/jwttest.json
new file mode 100644
index 00000000..bf3fb7d4
--- /dev/null
+++ b/public/data/jwttest.json
@@ -0,0 +1,25 @@
+{
+ "endpoints": [
+ {
+ "name": "JWT Sample API",
+ "methods": [
+ {
+ "MethodName": "Profile Information",
+ "Synopsis": "Returns profile information for a given user.",
+ "HTTPMethod": "GET",
+ "URI": "/users/:USER_ID",
+ "RequiresOAuth": "Y",
+ "parameters": [
+ {
+ "Name": "USER_ID",
+ "Required": "Y",
+ "Default": "1297336",
+ "Type": "int",
+ "Description": "id"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
From d8fe8e2f79c80eaa01c208e7bd14301467c69ce5 Mon Sep 17 00:00:00 2001
From: kushal Likhi
Date: Thu, 9 Jan 2014 22:13:50 +0530
Subject: [PATCH 3/7] Updated configurations
---
public/data/apiconfig.json | 4 +++-
public/data/jwttest.json | 25 ++++++++++++++++---------
2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/public/data/apiconfig.json b/public/data/apiconfig.json
index f4ec895e..f0c4b754 100644
--- a/public/data/apiconfig.json
+++ b/public/data/apiconfig.json
@@ -55,12 +55,14 @@
"protocol": "http",
"baseURL": "localhost:9091",
"publicPath": "",
+ "privatePath": "",
"auth": "oauth2",
"oauth2": {
"type": "bearer-jwt",
"baseSite": "localhost:9091",
"accessTokenURL": "/oauth/v2/token",
- "tokenName": "access_token"
+ "tokenName": "access_token",
+ "authorizationHeader": "Y"
},
"keyParam": ""
},
diff --git a/public/data/jwttest.json b/public/data/jwttest.json
index bf3fb7d4..8bc2f262 100644
--- a/public/data/jwttest.json
+++ b/public/data/jwttest.json
@@ -1,21 +1,28 @@
{
"endpoints": [
{
- "name": "JWT Sample API",
+ "name": "List Methods",
"methods": [
{
- "MethodName": "Profile Information",
- "Synopsis": "Returns profile information for a given user.",
+ "MethodName": "List Cluster Workers",
+ "Synopsis": "This method is used to list the cluster workers currently functioning. Its also lists its system info.
Will return the following status codes:
- 200: Successful
- 400: Validation Errors
- 401: Authentication Failure
- 500: Server Error
",
"HTTPMethod": "GET",
- "URI": "/users/:USER_ID",
+ "URI": "/cluster/worker/list",
"RequiresOAuth": "Y",
"parameters": [
{
- "Name": "USER_ID",
- "Required": "Y",
- "Default": "1297336",
- "Type": "int",
- "Description": "id"
+ "Name": "skip",
+ "Required": "N",
+ "Default": "0",
+ "Type": "number",
+ "Description": "For Pagination. How many records to skip."
+ },
+ {
+ "Name": "limit",
+ "Required": "N",
+ "Default": "-1",
+ "Type": "number",
+ "Description": "For Pagination. How many records to fetch. '-1' means infinite."
}
]
}
From 3616153397a4f3b28ec1a33aea01995b93045c05 Mon Sep 17 00:00:00 2001
From: kushal Likhi
Date: Fri, 10 Jan 2014 01:03:44 +0530
Subject: [PATCH 4/7] Added support for displaying response details
---
public/data/jwttest.json | 27 ++++++++++++++++++++++
views/api.jade | 48 ++++++++++++++++++++++++++++++++++++++--
2 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/public/data/jwttest.json b/public/data/jwttest.json
index 8bc2f262..d7741196 100644
--- a/public/data/jwttest.json
+++ b/public/data/jwttest.json
@@ -24,6 +24,33 @@
"Type": "number",
"Description": "For Pagination. How many records to fetch. '-1' means infinite."
}
+ ],
+ "responses": [
+ {
+ "Type": "SUCCESS - List Fetched",
+ "StatusCode": 200,
+ "Synopsis": "When everything goes good, you get the list.",
+ "Format": "JSON",
+ "parameters": [
+
+ ]
+ },
+ {
+ "Type": "ERROR - Server Error",
+ "StatusCode": 500,
+ "Synopsis": "When some error on server occurs.",
+ "Format": "JSON",
+ "parameters": [
+ {
+ "Name": "error",
+ "Type": "number",
+ "Description": "The Error Message"
+ }
+ ],
+ "sampleResponse": {
+ "error": "Unable to process, try again later."
+ }
+ }
]
}
]
diff --git a/views/api.jade b/views/api.jade
index df3cab11..05307aed 100644
--- a/views/api.jade
+++ b/views/api.jade
@@ -151,6 +151,7 @@ block content
- each description, choice in parameter.EnumeratedDescription
dt #{choice}
dd #{description}
+ // Create header fields and button to add/remove headers.
- if (method.headers && method.headers.length > 0)
div.headers
h4.title
@@ -175,6 +176,49 @@ block content
td
a(href='#', class='remove') Remove
a(href='#', class='add-headers') Add Header
- // Create header fields and button to add/remove headers.
+ div(style='background:#EFF5F5;padding:10px;border:1px solid #9ac0de')
+ h2 Response Types
+ hr
+ - if (method.responses && method.responses.length > 0)
+ - var paramCount =0
+ - each response in method.responses
+ div(style='background:#EEE;padding:10px;border:1px solid #9ac0de;margin-bottom:5px;')
+ h4
+ strong #{response.StatusCode}
+ span(style="display:inline-block;width:10px;")
+ span #{response.Type}
+ p #{response.Synopsis}
+ br
+ strong Respons Code:
+ span #{response.StatusCode}
+ br
+ strong Format:
+ span #{response.Format}
+ br
+ br
+ strong Response Data Description
+ br
+ - if (response.parameters)
+ table.parameters
+ thead
+ tr
+ th Parameter
+ th Type
+ th Description
+ tbody
+ - each parameter in response.parameters
+ div
+ tr
+ td.name!=parameter.Name
+ td.type!=parameter.Type
+ td.description
+ p!=parameter.Description || 'No description'
+ br
+ - if(response.sampleResponse)
+ h4
+ strong Example Response
+ pre #{JSON.stringify(response.sampleResponse,null,4)}
+ br
+ hr
- if (!method['read-only'])
- input(type='submit', id=method.MethodName, value='Try it!')
+ input(type='submit', id=method.MethodName, value='Try it!')
\ No newline at end of file
From bb8b509892c2ebac0000c4dfb8104686ee6f771d Mon Sep 17 00:00:00 2001
From: kushal Likhi
Date: Fri, 10 Jan 2014 17:44:26 +0530
Subject: [PATCH 5/7] Added show/hide button for the response docs.
---
views/api.jade | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/views/api.jade b/views/api.jade
index 05307aed..73aa2ba3 100644
--- a/views/api.jade
+++ b/views/api.jade
@@ -178,11 +178,13 @@ block content
a(href='#', class='add-headers') Add Header
div(style='background:#EFF5F5;padding:10px;border:1px solid #9ac0de')
h2 Response Types
+ button(onclick="$(this).parent('div').children('.responseBlock').toggle('fast');return false;") Show / Hide
+ span See the possible responses of the API method.
hr
- if (method.responses && method.responses.length > 0)
- var paramCount =0
- each response in method.responses
- div(style='background:#EEE;padding:10px;border:1px solid #9ac0de;margin-bottom:5px;')
+ div(style='background:#EEE;padding:10px;border:1px solid #9ac0de;margin-bottom:5px;display:none',class='responseBlock')
h4
strong #{response.StatusCode}
span(style="display:inline-block;width:10px;")
From 22e0662e09547b590531e620856c3d557fbe0215 Mon Sep 17 00:00:00 2001
From: kushal Likhi
Date: Thu, 16 Jan 2014 11:42:45 +0530
Subject: [PATCH 6/7] Added support for 201 responses.
---
app.js | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/app.js b/app.js
index 0535c2f6..43ce22cf 100755
--- a/app.js
+++ b/app.js
@@ -791,6 +791,12 @@ function processRequest(req, res, next) {
oa._request(httpMethod, privateReqURL, headers, requestBody, access_token, function (error, data, response) {
req.call = privateReqURL;
+ if(error && error.statusCode == 201){
+ data = error.data;
+ response = {headers:{statusCode:error.statusCode}, statusCode:error.statusCode};
+ error = null;
+ }
+
if (error) {
console.log('Got error: ' + util.inspect(error));
@@ -805,7 +811,8 @@ function processRequest(req, res, next) {
next();
} else {
req.resultHeaders = response.headers;
- req.result = JSON.parse(data);
+ req.result = data;
+ res.statusCode = response.statusCode;
next();
}
});
From 8879473f1ff267798c714024866887d3dca976e9 Mon Sep 17 00:00:00 2001
From: kushal Likhi
Date: Tue, 4 Feb 2014 17:54:37 +0530
Subject: [PATCH 7/7] Added Domain precaution for all requests
---
app.js | 524 +++++++++++++++++++++++++++++----------------------------
1 file changed, 269 insertions(+), 255 deletions(-)
diff --git a/app.js b/app.js
index 43ce22cf..a8f2306b 100755
--- a/app.js
+++ b/app.js
@@ -24,26 +24,27 @@
//
// Module dependencies
//
-var express = require('express'),
- util = require('util'),
- fs = require('fs'),
- path = require('path'),
- OAuth = require('oauth').OAuth,
- OAuth2 = require('oauth/lib/oauth2').OAuth2,
- query = require('querystring'),
- url = require('url'),
- http = require('http'),
- https = require('https'),
- crypto = require('crypto'),
- redis = require('redis'),
- jwt = require('jwt-simple'),
- request = require('request'),
- RedisStore = require('connect-redis')(express);
+var express = require('express'),
+ util = require('util'),
+ fs = require('fs'),
+ path = require('path'),
+ OAuth = require('oauth').OAuth,
+ OAuth2 = require('oauth/lib/oauth2').OAuth2,
+ query = require('querystring'),
+ url = require('url'),
+ http = require('http'),
+ https = require('https'),
+ crypto = require('crypto'),
+ domain = require('domain'),
+ redis = require('redis'),
+ jwt = require('jwt-simple'),
+ request = require('request'),
+ RedisStore = require('connect-redis')(express);
// Configuration
try {
var config = require('./config.json');
-} catch(e) {
+} catch (e) {
console.error("File config.json not found or is invalid. Try: `cp config.json.sample config.json`");
process.exit(1);
}
@@ -55,7 +56,7 @@ var defaultDB = '0';
config.redis.database = config.redis.database || defaultDB;
if (process.env.REDISTOGO_URL) {
- var rtg = require("url").parse(process.env.REDISTOGO_URL);
+ var rtg = require("url").parse(process.env.REDISTOGO_URL);
config.redis.host = rtg.hostname;
config.redis.port = rtg.port;
config.redis.password = rtg.auth.split(":")[1];
@@ -64,9 +65,9 @@ if (process.env.REDISTOGO_URL) {
var db = redis.createClient(config.redis.port, config.redis.host);
db.auth(config.redis.password);
-db.on("error", function(err) {
+db.on("error", function (err) {
if (config.debug) {
- console.log("Error " + err);
+ console.log("Error " + err);
}
});
@@ -85,34 +86,47 @@ try {
if (config.debug) {
console.log(util.inspect(apisConfig));
}
-} catch(e) {
+} catch (e) {
console.error("File apiconfig.json not found or is invalid.");
process.exit(1);
}
var app = module.exports = express();
-app.configure(function() {
+app.configure(function () {
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
+ app.use(function (req, res, next) {
+ var d = domain.create();
+ d.on("error", function (error) {
+ console.log(error);
+ res.end("Error procesing:", error.message);
+ });
+ d.add(req);
+ d.add(res);
+ d.add(next);
+ d.run(function () {
+ next();
+ });
+ });
app.use(express.logger());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({
secret: config.sessionSecret,
- store: new RedisStore({
- 'host': config.redis.host,
- 'port': config.redis.port,
- 'pass': config.redis.password,
- 'db' : config.redis.database,
+ store: new RedisStore({
+ 'host': config.redis.host,
+ 'port': config.redis.port,
+ 'pass': config.redis.password,
+ 'db': config.redis.database,
'maxAge': 1209600000
})
}));
// Global basic authentication on server (applied if configured)
if (config.basicAuth && config.basicAuth.username && config.basicAuth.password) {
- app.use(express.basicAuth(function(user, pass, callback) {
+ app.use(express.basicAuth(function (user, pass, callback) {
var result = (user === config.basicAuth.username && pass === config.basicAuth.password);
callback(null /* error */, result);
}));
@@ -124,11 +138,11 @@ app.configure(function() {
app.use(express.static(__dirname + '/public'));
});
-app.configure('development', function() {
+app.configure('development', function () {
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
-app.configure('production', function() {
+app.configure('production', function () {
app.use(express.errorHandler());
});
@@ -146,12 +160,12 @@ function oauth(req, res, next) {
refererURL = url.parse(req.headers.referer),
callbackURL = refererURL.protocol + '//' + refererURL.host + '/authSuccess/' + apiName,
oa = new OAuth(apiConfig.oauth.requestURL,
- apiConfig.oauth.accessURL,
- apiKey,
- apiSecret,
- apiConfig.oauth.version,
- callbackURL,
- apiConfig.oauth.crypt);
+ apiConfig.oauth.accessURL,
+ apiKey,
+ apiSecret,
+ apiConfig.oauth.version,
+ callbackURL,
+ apiConfig.oauth.crypt);
if (config.debug) {
console.log('OAuth type: ' + apiConfig.oauth.type);
@@ -162,7 +176,7 @@ function oauth(req, res, next) {
}
// Check if the API even uses OAuth, then if the method requires oauth, then if the session is not authed
- if (apiConfig.oauth.type == 'three-legged' && req.body.oauth == 'authrequired' && (!req.session[apiName] || !req.session[apiName].authed) ) {
+ if (apiConfig.oauth.type == 'three-legged' && req.body.oauth == 'authrequired' && (!req.session[apiName] || !req.session[apiName].authed)) {
if (config.debug) {
console.log('req.session: ' + util.inspect(req.session));
console.log('headers: ' + util.inspect(req.headers));
@@ -170,7 +184,7 @@ function oauth(req, res, next) {
console.log('sessionID: ' + util.inspect(req.sessionID));
}
- oa.getOAuthRequestToken(function(err, oauthToken, oauthTokenSecret, results) {
+ oa.getOAuthRequestToken(function (err, oauthToken, oauthTokenSecret, results) {
if (err) {
res.send("Error getting OAuth request token : " + util.inspect(err), 500);
} else {
@@ -204,12 +218,12 @@ function oauth(req, res, next) {
}
-function oauth2(req, res, next){
+function oauth2(req, res, next) {
console.log('OAuth2 process started');
var apiName = req.body.apiName,
apiConfig = apisConfig[apiName];
- if(!apiConfig.oauth2) {
+ if (!apiConfig.oauth2) {
next();
return;
}
@@ -220,21 +234,21 @@ function oauth2(req, res, next){
callbackURL = refererURL.protocol + '//' + refererURL.host + '/oauth2Success/' + apiName,
key = req.sessionID + ':' + apiName;
- if(apiConfig.oauth2.type == 'bearer-jwt'){
- console.log("Starting the JWT Bearer OAUTH, v2.0");
+ if (apiConfig.oauth2.type == 'bearer-jwt') {
+ console.log("Starting the JWT Bearer OAUTH, v2.0");
- //API url
- var accessTokenAPIUrl = apiConfig.protocol + "://" + apiConfig.baseURL + apiConfig.oauth2.accessTokenURL;
+ //API url
+ var accessTokenAPIUrl = apiConfig.protocol + "://" + apiConfig.baseURL + apiConfig.oauth2.accessTokenURL;
- var claimSet = {
+ var claimSet = {
id: apiKey,
scope: "all", //For now only all scope is supported
- exp: (1000*60*60*24) //24 hours
- };
+ exp: (1000 * 60 * 60 * 24) //24 hours
+ };
- var jwtToken = jwt.encode(claimSet, apiSecret);
+ var jwtToken = jwt.encode(claimSet, apiSecret);
- request.post(accessTokenAPIUrl, {
+ request.post(accessTokenAPIUrl, {
form: {
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", //Only this grant type is supported, i.e. Bearer. Pass this string as it is.
"assertion": jwtToken //pass the token
@@ -246,17 +260,17 @@ function oauth2(req, res, next){
var bodyObj = JSON.parse(body);
var token = bodyObj[apiConfig.oauth2.tokenName];
console.log("Access Token:", token);
- if(!token){
+ if (!token) {
req.session[apiName] = null;
- db.del(key + ':access_token',function(){
- db.del(key + ':refresh_token',function(){
- res.send(body);
- });
- });
+ db.del(key + ':access_token', function () {
+ db.del(key + ':refresh_token', function () {
+ res.send(body);
+ });
+ });
} else {
db.mset([key + ':access_token', token,
key + ':refresh_token', token
- ], function(err, results2) {
+ ], function (err, results2) {
req.session[apiName] = {};
req.session[apiName].authed = true;
if (config.debug) {
@@ -266,14 +280,14 @@ function oauth2(req, res, next){
});
}
}
- );
+ );
} else {
var oa = new OAuth2(apiKey,
- apiSecret,
- apiConfig.oauth2.baseSite,
- apiConfig.oauth2.authorizeURL,
- apiConfig.oauth2.accessTokenURL);
+ apiSecret,
+ apiConfig.oauth2.baseSite,
+ apiConfig.oauth2.authorizeURL,
+ apiConfig.oauth2.accessTokenURL);
if (apiConfig.oauth2.tokenName) {
oa.setAccessTokenName(apiConfig.oauth2.tokenName);
@@ -289,7 +303,7 @@ function oauth2(req, res, next){
var redirectUrl;
if (apiConfig.oauth2.type == 'authorization-code') {
- redirectUrl = oa.getAuthorizeUrl({redirect_uri : callbackURL, response_type : 'code'});
+ redirectUrl = oa.getAuthorizeUrl({redirect_uri: callbackURL, response_type: 'code'});
db.set(key + ':apiKey', apiKey, redis.print);
db.set(key + ':apiSecret', apiSecret, redis.print);
@@ -304,7 +318,7 @@ function oauth2(req, res, next){
}
else if (apiConfig.oauth2.type == 'implicit') {
oa._authorizeUrl = oa._accessTokenUrl;
- redirectUrl = oa.getAuthorizeUrl({redirect_uri : callbackURL, response_type : 'token'});
+ redirectUrl = oa.getAuthorizeUrl({redirect_uri: callbackURL, response_type: 'token'});
db.set(key + ':apiKey', apiKey, redis.print);
db.set(key + ':apiSecret', apiSecret, redis.print);
@@ -321,10 +335,10 @@ function oauth2(req, res, next){
var accessURL = apiConfig.oauth2.baseSite + apiConfig.oauth2.accessTokenURL;
var basic_cred = apiKey + ':' + apiSecret;
var encoded_basic = new Buffer(basic_cred).toString('base64');
-
+
var http_method = (apiConfig.oauth2.authorizationHeader == 'Y') ? "POST" : "GET";
- var header = (apiConfig.oauth2.authorizationHeader == 'Y') ? {'Authorization' : 'Basic ' + encoded_basic} : '';
- var fillerpost = query.stringify({grant_type : "client_credentials", client_id : apiKey, client_secret : apiSecret});
+ var header = (apiConfig.oauth2.authorizationHeader == 'Y') ? {'Authorization': 'Basic ' + encoded_basic} : '';
+ var fillerpost = query.stringify({grant_type: "client_credentials", client_id: apiKey, client_secret: apiSecret});
db.set(key + ':apiKey', apiKey, redis.print);
db.set(key + ':apiSecret', apiSecret, redis.print);
@@ -336,38 +350,38 @@ function oauth2(req, res, next){
db.expire(key + ':baseURL', 1209600000);
//client_credentials w/Authorization header
- oa._request(http_method, accessURL, header,
+ oa._request(http_method, accessURL, header,
fillerpost,
- '', function(error, data, response) {
- if (error) {
- res.send("Error getting OAuth access token : " + util.inspect(error), 500);
- }
- else {
- var results;
- try {
- results = JSON.parse(data);
- }
- catch(e) {
- results = query.parse(data)
+ '', function (error, data, response) {
+ if (error) {
+ res.send("Error getting OAuth access token : " + util.inspect(error), 500);
}
- var oauth2access_token = results["access_token"];
- var oauth2refresh_token = results["refresh_token"];
+ else {
+ var results;
+ try {
+ results = JSON.parse(data);
+ }
+ catch (e) {
+ results = query.parse(data)
+ }
+ var oauth2access_token = results["access_token"];
+ var oauth2refresh_token = results["refresh_token"];
- if (config.debug) {
- console.log('results: ' + util.inspect(results));
- }
- db.mset([key + ':access_token', oauth2access_token,
+ if (config.debug) {
+ console.log('results: ' + util.inspect(results));
+ }
+ db.mset([key + ':access_token', oauth2access_token,
key + ':refresh_token', oauth2refresh_token
- ], function(err, results2) {
- db.set(key + ':accessToken', oauth2access_token, redis.print);
- db.set(key + ':refreshToken', oauth2refresh_token, redis.print);
- db.expire(key + ':accessToken', 1209600000);
- db.expire(key + ':refreshToken', 1209600000);
-
- res.send({'refresh': callbackURL});
- });
- }
- })
+ ], function (err, results2) {
+ db.set(key + ':accessToken', oauth2access_token, redis.print);
+ db.set(key + ':refreshToken', oauth2refresh_token, redis.print);
+ db.expire(key + ':accessToken', 1209600000);
+ db.expire(key + ':refreshToken', 1209600000);
+
+ res.send({'refresh': callbackURL});
+ });
+ }
+ })
}
}
}
@@ -375,72 +389,72 @@ function oauth2(req, res, next){
function oauth2Success(req, res, next) {
console.log('oauth2Success started');
- var apiKey,
- apiSecret,
- apiName = req.params.api,
- apiConfig = apisConfig[apiName],
- key = req.sessionID + ':' + apiName,
- baseURL;
+ var apiKey,
+ apiSecret,
+ apiName = req.params.api,
+ apiConfig = apisConfig[apiName],
+ key = req.sessionID + ':' + apiName,
+ baseURL;
- if (config.debug) {
- console.log('apiName: ' + apiName);
- console.log('key: ' + key);
- console.log(util.inspect(req.params));
+ if (config.debug) {
+ console.log('apiName: ' + apiName);
+ console.log('key: ' + key);
+ console.log(util.inspect(req.params));
+ }
+ db.mget([
+ key + ':apiKey',
+ key + ':apiSecret',
+ key + ':baseURL',
+ key + ':accessToken',
+ key + ':refreshToken'
+ ], function (err, result) {
+ if (err) {
+ console.log(util.inspect(err));
}
- db.mget([
- key + ':apiKey',
- key + ':apiSecret',
- key + ':baseURL',
- key + ':accessToken',
- key + ':refreshToken'
- ], function(err, result) {
- if (err) {
- console.log(util.inspect(err));
- }
- apiKey = result[0];
- apiSecret = result[1];
- baseURL = result[2];
-
- if (result[3] && apiConfig.oauth2.type == 'client_credentials') {
- req.session[apiName] = {};
- req.session[apiName].authed = true;
- if (config.debug) {
- console.log('session[apiName].authed: ' + util.inspect(req.session));
- }
- next();
- }
+ apiKey = result[0];
+ apiSecret = result[1];
+ baseURL = result[2];
+ if (result[3] && apiConfig.oauth2.type == 'client_credentials') {
+ req.session[apiName] = {};
+ req.session[apiName].authed = true;
if (config.debug) {
- console.log(util.inspect(">>"+req.query.oauth_verifier));
+ console.log('session[apiName].authed: ' + util.inspect(req.session));
}
+ next();
+ }
- var oa = new OAuth2(apiKey,
- apiSecret,
- apiConfig.oauth2.baseSite,
- apiConfig.oauth2.authorizeURL,
- apiConfig.oauth2.accessTokenURL);
+ if (config.debug) {
+ console.log(util.inspect(">>" + req.query.oauth_verifier));
+ }
- if (apiConfig.oauth2.tokenName) {
- oa.setAccessTokenName(apiConfig.oauth2.tokenName);
- }
+ var oa = new OAuth2(apiKey,
+ apiSecret,
+ apiConfig.oauth2.baseSite,
+ apiConfig.oauth2.authorizeURL,
+ apiConfig.oauth2.accessTokenURL);
- if (config.debug) {
- console.log(util.inspect(oa));
- }
+ if (apiConfig.oauth2.tokenName) {
+ oa.setAccessTokenName(apiConfig.oauth2.tokenName);
+ }
+
+ if (config.debug) {
+ console.log(util.inspect(oa));
+ }
- if (apiConfig.oauth2.type == 'authorization-code') {
- oa.getOAuthAccessToken(req.query.code,
- {grant_type : "authorization_code", redirect_uri : baseURL, client_id : apiKey, client_secret : apiSecret},
- function(error, oauth2access_token, oauth2refresh_token, results){
+ if (apiConfig.oauth2.type == 'authorization-code') {
+ oa.getOAuthAccessToken(req.query.code,
+ {grant_type: "authorization_code", redirect_uri: baseURL, client_id: apiKey, client_secret: apiSecret},
+ function (error, oauth2access_token, oauth2refresh_token, results) {
if (error) {
- res.send("Error getting OAuth access token : " + util.inspect(error) + "["+oauth2access_token+"]"+ "["+oauth2refresh_token+"]", 500);
+ res.send("Error getting OAuth access token : " + util.inspect(error) + "[" + oauth2access_token + "]" + "[" + oauth2refresh_token + "]", 500);
} else {
if (config.debug) {
console.log('results: ' + util.inspect(results));
}
db.mset([key + ':access_token', oauth2access_token,
- key + ':refresh_token', oauth2refresh_token
- ], function(err, results2) {
+ key + ':refresh_token', oauth2refresh_token
+ ], function (err, results2) {
req.session[apiName] = {};
req.session[apiName].authed = true;
if (config.debug) {
@@ -450,11 +464,11 @@ function oauth2Success(req, res, next) {
});
}
});
- }
- else if (apiConfig.oauth2.type == 'implicit') {
- next();
- }
- });
+ }
+ else if (apiConfig.oauth2.type == 'implicit') {
+ next();
+ }
+ });
}
@@ -482,7 +496,7 @@ function oauthSuccess(req, res, next) {
key + ':requestTokenSecret',
key + ':apiKey',
key + ':apiSecret'
- ], function(err, result) {
+ ], function (err, result) {
if (err) {
console.log(util.inspect(err));
}
@@ -492,34 +506,34 @@ function oauthSuccess(req, res, next) {
apiSecret = result[3];
if (config.debug) {
- console.log(util.inspect(">>"+oauthRequestToken));
- console.log(util.inspect(">>"+oauthRequestTokenSecret));
- console.log(util.inspect(">>"+req.query.oauth_verifier));
+ console.log(util.inspect(">>" + oauthRequestToken));
+ console.log(util.inspect(">>" + oauthRequestTokenSecret));
+ console.log(util.inspect(">>" + req.query.oauth_verifier));
}
var oa = new OAuth(apiConfig.oauth.requestURL,
- apiConfig.oauth.accessURL,
- apiKey,
- apiSecret,
- apiConfig.oauth.version,
- null,
- apiConfig.oauth.crypt);
+ apiConfig.oauth.accessURL,
+ apiKey,
+ apiSecret,
+ apiConfig.oauth.version,
+ null,
+ apiConfig.oauth.crypt);
if (config.debug) {
console.log(util.inspect(oa));
}
- oa.getOAuthAccessToken(oauthRequestToken, oauthRequestTokenSecret, req.query.oauth_verifier, function(error, oauthAccessToken, oauthAccessTokenSecret, results) {
+ oa.getOAuthAccessToken(oauthRequestToken, oauthRequestTokenSecret, req.query.oauth_verifier, function (error, oauthAccessToken, oauthAccessTokenSecret, results) {
if (error) {
- res.send("Error getting OAuth access token : " + util.inspect(error) + "["+oauthAccessToken+"]"+ "["+oauthAccessTokenSecret+"]"+ "["+util.inspect(results)+"]", 500);
+ res.send("Error getting OAuth access token : " + util.inspect(error) + "[" + oauthAccessToken + "]" + "[" + oauthAccessTokenSecret + "]" + "[" + util.inspect(results) + "]", 500);
} else {
if (config.debug) {
console.log('results: ' + util.inspect(results));
}
db.mset([key + ':accessToken', oauthAccessToken,
key + ':accessTokenSecret', oauthAccessTokenSecret
- ], function(err, results2) {
+ ], function (err, results2) {
req.session[apiName] = {};
req.session[apiName].authed = true;
if (config.debug) {
@@ -545,7 +559,7 @@ function processRequest(req, res, next) {
var reqQuery = req.body,
customHeaders = {},
params = reqQuery.params || {},
- locations = reqQuery.locations || {},
+ locations = reqQuery.locations || {},
methodURL = reqQuery.methodUri,
httpMethod = reqQuery.httpMethod,
apiKey = reqQuery.apiKey,
@@ -556,27 +570,27 @@ function processRequest(req, res, next) {
implicitAccessToken = reqQuery.accessToken;
for (var param in params) {
- if (params.hasOwnProperty(param)) {
- if (params[param] !== '') {
- if (locations[param] == 'header') {
- // Extract custom headers from the params
- customHeaders[param] = params[param];
- delete params[param];
- } else {
- // Replace placeholders in the methodURL with matching params
- // URL params are prepended with ":"
- var regx = new RegExp(':' + param);
-
- // If the param is actually a part of the URL, put it in the URL and remove the param
- if (!!regx.test(methodURL)) {
- methodURL = methodURL.replace(regx, encodeURIComponent(params[param]));
- delete params[param]
- }
- }
- } else {
- delete params[param]; // Delete blank params
- }
- }
+ if (params.hasOwnProperty(param)) {
+ if (params[param] !== '') {
+ if (locations[param] == 'header') {
+ // Extract custom headers from the params
+ customHeaders[param] = params[param];
+ delete params[param];
+ } else {
+ // Replace placeholders in the methodURL with matching params
+ // URL params are prepended with ":"
+ var regx = new RegExp(':' + param);
+
+ // If the param is actually a part of the URL, put it in the URL and remove the param
+ if (!!regx.test(methodURL)) {
+ methodURL = methodURL.replace(regx, encodeURIComponent(params[param]));
+ delete params[param]
+ }
+ }
+ } else {
+ delete params[param]; // Delete blank params
+ }
+ }
}
var baseHostInfo = apiConfig.baseURL.split(':');
@@ -605,7 +619,7 @@ function processRequest(req, res, next) {
path: apiConfig.publicPath + methodURL// + ((paramString.length > 0) ? '?' + paramString : "")
};
- if (['POST','DELETE','PUT'].indexOf(httpMethod) !== -1) {
+ if (['POST', 'DELETE', 'PUT'].indexOf(httpMethod) !== -1) {
var requestBody = query.stringify(params);
}
@@ -619,24 +633,24 @@ function processRequest(req, res, next) {
}
db.mget([key + ':apiKey',
- key + ':apiSecret',
- key + ':accessToken',
- key + ':accessTokenSecret'
- ],
- function(err, results) {
-
- var apiKey = (typeof reqQuery.apiKey == "undefined" || reqQuery.apiKey == "undefined")?results[0]:reqQuery.apiKey,
- apiSecret = (typeof reqQuery.apiSecret == "undefined" || reqQuery.apiSecret == "undefined")?results[1]:reqQuery.apiSecret,
+ key + ':apiSecret',
+ key + ':accessToken',
+ key + ':accessTokenSecret'
+ ],
+ function (err, results) {
+
+ var apiKey = (typeof reqQuery.apiKey == "undefined" || reqQuery.apiKey == "undefined") ? results[0] : reqQuery.apiKey,
+ apiSecret = (typeof reqQuery.apiSecret == "undefined" || reqQuery.apiSecret == "undefined") ? results[1] : reqQuery.apiSecret,
accessToken = results[2],
accessTokenSecret = results[3];
var oa = new OAuth(apiConfig.oauth.requestURL || null,
- apiConfig.oauth.accessURL || null,
- apiKey || null,
- apiSecret || null,
- apiConfig.oauth.version || null,
- null,
- apiConfig.oauth.crypt);
+ apiConfig.oauth.accessURL || null,
+ apiKey || null,
+ apiSecret || null,
+ apiConfig.oauth.version || null,
+ null,
+ apiConfig.oauth.crypt);
if (config.debug) {
console.log('Access token: ' + accessToken);
@@ -644,7 +658,7 @@ function processRequest(req, res, next) {
console.log('key: ' + key);
}
- oa.getProtectedResource(privateReqURL, httpMethod, accessToken, accessTokenSecret, function (error, data, response) {
+ oa.getProtectedResource(privateReqURL, httpMethod, accessToken, accessTokenSecret, function (error, data, response) {
req.call = privateReqURL;
if (error) {
@@ -675,15 +689,15 @@ function processRequest(req, res, next) {
var body,
oa = new OAuth(null,
- null,
- apiKey || null,
- apiSecret || null,
- apiConfig.oauth.version || null,
- null,
- apiConfig.oauth.crypt);
+ null,
+ apiKey || null,
+ apiSecret || null,
+ apiConfig.oauth.version || null,
+ null,
+ apiConfig.oauth.crypt);
var resource = options.protocol + '://' + options.host + options.path,
- cb = function(error, data, response) {
+ cb = function (error, data, response) {
if (error) {
if (error.data == 'Server Error' || error.data == '') {
req.result = 'Server Error';
@@ -723,14 +737,14 @@ function processRequest(req, res, next) {
switch (httpMethod) {
case 'GET':
console.log(resource);
- oa.get(resource, '', '',cb);
+ oa.get(resource, '', '', cb);
break;
case 'PUT':
case 'POST':
oa.post(resource, '', '', JSON.stringify(obj), null, cb);
break;
case 'DELETE':
- oa.delete(resource,'','',cb);
+ oa.delete(resource, '', '', cb);
break;
}
@@ -743,13 +757,13 @@ function processRequest(req, res, next) {
if (implicitAccessToken) {
db.mset([key + ':access_token', implicitAccessToken
- ], function(err, results2) {
- req.session[apiName] = {};
- req.session[apiName].authed = true;
- if (config.debug) {
- console.log('session[apiName].authed: ' + util.inspect(req.session));
- }
- });
+ ], function (err, results2) {
+ req.session[apiName] = {};
+ req.session[apiName].authed = true;
+ if (config.debug) {
+ console.log('session[apiName].authed: ' + util.inspect(req.session));
+ }
+ });
}
if (reqQuery.oauth == 'authrequired' || (req.session[apiName] && req.session[apiName].authed)) {
@@ -758,21 +772,21 @@ function processRequest(req, res, next) {
}
db.mget([key + ':apiKey',
- key + ':apiSecret',
- key + ':access_token',
- key + ':refresh_token'
- ],
- function(err, results) {
- var apiKey = (typeof reqQuery.apiKey == "undefined" || reqQuery.apiKey == "undefined")?results[0]:reqQuery.apiKey,
- apiSecret = (typeof reqQuery.apiSecret == "undefined" || reqQuery.apiSecret == "undefined")?results[1]:reqQuery.apiSecret,
+ key + ':apiSecret',
+ key + ':access_token',
+ key + ':refresh_token'
+ ],
+ function (err, results) {
+ var apiKey = (typeof reqQuery.apiKey == "undefined" || reqQuery.apiKey == "undefined") ? results[0] : reqQuery.apiKey,
+ apiSecret = (typeof reqQuery.apiSecret == "undefined" || reqQuery.apiSecret == "undefined") ? results[1] : reqQuery.apiSecret,
access_token = (implicitAccessToken) ? implicitAccessToken : results[2],
refresh_token = results[3];
var oa = new OAuth2(apiKey,
- apiSecret,
- apiConfig.oauth2.baseSite,
- apiConfig.oauth2.authorizeURL,
- apiConfig.oauth2.accessTokenURL);
+ apiSecret,
+ apiConfig.oauth2.baseSite,
+ apiConfig.oauth2.authorizeURL,
+ apiConfig.oauth2.accessTokenURL);
if (apiConfig.oauth2.tokenName) {
oa.setAccessTokenName(apiConfig.oauth2.tokenName);
@@ -785,15 +799,15 @@ function processRequest(req, res, next) {
}
if (apiConfig.oauth2.authorizationHeader && (apiConfig.oauth2.authorizationHeader == 'Y')) {
- var headers = {Authorization : "Bearer " + access_token};
+ var headers = {Authorization: "Bearer " + access_token};
}
oa._request(httpMethod, privateReqURL, headers, requestBody, access_token, function (error, data, response) {
req.call = privateReqURL;
- if(error && error.statusCode == 201){
+ if (error && error.statusCode == 201) {
data = error.data;
- response = {headers:{statusCode:error.statusCode}, statusCode:error.statusCode};
+ response = {headers: {statusCode: error.statusCode}, statusCode: error.statusCode};
error = null;
}
@@ -831,7 +845,7 @@ function processRequest(req, res, next) {
function unsecuredCall() {
console.log('Unsecured Call');
- if (['POST','PUT','DELETE'].indexOf(httpMethod) === -1) {
+ if (['POST', 'PUT', 'DELETE'].indexOf(httpMethod) === -1) {
options.path += ((paramString.length > 0) ? '?' + paramString : "");
}
@@ -851,13 +865,13 @@ function processRequest(req, res, next) {
var timeStamp, sig;
if (apiConfig.signature.type == 'signed_md5') {
// Add signature parameter
- timeStamp = Math.round(new Date().getTime()/1000);
+ timeStamp = Math.round(new Date().getTime() / 1000);
sig = crypto.createHash('md5').update('' + apiKey + apiSecret + timeStamp + '').digest(apiConfig.signature.digest);
options.path += '&' + apiConfig.signature.sigParam + '=' + sig;
}
else if (apiConfig.signature.type == 'signed_sha256') { // sha256(key+secret+epoch)
// Add signature parameter
- timeStamp = Math.round(new Date().getTime()/1000);
+ timeStamp = Math.round(new Date().getTime() / 1000);
sig = crypto.createHash('sha256').update('' + apiKey + apiSecret + timeStamp + '').digest(apiConfig.signature.digest);
options.path += '&' + apiConfig.signature.sigParam + '=' + sig;
}
@@ -872,7 +886,7 @@ function processRequest(req, res, next) {
for (var x = 0, len = reqQuery.headerNames.length; x < len; x++) {
if (config.debug) {
- console.log('Setting header: ' + reqQuery.headerNames[x] + ':' + reqQuery.headerValues[x]);
+ console.log('Setting header: ' + reqQuery.headerNames[x] + ':' + reqQuery.headerValues[x]);
}
if (reqQuery.headerNames[x] != '') {
headers[reqQuery.headerNames[x]] = reqQuery.headerValues[x];
@@ -881,7 +895,7 @@ function processRequest(req, res, next) {
options.headers = headers;
}
- if(options.headers === void 0){
+ if (options.headers === void 0) {
options.headers = {}
}
if (!options.headers['Content-Length']) {
@@ -912,7 +926,7 @@ function processRequest(req, res, next) {
}
// API Call. response is the response from the API, res is the response we will send back to the user.
- var apiCall = doRequest(options, function(response) {
+ var apiCall = doRequest(options,function (response) {
response.setEncoding('utf-8');
if (config.debug) {
@@ -924,11 +938,11 @@ function processRequest(req, res, next) {
var body = '';
- response.on('data', function(data) {
+ response.on('data', function (data) {
body += data;
});
- response.on('end', function() {
+ response.on('end', function () {
delete options.agent;
var responseContentType = response.headers['content-type'];
@@ -950,13 +964,13 @@ function processRequest(req, res, next) {
next();
})
- }).on('error', function(e) {
- if (config.debug) {
- console.log('HEADERS: ' + JSON.stringify(res.headers));
- console.log("Got error: " + e.message);
- console.log("Error: " + util.inspect(e));
- }
- });
+ }).on('error', function (e) {
+ if (config.debug) {
+ console.log('HEADERS: ' + JSON.stringify(res.headers));
+ console.log("Got error: " + e.message);
+ console.log("Error: " + util.inspect(e));
+ }
+ });
if (requestBody) {
apiCall.end(requestBody, 'utf-8');
@@ -972,7 +986,7 @@ function checkPathForAPI(req, res, next) {
if (!req.params) req.params = {};
if (!req.params.api) {
// If api wasn't passed in as a parameter, check the path to see if it's there
- var pathName = req.url.replace('/','');
+ var pathName = req.url.replace('/', '');
// Is it a valid API - if there's a config file we can assume so
fs.stat(path.join(config.apiConfigDir, pathName + '.json'), function (error, stats) {
if (stats) {
@@ -1008,14 +1022,14 @@ function dynamicHelpers(req, res, next) {
//
// Routes
//
-app.get('/', function(req, res) {
+app.get('/', function (req, res) {
res.render('listAPIs', {
title: config.title
});
});
// Process the API request
-app.post('/processReq', oauth, processRequest, function(req, res) {
+app.post('/processReq', oauth, processRequest, function (req, res) {
var result = {
headers: req.resultHeaders,
response: req.result,
@@ -1031,26 +1045,26 @@ app.all('/auth2', oauth2);
// OAuth callback page, closes the window immediately after storing access token/secret
-app.get('/authSuccess/:api', oauthSuccess, function(req, res) {
+app.get('/authSuccess/:api', oauthSuccess, function (req, res) {
res.render('authSuccess', {
title: 'OAuth Successful'
});
});
// OAuth callback page, closes the window immediately after storing access token/secret
-app.get('/oauth2Success/:api', oauth2Success, function(req, res) {
+app.get('/oauth2Success/:api', oauth2Success, function (req, res) {
res.render('authSuccess', {
title: 'OAuth Successful'
});
});
-app.post('/upload', function(req, res) {
- res.redirect('back');
+app.post('/upload', function (req, res) {
+ res.redirect('back');
});
// API shortname, all lowercase
-app.get('/:api([^\.]+)', function(req, res) {
- req.params.api=req.params.api.replace(/\/$/,'');
+app.get('/:api([^\.]+)', function (req, res) {
+ req.params.api = req.params.api.replace(/\/$/, '');
res.render('api');
});
@@ -1059,7 +1073,7 @@ app.get('/:api([^\.]+)', function(req, res) {
if (!module.parent) {
var port = process.env.PORT || config.port;
var l = app.listen(port);
- l.on('listening', function(err) {
+ l.on('listening', function (err) {
console.log("Express server listening on port %d", port);
});
}