Permalink
Browse files

initial import

  • Loading branch information...
0 parents commit 13716cf84033193927edf6041e394a1f79b62f45 @rsms committed Mar 20, 2011
Showing with 198 additions and 0 deletions.
  1. +45 −0 README.md
  2. +40 −0 connect_facebook.mv
  3. +86 −0 example/index.html
  4. +16 −0 example/server.mv
  5. +11 −0 package.json
45 README.md
@@ -0,0 +1,45 @@
+# connect_facebook
+
+Facebook session support for [Connect](http://senchalabs.github.com/connect/).
+
+*connect\_facebook* enables you to build web sites that use [Facebook authentication](https://developers.facebook.com/docs/reference/javascript/FB.login/) both on the front-end (HTML/JS) and the back-end (server-side), allowing for a smooth user experience.
+
+This middleware reads and cryptographically verifies the session, making it accessible from `req.fb_session` -- an object if authorized and valid, otherwise the request has no valid Facebook user session. The `req.fb_session` object is the same as returned by the client-side `FB.getLoginStatus`, `auth.sessionChange` event, etc.
+
+
+## Example
+
+server.mv
+
+ import connect, connect_facebook
+ connect()
+ .use(connect_facebook('YOUR_FACEBOOK_APP_ID', 'YOUR_FACEBOOK_APP_SECRET'))
+ .use(^(req, res, next) {
+ res.end(req.fb_session ? 'Logged in' : 'Not logged in')
+ })
+ .listen 3000
+
+See `example/` for a complete demo including client-side code.
+
+
+## MIT license
+
+Copyright (c) 2011 Rasmus Andersson <http://rsms.me/>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
40 connect_facebook.mv
@@ -0,0 +1,40 @@
+# Facebook support for Connect, enabling the use of Facebook user sessions
+import crypto, connect
+parse_qs = require('querystring').parse
+
+connect_facebook = ^(app_id, app_secret) {
+ if (!app_id) throw new TypeError('missing app_id argument')
+ if (!app_secret) throw new TypeError('missing app_secret argument')
+ if (typeof app_id != 'string')
+ throw new TypeError('invalid app_id -- did you forget to configure the'+
+ ' connect_facebook middleware?')
+ ^(req, res, next) {
+ if (!req.cookies) {
+ # Parse cookies using the connect cookie parser, unless already parsed
+ err = null
+ connect.cookieParser() req, res, ^(e){ err = e }
+ if (err) return next err
+ }
+
+ # Acquire the Facebook app session cookie and proceed if found
+ fb_session = req.cookies["fbs_"+app_id]
+ if (!fb_session) return next()
+ fb_session = parse_qs fb_session
+
+ # Verify session signature
+ hash = crypto.createHash 'md5'
+ hash.update Object.keys(fb_session).sort().map(^(k){
+ (k == 'sig') ? "" : k+"="+fb_session[k]
+ }).join('')+app_secret
+ actual_signature = hash.digest 'hex'
+ expected_signature = fb_session.sig
+
+ # Assign req.fb_session if valid
+ if (actual_signature == expected_signature)
+ req.fb_session = fb_session
+
+ next()
+ }
+}
+
+module.exports = connect_facebook
86 example/index.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
+ <script src="http://connect.facebook.net/en_US/all.js"></script>
+ <script src="http://movelang.org/move.js"></script>
+ <script type="text/move">
+
+FB.init { appId: 'YOUR_FACEBOOK_APP_ID', status: true, cookie: true }
+
+// Setup needed?
+if (FB._apiKey == 'YOUR_FACEBOOK_APP_ID') {
+ $('body').html '<h1>Setup</h1><ol>'+
+ '<li>Replace <tt>YOUR_FACEBOOK_APP_ID</tt> in <b>index.html</b> with your '+
+ 'Facebook app ID</li>'+
+ '<li>Replace <tt>YOUR_FACEBOOK_APP_ID</tt> in <b>server.mv</b> with your '+
+ 'Facebook app ID</li>'+
+ '<li>Replace <tt>YOUR_FACEBOOK_APP_SECRET</tt> in <b>server.mv</b> with '+
+ 'your Facebook app secret</li>'+
+ '<li>(Re)start <tt>move server.mv</tt> and reload this site</li>'+
+ '</ol>'+
+ '<a href="https://www.facebook.com/developers/apps.php">'+
+ 'Your Facebook apps &rarr;</a>'
+ throw new Error('App not configured')
+}
+
+onSessionChanged = ^(response) {
+ print 'onSessionChanged:', response.session
+ if (response.session) {
+ $('body').removeClass('fb-logged-out').addClass 'fb-logged-in'
+ } else {
+ $('body').removeClass('fb-logged-in').addClass 'fb-logged-out'
+ }
+}
+
+FB.Event.subscribe 'auth.sessionChange', onSessionChanged
+FB.getLoginStatus onSessionChanged
+
+$('button.login').click ^{
+ !FB.login ^{}, {perms: 'read_stream'}
+}
+
+$('button.test').click ^{
+ $('pre.message').text "Sending request..."
+ !$.get '/test', ^(response) {
+ $('pre.message').text "Response: "+response
+ }
+}
+
+// Running from file: or localhost will not work in most browsers
+if (document.location.protocol.indexOf('file') == 0) {
+ $('body').append '<h2>Warning</h2><p>You are accessing this example from a '+
+ 'file. You need to access this example at http://yourhostname:3000/.'
+} else if (document.location.hostname == 'localhost') {
+ $('body').append '<b>Warning:</b> You are running this from "localhost". '+
+ 'Some browsers will not save and/or pass cookies around. If you are '+
+ 'having trouble, try running this from another hostname (e.g. john.local '+
+ 'or your IP address)'
+}
+
+ </script>
+ <style type="text/css" media="screen">
+ body { font: 18px/1.5 sans-serif; padding:0; margin:2em; }
+ tt, pre { background: #f0f0f0; padding:0 0.2em; }
+ body.fb-logged-out .loading, body.fb-logged-in .loading { display:none; }
+ .not-loading, .logged-in, .logged-out { display:none; }
+ body.fb-logged-out .not-loading, body.fb-logged-in .not-loading,
+ body.fb-logged-out .logged-out, body.fb-logged-in .logged-in {
+ display:inline-block;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="fb-root"></div>
+ <p class="loading">Checking session with Facebook...</p>
+ <p class="logged-in">You are logged in to and connected with Facebook</p>
+ <p class="logged-out">
+ You are not logged in to Facebook or the app has not been authorized.
+ Please, <button class="login">Log in...</button>
+ </p>
+ <hr>
+ <button class="test not-loading">Ask the server to verify the session</button>
+ <pre class="message"></pre>
+ </body>
+</html>
16 example/server.mv
@@ -0,0 +1,16 @@
+import connect, connect_facebook = '../connect_facebook'
+
+connect()
+ .use(^(req, res, next) {
+ # Default to "/index.html"
+ if (req.url == '/') req.url = '/index.html'; next()
+ })
+ .use(connect['static'] __dirname)
+ .use(connect_facebook 'YOUR_FACEBOOK_APP_ID', 'YOUR_FACEBOOK_APP_SECRET')
+ .use(^(req, res, next) {
+ if (req.fb_session)
+ res.end Object.inspect req.fb_session
+ else
+ res.end 'No session or invalid session'
+ })
+ .listen 3000
11 package.json
@@ -0,0 +1,11 @@
+{ "name": "connect_facebook",
+ "version": "0.1.0",
+ "description": "Facebook session support for Connect",
+ "homepage": "https://github.com/rsms/connect_facebook",
+ "author": "Rasmus Andersson (http://rsms.me/)",
+ "main": "connect_facebook.mv",
+ "keywords": ["connect", "facebook", "move"],
+ "engines": {"node": ">=0.3.0"},
+ "repository": {"type": "git", "url": "http://github.com/rsms/connect_facebook.git"},
+ "dependencies":{ "move": ">=0.2.3", "connect": ">=1.1.1" }
+}

0 comments on commit 13716cf

Please sign in to comment.