2014-02-14 16:29:28 +00:00
var _ = require ( 'underscore' ) ;
2013-12-07 03:21:46 +00:00
var passport = require ( 'passport' ) ;
var LocalStrategy = require ( 'passport-local' ) . Strategy ;
var FacebookStrategy = require ( 'passport-facebook' ) . Strategy ;
var TwitterStrategy = require ( 'passport-twitter' ) . Strategy ;
var GitHubStrategy = require ( 'passport-github' ) . Strategy ;
var GoogleStrategy = require ( 'passport-google-oauth' ) . OAuth2Strategy ;
2014-02-27 18:08:26 +00:00
var LinkedInStrategy = require ( 'passport-linkedin-oauth2' ) . Strategy ;
2014-02-14 16:29:28 +00:00
var OAuthStrategy = require ( 'passport-oauth' ) . OAuthStrategy ; // Tumblr
var OAuth2Strategy = require ( 'passport-oauth' ) . OAuth2Strategy ; // Venmo, Foursquare
2013-12-07 03:21:46 +00:00
var User = require ( '../models/User' ) ;
2013-12-20 06:31:16 +00:00
var secrets = require ( './secrets' ) ;
2013-11-19 00:43:45 +00:00
2013-11-14 07:29:55 +00:00
passport . serializeUser ( function ( user , done ) {
done ( null , user . id ) ;
} ) ;
2013-11-14 03:19:37 +00:00
2013-11-14 07:29:55 +00:00
passport . deserializeUser ( function ( id , done ) {
2014-02-14 17:28:01 +00:00
User . findById ( id , function ( err , user ) {
2013-11-14 07:29:55 +00:00
done ( err , user ) ;
2013-11-14 03:19:37 +00:00
} ) ;
2013-11-14 07:29:55 +00:00
} ) ;
2013-11-14 03:19:37 +00:00
2014-02-14 16:29:28 +00:00
/ * *
* Sign in using Email and Password .
* /
2014-01-07 20:48:21 +00:00
passport . use ( new LocalStrategy ( { usernameField : 'email' } , function ( email , password , done ) {
User . findOne ( { email : email } , function ( err , user ) {
2014-01-24 03:47:21 +00:00
if ( ! user ) return done ( null , false , { message : 'Email ' + email + ' not found' } ) ;
2013-11-14 07:29:55 +00:00
user . comparePassword ( password , function ( err , isMatch ) {
2014-01-24 03:47:21 +00:00
if ( isMatch ) {
2013-11-14 03:19:37 +00:00
return done ( null , user ) ;
} else {
2014-01-12 20:31:17 +00:00
return done ( null , false , { message : 'Invalid email or password.' } ) ;
2013-11-14 03:19:37 +00:00
}
} ) ;
2013-11-14 07:29:55 +00:00
} ) ;
} ) ) ;
2014-03-03 21:32:13 +00:00
/ * *
* OAuth Strategy Overview
*
* - User is already logged in .
* - Check if there is an existing account with a provider id or email .
* - If there is , return an error message . ( Account merging not supported )
* - Else link new OAuth account with currently logged - in user .
* - User is not logged in .
* - Check if it ' s a returning user .
* - If returning user , sign in and we are done .
* - Else check if there is an existing account with user ' s email .
* - If there is , return an error message .
* - Else create a new account .
* /
2014-01-31 21:28:12 +00:00
/ * *
2014-02-01 04:56:50 +00:00
* Sign in with Facebook .
* /
2014-01-31 21:28:12 +00:00
2014-02-05 16:37:48 +00:00
passport . use ( new FacebookStrategy ( secrets . facebook , function ( req , accessToken , refreshToken , profile , done ) {
2013-12-14 06:32:33 +00:00
if ( req . user ) {
2014-02-01 03:23:19 +00:00
User . findOne ( { $or : [ { facebook : profile . id } , { email : profile . email } ] } , function ( err , existingUser ) {
2014-01-31 21:28:12 +00:00
if ( existingUser ) {
2014-02-01 04:58:59 +00:00
req . flash ( 'errors' , { msg : 'There is already a Facebook account that belongs to you. Sign in with that account or delete it, then link it with your current account.' } ) ;
done ( err ) ;
2014-01-31 21:28:12 +00:00
} else {
User . findById ( req . user . id , function ( err , user ) {
user . facebook = profile . id ;
user . tokens . push ( { kind : 'facebook' , accessToken : accessToken } ) ;
user . profile . name = user . profile . name || profile . displayName ;
user . profile . gender = user . profile . gender || profile . _json . gender ;
2014-02-01 03:23:19 +00:00
user . profile . picture = user . profile . picture || 'https://graph.facebook.com/' + profile . id + '/picture?type=large' ;
2014-01-31 21:28:12 +00:00
user . save ( function ( err ) {
2014-02-01 04:58:59 +00:00
req . flash ( 'info' , { msg : 'Facebook account has been linked.' } ) ;
2014-01-31 21:28:12 +00:00
done ( err , user ) ;
} ) ;
} ) ;
}
2013-12-03 00:16:27 +00:00
} ) ;
2013-12-14 06:32:33 +00:00
} else {
User . findOne ( { facebook : profile . id } , function ( err , existingUser ) {
if ( existingUser ) return done ( null , existingUser ) ;
2014-02-14 17:26:47 +00:00
User . findOne ( { email : profile . _json . email } , function ( err , existingEmailUser ) {
if ( existingEmailUser ) {
req . flash ( 'errors' , { msg : 'There is already an account using this email address. Sign in to that account and link it with Facebook manually from Account Settings.' } ) ;
done ( err ) ;
} else {
var user = new User ( ) ;
user . email = profile . _json . email ;
user . facebook = profile . id ;
user . tokens . push ( { kind : 'facebook' , accessToken : accessToken } ) ;
user . profile . name = profile . displayName ;
user . profile . gender = profile . _json . gender ;
user . profile . picture = 'https://graph.facebook.com/' + profile . id + '/picture?type=large' ;
user . profile . location = ( profile . _json . location ) ? profile . _json . location . name : '' ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
}
2013-12-14 06:32:33 +00:00
} ) ;
} ) ;
}
2013-12-07 01:16:39 +00:00
} ) ) ;
2013-12-06 06:44:45 +00:00
2014-02-01 03:39:13 +00:00
/ * *
* Sign in with GitHub .
* /
2013-12-20 06:31:16 +00:00
passport . use ( new GitHubStrategy ( secrets . github , function ( req , accessToken , refreshToken , profile , done ) {
2013-12-14 06:29:49 +00:00
if ( req . user ) {
2014-02-01 03:39:13 +00:00
User . findOne ( { $or : [ { github : profile . id } , { email : profile . email } ] } , function ( err , existingUser ) {
if ( existingUser ) {
2014-02-01 04:58:59 +00:00
req . flash ( 'errors' , { msg : 'There is already a GitHub account that belongs to you. Sign in with that account or delete it, then link it with your current account.' } ) ;
done ( err ) ;
2014-02-01 03:39:13 +00:00
} else {
User . findById ( req . user . id , function ( err , user ) {
user . github = profile . id ;
user . tokens . push ( { kind : 'github' , accessToken : accessToken } ) ;
user . profile . name = user . profile . name || profile . displayName ;
user . profile . picture = user . profile . picture || profile . _json . avatar _url ;
user . profile . location = user . profile . location || profile . _json . location ;
user . profile . website = user . profile . website || profile . _json . blog ;
user . save ( function ( err ) {
2014-02-01 04:58:59 +00:00
req . flash ( 'info' , { msg : 'GitHub account has been linked.' } ) ;
2014-02-01 03:39:13 +00:00
done ( err , user ) ;
} ) ;
} ) ;
}
2013-12-03 22:38:14 +00:00
} ) ;
2013-12-14 06:29:49 +00:00
} else {
User . findOne ( { github : profile . id } , function ( err , existingUser ) {
if ( existingUser ) return done ( null , existingUser ) ;
2014-02-14 17:23:50 +00:00
User . findOne ( { email : profile . _json . email } , function ( err , existingEmailUser ) {
if ( existingEmailUser ) {
req . flash ( 'errors' , { msg : 'There is already an account using this email address. Sign in to that account and link it with GitHub manually from Account Settings.' } ) ;
done ( err ) ;
} else {
var user = new User ( ) ;
user . email = profile . _json . email ;
user . github = profile . id ;
user . tokens . push ( { kind : 'github' , accessToken : accessToken } ) ;
user . profile . name = profile . displayName ;
user . profile . picture = profile . _json . avatar _url ;
user . profile . location = profile . _json . location ;
user . profile . website = profile . _json . blog ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
}
2013-12-14 06:29:49 +00:00
} ) ;
} ) ;
}
2013-12-07 01:16:39 +00:00
} ) ) ;
2013-12-06 06:24:12 +00:00
2014-02-01 04:17:58 +00:00
/ * *
* Sign in with Twitter .
* /
2013-12-20 06:31:16 +00:00
passport . use ( new TwitterStrategy ( secrets . twitter , function ( req , accessToken , tokenSecret , profile , done ) {
2013-12-14 06:27:10 +00:00
if ( req . user ) {
2014-02-01 04:56:50 +00:00
User . findOne ( { twitter : profile . id } , function ( err , existingUser ) {
2014-02-01 04:17:58 +00:00
if ( existingUser ) {
2014-02-01 04:58:59 +00:00
req . flash ( 'errors' , { msg : 'There is already a Twitter account that belongs to you. Sign in with that account or delete it, then link it with your current account.' } ) ;
done ( err ) ;
2014-02-01 04:17:58 +00:00
} else {
User . findById ( req . user . id , function ( err , user ) {
user . twitter = profile . id ;
user . tokens . push ( { kind : 'twitter' , accessToken : accessToken , tokenSecret : tokenSecret } ) ;
user . profile . name = user . profile . name || profile . displayName ;
user . profile . location = user . profile . location || profile . _json . location ;
user . profile . picture = user . profile . picture || profile . _json . profile _image _url ;
user . save ( function ( err ) {
2014-02-01 04:58:59 +00:00
req . flash ( 'info' , { msg : 'Twitter account has been linked.' } ) ;
2014-02-01 04:17:58 +00:00
done ( err , user ) ;
} ) ;
} ) ;
}
2013-11-19 06:03:11 +00:00
} ) ;
2014-02-01 04:17:58 +00:00
2013-12-14 06:27:10 +00:00
} else {
User . findOne ( { twitter : profile . id } , function ( err , existingUser ) {
if ( existingUser ) return done ( null , existingUser ) ;
var user = new User ( ) ;
2014-02-04 16:23:52 +00:00
// Twitter will not provide an email address. Period.
// But a person’ s twitter username is guaranteed to be unique
2014-02-04 18:28:27 +00:00
// so we can "fake" a twitter email address as follows:
2014-02-04 16:23:52 +00:00
user . email = profile . username + "@twitter.com" ;
2013-12-14 06:27:10 +00:00
user . twitter = profile . id ;
2013-12-20 18:48:33 +00:00
user . tokens . push ( { kind : 'twitter' , accessToken : accessToken , tokenSecret : tokenSecret } ) ;
2013-12-14 06:27:10 +00:00
user . profile . name = profile . displayName ;
user . profile . location = profile . _json . location ;
user . profile . picture = profile . _json . profile _image _url ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
} ) ;
}
2013-12-07 01:16:39 +00:00
} ) ) ;
2013-11-19 06:03:11 +00:00
2014-02-01 03:39:13 +00:00
/ * *
* Sign in with Google .
* /
2013-12-20 06:31:16 +00:00
passport . use ( new GoogleStrategy ( secrets . google , function ( req , accessToken , refreshToken , profile , done ) {
2013-12-13 05:28:29 +00:00
if ( req . user ) {
2014-02-01 03:39:13 +00:00
User . findOne ( { $or : [ { google : profile . id } , { email : profile . email } ] } , function ( err , existingUser ) {
if ( existingUser ) {
2014-02-01 04:56:50 +00:00
req . flash ( 'errors' , { msg : 'There is already a Google account that belongs to you. Sign in with that account or delete it, then link it with your current account.' } ) ;
done ( err ) ;
2014-02-01 03:39:13 +00:00
} else {
User . findById ( req . user . id , function ( err , user ) {
user . google = profile . id ;
user . tokens . push ( { kind : 'google' , accessToken : accessToken } ) ;
user . profile . name = user . profile . name || profile . displayName ;
user . profile . gender = user . profile . gender || profile . _json . gender ;
user . profile . picture = user . profile . picture || profile . _json . picture ;
user . save ( function ( err ) {
2014-02-01 04:56:50 +00:00
req . flash ( 'info' , { msg : 'Google account has been linked.' } ) ;
2014-02-01 03:39:13 +00:00
done ( err , user ) ;
} ) ;
} ) ;
}
2013-11-21 19:20:38 +00:00
} ) ;
2013-12-13 05:28:29 +00:00
} else {
User . findOne ( { google : profile . id } , function ( err , existingUser ) {
if ( existingUser ) return done ( null , existingUser ) ;
2014-02-14 17:24:23 +00:00
User . findOne ( { email : profile . _json . email } , function ( err , existingEmailUser ) {
2014-02-14 17:28:01 +00:00
if ( existingEmailUser ) {
2014-02-14 17:26:47 +00:00
req . flash ( 'errors' , { msg : 'There is already an account using this email address. Sign in to that account and link it with Google manually from Account Settings.' } ) ;
2014-02-14 17:24:23 +00:00
done ( err ) ;
2014-02-14 02:54:09 +00:00
} else {
var user = new User ( ) ;
user . email = profile . _json . email ;
user . google = profile . id ;
user . tokens . push ( { kind : 'google' , accessToken : accessToken } ) ;
user . profile . name = profile . displayName ;
user . profile . gender = profile . _json . gender ;
user . profile . picture = profile . _json . picture ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
}
2013-12-13 05:28:29 +00:00
} ) ;
} ) ;
}
2013-12-07 01:16:39 +00:00
} ) ) ;
2013-11-19 00:43:45 +00:00
2014-02-27 18:08:26 +00:00
/ * *
* Sign in with LinkedIn .
* /
passport . use ( new LinkedInStrategy ( secrets . linkedin , function ( req , accessToken , refreshToken , profile , done ) {
if ( req . user ) {
User . findOne ( { $or : [
{ linkedin : profile . id } ,
{ email : profile . _json . emailAddress }
] } , function ( err , existingUser ) {
if ( existingUser ) {
req . flash ( 'errors' , { msg : 'There is already a LinkedIn account that belongs to you. Sign in with that account or delete it, then link it with your current account.' } ) ;
done ( err ) ;
} else {
User . findById ( req . user . id , function ( err , user ) {
user . linkedin = profile . id ;
user . tokens . push ( { kind : 'linkedin' , accessToken : accessToken } ) ;
user . profile . name = user . profile . name || profile . displayName ;
user . profile . location = user . profile . location || profile . _json . location . name ;
user . profile . picture = user . profile . picture || profile . _json . pictureUrl ;
user . profile . website = user . profile . website || profile . _json . publicProfileUrl ;
user . save ( function ( err ) {
req . flash ( 'info' , { msg : 'LinkedIn account has been linked.' } ) ;
done ( err , user ) ;
} ) ;
} ) ;
}
} ) ;
} else {
User . findOne ( { linkedin : profile . id } , function ( err , existingUser ) {
if ( existingUser ) return done ( null , existingUser ) ;
User . findOne ( { email : profile . _json . emailAddress } , function ( err , existingEmailUser ) {
if ( existingEmailUser ) {
2014-02-27 22:57:13 +00:00
req . flash ( 'errors' , { msg : 'There is already an account using this email address. Sign in to that account and link it with LinkedIn manually from Account Settings.' } ) ;
2014-02-27 18:08:26 +00:00
done ( err ) ;
} else {
var user = new User ( ) ;
user . linkedin = profile . id ;
user . tokens . push ( { kind : 'linkedin' , accessToken : accessToken } ) ;
user . email = profile . _json . emailAddress ;
user . profile . name = profile . displayName ;
user . profile . location = profile . _json . location . name ;
user . profile . picture = profile . _json . pictureUrl ;
user . profile . website = profile . _json . publicProfileUrl ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
}
} ) ;
} ) ;
}
} ) ) ;
2014-02-14 16:29:28 +00:00
/ * *
* Tumblr API
* Uses OAuth 1.0 a Strategy .
* /
2013-12-07 03:49:40 +00:00
passport . use ( 'tumblr' , new OAuthStrategy ( {
requestTokenURL : 'http://www.tumblr.com/oauth/request_token' ,
accessTokenURL : 'http://www.tumblr.com/oauth/access_token' ,
userAuthorizationURL : 'http://www.tumblr.com/oauth/authorize' ,
2013-12-20 06:31:16 +00:00
consumerKey : secrets . tumblr . consumerKey ,
consumerSecret : secrets . tumblr . consumerSecret ,
callbackURL : secrets . tumblr . callbackURL ,
2013-12-07 05:29:32 +00:00
passReqToCallback : true
2013-12-07 03:49:40 +00:00
} ,
2014-02-14 17:28:01 +00:00
function ( req , token , tokenSecret , profile , done ) {
2013-12-07 05:29:32 +00:00
User . findById ( req . user . _id , function ( err , user ) {
2013-12-20 18:48:33 +00:00
user . tokens . push ( { kind : 'tumblr' , accessToken : token , tokenSecret : tokenSecret } ) ;
2013-12-07 05:29:32 +00:00
user . save ( function ( err ) {
2013-12-07 07:18:26 +00:00
done ( err , user ) ;
2013-12-07 05:29:32 +00:00
} ) ;
2013-12-07 03:49:40 +00:00
} ) ;
2013-12-04 12:44:07 +00:00
}
2013-12-07 03:49:40 +00:00
) ) ;
2014-02-14 16:29:28 +00:00
/ * *
* Foursquare API
* Uses OAuth 2.0 Strategy .
* /
2013-12-07 17:30:54 +00:00
passport . use ( 'foursquare' , new OAuth2Strategy ( {
authorizationURL : 'https://foursquare.com/oauth2/authorize' ,
tokenURL : 'https://foursquare.com/oauth2/access_token' ,
2013-12-20 06:31:16 +00:00
clientID : secrets . foursquare . clientId ,
clientSecret : secrets . foursquare . clientSecret ,
callbackURL : secrets . foursquare . redirectUrl ,
2013-12-07 17:30:54 +00:00
passReqToCallback : true
} ,
2014-02-14 17:28:01 +00:00
function ( req , accessToken , refreshToken , profile , done ) {
2013-12-07 17:30:54 +00:00
User . findById ( req . user . _id , function ( err , user ) {
2013-12-20 18:48:33 +00:00
user . tokens . push ( { kind : 'foursquare' , accessToken : accessToken } ) ;
2013-12-07 17:30:54 +00:00
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
} ) ;
}
) ) ;
2014-02-14 16:29:28 +00:00
/ * *
* Venmo API
* Uses OAuth 2.0 Strategy .
* /
2014-02-11 00:20:45 +00:00
passport . use ( 'venmo' , new OAuth2Strategy ( {
authorizationURL : 'https://api.venmo.com/v1/oauth/authorize' ,
tokenURL : 'https://api.venmo.com/v1/oauth/access_token' ,
clientID : secrets . venmo . clientId ,
clientSecret : secrets . venmo . clientSecret ,
callbackURL : secrets . venmo . redirectUrl ,
passReqToCallback : true
} ,
2014-02-14 17:28:01 +00:00
function ( req , accessToken , refreshToken , profile , done ) {
2014-02-11 00:20:45 +00:00
User . findById ( req . user . _id , function ( err , user ) {
user . tokens . push ( { kind : 'venmo' , accessToken : accessToken } ) ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
} ) ;
}
) ) ;
2014-02-14 16:29:28 +00:00
/ * *
* Login Required middleware .
* /
2013-12-08 07:23:59 +00:00
exports . isAuthenticated = function ( req , res , next ) {
2013-12-07 03:49:40 +00:00
if ( req . isAuthenticated ( ) ) return next ( ) ;
2013-11-14 07:29:55 +00:00
res . redirect ( '/login' ) ;
2013-12-08 07:10:49 +00:00
} ;
2013-12-08 09:30:43 +00:00
2014-02-14 16:29:28 +00:00
/ * *
* Authorization Required middleware .
* /
2013-12-08 09:30:43 +00:00
exports . isAuthorized = function ( req , res , next ) {
var provider = req . path . split ( '/' ) . slice ( - 1 ) [ 0 ] ;
if ( _ . findWhere ( req . user . tokens , { kind : provider } ) ) next ( ) ;
else res . redirect ( '/auth/' + provider ) ;
2013-12-20 06:31:16 +00:00
} ;