const passport = require('passport'); const { Strategy: GoogleStrategy } = require('passport-google-oauth20'); const jwt = require('jsonwebtoken'); const db = require('../db'); function deriveBase(email) { const local = email.split('@')[0]; const sanitized = local .replace(/\./g, '_') .replace(/[^a-zA-Z0-9_]/g, '') .slice(0, 15) .toLowerCase(); return sanitized || 'user'; } async function generateUniqueUsername(email) { const base = deriveBase(email); const taken = await db.user.findFirst({ where: { username: base } }); if (!taken) return base; let attempts = 0; while (attempts < 20) { const suffix = String(Math.floor(1000 + Math.random() * 9000)); const username = `${base}_${suffix}`; const collision = await db.user.findFirst({ where: { username } }); if (!collision) return username; attempts++; } return `${base}_${Date.now()}`; } passport.use( new GoogleStrategy( { clientID: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, callbackURL: process.env.GOOGLE_CALLBACK_URL, }, async (_accessToken, _refreshToken, profile, done) => { try { const email = profile.emails?.[0]?.value ?? ''; let user = await db.user.findUnique({ where: { googleId: profile.id } }); if (!user) { const username = await generateUniqueUsername(email); user = await db.user.create({ data: { googleId: profile.id, email, displayName: profile.displayName, avatarUrl: profile.photos?.[0]?.value ?? null, username, }, }); } else { user = await db.user.update({ where: { googleId: profile.id }, data: { email, displayName: profile.displayName, avatarUrl: profile.photos?.[0]?.value ?? null, }, }); if (!user.username) { const username = await generateUniqueUsername(user.email ?? ''); user = await db.user.update({ where: { id: user.id }, data: { username } }); } } const token = jwt.sign( { userId: user.id, email: user.email, name: user.displayName, picture: user.avatarUrl, }, process.env.JWT_SECRET, { algorithm: 'HS256', expiresIn: '7d' } ); done(null, { token }); } catch (err) { done(err); } } ) ); module.exports = passport;