2014-06-06 19:43:49 +00:00
var _ = require ( 'lodash' ) ;
2013-12-07 03:21:46 +00:00
var passport = require ( 'passport' ) ;
var LocalStrategy = require ( 'passport-local' ) . Strategy ;
var TwitterStrategy = require ( 'passport-twitter' ) . Strategy ;
2014-02-14 16:29:28 +00:00
var OAuthStrategy = require ( 'passport-oauth' ) . OAuthStrategy ; // Tumblr
var OAuth2Strategy = require ( 'passport-oauth' ) . OAuth2Strategy ; // Venmo, Foursquare
2014-10-13 21:14:51 +00:00
var GitHubStrategy = require ( 'passport-github' ) . Strategy ;
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' ) ;
2014-10-13 21:14:51 +00:00
var LinkedInStrategy = require ( 'passport-linkedin-oauth2' ) . Strategy ;
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-04-13 04:28:11 +00:00
// Sign in using Email and Password.
2014-02-14 16:29:28 +00:00
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 .
2014-04-25 18:33:54 +00:00
* - Check if there is an existing account with a < provider > id .
2014-03-03 21:32:13 +00:00
* - 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-04-13 04:28:11 +00:00
// Sign in with Twitter.
2014-02-01 04:17:58 +00:00
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 ;
2014-09-01 19:12:53 +00:00
user . profile . picture = user . profile . picture || profile . _json . profile _image _url _https ;
2014-10-14 04:38:10 +00:00
user . profile . username = profile . username ;
2014-02-01 04:17:58 +00:00
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 ;
2014-09-01 19:12:53 +00:00
user . profile . picture = profile . _json . profile _image _url _https ;
2014-10-14 04:38:10 +00:00
user . profile . username = profile . username ;
2013-12-14 06:27:10 +00:00
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-27 18:08:26 +00:00
2014-04-13 04:28:11 +00:00
// Tumblr API setup.
2014-02-14 16:29:28 +00:00
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-04-13 04:28:11 +00:00
// Foursquare API setup.
2014-02-14 16:29:28 +00:00
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-04-13 04:28:11 +00:00
// Venmo API setup.
2014-02-14 16:29:28 +00:00
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-04-15 15:10:54 +00:00
// Login Required middleware.
2014-02-14 16:29:28 +00:00
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-04-15 15:10:54 +00:00
// Authorization Required middleware.
2014-02-14 16:29:28 +00:00
2013-12-08 09:30:43 +00:00
exports . isAuthorized = function ( req , res , next ) {
var provider = req . path . split ( '/' ) . slice ( - 1 ) [ 0 ] ;
2014-04-15 15:10:54 +00:00
2014-06-06 20:02:37 +00:00
if ( _ . find ( req . user . tokens , { kind : provider } ) ) {
2014-04-15 15:10:54 +00:00
next ( ) ;
} else {
res . redirect ( '/auth/' + provider ) ;
}
2014-10-13 21:14:51 +00:00
} ;
// Sign in with LinkedIn.
passport . use ( new LinkedInStrategy ( secrets . linkedin , function ( req , accessToken , refreshToken , profile , done ) {
if ( req . user ) {
User . findOne ( { linkedin : profile . id } , 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 ) {
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.' } ) ;
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 ) ;
} ) ;
}
} ) ;
} ) ;
}
} ) ) ;
// Sign in with GitHub.
passport . use ( new GitHubStrategy ( secrets . github , function ( req , accessToken , refreshToken , profile , done ) {
if ( req . user ) {
User . findOne ( { github : profile . id } , function ( err , existingUser ) {
if ( existingUser ) {
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 ) ;
} 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 ) {
req . flash ( 'info' , { msg : 'GitHub account has been linked.' } ) ;
done ( err , user ) ;
} ) ;
} ) ;
}
} ) ;
} else {
User . findOne ( { github : profile . id } , function ( err , existingUser ) {
if ( existingUser ) return done ( null , existingUser ) ;
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 ) ;
} ) ;
}
} ) ;
} ) ;
}
} ) ) ;