Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Dominiek ter Heide
committed
Mar 4, 2010
0 parents
commit 2c9eb0b
Showing
9 changed files
with
370 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[submodule "lib/support/express"] | ||
path = lib/support/express | ||
url = git://github.com/visionmedia/express.git | ||
[submodule "lib/support/hashlib"] | ||
path = lib/support/hashlib | ||
url = git://github.com/brainfucker/hashlib.git |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
h1. Facebook Connect for NodeJS | ||
|
||
|
||
h2. Example: FB Connect | ||
|
||
|
||
h2. Example: A Facebook Application | ||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
|
||
require.paths.unshift(__dirname + '/../../lib') | ||
require.paths.unshift(__dirname + '/../../lib/support/express/lib') | ||
require.paths.unshift(__dirname + '/../../lib/support/hashlib/build/default') | ||
|
||
require('express') | ||
require('express/plugins') | ||
require('sys') | ||
|
||
configure(function(){ | ||
use(MethodOverride) | ||
use(ContentLength) | ||
use(Cookie) | ||
use(Session) | ||
use(CommonLogger) | ||
use(require('facebook').Facebook, { | ||
apiKey: 'e1249f7d4bc25b8f90e5c9c7523e3ee1', | ||
apiSecret: '4ae45734dd66fa85c7b189fc2d7d5b4c' | ||
}) | ||
set('root', __dirname) | ||
}) | ||
|
||
// Called to get information about the current authenticated user | ||
get('/fbSession', function(){ | ||
var fbSession = this.fbSession() | ||
|
||
if(fbSession) { | ||
// Here would be a nice place to lookup userId in the database | ||
// and supply some additional information for the client to use | ||
} | ||
|
||
// The client will only assume authentication was OK if userId exists | ||
this.contentType('json') | ||
this.halt(200, JSON.stringify(fbSession || {})) | ||
}) | ||
|
||
// Called after a successful FB Connect | ||
post('/fbSession', function() { | ||
var fbSession = this.fbSession() // Will return null if verification was unsuccesful | ||
|
||
if(fbSession) { | ||
// Now that we have a Facebook Session, we might want to store this new user in the db | ||
// Also, in this.params there is additional information about the user (name, pic, first_name, etc) | ||
// Note of warning: unlike fbSession, this additional information has not been verified | ||
fbSession.first_name = this.params.post['first_name'] | ||
} | ||
|
||
this.contentType('json') | ||
this.halt(200, JSON.stringify(fbSession || {})) | ||
}) | ||
|
||
// Called on Facebook logout | ||
post('/fbLogout', function() { | ||
this.fbLogout(); | ||
this.halt(200, JSON.stringify({})) | ||
}) | ||
|
||
// Static files in ./public | ||
get('/', function(file){ this.sendfile(__dirname + '/public/index.html') }) | ||
get('/xd_receiver.htm', function(file){ this.sendfile(__dirname + '/public/xd_receiver.htm') }) | ||
get('/javascripts/jquery.facebook.js', function(file){ this.sendfile(__dirname + '/public/javascripts/jquery.facebook.js') }) | ||
|
||
run() |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
<html xmlns="http://www.w3.org/1999/xhtml"> | ||
<head> | ||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> | ||
<script type="text/javascript" src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php"></script> | ||
<script type="text/javascript" src="/javascripts/jquery.facebook.js"></script> | ||
<script type="text/javascript"> | ||
$(document).ready(function () { | ||
$.fbInit('e1249f7d4bc25b8f90e5c9c7523e3ee1'); | ||
|
||
// FB Connect action | ||
$('#fb-connect').bind('click', function () { | ||
$.fbConnect({'include': ['first_name', 'last_name', 'name', 'pic']}, function (fbSession) { | ||
$('.not_authenticated').hide(); | ||
$('.authenticated').show(); | ||
$('#fb-first_name').html(fbSession.first_name); | ||
}); | ||
return false; | ||
}); | ||
|
||
// FB Logout action | ||
$('#fb-logout').bind('click', function () { | ||
$.fbLogout(function () { | ||
$('.authenticated').hide(); | ||
$('.not_authenticated').show(); | ||
}); | ||
return false; | ||
}); | ||
|
||
// Check whether we're logged in and arrange page accordingly | ||
$.fbIsAuthenticated(function (fbSession) { | ||
// Authenticated! | ||
$('.authenticated').show(); | ||
$('#fb-first_name').html(fbSession.first_name); | ||
}, function () { | ||
// Not authenticated | ||
$('.not_authenticated').show(); | ||
}); | ||
|
||
}); | ||
</script> | ||
</head> | ||
|
||
<body> | ||
<div id="fb-root"></div> | ||
<div id="my-account"> | ||
<div class="authenticated" style="display: none"> | ||
Hi there <span id="fb-first_name"></span>! | ||
<a href="#" id="fb-logout">Logout</a> | ||
</div> | ||
<div class="not_authenticated" style="display: none"> | ||
<a href="#" id="fb-connect">Connect with Facebook</a> | ||
</div> | ||
</div> | ||
</body> | ||
</html> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
|
||
(function($){ | ||
|
||
// Note: these variables are cache, validation is still server-side | ||
var authenticated = null; | ||
var authenticatedFbSession = null; | ||
var apiKey = null; | ||
var fbOptions = null; | ||
|
||
$.fbInit = function (api_key, options) { | ||
apiKey = api_key; | ||
fbOptions = options || {}; | ||
FB_RequireFeatures(["Api"], function() { | ||
FB.Facebook.init(api_key, fbOptions['xd_receiver'] || '/xd_receiver.htm'); | ||
}); | ||
}; | ||
|
||
$.fbConnect = function(options, callback) { | ||
options = options || {}; | ||
if(!options['include']) { | ||
options['include'] = ['name', 'pic']; | ||
} | ||
FB.Connect.requireSession(function () { | ||
FB.Facebook.apiClient.fql_query("SELECT " + options['include'].join(', ') + " FROM user WHERE uid="+$.fbCookie('user'), function(rows) { | ||
$.post("/fbSession", rows[0], function (fbSession) { | ||
if (fbSession['userId']) { | ||
authenticated = true; | ||
authenticatedFbSession = fbSession; | ||
if(callback) { | ||
callback(fbSession); | ||
} | ||
} else { | ||
authenticated = false; | ||
if(callback) { | ||
callback(); | ||
} | ||
} | ||
}, 'json'); | ||
}); | ||
}); | ||
}; | ||
|
||
$.fbLogout = function (callback) { | ||
FB.Connect.logout(function () { | ||
$.post("/fbLogout", {}, function () { | ||
callback(); | ||
}, 'json'); | ||
}); | ||
}; | ||
|
||
$.fbIsAuthenticated = function (authenticated_callback, not_authenticated_callback) { | ||
if(authenticated === null) { | ||
$.get(fbOptions['sessionSyncAction'] || '/fbSession', {}, function (fbSession) { | ||
if (fbSession['userId']) { | ||
authenticated = true; | ||
authenticatedFbSession = fbSession; | ||
authenticated_callback(authenticatedFbSession); | ||
} else { | ||
authenticated = false; | ||
not_authenticated_callback(); | ||
} | ||
}, 'json'); | ||
return; | ||
} | ||
if(authenticated === true) { | ||
authenticated_callback(authenticatedFbSession); | ||
} else { | ||
not_authenticated_callback(); | ||
} | ||
}; | ||
|
||
$.fbCookie = function (name) { | ||
name = apiKey + '_' +name; | ||
var cookieValue = null; | ||
if (document.cookie && document.cookie != '') { | ||
var cookies = document.cookie.split(';'); | ||
for (var i = 0; i < cookies.length; i++) { | ||
var cookie = jQuery.trim(cookies[i]); | ||
// Does this cookie string begin with the name we want? | ||
if (cookie.substring(0, name.length + 1) == (name + '=')) { | ||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); | ||
break; | ||
} | ||
} | ||
} | ||
return cookieValue; | ||
}; | ||
|
||
})(jQuery); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | ||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
<html xmlns="http://www.w3.org/1999/xhtml" > | ||
<head> | ||
<title>Cross-Domain Receiver Page</title> | ||
</head> | ||
<body> | ||
<script src="http://static.ak.facebook.com/js/api_lib/v0.4/XdCommReceiver.js?v2" type="text/javascript"></script> | ||
</body> | ||
</html> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
|
||
// Express - Facebook - By Dominiek ter Heide (MIT Licensed) | ||
|
||
sys = require('sys') | ||
hashlib = require('hashlib') | ||
events = require('events') | ||
http = require('express/http') | ||
|
||
exports.FBSession = Class({ | ||
init: function (userId) { | ||
this.userId = userId; | ||
} | ||
}); | ||
|
||
|
||
exports.Facebook = Plugin.extend({ | ||
extend: { | ||
|
||
/** | ||
* Initialize extensions. | ||
*/ | ||
|
||
init: function(options) { | ||
var apiKey = options['apiKey'] | ||
var apiSecret = options['apiSecret'] | ||
|
||
// --- Internal methods | ||
|
||
var getFingerprintForCookie = function (cookies) { | ||
var fields = ['expires', 'session_key', 'ss', 'user']; | ||
var fingerprint = ''; | ||
fields.sort(); | ||
for(var i in fields) { | ||
fingerprint += fields[i]+'='+cookies[apiKey + '_' + fields[i]]; | ||
} | ||
return fingerprint; | ||
} | ||
|
||
var getFingerprintForParams = function (params) { | ||
var fields = []; | ||
for(var i in params) { | ||
if(i.match(/^fb_sig_/)) { | ||
fields.push(i); | ||
} | ||
} | ||
fields.sort(); | ||
var fingerprint = ''; | ||
fields.sort(); | ||
for(var i in fields) { | ||
fingerprint += fields[i].replace(/^fb_sig_/, '')+'='+params[fields[i]]; | ||
} | ||
return fingerprint; | ||
} | ||
|
||
Request.include({ | ||
|
||
/** | ||
* Find or create Facebook session based on stored session, GET params or cookie | ||
* | ||
* Options: | ||
* | ||
* - | ||
* - | ||
* | ||
* @param {hash} options | ||
* @return {string} | ||
* @api public | ||
*/ | ||
|
||
fbSession: function(options) { | ||
var session = this.session.fbSession; | ||
if(session) | ||
sys.puts("Cool, found existing session!") | ||
if(session) | ||
return session; | ||
if(this.fbAuthenticate()) { | ||
var fbUserId = this.param('fb_sig_user') ? this.param('fb_sig_user') : this.cookie(apiKey + '_user') | ||
this.session.fbSession = new exports.FBSession(fbUserId); | ||
return this.session.fbSession; | ||
} | ||
return null; | ||
}, | ||
|
||
/** | ||
* Try authenticating by verifying Facebook data in GET params and cookie | ||
* | ||
* Options: | ||
* | ||
* - | ||
* - | ||
* | ||
* @param {hash} options | ||
* @return {string} | ||
* @api public | ||
*/ | ||
|
||
fbAuthenticate: function(options) { | ||
var cookies = this.cookies; | ||
var params = this.params; | ||
|
||
// Get a fingerprint and signature | ||
var fingerprint = null; | ||
var signature = null; | ||
if(cookies[apiKey]) { | ||
fingerprint = getFingerprintForCookie(cookies) | ||
signature = cookies[apiKey] | ||
} | ||
if(params['fb_sig']) { | ||
fingerprint = getFingerprintForParams(params) | ||
signature = params['fb_sig'] | ||
} | ||
if(!fingerprint) | ||
return null; | ||
|
||
// Verify signature using apiSecret | ||
var expected_signature = hashlib.md5(fingerprint+apiSecret); | ||
var valid = (expected_signature === signature) | ||
if(!valid) | ||
sys.puts("Warning, invalid signature: "+fingerprint) | ||
return valid | ||
}, | ||
|
||
/** | ||
* Logout | ||
* @return null | ||
* @api public | ||
*/ | ||
fbLogout: function() { | ||
this.session.fbSession = null | ||
return null | ||
}, | ||
}) | ||
} | ||
} | ||
}) |
Submodule express
added at
7bd834
Submodule hashlib
added at
a1a03f