Files
freeCodeCamp/config/passport.js
2014-12-23 08:48:28 -08:00

526 lines
17 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var _ = require('lodash'),
passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
FacebookStrategy = require('passport-facebook').Strategy,
TwitterStrategy = require('passport-twitter').Strategy,
GitHubStrategy = require('passport-github').Strategy,
GoogleStrategy = require('passport-google-oauth').OAuth2Strategy,
LinkedInStrategy = require('passport-linkedin-oauth2').Strategy,
OAuthStrategy = require('passport-oauth').OAuthStrategy,
OAuth2Strategy = require('passport-oauth').OAuth2Strategy,
User = require('../models/User'),
secrets = require('./secrets');
// Login Required middleware.
module.exports = {
isAuthenticated: isAuthenticated,
isAuthorized: isAuthorized
};
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
if (err) { return done(err); }
done(null, user);
});
});
//function sendWelcomeEmail(u) {
// var transporter = nodemailer.createTransport({
// service: 'Mandrill',
// auth: {
// user: secrets.mandrill.user,
// pass: secrets.mandrill.password
// }
// });
// var mailOptions = {
// to: u.email,
// from: 'Team@freecodecamp.com',
// subject: 'Welcome to Free Code Camp ' + u.name + '!',
// text: 'Hello,\n\n' +
// 'Welcome to Free Code Camp!'
// };
//}
/**
* 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) {
if (err) { return done(err); }
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.'
].join('')
});
done();
} else {
User.findById(req.user.id, function(err, user) {
if (err) { return done(err); }
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(null, user);
});
});
}
});
} else {
User.findOne({ twitter: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
//if (existingUser) return done(null, existingUser);
// Twitter will not provide an email address. Period.
// But a persons twitter username is guaranteed to be unique
// so we can "fake" a twitter email address as follows:
//user.email = profile.username + "@twitter.com";
var user = existingUser || new User();
user.twitter = profile.id;
user.email = user.email || '';
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.save(function(err) {
if (err) { return done(err); }
done(null, user);
});
//TODO: Twitter redirect to capture user email.
//if (!user.email) {
// req.redirect('/account');
// req.flash('errors', {
// msg:
// 'OK, you are signed in. ' +
// 'Please add your email address to your profile.'
// });
//}
});
}
})
);
// 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 (err) { return done(err); }
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.'
].join('')
});
done();
} else {
User.findById(req.user.id, function(err, user) {
if (err) { return done(err); }
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, _user) {
if (err) { return done(err); }
req.flash(
'info', { msg: 'LinkedIn account has been linked.' }
);
done(null, user);
});
});
}
});
} else {
User.findOne({ linkedin: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
if (existingUser) { return done(null, existingUser); }
User.findOne(
{ email: profile._json.emailAddress },
function(err, existingEmailUser) {
if (err) { return done(err); }
var user = existingEmailUser || new User();
user.linkedin = profile.id;
user.tokens.push({
kind: 'linkedin',
accessToken: accessToken
});
user.email = user.email || profile._json.emailAddress;
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) {
if (err) { return done(err); }
done(null, user);
});
});
});
}
}));
// Sign in using Email and Password.
passport.use(
new LocalStrategy(
{ usernameField: 'email' }, function(email, password, done) {
User.findOne({ email: email }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Email ' + email + ' not found'});
}
user.comparePassword(password, function(err, isMatch) {
if (err) { return done(err); }
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Invalid email or password.' });
}
});
});
}));
// Sign in with Facebook.
passport.use(
new FacebookStrategy(
secrets.facebook, function(req, accessToken, refreshToken, profile, done) {
if (req.user) {
User.findOne({ facebook: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
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.'
].join(' ')
});
done();
} else {
User.findById(req.user.id, function(err, user) {
if (err) { return done(err); }
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.save(function(err) {
if (err) { return done(err); }
req.flash(
'info', { msg: 'Facebook account has been linked.' });
done(null, user);
});
});
}
});
} else {
User.findOne({ facebook: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
if (existingUser) { return done(null, existingUser); }
User.findOne(
{ email: profile._json.email }, function(err, existingEmailUser) {
if (err) { return done(err); }
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) {
if (err) { return done(err); }
done(null, 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 (err) { return done(err); }
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.'
].join(' ')
});
done();
} else {
User.findById(req.user.id, function(err, user) {
if (err) { return done(err); }
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) {
if (err) { return done(err); }
req.flash('info', { msg: 'GitHub account has been linked.' });
done(null, user);
});
});
}
});
} else {
User.findOne({ github: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
if (existingUser) { return done(null, existingUser); }
User.findOne(
{ email: profile._json.email }, function(err, existingEmailUser) {
if (err) { return done(err); }
var user = existingEmailUser || new User();
user.email = user.email || profile._json.email;
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) {
if (err) { return done(err); }
done(null, user);
});
});
});
}
}));
// 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) {
if (err) { return done(err); }
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.'
].join(' ')
});
done();
} else {
User.findById(req.user.id, function(err, user) {
if (err) { return done(err); }
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) {
if (err) { return done(err); }
req.flash('info', { msg: 'Google account has been linked.' });
done(null, user);
});
});
}
});
} else {
User.findOne({ google: profile.id }, function(err, existingUser) {
if (err) { return done(err); }
if (existingUser) { return done(null, existingUser); }
User.findOne(
{ email: profile._json.email }, function(err, existingEmailUser) {
if (err) { return done(err); }
var user = existingEmailUser || new User();
user.email = user.email || profile._json.email;
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;
//TODO: Greeting email
//if (!existingEmailUser) {
// sendWelcomeEmail(user);
//}
user.save(function(err) {
if (err) { return done(err); }
done(null, user);
});
});
});
}
}));
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);
}
}