2014-06-06 19:43:49 +00:00
var _ = require ( 'lodash' ) ;
2013-12-07 03:21:46 +00:00
var passport = require ( 'passport' ) ;
2014-10-15 21:53:36 +00:00
var InstagramStrategy = require ( 'passport-instagram' ) . Strategy ;
2013-12-07 03:21:46 +00:00
var LocalStrategy = require ( 'passport-local' ) . Strategy ;
2014-10-15 21:53:36 +00:00
var FacebookStrategy = require ( 'passport-facebook' ) . Strategy ;
2013-12-07 03:21:46 +00:00
var TwitterStrategy = require ( 'passport-twitter' ) . Strategy ;
2014-10-15 21:53:36 +00:00
var GitHubStrategy = require ( 'passport-github' ) . Strategy ;
var GoogleStrategy = require ( 'passport-google-oauth' ) . OAuth2Strategy ;
var LinkedInStrategy = require ( 'passport-linkedin-oauth2' ) . Strategy ;
2014-11-19 23:30:36 +00:00
var OAuthStrategy = require ( 'passport-oauth' ) . OAuthStrategy ;
var OAuth2Strategy = require ( 'passport-oauth' ) . OAuth2Strategy ;
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 ) {
2014-10-15 21:53:36 +00:00
done ( null , user . id ) ;
2013-11-14 07:29:55 +00:00
} ) ;
2013-11-14 03:19:37 +00:00
2013-11-14 07:29:55 +00:00
passport . deserializeUser ( function ( id , done ) {
2014-10-15 21:53:36 +00:00
User . findById ( id , function ( err , user ) {
done ( err , user ) ;
} ) ;
2013-11-14 07:29:55 +00:00
} ) ;
2013-11-14 03:19:37 +00:00
2014-12-08 04:50:53 +00:00
function sendWelcomeEmail ( user ) {
var transporter = nodemailer . createTransport ( {
service : 'Mandrill' ,
auth : {
user : secrets . mandrill . user ,
pass : secrets . mandrill . password
}
} ) ;
var mailOptions = {
to : user . email ,
from : 'Team@freecodecamp.com' ,
subject : 'Welcome to Free Code Camp ' + user . name + '!' ,
text : 'Hello,\n\n' +
'Welcome to Free Code Camp!'
} ;
}
2014-11-19 23:30:36 +00:00
/ * *
* OAuth Strategy Overview
*
* - User is already logged in .
* - Check if there is an existing account with a < provider > id .
* - 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 .
* /
// Sign in with Twitter.
passport . use ( new TwitterStrategy ( secrets . twitter , function ( req , accessToken , tokenSecret , profile , done ) {
if ( req . user ) {
User . findOne ( { twitter : profile . id } , function ( err , existingUser ) {
2014-12-04 07:28:10 +00:00
if ( existingUser ) {
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 ) ;
} else {
2014-11-19 23:30:36 +00:00
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 _https ;
user . profile . username = profile . username ;
user . save ( function ( err ) {
req . flash ( 'info' , { msg : 'Twitter account has been linked.' } ) ;
done ( err , user ) ;
} ) ;
} ) ;
2014-12-04 07:28:10 +00:00
}
2014-11-19 23:30:36 +00:00
} ) ;
} else {
User . findOne ( { twitter : profile . id } , function ( err , existingUser ) {
2014-12-04 07:28:10 +00:00
//if (existingUser) return done(null, existingUser);
2014-11-19 23:30:36 +00:00
// Twitter will not provide an email address. Period.
// But a person’ s twitter username is guaranteed to be unique
// so we can "fake" a twitter email address as follows:
2014-12-02 05:06:19 +00:00
//user.email = profile.username + "@twitter.com";
2014-12-04 07:28:10 +00:00
var user = existingUser || new User ;
2014-11-19 23:30:36 +00:00
user . twitter = profile . id ;
2014-12-04 07:28:10 +00:00
user . email = user . email || '' ;
2014-11-19 23:30:36 +00:00
user . tokens . push ( { kind : 'twitter' , accessToken : accessToken , tokenSecret : tokenSecret } ) ;
2014-12-04 07:28:10 +00:00
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 _https ;
2014-11-19 23:30:36 +00:00
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
2014-12-04 07:44:28 +00:00
//if (!user.email) {
// req.redirect('/account');
// req.flash('errors', { msg: 'OK, you are signed in. Please add your email address to your profile.' });
//}
2014-11-19 23:30:36 +00:00
} ) ;
}
} ) ) ;
2014-10-15 21:53:36 +00:00
2014-11-19 23:30:36 +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 ) {
2014-12-04 02:17:21 +00:00
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 {
2014-11-19 23:30:36 +00:00
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 ) ;
} ) ;
} ) ;
2014-12-04 02:17:21 +00:00
}
2014-11-19 23:30:36 +00:00
} ) ;
} else {
User . findOne ( { linkedin : profile . id } , function ( err , existingUser ) {
if ( existingUser ) return done ( null , existingUser ) ;
User . findOne ( { email : profile . _json . emailAddress } , function ( err , existingEmailUser ) {
2014-12-04 02:34:42 +00:00
var user = existingEmailUser || new User ;
user . linkedin = profile . id ;
user . tokens . push ( { kind : 'linkedin' , accessToken : accessToken } ) ;
2014-12-04 07:28:10 +00:00
user . email = user . email || profile . _json . emailAddress ;
2014-12-04 02:34:42 +00:00
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 . challengesComplete = user . challengesCompleted || [ ] ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
2014-11-19 23:30:36 +00:00
} ) ;
} ) ;
}
} ) ) ;
2014-04-13 04:28:11 +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 ) {
2014-10-15 21:53:36 +00:00
User . findOne ( { email : email } , function ( err , user ) {
if ( ! user ) return done ( null , false , { message : 'Email ' + email + ' not found' } ) ;
user . comparePassword ( password , function ( err , isMatch ) {
if ( isMatch ) {
return done ( null , user ) ;
} else {
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
2014-10-15 21:53:36 +00:00
// Sign in with Facebook.
2014-02-01 04:17:58 +00:00
2014-10-15 21:53:36 +00:00
passport . use ( new FacebookStrategy ( secrets . facebook , function ( req , accessToken , refreshToken , profile , done ) {
2014-10-13 21:14:51 +00:00
if ( req . user ) {
2014-10-15 21:53:36 +00:00
User . findOne ( { facebook : profile . id } , function ( err , existingUser ) {
2014-12-04 02:17:21 +00:00
if ( existingUser ) {
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 ) ;
} else {
2014-10-13 21:14:51 +00:00
User . findById ( req . user . id , function ( err , user ) {
2014-10-15 21:53:36 +00:00
user . facebook = profile . id ;
user . tokens . push ( { kind : 'facebook' , accessToken : accessToken } ) ;
2014-10-13 21:14:51 +00:00
user . profile . name = user . profile . name || profile . displayName ;
2014-10-15 21:53:36 +00:00
user . profile . gender = user . profile . gender || profile . _json . gender ;
user . profile . picture = user . profile . picture || 'https://graph.facebook.com/' + profile . id + '/picture?type=large' ;
2014-10-13 21:14:51 +00:00
user . save ( function ( err ) {
2014-10-15 21:53:36 +00:00
req . flash ( 'info' , { msg : 'Facebook account has been linked.' } ) ;
2014-10-13 21:14:51 +00:00
done ( err , user ) ;
} ) ;
} ) ;
2014-12-04 02:17:21 +00:00
}
2014-10-13 21:14:51 +00:00
} ) ;
} else {
2014-10-15 21:53:36 +00:00
User . findOne ( { facebook : profile . id } , function ( err , existingUser ) {
2014-10-13 21:14:51 +00:00
if ( existingUser ) return done ( null , existingUser ) ;
2014-10-15 21:53:36 +00:00
User . findOne ( { email : profile . _json . email } , function ( err , existingEmailUser ) {
2014-12-04 02:17:21 +00:00
var user = existingEmailUser || new User ;
user . email = user . email || profile . _json . email ;
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 ;
user . profile . picture = user . profile . picture || 'https://graph.facebook.com/' + profile . id + '/picture?type=large' ;
user . profile . location = user . profile . location || ( profile . _json . location ) ? profile . _json . location . name : '' ;
user . challengesComplete = user . challengesCompleted || [ ] ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
2014-10-13 21:14:51 +00:00
} ) ;
} ) ;
}
} ) ) ;
// 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 ) {
2014-12-04 02:34:42 +00:00
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 {
2014-10-13 21:14:51 +00:00
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 ) ;
} ) ;
} ) ;
2014-12-04 02:34:42 +00:00
}
2014-10-13 21:14:51 +00:00
} ) ;
} else {
User . findOne ( { github : profile . id } , function ( err , existingUser ) {
if ( existingUser ) return done ( null , existingUser ) ;
User . findOne ( { email : profile . _json . email } , function ( err , existingEmailUser ) {
2014-12-04 02:34:42 +00:00
var user = existingEmailUser || new User ;
2014-12-04 07:28:10 +00:00
user . email = user . email || profile . _json . email ;
2014-12-04 02:34:42 +00:00
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 ) {
done ( err , user ) ;
} ) ;
2014-10-13 21:14:51 +00:00
} ) ;
} ) ;
}
2014-10-15 21:53:36 +00:00
} ) ) ;
// Sign in with Google.
passport . use ( new GoogleStrategy ( secrets . google , function ( req , accessToken , refreshToken , profile , done ) {
if ( req . user ) {
User . findOne ( { google : profile . id } , function ( err , existingUser ) {
2014-12-04 02:34:42 +00:00
if ( existingUser ) {
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 ) ;
} else {
2014-10-15 21:53:36 +00:00
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 ) {
req . flash ( 'info' , { msg : 'Google account has been linked.' } ) ;
done ( err , user ) ;
} ) ;
} ) ;
2014-12-04 02:34:42 +00:00
}
2014-10-15 21:53:36 +00:00
} ) ;
} else {
User . findOne ( { google : profile . id } , function ( err , existingUser ) {
if ( existingUser ) return done ( null , existingUser ) ;
User . findOne ( { email : profile . _json . email } , function ( err , existingEmailUser ) {
2014-12-04 02:34:42 +00:00
var user = existingEmailUser || new User ;
2014-12-04 07:28:10 +00:00
user . email = user . email || profile . _json . email ;
2014-12-04 02:34:42 +00:00
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 ) {
done ( err , user ) ;
} ) ;
2014-12-08 04:50:53 +00:00
if ( ! existingEmailUser ) {
sendWelcomeEmail ( user ) ;
}
2014-10-15 21:53:36 +00:00
} ) ;
} ) ;
}
} ) ) ;
2014-11-30 06:30:02 +00:00
// Login Required middleware.
module . exports = {
isAuthenticated : isAuthenticated ,
isAuthorized : isAuthorized
} ;
function isAuthenticated ( req , res , next ) {
if ( req . isAuthenticated ( ) ) return next ( ) ;
res . redirect ( '/login' ) ;
}
// Authorization Required middleware.
function isAuthorized ( req , res , next ) {
var provider = req . path . split ( '/' ) . slice ( - 1 ) [ 0 ] ;
if ( _ . find ( req . user . tokens , { kind : provider } ) ) {
next ( ) ;
} else {
res . redirect ( '/auth/' + provider ) ;
}
}
/ *
passport . use ( new InstagramStrategy ( secrets . instagram , function ( req , accessToken , refreshToken , profile , done ) {
if ( req . user ) {
User . findOne ( { instagram : profile . id } , function ( err , existingUser ) {
if ( existingUser ) {
req . flash ( 'errors' , { msg : 'There is already an Instagram 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 . instagram = profile . id ;
user . tokens . push ( { kind : 'instagram' , accessToken : accessToken } ) ;
user . profile . name = user . profile . name || profile . displayName ;
user . profile . picture = user . profile . picture || profile . _json . data . profile _picture ;
user . profile . website = user . profile . website || profile . _json . data . website ;
user . save ( function ( err ) {
req . flash ( 'info' , { msg : 'Instagram account has been linked.' } ) ;
done ( err , user ) ;
} ) ;
} ) ;
}
} ) ;
} else {
User . findOne ( { instagram : profile . id } , function ( err , existingUser ) {
if ( existingUser ) return done ( null , existingUser ) ;
var user = new User ( ) ;
user . instagram = profile . id ;
user . tokens . push ( { kind : 'instagram' , accessToken : accessToken } ) ;
user . profile . name = profile . displayName ;
// Similar to Twitter API, assigns a temporary e-mail address
// to get on with the registration process. It can be changed later
// to a valid e-mail address in Profile Management.
user . email = profile . username + "@instagram.com" ;
user . profile . website = profile . _json . data . website ;
user . profile . picture = profile . _json . data . profile _picture ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
} ) ;
}
} ) ) ;
2014-10-15 21:53:36 +00:00
// Tumblr API setup.
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' ,
consumerKey : secrets . tumblr . consumerKey ,
consumerSecret : secrets . tumblr . consumerSecret ,
callbackURL : secrets . tumblr . callbackURL ,
passReqToCallback : true
} ,
function ( req , token , tokenSecret , profile , done ) {
User . findById ( req . user . _id , function ( err , user ) {
user . tokens . push ( { kind : 'tumblr' , accessToken : token , tokenSecret : tokenSecret } ) ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
} ) ;
}
) ) ;
// Foursquare API setup.
passport . use ( 'foursquare' , new OAuth2Strategy ( {
authorizationURL : 'https://foursquare.com/oauth2/authorize' ,
tokenURL : 'https://foursquare.com/oauth2/access_token' ,
clientID : secrets . foursquare . clientId ,
clientSecret : secrets . foursquare . clientSecret ,
callbackURL : secrets . foursquare . redirectUrl ,
passReqToCallback : true
} ,
function ( req , accessToken , refreshToken , profile , done ) {
User . findById ( req . user . _id , function ( err , user ) {
user . tokens . push ( { kind : 'foursquare' , accessToken : accessToken } ) ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
} ) ;
}
) ) ;
// Venmo API setup.
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
} ,
function ( req , accessToken , refreshToken , profile , done ) {
User . findById ( req . user . _id , function ( err , user ) {
user . tokens . push ( { kind : 'venmo' , accessToken : accessToken } ) ;
user . save ( function ( err ) {
done ( err , user ) ;
} ) ;
} ) ;
}
) ) ;
2014-11-19 23:30:36 +00:00
* /