Created
June 3, 2012 02:23
-
-
Save max-mapper/2861012 to your computer and use it in GitHub Desktop.
github oauth with tako and leveldb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var path = require('path') | |
var tako = require('tako') | |
var gist = require('gist') | |
var request = require('request') | |
var qs = require('querystring') | |
var leveldb = require('leveldb') | |
var https = require('https') | |
var htmldir = path.resolve(__dirname, 'attachments') | |
var t = tako() | |
t.templates.directory(path.resolve(__dirname, 'templates')) | |
var options = { | |
clientID: process.env['GITHUB_KEY'], | |
clientSecret: process.env['GITHUB_SECRET'], | |
callbackURL: process.env['VHOST'] + "/githuboauthcallback" | |
} | |
t.route('/', function (req, resp) { | |
var page = t.page() | |
page.template('index') | |
page.on('finish', function(results) { | |
results.user = req.user | |
}) | |
req.pipe(page).pipe(resp) | |
}) | |
t.route('/me', function (req, resp) { | |
getProfile(req.user.token, function(err, data) { | |
resp.end(data) | |
}) | |
}).must('auth') | |
t.route('/logout', function (req, resp) { | |
setCookie('', resp) | |
resp.statusCode = 302 | |
resp.setHeader('location', process.env['VHOST']) | |
resp.end() | |
}) | |
t.route('/githuboauth', function (req, resp) { | |
var u = 'https://github.com/login/oauth/authorize' | |
+ '?client_id=' + options.clientID | |
+ '&redirect_uri=' + options.callbackURL | |
+ '&scope=user,public_repo,repo,gist' | |
resp.statusCode = 302 | |
resp.setHeader('location', u) | |
resp.end() | |
}) | |
t.route('/githuboauthcallback', function (req, resp) { | |
var reqBody = { | |
client_id: options.clientID, | |
client_secret: options.clientSecret, | |
redirect_uri: options.callbackURL, | |
code: req.qs.code | |
} | |
request.post({ | |
uri: 'https://github.com/login/oauth/access_token', | |
headers: { | |
"content-type": "application/x-www-form-urlencoded", | |
"accept": "application/json" | |
}, | |
body: qs.encode(reqBody) | |
}, | |
function (e, r, body) { | |
resp.statusCode = 200 | |
var data = JSON.parse(body) | |
var token = data.access_token | |
setCookie(token, resp) | |
saveUser(token, resp) | |
} | |
) | |
}) | |
t.route('/*').files(htmldir) | |
t.auth(function(req, resp, cb) { | |
var token = extractToken(req) | |
if (!token) return cb(null) | |
getDB('users', function(err, db) { | |
db.get(token, function(err, data) { | |
if (err) return cb(null) | |
if (!data) return cb(null) | |
cb(JSON.parse(data)) | |
}) | |
}) | |
}) | |
function getProfile(token, cb) { | |
var options = { | |
host: 'api.github.com', | |
port: 443, | |
path: '/user?' + qs.stringify({access_token: token}), | |
method: 'GET' | |
} | |
var req = https.request(options, function(res) { | |
var resp = "" | |
res.on('data', function(d) { | |
resp += d.toString() | |
}) | |
res.on('end', function() { cb(false, JSON.parse(resp)) }) | |
res.on('error', function(err) { cb(err) }) | |
}) | |
req.end() | |
} | |
function saveUser(token, resp) { | |
getDB('users', function(err, db) { | |
db.put(token, JSON.stringify({token: token}), function(err) { | |
if (err) { | |
resp.statusCode = 500 | |
return resp.end('error saving user') | |
} | |
resp.statusCode = 302 | |
resp.setHeader('location', process.env['VHOST']) | |
resp.end() | |
}) | |
}) | |
} | |
function getDB(name, cb) { | |
if (!t.dbs) t.dbs = {} | |
if (t.dbs[name]) return cb(null, t.dbs[name]) | |
leveldb.open(name + ".leveldb", { create_if_missing: true }, function(err, db) { | |
if (err) return cb(err) | |
t.dbs[name] = db | |
cb(null, db) | |
}) | |
} | |
function setCookie(id, resp) { | |
var twoWeeks = new Date(new Date().getTime()+1209726000).toUTCString() | |
resp.setHeader('set-cookie', ['Token='+id + '; Version=1; Path=/; HttpOnly; Expires=' + twoWeeks]) | |
resp.setHeader('x-token', id) | |
} | |
function extractToken(req) { | |
if (req.headers.cookie) { | |
var cookies = parseCookies(req.headers.cookie) | |
if (cookies['Token']) return cookies['Token'] | |
} | |
if (req.headers['x-token']) return req.headers['x-token'] | |
if (req.qs && req.qs.token) return req.qs.token | |
return false | |
} | |
function parseCookies(cookie) { | |
var cookies = {} | |
cookie.split(';').forEach(function( cookie ) { | |
var parts = cookie.split('=') | |
cookies[ parts[ 0 ].trim() ] = ( parts[ 1 ] || '' ).trim() | |
}) | |
return cookies | |
} | |
t.httpServer.listen(8000, function () { | |
console.log('dun runnin') | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
what leveldb bindings are you using? there are like 3 that are all incompatible forks, some of which aren't in npm.