diff --git a/server/config/passport.js b/server/config/passport.js index ea8163e975..87dd8e49a1 100644 --- a/server/config/passport.js +++ b/server/config/passport.js @@ -124,6 +124,18 @@ const getVerifiedEmails = (githubEmails) => const getPrimaryEmail = (githubEmails) => (lodash.find(githubEmails, { primary: true }) || {}).value; +/** + * Get primary email from Google OAuth profile. + * Returns the first email if available, or null if emails array is missing/empty. + */ +const getGooglePrimaryEmail = (googleEmails) => { + if (!Array.isArray(googleEmails) || googleEmails.length === 0) { + return null; + } + const primaryEmail = googleEmails[0]?.value?.trim(); + return primaryEmail || null; +}; + /** * Sign in with GitHub. */ @@ -240,8 +252,18 @@ passport.use( }, async (req, accessToken, refreshToken, profile, done) => { try { + // Validate that emails array exists and has at least one element + const primaryEmail = getGooglePrimaryEmail(profile._json?.emails); + if (!primaryEmail) { + return done(null, false, { + msg: + 'Unable to retrieve email from Google account. ' + + 'Please ensure your Google account has an email address and try again.' + }); + } + const existingUser = await User.findOne({ - google: profile._json.emails[0].value + google: primaryEmail }).exec(); if (existingUser) { @@ -258,18 +280,16 @@ passport.use( return done(null, existingUser); } - const primaryEmail = profile._json.emails[0].value; - if (req.user) { if (!req.user.google) { - req.user.google = profile._json.emails[0].value; + req.user.google = primaryEmail; req.user.tokens.push({ kind: 'google', accessToken }); req.user.verified = User.EmailConfirmation().Verified; } await req.user.save(); return done(null, req.user); } - let username = profile._json.emails[0].value.split('@')[0]; + let username = primaryEmail.split('@')[0]; const existingEmailUser = await User.findByEmail(primaryEmail); const existingUsernameUser = await User.findByUsername(username, { caseInsensitive: true @@ -285,7 +305,7 @@ passport.use( return done(null, false, { msg: accountSuspensionMessage }); } existingEmailUser.email = existingEmailUser.email || primaryEmail; - existingEmailUser.google = profile._json.emails[0].value; + existingEmailUser.google = primaryEmail; existingEmailUser.username = existingEmailUser.username || username; existingEmailUser.tokens.push({ kind: 'google', @@ -301,7 +321,7 @@ passport.use( const user = new User(); user.email = primaryEmail; - user.google = profile._json.emails[0].value; + user.google = primaryEmail; user.username = username; user.tokens.push({ kind: 'google', accessToken }); user.name = profile._json.displayName;