andbang-express-auth
Advanced tools
Comparing version 0.0.2 to 0.0.3
159
index.js
var _ = require('underscore'), | ||
colors = require('colors'), | ||
crypto = require('crypto'), | ||
request = require('request'), | ||
@@ -8,2 +9,4 @@ querystring = require('querystring'); | ||
function AndBangMiddleware() { | ||
var self = this; | ||
this.showHelp = function (message) { | ||
@@ -52,3 +55,4 @@ var output = [ | ||
loggedOutRedirect: '/', | ||
loginPageUrl: '/login' | ||
loginPageUrl: '/login', | ||
loginFailedRedirect: '/login-failed' | ||
}, config); | ||
@@ -59,24 +63,37 @@ | ||
this.apiUrl = config.local ? 'http://localhost:3000' : 'https://api.andbang.com'; | ||
this.secureCookies = !config.local; | ||
// the login route | ||
// The login route. If we already have a token in the session we'll | ||
// just continue through. | ||
this.app.get('/auth', function (req, res) { | ||
if (req.session.accessToken) { | ||
res.redirect(self.defaultRedirect); | ||
} else { | ||
var url = self.accountsUrl + '/oauth/authorize?' + querystring.stringify({ | ||
response_type: 'code', | ||
client_id: self.clientId, | ||
type: 'web_server' | ||
}); | ||
res.redirect(url); | ||
if (req.cookies.accessToken || req.session.token) { | ||
return res.redirect(self.defaultRedirect); | ||
} | ||
delete req.session.token; | ||
res.clearCookie('accessToken'); | ||
req.session.oauthState = crypto.createHash('sha1').update(crypto.randomBytes(4098)).digest('hex') | ||
var url = self.accountsUrl + '/oauth/authorize?' + querystring.stringify({ | ||
response_type: 'code', | ||
client_id: self.clientId, | ||
state: req.session.oauthState | ||
}); | ||
res.redirect(url); | ||
}); | ||
this.app.get('/auth/andbang/callback', function (req, response) { | ||
var code = querystring.parse(req.url.split('?')[1]).code, | ||
token; | ||
var result = querystring.parse(req.url.split('?')[1]); | ||
if (result.error) { | ||
response.redirect('/auth/andbang/failed'); | ||
} | ||
if (result.state != req.session.oauthState) { | ||
response.redirect('/auth/andbang/failed'); | ||
} | ||
request.post({ | ||
url: self.accountsUrl + '/oauth/access_token', | ||
form: { | ||
code: code, | ||
code: result.code, | ||
grant_type: 'authorization_code', | ||
@@ -88,26 +105,28 @@ client_id: self.clientId, | ||
if (res && res.statusCode === 200) { | ||
token = JSON.parse(body).access_token; | ||
} | ||
request.get({ | ||
url: self.apiUrl + '/me', | ||
headers: { | ||
authorization: 'Bearer ' + token | ||
}, | ||
json: true | ||
}, function (err, res, body) { | ||
token = JSON.parse(body); | ||
req.session.token = token; | ||
req.session.token.grant_date = Date.now(); | ||
var nextUrl = req.session.nextUrl || self.defaultRedirect || '/'; | ||
if (res && res.statusCode === 200) { | ||
req.session.user = body; | ||
req.session.accessToken = token; | ||
delete req.session.nextUrl; | ||
req.session.save(function () { | ||
delete req.session.nextUrl; | ||
req.session.save(function () { | ||
response.cookie('accessToken', token.access_token, { | ||
maxAge: 86400000, | ||
secure: self.secureCookies | ||
}); | ||
return self.userRequired(req, response, function () { | ||
response.redirect(nextUrl); | ||
}); | ||
} else { | ||
response.redirect('/login-failed'); | ||
} | ||
}); | ||
}); | ||
} else { | ||
response.redirect('/auth/andbang/failed'); | ||
} | ||
}); | ||
}); | ||
this.app.get('/auth/andbang/failed', function (req, res) { | ||
delete req.session.token; | ||
res.clearCookie('accessToken'); | ||
res.redirect(self.loginFailedRedirect); | ||
}); | ||
this.app.get('/logout', function (req, res) { | ||
@@ -124,12 +143,76 @@ req.session.destroy(); | ||
this.userRequired = function (req, res, next) { | ||
// Ensure that a user object is available after validating | ||
// or retrieving a token. | ||
if (req.session.user) { | ||
next(); | ||
} else { | ||
request.get({ | ||
url: self.apiUrl + '/me', | ||
headers: { | ||
authorization: 'Bearer ' + req.session.token.access_token | ||
}, | ||
json: true | ||
}, function (err, res2, body) { | ||
if (res2 && res2.statusCode === 200) { | ||
req.session.user = body; | ||
next(); | ||
} else { | ||
res.redirect('/auth/andbang/failed'); | ||
} | ||
}); | ||
} | ||
} | ||
this.secure = function () { | ||
var self = this; | ||
// Check that an access token is available, either in the current | ||
// session or cached in a cookie. We'll validate cached tokens to | ||
// ensure that they were issued for our app and aren't expired. | ||
return function (req, res, next) { | ||
if (req.session.user) { | ||
next(); | ||
var cookieToken = req.cookies.accessToken, | ||
sessionToken; | ||
if (req.session.token) { | ||
sessionToken = req.session.token.access_token; | ||
} | ||
if (!cookieToken && !sessionToken) { | ||
req.session.nextUrl = req.url; | ||
return res.redirect('/auth'); | ||
} else if (!cookieToken && sessionToken) { | ||
res.cookie('accessToken', sessionToken, { | ||
maxAge: 86400000, | ||
secure: self.secureCookies | ||
}); | ||
return self.userRequired(req, res, next); | ||
} else if (cookieToken && !sessionToken) { | ||
request.post({ | ||
url: self.accountsUrl + '/oauth/validate', | ||
form: { | ||
access_token: cookieToken, | ||
client_id: self.clientId, | ||
client_secret: self.clientSecret | ||
}, | ||
}, function (err, res2, body) { | ||
if (res2 && res2.statusCode === 200) { | ||
var token = JSON.parse(body); | ||
if (token.access_token === cookieToken) { | ||
req.session.token = token; | ||
req.session.token.grant_date = Date.now(); | ||
return self.userRequired(req, res, next); | ||
} | ||
} | ||
res.clearCookie('accessToken'); | ||
res.redirect('/auth'); | ||
}); | ||
} else if (cookieToken && sessionToken && cookieToken !== sessionToken) { | ||
res.cookie('accessToken', sessionToken, { | ||
maxAge: 86400000, | ||
secure: self.secureCookies | ||
}); | ||
return self.userRequired(req, res, next); | ||
} else { | ||
req.session.nextUrl = req.url; | ||
res.redirect(self.loginPageUrl); | ||
return self.userRequired(req, res, next); | ||
} | ||
} | ||
} | ||
}; | ||
@@ -136,0 +219,0 @@ } |
{ | ||
"name": "andbang-express-auth", | ||
"description": "Dead simple And Bang auth middleware.", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"dependencies": { | ||
"express": "3.x", | ||
"colors": "", | ||
"request": "" | ||
"request": "", | ||
"crypto": "" | ||
}, | ||
"main": "index.js" | ||
} |
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Found 1 instance in 1 package
10560
220
4
4
+ Addedcrypto@
+ Addedcrypto@1.0.1(transitive)