89 lines
2.5 KiB
JavaScript
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;
|