Permalink
Browse files

its alivvvveeeee

  • Loading branch information...
0 parents commit e06e96bdf704cdd05b8966b3f0b0e7c5378fa588 @dhigginbotham committed Jul 24, 2013
Showing with 613 additions and 0 deletions.
  1. +22 −0 .gitattributes
  2. +1 −0 .gitignore
  3. +6 −0 Cakefile
  4. +21 −0 LICENSE.md
  5. +83 −0 README.md
  6. +63 −0 examples/example.coffee
  7. +62 −0 lib/auth.js
  8. +117 −0 lib/facebook.js
  9. +4 −0 lib/index.js
  10. +46 −0 package.json
  11. +45 −0 src/auth.coffee
  12. +142 −0 src/facebook.coffee
  13. +1 −0 src/index.coffee
@@ -0,0 +1,22 @@
+# Auto detect text files and perform LF normalization
+* text=auto
+
+# Custom for Visual Studio
+*.cs diff=csharp
+*.sln merge=union
+*.csproj merge=union
+*.vbproj merge=union
+*.fsproj merge=union
+*.dbproj merge=union
+
+# Standard to msysgit
+*.doc diff=astextplain
+*.DOC diff=astextplain
+*.docx diff=astextplain
+*.DOCX diff=astextplain
+*.dot diff=astextplain
+*.DOT diff=astextplain
+*.pdf diff=astextplain
+*.PDF diff=astextplain
+*.rtf diff=astextplain
+*.RTF diff=astextplain
@@ -0,0 +1 @@
+node_modules/*
@@ -0,0 +1,6 @@
+flour = require "flour"
+
+task "build:coffee", ->
+ compile './src/auth.coffee', './lib/auth.js'
+ compile './src/facebook.coffee', './lib/facebook.js'
+ compile './src/index.coffee', './lib/index.js'
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 David Higginbotham
+
+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.
@@ -0,0 +1,83 @@
+## Express FBAuth
+I needed a way to play with facebook that did things like passport, but allowed me to store things to different `req` objects, as well as send `res.locals` some goods.
+
+I decided that i would implement someone elses library to handle to oauth/facebook graph stuff, why reinvent a perfectly good wheel? I chose `fbgraph` and from experience it's one of the better facebook graph api wrappers for `node.js`
+
+### Usage
+```md
+npm install git+https://github.com/dhigginbotham/express-fbauth
+```
+
+### Example setup
+```js
+var express = require('express');
+var app = express();
+
+// require fbauth
+var fbauth = require('express-fbauth');
+
+// some collection you'd like to use for your authed users
+var Model = require('./some/db/collection/path');
+
+// options you'll want to set...
+var options = {
+ model: Model,
+ prefix: "/auth/facebook"
+ client_id: "CLIENT_ID",
+ client_secret: "CLIENT_SECRET",
+ redirect_uri: "http://localhost:3000/auth/facebook/callback",
+ scope: "email, publish_actions"
+ key: "optin",
+ strategy: function (profile, fn) {
+ // do a crud task with `mongoose` like `findAndUpdate` or `findAndCreate`
+ }
+};
+
+// create your `facebook` object so you can do stuff
+facebook = new fbauth(options);
+
+// mount the auth routes
+facebook.mount(app);
+
+// persist your session like you can in `passport.js`
+app.use facebook.session
+```
+
+## Options
+Key | Default | Description
+--- | --- | ---
+**model** | `null` | The users/optins model you want to use
+**prefix** | `/auth/facebook` | route prefix, ie `http://localhost:3000/auth/facebook`
+**redirect_uri** | `/callback` | you gotta have one,
+**callback_uri** | `/callback` | which is why it might be nice to have two..
+**client_id** | `null` | use the one from your facebook app
+**key** | `null` | almost anything works, however I am not sanitizing yet
+**client_secret** | `null` | use the one from your facebook app
+**scope** | `email, publish_actions` | see facebook docs for full list of scope/perms
+**strategy** | `null` | finally, your end-point, the little guy that goes in and finds, updates or creates something
+
+## License
+```md
+The MIT License (MIT)
+
+Copyright (c) 2013 David Higginbotham
+
+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.
+```
+
@@ -0,0 +1,63 @@
+express = require "express"
+app = module.exports = express()
+
+# going to make mount point for `facebook` auth for optins
+# this will allow us to not use passport to create the optin,
+# but still keep up with our consistency.
+
+facebook = require "../../apps/express-facebook-authorize"
+
+Optin = require "../../../app/models/donation/optin"
+
+conf = require "../../../helpers/config"
+
+findOrCreate = (profile, fn) ->
+
+ # we're going to check for the existence of this optin
+ # user and update their account or make a new one..
+
+ # rename profile to `fb` keeps some scope
+ fb = profile
+
+ # build out a query string, we can be pretty strict here
+ # because we're requiring an email directly from facebook
+ # and not determined upon user input..
+ query = if fb? then {email: fb.email} else {}
+
+ # let's just be super truthy here and make sure that we've
+ # actually got this validating.
+ if query.hasOwnProperty("email")
+
+ # build out our new optin object
+ _optin = fb
+ # we're going to store extended as JSON, we'll parse it later
+ # if necessary
+ json = JSON.stringify profile
+
+ _optin.ts = new Date()
+ _optin._extended = json
+ _optin.facebook = JSON.parse json
+
+ # do findOrCreate and set upsert to true, this will give us a
+ # pseudo update that we'll appreciate later
+ Optin.findOrCreate query, _optin, {upsert: true}, (err, optin) ->
+ return if err? then fn err, null
+
+ # check that optin is there, otherwise -- issues.
+ if optin?
+
+ # pass through our optin, just in case we need to add another
+ # middleware to the stack later on
+ fn null, optin
+
+options =
+ model: Optin
+ client_id: conf.pass.fb.id
+ client_secret: conf.pass.fb.secret
+ redirect_uri: conf.pass.redirectUrl + conf.pass.fb.route
+ key: "optin"
+ strategy: findOrCreate
+
+fb = new facebook options
+app.use fb.session
+fb.mount app
@@ -0,0 +1,62 @@
+(function() {
+ var auth, _;
+
+ _ = require("underscore");
+
+ auth = function(model, key, opts) {
+ this.model = model;
+ this.key = key;
+ this._col = key + "_id";
+ if (opts != null) {
+ return _.extend(this, opts);
+ }
+ };
+
+ auth.prototype.serialize = function(user, fn) {
+ if (user != null) {
+ return fn(null, user._id);
+ } else {
+ return fn("Sorry, we couldn't connect you to the server, please try again.", null);
+ }
+ };
+
+ auth.prototype.deserialize = function(id, fn) {
+ var self;
+ self = this;
+ return self.model.findOne({
+ _id: id
+ }, function(err, model) {
+ if (err != null) {
+ return fn(err, null);
+ }
+ if (model != null) {
+ return fn(null, model);
+ }
+ });
+ };
+
+ auth.prototype.ensureAuthenticated = function(req, fn) {
+ var query, self;
+ self = this;
+ if (req.session.hasOwnProperty(self._col)) {
+ query = req.session[self._col];
+ return self.model.findOne({
+ _id: query
+ }, function(err, model) {
+ if (err != null) {
+ return fn(err, null);
+ }
+ if (model != null) {
+ return fn(null, model);
+ } else {
+ return fn("Your _id could not be validated, please try again", null);
+ }
+ });
+ } else {
+ return fn("You must be authenticated to use this route", null);
+ }
+ };
+
+ module.exports = auth;
+
+}).call(this);
@@ -0,0 +1,117 @@
+(function() {
+ var facebook, fbgraph, oauth, _;
+
+ _ = require("underscore");
+
+ fbgraph = require("fbgraph");
+
+ oauth = require("./auth");
+
+ facebook = function(opts) {
+ var self;
+ this.model = null;
+ this.prefix = "/auth/facebook";
+ this.redirect_uri = "/callback";
+ this.callback_url = "/callback";
+ this.client_id = null;
+ this.key = null;
+ this.client_secret = null;
+ this.scope = "email, publish_actions";
+ this.strategy = null;
+ if (opts != null) {
+ _.extend(this, opts);
+ }
+ this._col = this.key + "_id";
+ self = this;
+ this.oauth = function(req, res, next) {
+ var oauth_callback, oauth_uri;
+ if (!req.query.code) {
+ oauth_uri = fbgraph.getOauthUrl({
+ client_id: self.client_id,
+ redirect_uri: self.redirect_uri,
+ scope: self.scope
+ });
+ if (!req.query.error) {
+ return res.redirect(oauth_uri);
+ } else {
+ return next("Sorry, facebook has reported an error: " + req.query.error, null);
+ }
+ } else {
+ oauth_callback = {
+ client_id: self.client_id,
+ client_secret: self.client_secret,
+ redirect_uri: self.redirect_uri,
+ code: req.query.code
+ };
+ return fbgraph.authorize(oauth_callback, function(err, response) {
+ if (err != null) {
+ return next(err, null);
+ }
+ if (response.access_token != null) {
+ fbgraph.setAccessToken(response.access_token);
+ }
+ return fbgraph.get("me", function(err, response) {
+ if (err != null) {
+ return next(err, null);
+ }
+ if (response != null) {
+ if (self.strategy === null) {
+ req[self.key] = res.locals[self.key] = response;
+ return next(null, response);
+ } else {
+ return self.strategy(response, function(err, saved) {
+ if (err != null) {
+ return next(err, null);
+ }
+ if (saved != null) {
+ req[self.key] = res.locals[self.key] = saved;
+ return next(null, saved);
+ }
+ });
+ }
+ } else {
+ return fn("Facebook lost your token while redirecting back here, please try again.", null);
+ }
+ });
+ });
+ }
+ };
+ this.auth = new oauth(self.model, self.key);
+ this.authenticate = function(req, res) {
+ return self.auth.serialize(req[self.key], function(err, id) {
+ req.session[self._col] = id;
+ return res.redirect(req.get("Referer"));
+ });
+ };
+ this.mount = function(app) {
+ app.get(self.prefix, self.oauth);
+ if (self.strategy === null) {
+ return app.get(self.prefix + self.callback_url, self.oauth, self.authenticate);
+ } else {
+ return app.get(self.prefix + self.callback_url, self.oauth, self.authenticate, self.strategy);
+ }
+ };
+ return this;
+ };
+
+ facebook.prototype.session = function(req, res, next) {
+ var self;
+ self = this;
+ if (req.session.hasOwnProperty(self._col)) {
+ return self.deserialize(req.session[self._col], function(err, deserialized) {
+ if (err != null) {
+ return next(err, null);
+ }
+ if (deserialized != null) {
+ req[self.key] = res.locals[self.key] = deserialized;
+ }
+ return next();
+ });
+ } else {
+ return next();
+ }
+ };
+
+ module.exports = facebook;
+
+}).call(this);
@@ -0,0 +1,4 @@
+(function() {
+ module.exports = require("./facebook");
+
+}).call(this);
Oops, something went wrong. Retry.

0 comments on commit e06e96b

Please sign in to comment.