#32 Fixed social logins
parent
8069dcd1d1
commit
c71c1fd1c1
|
@ -5,6 +5,9 @@ const
|
|||
GoogleStrategy = require('passport-google-oauth20').Strategy,
|
||||
FacebookStrategy = require('passport-facebook').Strategy,
|
||||
TwitterStrategy = require('passport-twitter').Strategy,
|
||||
GoogleTokenStrategy = require('passport-google-id-token'),
|
||||
FacebookTokenStrategy = require('passport-facebook-token'),
|
||||
TwitterTokenStrategy = require('passport-twitter-token'),
|
||||
env = require('./env.js'),
|
||||
mw = require('./middleware.js'),
|
||||
User = require('./models.js').user;
|
||||
|
@ -34,7 +37,7 @@ module.exports = (passport)=>{
|
|||
// No user with that email
|
||||
if (!user) {
|
||||
req.session.next = undefined;
|
||||
return done( null, false, req.flash('danger','Incorrect email or password.') );
|
||||
return done( null, false, req.flash('warning','Incorrect email or password.') );
|
||||
}
|
||||
|
||||
// User exists
|
||||
|
@ -47,7 +50,7 @@ module.exports = (passport)=>{
|
|||
// Password incorrect
|
||||
if (!res) {
|
||||
req.session.next = undefined;
|
||||
return done( null, false, req.flash('danger','Incorrect email or password.') );
|
||||
return done( null, false, req.flash('warning','Incorrect email or password.') );
|
||||
}
|
||||
|
||||
// Successful login
|
||||
|
@ -65,41 +68,55 @@ module.exports = (passport)=>{
|
|||
|
||||
// Social login
|
||||
function socialLogin(req, service, profileId, done) {
|
||||
|
||||
// Log in
|
||||
if (!req.user) {
|
||||
// console.log(`Logging in with ${service}.`);
|
||||
|
||||
var query = {};
|
||||
// console.log(`socialLogin() called`);
|
||||
let query = {};
|
||||
query['auth.'+service] = profileId;
|
||||
User.findOne(query, (err,user)=>{
|
||||
if (err){ return done(err); }
|
||||
|
||||
// Intent to log in
|
||||
if (!req.user) {
|
||||
// console.log(`Logging in with ${service}...`);
|
||||
User.findOne(query)
|
||||
.then( (user)=>{
|
||||
|
||||
// Can't find user
|
||||
else if (!user){
|
||||
if (!user){
|
||||
|
||||
// Lazy update from old googleId field
|
||||
if (service==='google') {
|
||||
User.findOne( {'googleID':parseInt(profileId)}, (err,user)=>{
|
||||
if (err){ return done(err); }
|
||||
User.findOne({ 'googleID': parseInt(profileId) })
|
||||
.then( (user)=>{
|
||||
|
||||
// User exists with old schema
|
||||
if (user) {
|
||||
user.auth.google = profileId;
|
||||
user.googleId = null;
|
||||
user.save( (err)=>{
|
||||
if (err){ mw.throwErr(err,req); }
|
||||
else { console.info(`🗂️ Lazily updated schema for ${user.name}.`); }
|
||||
user.googleId = undefined;
|
||||
user.save()
|
||||
.then( ()=>{
|
||||
console.info(`🗂️ Lazily updated schema for ${user.name}.`);
|
||||
return done(null, user);
|
||||
})
|
||||
.catch( (err)=>{
|
||||
mw.throwErr(err,req);
|
||||
return done(err);
|
||||
});
|
||||
} else {
|
||||
req.flash('danger',`There's no user for that ${service} account. `);
|
||||
}
|
||||
|
||||
// No such user
|
||||
else {
|
||||
req.flash('warning',`There's no user for that ${service} account. `);
|
||||
return done();
|
||||
}
|
||||
|
||||
})
|
||||
.catch ( (err)=>{
|
||||
mw.throwErr(err,req);
|
||||
return done(err);
|
||||
});
|
||||
}
|
||||
|
||||
// No googleId either
|
||||
else {
|
||||
req.flash('danger',`There's no user for that ${service} account. `);
|
||||
req.flash('warning',`There's no user for that ${service} account. `);
|
||||
return done();
|
||||
}
|
||||
}
|
||||
|
@ -109,19 +126,51 @@ module.exports = (passport)=>{
|
|||
// console.log(`Found user: ${user}`);
|
||||
return done(null, user);
|
||||
}
|
||||
|
||||
})
|
||||
.catch( (err)=>{
|
||||
mw.throwErr(err,req);
|
||||
return done(err);
|
||||
});
|
||||
}
|
||||
|
||||
// Connect account
|
||||
// Intent to connect account
|
||||
else {
|
||||
// console.log(`Connecting ${service} account...`);
|
||||
|
||||
// Check for unique profileId
|
||||
User.findOne(query)
|
||||
.then( (existingUser)=>{
|
||||
|
||||
// Social account already in use
|
||||
if (existingUser) {
|
||||
req.flash('warning',`Another user is already connected to that ${service} account. `);
|
||||
return done();
|
||||
}
|
||||
|
||||
// Connect to account
|
||||
else {
|
||||
// console.log(`Connecting ${service} account.`);
|
||||
req.user.auth[service] = profileId;
|
||||
req.user.save( (err)=>{
|
||||
if (err){ return done(err); }
|
||||
else { return done(null, req.user); }
|
||||
req.user.save()
|
||||
.then( ()=>{
|
||||
req.flash('success', `${mw.capitalize(service)} account connected. `);
|
||||
return done(null,req.user);
|
||||
} )
|
||||
.catch( (err)=>{
|
||||
mw.throwErr(err);
|
||||
return done(err);
|
||||
} );
|
||||
}
|
||||
|
||||
})
|
||||
.catch( (err)=>{
|
||||
mw.throwErr(err,req);
|
||||
return done(err);
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Google
|
||||
|
@ -133,6 +182,12 @@ module.exports = (passport)=>{
|
|||
}, (req, accessToken, refreshToken, profile, done)=>{
|
||||
socialLogin(req, 'google', profile.id, done);
|
||||
}
|
||||
)).use('google-token', new GoogleTokenStrategy({
|
||||
clientID: env.googleClientId,
|
||||
passReqToCallback: true
|
||||
}, (req, parsedToken, googleId, done)=>{
|
||||
socialLogin(req,'google', googleId, done);
|
||||
}
|
||||
));
|
||||
|
||||
// Facebook
|
||||
|
@ -144,6 +199,13 @@ module.exports = (passport)=>{
|
|||
}, (req, accessToken, refreshToken, profile, done)=>{
|
||||
socialLogin(req, 'facebook', profile.id, done);
|
||||
}
|
||||
)).use('facebook-token', new FacebookTokenStrategy({
|
||||
clientID: env.facebookAppId,
|
||||
clientSecret: env.facebookAppSecret,
|
||||
passReqToCallback: true
|
||||
}, (req, accessToken, refreshToken, profile, done)=>{
|
||||
socialLogin(req,'facebook', profile.id, done);
|
||||
}
|
||||
));
|
||||
|
||||
// Twitter
|
||||
|
@ -155,6 +217,13 @@ module.exports = (passport)=>{
|
|||
}, (req, token, tokenSecret, profile, done)=>{
|
||||
socialLogin(req, 'twitter', profile.id, done);
|
||||
}
|
||||
)).use('twitter-token', new TwitterTokenStrategy({
|
||||
consumerKey: env.twitterConsumerKey,
|
||||
consumerSecret: env.twitterConsumerSecret,
|
||||
passReqToCallback: true
|
||||
}, (req, token, tokenSecret, profile, done)=>{
|
||||
socialLogin(req,'twitter', profile.id, done);
|
||||
}
|
||||
));
|
||||
|
||||
return passport;
|
||||
|
|
|
@ -15,14 +15,12 @@ module.exports = (app, passport) => {
|
|||
failureRedirect: '/login',
|
||||
failureFlash: true
|
||||
},
|
||||
connectOutcome = {
|
||||
failureRedirect: '/settings',
|
||||
failureFlash: true
|
||||
},
|
||||
loginCallback = (req,res)=>{
|
||||
// console.log(`Login callback called... redirecting to ${req.session.next}`);
|
||||
req.flash('success',"You have been logged in.");
|
||||
res.redirect( req.session.next || '/map' );
|
||||
},
|
||||
androidLoginCallback = (req,res)=>{
|
||||
appLoginCallback = (req,res)=>{
|
||||
if (req.user){ res.send(req.user); }
|
||||
else { res.sendStatus(401); }
|
||||
};
|
||||
|
@ -212,7 +210,8 @@ module.exports = (app, passport) => {
|
|||
req.flash('success', `If an account exists with the email <u>${req.body.email}</u>, an email has been sent there with a password reset link. `);
|
||||
res.redirect('/login');
|
||||
}).catch((err)=>{
|
||||
mw.throwErr(err);
|
||||
mw.throwErr(err,req);
|
||||
res.redirect('/login');
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -226,49 +225,58 @@ module.exports = (app, passport) => {
|
|||
|
||||
} );
|
||||
|
||||
// Android
|
||||
app.get('/login/app/', passport.authenticate('local'), appLoginCallback);
|
||||
|
||||
// Token-based
|
||||
app.get(['/login/app/google','/auth/google/idtoken'], passport.authenticate('google-token'), appLoginCallback);
|
||||
app.get('/login/app/facebook', passport.authenticate('facebook-token'), appLoginCallback);
|
||||
app.get('/login/app/twitter', passport.authenticate('twitter-token'), appLoginCallback);
|
||||
|
||||
// Social
|
||||
app.get('/login/:service', (req,res,next)=>{
|
||||
let service = req.params.service,
|
||||
sendParams = (service==='google')? {scope:['profile']} : null;
|
||||
sendParams = (service==='google')?{scope:['https://www.googleapis.com/auth/userinfo.profile']}:null;
|
||||
|
||||
// Social login
|
||||
if (!req.user) {
|
||||
// console.log(`Attempting to login with ${service} with params: ${JSON.stringify(sendParams)}...`);
|
||||
passport.authenticate(service, sendParams)(req,res,next);
|
||||
}
|
||||
|
||||
// Connect social account
|
||||
else if (!req.user.auth[service]) {
|
||||
// console.log(`Attempting to connect ${service} account...`);
|
||||
passport.authorize(service, sendParams)(req,res,next);
|
||||
}
|
||||
|
||||
// Disconnect social account
|
||||
else {
|
||||
// console.log(`Attempting to disconnect ${service} account...`);
|
||||
req.user.auth[service] = undefined;
|
||||
req.user.save()
|
||||
.then(()=>{
|
||||
req.flash('success', `${mw.capitalize(service)} account disconnected. `);
|
||||
res.redirect('/settings');
|
||||
})
|
||||
.catch((err)=>{
|
||||
mw.throwErr(err,req);
|
||||
res.redirect('/settings');
|
||||
}).then(()=>{
|
||||
req.flash('success', `${mw.capitalize(service)} account disconnected. `);
|
||||
res.redirect('/settings');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
app.get('/login/:service/cb', (req,res,next)=>{
|
||||
var service = req.params.service;
|
||||
if (!req.user) {
|
||||
passport.authenticate(service, loginOutcome)(req,res,next);
|
||||
} else {
|
||||
req.flash('success', `${mw.capitalize(service)} account connected. `);
|
||||
passport.authenticate(service, connectOutcome)(req,res,next);
|
||||
}
|
||||
}, loginCallback);
|
||||
|
||||
// Android
|
||||
app.get('/login/android/', passport.authenticate('local'), androidLoginCallback);
|
||||
app.get('/login/android/google', passport.authenticate('google-id-token'), androidLoginCallback);
|
||||
//TODO: Add android facebook login
|
||||
//TODO: Add android twitter login
|
||||
|
||||
app.get('/login/google/cb',
|
||||
passport.authenticate('google',loginOutcome),
|
||||
loginCallback
|
||||
);
|
||||
app.get('/login/facebook/cb',
|
||||
passport.authenticate('facebook',loginOutcome),
|
||||
loginCallback
|
||||
);
|
||||
app.get('/login/twitter/cb',
|
||||
passport.authenticate('twitter',loginOutcome),
|
||||
loginCallback
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -24,11 +24,12 @@
|
|||
"nunjucks": "^2.3.0",
|
||||
"passport": "^0.3.2",
|
||||
"passport-facebook": "^2.1.1",
|
||||
"passport-facebook-token": "^3.3.0",
|
||||
"passport-google-id-token": "^0.4.0",
|
||||
"passport-google-oauth2": "^0.1.6",
|
||||
"passport-google-oauth20": "^1.0.0",
|
||||
"passport-local": "^1.0.0",
|
||||
"passport-twitter": "^1.0.4",
|
||||
"passport-twitter-token": "^1.3.0",
|
||||
"slug": "^0.9.1",
|
||||
"socket.io": "^1.4.4",
|
||||
"xss": "^0.3.3"
|
||||
|
|
|
@ -81,7 +81,8 @@ const
|
|||
|
||||
// Path for redirects
|
||||
let nextPath = ( req.path.substring(0, req.path.indexOf('#')) || req.path );
|
||||
if ( nextPath!=='/login' && nextPath!=='/logout' ){
|
||||
if ( nextPath.substring(0,6)!=='/login' && nextPath.substring(0,7)!=='/logout' ){
|
||||
console.log(`Setting redirect path to "${nextPath}#"`);
|
||||
req.session.next = nextPath+'#';
|
||||
}
|
||||
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
<h3>Display your realtime GPS location on a map</h3>
|
||||
{% if user %}
|
||||
<a class='btn' href="/map">Map<i class='fa fa-angle-right'></i></a>
|
||||
<a class='btn' href="/settings">Settings<i class='fa fa-angle-right'></i></a>
|
||||
{% if user.isAdmin %}
|
||||
<a class='btn' href="/admin">Admin<i class='fa fa-angle-right'></i></a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<a class='btn' href="/map/keith">View example<i class='fa fa-angle-right'></i></a>
|
||||
<a class='btn' href="/login#signup">Join<i class='fa fa-angle-down'></i></a>
|
||||
<a class='btn' href="/login#signup">Join<i class='fa fa-angle-right'></i></a>
|
||||
<a class='btn' href="/login#login">Login<i class='fa fa-angle-right'></i></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue