diff --git a/common/models/User-Identity.js b/common/models/User-Identity.js index b04b27fcf1..f6815a38bc 100644 --- a/common/models/User-Identity.js +++ b/common/models/User-Identity.js @@ -12,18 +12,6 @@ const { defaultProfileImage } = require('../utils/constantStrings.json'); const githubRegex = (/github/i); const debug = debugFactory('fcc:models:userIdent'); -function createAccessToken(user, ttl, cb) { - if (arguments.length === 2 && typeof ttl === 'function') { - cb = ttl; - ttl = 0; - } - user.accessTokens.create({ - created: new Date(), - ttl: Math.min(ttl || user.constructor.settings.ttl, - user.constructor.settings.maxTTL) - }, cb); -} - export default function(UserIdent) { // original source // github.com/strongloop/loopback-component-passport @@ -40,88 +28,89 @@ export default function(UserIdent) { cb = options; options = {}; } - const autoLogin = options.autoLogin || !options.autoLogin; const userIdentityModel = UserIdent; profile.id = profile.id || profile.openid; - return userIdentityModel.findOne({ + const filter = { where: { provider: getSocialProvider(provider), externalId: profile.id } - }) - .then(identity => { - if (identity) { - identity.credentials = credentials; - return identity.updateAttributes({ - profile: profile, - credentials: credentials, - modified: new Date() - }) - .then(function() { - // Find the user for the given identity - return identity.user(function(err, user) { - // Create access token if the autoLogin flag is set to true - if (!err && user && autoLogin) { - return (options.createAccessToken || createAccessToken)( - user, - function(err, token) { - cb(err, user, identity, token); - } - ); - } - return cb(err, user, identity); - }); - }); - } - // Find the user model - const userModel = userIdentityModel.relations.user && - userIdentityModel.relations.user.modelTo || - loopback.getModelByType(loopback.User); - - const userObj = options.profileToUser(provider, profile, options); - - if (!userObj.email && !options.emailOptional) { - process.nextTick(function() { - return cb('email is missing from the user profile'); - }); - } - - const query; - if (userObj.email) { - query = { or: [ - { username: userObj.username }, - { email: userObj.email } - ]}; - } else { - query = { username: userObj.username }; - } - return userModel.findOrCreate({ where: query }, userObj, (err, user) => { - if (err) { - return cb(err); + }; + return userIdentityModel.findOne(filter) + .then(identity => { + // identity already exists + // find user and log them in + if (identity) { + identity.credentials = credentials; + const options = { + profile: profile, + credentials: credentials, + modified: new Date() + }; + return identity.updateAttributes(options) + // grab user associated with identity + .then(() => identity.user()) + .then(user => { + // Create access token for user + const options = { + created: new Date(), + ttl: user.constructor.settings.ttl + }; + return user.accessTokens.create(options) + .then(token => ({ user, token })); + }) + .then(({ token, user })=> { + cb(null, user, identity, token); + }) + .catch(err => cb(err)); } - const date = new Date(); - return userIdentityModel.create({ - provider: getSocialProvider(provider), - externalId: profile.id, - authScheme: authScheme, - profile: profile, - credentials: credentials, - userId: user.id, - created: date, - modified: date - }, function(err, identity) { - if (!err && user && autoLogin) { - return (options.createAccessToken || createAccessToken)( - user, - function(err, token) { - cb(err, user, identity, token); - } - ); - } - return cb(err, user, identity); - }); + // Find the user model + const userModel = userIdentityModel.relations.user && + userIdentityModel.relations.user.modelTo || + loopback.getModelByType(loopback.User); + + const userObj = options.profileToUser(provider, profile, options); + if (getSocialProvider(provider) !== 'github') { + return process.nextTick(() => cb( + new Error( + 'accounts can only be created using Github or though email' + ) + )); + } + + let query; + if (userObj.email) { + query = { or: [ + { username: userObj.username }, + { email: userObj.email } + ]}; + } else { + query = { username: userObj.username }; + } + return userModel.findOrCreate({ where: query }, userObj) + .then(([ user ]) => { + const promises = [ + userIdentityModel.create({ + provider: getSocialProvider(provider), + externalId: profile.id, + authScheme: authScheme, + profile: profile, + credentials: credentials, + userId: user.id, + created: new Date(), + modified: new Date() + }), + user.accessTokens.create({ + created: new Date(), + ttl: user.constructor.settings.ttl + }) + ]; + return Promise.all(promises) + .then(([ identity, token ]) => ({ user, identity, token })); + }) + .then(({ user, token, identity }) => cb(null, user, identity, token)) + .catch(err => cb(err)); }); - }); }; UserIdent.observe('before save', function(ctx, next) { diff --git a/common/models/user.js b/common/models/user.js index e406eecf1c..0ced33a968 100644 --- a/common/models/user.js +++ b/common/models/user.js @@ -41,6 +41,8 @@ module.exports = function(User) { User.definition.properties.rand.default = function() { return Math.random(); }; + // increase user accessToken ttl to 900 days + User.settings.ttl = 900 * 24 * 60 * 60 * 1000; // username should not be in blacklist User.validatesExclusionOf('username', { diff --git a/server/component-passport.js b/server/component-passport.js index db96edcb86..88be17fd71 100644 --- a/server/component-passport.js +++ b/server/component-passport.js @@ -13,18 +13,18 @@ import { const passportOptions = { emailOptional: true, profileToUser(provider, profile) { - var emails = profile.emails; + const emails = profile.emails; // NOTE(berks): get email or set to null. // MongoDB indexs email but can be sparse(blank) - var email = emails && emails[0] && emails[0].value ? + const email = emails && emails[0] && emails[0].value ? emails[0].value : null; // create random username // username will be assigned when camper signups for Github - var username = 'fcc' + uuid.v4().slice(0, 8); - var password = generateKey('password'); - var userObj = { + const username = 'fcc' + uuid.v4().slice(0, 8); + const password = generateKey('password'); + let userObj = { username: username, password: password }; @@ -41,7 +41,7 @@ const passportOptions = { } if (/github/.test(provider)) { - setProfileFromGithub(userObj, profile, profile._json); + userObj = setProfileFromGithub(userObj, profile, profile._json); } return userObj; } diff --git a/server/utils/auth.js b/server/utils/auth.js index 52afd45861..da282b7022 100644 --- a/server/utils/auth.js +++ b/server/utils/auth.js @@ -1,5 +1,3 @@ -import assign from 'object.assign'; - const providerHash = { facebook: ({ id }) => id, twitter: ({ username }) => username, @@ -32,15 +30,16 @@ export function setProfileFromGithub( name } ) { - return assign( + return Object.assign( user, - { isGithubCool: true, isMigrationGrandfathered: false }, { name, + email: user.email || githubEmail, username: username.toLowerCase(), location, joinedGithubOn, website, + isGithubCool: true, picture, githubId, githubURL,