Files
ranked-eqao/src/auth/google.js
T
2026-07-11 11:27:43 -04:00

89 lines
2.5 KiB
JavaScript

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;