From 7be45ce87556a5aae60fd6048d10d4f39270206b Mon Sep 17 00:00:00 2001 From: Andrew Nicolaou Date: Thu, 13 Apr 2017 18:04:10 +0200 Subject: [PATCH] Search for existing user account using Github emails (#337) * Tries to match user account from list of emails in Github API Requests the 'user:email' scope from Github which returns the private emails associated with the user's account. * Centres GitHub button in layout --- client/modules/User/pages/AccountView.jsx | 5 ++- client/modules/User/pages/LoginView.jsx | 7 ++-- client/styles/components/_form-container.scss | 1 + server/config/passport.js | 38 +++++++++++++++++-- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/client/modules/User/pages/AccountView.jsx b/client/modules/User/pages/AccountView.jsx index 00397c0a..81f56e11 100644 --- a/client/modules/User/pages/AccountView.jsx +++ b/client/modules/User/pages/AccountView.jsx @@ -7,6 +7,7 @@ import axios from 'axios'; import { updateSettings } from '../actions'; import AccountForm from '../components/AccountForm'; import { validateSettings } from '../../../utils/reduxFormUtils'; +import GithubButton from '../components/GithubButton'; const exitUrl = require('../../../images/exit.svg'); const logoUrl = require('../../../images/p5js-logo.svg'); @@ -41,8 +42,8 @@ class AccountView extends React.Component {

My Account

- {/*

Or

- */} +

Or

+
); diff --git a/client/modules/User/pages/LoginView.jsx b/client/modules/User/pages/LoginView.jsx index b25e5053..66cdea1a 100644 --- a/client/modules/User/pages/LoginView.jsx +++ b/client/modules/User/pages/LoginView.jsx @@ -5,7 +5,8 @@ import InlineSVG from 'react-inlinesvg'; import { validateAndLoginUser } from '../actions'; import LoginForm from '../components/LoginForm'; import { validateLogin } from '../../../utils/reduxFormUtils'; -// import GithubButton from '../components/GithubButton'; +import GithubButton from '../components/GithubButton'; + const exitUrl = require('../../../images/exit.svg'); const logoUrl = require('../../../images/p5js-logo.svg'); @@ -39,8 +40,8 @@ class LoginView extends React.Component {

Log In

- {/*

Or

- */} +

Or

+

Don't have an account?  Sign Up diff --git a/client/styles/components/_form-container.scss b/client/styles/components/_form-container.scss index 5f4a96a4..225dc155 100644 --- a/client/styles/components/_form-container.scss +++ b/client/styles/components/_form-container.scss @@ -18,6 +18,7 @@ display: flex; flex-direction: column; justify-content: center; + align-items: center; } .form-container__title { diff --git a/server/config/passport.js b/server/config/passport.js index 515f816c..9ad46659 100644 --- a/server/config/passport.js +++ b/server/config/passport.js @@ -1,5 +1,6 @@ import User from '../models/user'; +const lodash = require('lodash'); const passport = require('passport'); const GitHubStrategy = require('passport-github').Strategy; const LocalStrategy = require('passport-local').Strategy; @@ -33,6 +34,28 @@ passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, don .catch(err => done(null, false, { msg: err })); })); +/* + Input: + [ + { value: 'email@example.com', primary: false, verified: true }, + { value: 'unverified@example.com', primary: false, verified: false } + ] + + Output: + ['email@example.com'] +*/ +const getVerifiedEmails = githubEmails => ( + (githubEmails || []) + .filter(item => item.verified === true) + .map(item => item.value) +); + +const getPrimaryEmail = githubEmails => ( + ( + lodash.find(githubEmails, { primary: true }) || {} + ).value +); + /** * Sign in with GitHub. */ @@ -40,16 +63,23 @@ passport.use(new GitHubStrategy({ clientID: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET, callbackURL: '/auth/github/callback', - passReqToCallback: true + passReqToCallback: true, + scope: ['user:email'], }, (req, accessToken, refreshToken, profile, done) => { User.findOne({ github: profile.id }, (findByGithubErr, existingUser) => { if (existingUser) { done(null, existingUser); return; } - User.findOne({ email: profile._json.email }, (findByEmailErr, existingEmailUser) => { + + const emails = getVerifiedEmails(profile.emails); + const primaryEmail = getPrimaryEmail(profile.emails); + + User.findOne({ + email: { $in: emails }, + }, (findByEmailErr, existingEmailUser) => { if (existingEmailUser) { - existingEmailUser.email = existingEmailUser.email || profile._json.email; + existingEmailUser.email = existingEmailUser.email || primaryEmail; existingEmailUser.github = profile.id; existingEmailUser.username = existingEmailUser.username || profile.username; existingEmailUser.tokens.push({ kind: 'github', accessToken }); @@ -57,7 +87,7 @@ passport.use(new GitHubStrategy({ existingEmailUser.save(saveErr => done(null, existingEmailUser)); } else { const user = new User(); - user.email = profile._json.email; + user.email = primaryEmail; user.github = profile.id; user.username = profile.username; user.tokens.push({ kind: 'github', accessToken });