diff --git a/packages/models/user.js b/packages/models/user.js index 6c3bc44..1fad86d 100644 --- a/packages/models/user.js +++ b/packages/models/user.js @@ -1,5 +1,20 @@ import { model, Schema } from 'mongoose' +const socialLoginSchema = new Schema({ + provider: { + type: String, + required: true, + }, + id: { + type: String, + required: true, + }, + displayName: { + type: String, + required: false, + }, +}) + const User = model( 'User', new Schema( @@ -15,13 +30,11 @@ const User = model( required: true, }, hashedPassword: String, - google: { - id: String, - displayName: String, - }, - github: { - id: String, - displayName: String, + socialLogins: { + type: Map, + of: socialLoginSchema, + default: {}, + required: true, }, }, { diff --git a/server/src/api/controllers/authController.js b/server/src/api/controllers/authController.js index 8ae7978..30af2c1 100644 --- a/server/src/api/controllers/authController.js +++ b/server/src/api/controllers/authController.js @@ -1,5 +1,4 @@ import { matchedData } from 'express-validator' -import { User } from '@linux-odyssey/models' import { genJWT } from '../../utils/auth.js' import { createUser } from '../../models/userManager.js' import { asyncHandler } from '../../middleware/error.js' @@ -50,7 +49,7 @@ export function checkSession(req, res) { }) } -export function socialLogin(req, res) { +export function socialLoginHandler(req, res) { const { newUser } = req.user if (newUser) { req.session.newUser = newUser @@ -71,10 +70,13 @@ export const registerFromSession = asyncHandler(async (req, res, next) => { return } - newUser.username = username - const user = new User(newUser) + const { email, socialLogin } = newUser - await user.save() + if (!socialLogin) { + throw new Error('Socail Login not found') + } + + const user = await createUser(username, email, { socialLogin }) req.login(user, (err) => { if (err) { diff --git a/server/src/api/routes/authRouter.js b/server/src/api/routes/authRouter.js index 6307264..2aa0319 100644 --- a/server/src/api/routes/authRouter.js +++ b/server/src/api/routes/authRouter.js @@ -7,8 +7,8 @@ import { register, checkSession, logout, - socialLogin, registerFromSession, + socialLoginHandler, } from '../controllers/authController.js' import { checkUsernameValidators, @@ -49,7 +49,7 @@ if (enabledMethods.google) { '/google/callback', authenticateRateLimit, passport.authenticate('google'), - socialLogin + socialLoginHandler ) } @@ -59,7 +59,7 @@ if (enabledMethods.github) { '/github/callback', authenticateRateLimit, passport.authenticate('github'), - socialLogin + socialLoginHandler ) } diff --git a/server/src/auth/githubStrategy.js b/server/src/auth/githubStrategy.js index d3af989..e6fe4ce 100644 --- a/server/src/auth/githubStrategy.js +++ b/server/src/auth/githubStrategy.js @@ -4,7 +4,7 @@ import config from '../config.js' import oauthVerify from './oauthVerify.js' function verify(accessToken, refreshToken, profile, cb) { - oauthVerify('github', profile, { 'github.id': profile.id }, cb) + oauthVerify('github', profile, { 'socialLogins.github.id': profile.id }, cb) } const enabled = config.github.clientID && config.github.clientSecret diff --git a/server/src/auth/googleStrategy.js b/server/src/auth/googleStrategy.js index 566a09e..a29b79d 100644 --- a/server/src/auth/googleStrategy.js +++ b/server/src/auth/googleStrategy.js @@ -4,7 +4,7 @@ import config from '../config.js' import oauthVerify from './oauthVerify.js' function verify(issuer, profile, cb) { - oauthVerify('google', profile, { 'google.id': profile.id }, cb) + oauthVerify('google', profile, { 'socialLogins.google.id': profile.id }, cb) } const enabled = config.google.clientID && config.google.clientSecret diff --git a/server/src/auth/oauthVerify.js b/server/src/auth/oauthVerify.js index 409fde3..8699ca8 100644 --- a/server/src/auth/oauthVerify.js +++ b/server/src/auth/oauthVerify.js @@ -7,18 +7,19 @@ export default async function oauthVerify(provider, profile, query, cb) { return cb(new Error('No email found')) } + const socialLogin = { + provider, + id: profile.id, + displayName: profile.displayName, + } let user = await User.findOne(query) if (!user) { user = await User.findOne({ email }) if (!user) { - const newUser = { email } - newUser[provider] = profile + const newUser = { email, socialLogin } return cb(null, { newUser }) } - user[provider] = { - id: profile.id, - displayName: profile.displayName, - } + user.socialLogins.set(provider, socialLogin) await user.save() } diff --git a/server/src/auth/passport.js b/server/src/auth/passport.js index 47f9776..16b26f9 100644 --- a/server/src/auth/passport.js +++ b/server/src/auth/passport.js @@ -26,14 +26,18 @@ if (enabledMethods.github) { passport.serializeUser((user, done) => { process.nextTick(async () => { - if (!(await UserProfile.exists({ user: user._id }))) { - UserProfile.create({ user: user._id }) + try { + if (user._id && !(await UserProfile.exists({ user: user._id }))) { + await UserProfile.create({ user: user._id }) + } + done(null, { + _id: user._id, + username: user.username, + email: user.email, + }) + } catch (err) { + done(err) } - done(null, { - _id: user._id, - username: user.username, - email: user.email, - }) }) }) diff --git a/server/src/models/userManager.js b/server/src/models/userManager.js index aa877fb..1fa1fe6 100644 --- a/server/src/models/userManager.js +++ b/server/src/models/userManager.js @@ -1,16 +1,23 @@ import { User, UserProfile } from '@linux-odyssey/models' import { hashPassword } from '../utils/auth.js' -export async function createUser(username, email, password) { +export async function createUser(username, email, { password, socialLogin }) { const user = new User({ username, email, }) - user.hashedPassword = await hashPassword(password) + if (password) { + user.hashedPassword = await hashPassword(password) + } + if (socialLogin) { + user.socialLogins.set(socialLogin.provider, socialLogin) + } await user.save() const userProfile = new UserProfile({ user, }) await userProfile.save() + + return user }