mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-05-13 16:07:30 +00:00
The Passport local strategy validation error logged the entire request body (including the password) into error logs. Replace it with the email only, matching the metadata shape used by sibling log calls in the same function.
90 lines
3.3 KiB
JavaScript
90 lines
3.3 KiB
JavaScript
const bcrypt = require('bcryptjs');
|
|
const { logger } = require('@librechat/data-schemas');
|
|
const { errorsToString } = require('librechat-data-provider');
|
|
const { Strategy: PassportLocalStrategy } = require('passport-local');
|
|
const { isEnabled, checkEmailConfig, comparePassword } = require('@librechat/api');
|
|
const { findUser, updateUser } = require('~/models');
|
|
const { loginSchema } = require('./validators');
|
|
|
|
// Unix timestamp for 2024-06-07 15:20:18 Eastern Time
|
|
const verificationEnabledTimestamp = 1717788018;
|
|
|
|
async function validateLoginRequest(req) {
|
|
const { error } = loginSchema.safeParse(req.body);
|
|
return error ? errorsToString(error.errors) : null;
|
|
}
|
|
|
|
async function passportLogin(req, email, password, done) {
|
|
try {
|
|
const validationError = await validateLoginRequest(req);
|
|
if (validationError) {
|
|
logError('Passport Local Strategy - Validation Error', { email: req.body?.email });
|
|
logger.error(`[Login] [Login failed] [Username: ${email}] [Request-IP: ${req.ip}]`);
|
|
return done(null, false, { message: validationError });
|
|
}
|
|
|
|
const user = await findUser({ email: email.trim() }, '+password');
|
|
if (!user) {
|
|
logError('Passport Local Strategy - User Not Found', { email });
|
|
logger.error(`[Login] [Login failed] [Username: ${email}] [Request-IP: ${req.ip}]`);
|
|
return done(null, false, { message: 'Email does not exist.' });
|
|
}
|
|
|
|
if (!user.password) {
|
|
logError('Passport Local Strategy - User has no password', { email });
|
|
logger.error(`[Login] [Login failed] [Username: ${email}] [Request-IP: ${req.ip}]`);
|
|
return done(null, false, { message: 'Email does not exist.' });
|
|
}
|
|
|
|
const isMatch = await comparePassword(user, password, { compare: bcrypt.compare });
|
|
if (!isMatch) {
|
|
logError('Passport Local Strategy - Password does not match', { isMatch });
|
|
logger.error(`[Login] [Login failed] [Username: ${email}] [Request-IP: ${req.ip}]`);
|
|
return done(null, false, { message: 'Incorrect password.' });
|
|
}
|
|
|
|
const emailEnabled = checkEmailConfig();
|
|
const userCreatedAtTimestamp = Math.floor(new Date(user.createdAt).getTime() / 1000);
|
|
|
|
if (
|
|
!emailEnabled &&
|
|
!user.emailVerified &&
|
|
userCreatedAtTimestamp < verificationEnabledTimestamp
|
|
) {
|
|
await updateUser(user._id, { emailVerified: true });
|
|
user.emailVerified = true;
|
|
}
|
|
|
|
const unverifiedAllowed = isEnabled(process.env.ALLOW_UNVERIFIED_EMAIL_LOGIN);
|
|
if (user.expiresAt && unverifiedAllowed) {
|
|
await updateUser(user._id, {});
|
|
}
|
|
|
|
if (!user.emailVerified && !unverifiedAllowed) {
|
|
logError('Passport Local Strategy - Email not verified', { email });
|
|
logger.error(`[Login] [Login failed] [Username: ${email}] [Request-IP: ${req.ip}]`);
|
|
return done(null, user, { message: 'Email not verified.' });
|
|
}
|
|
|
|
logger.info(`[Login] [Login successful] [Username: ${email}] [Request-IP: ${req.ip}]`);
|
|
return done(null, user);
|
|
} catch (err) {
|
|
return done(err);
|
|
}
|
|
}
|
|
|
|
function logError(title, parameters) {
|
|
const entries = Object.entries(parameters).map(([name, value]) => ({ name, value }));
|
|
logger.error(title, { parameters: entries });
|
|
}
|
|
|
|
module.exports = () =>
|
|
new PassportLocalStrategy(
|
|
{
|
|
usernameField: 'email',
|
|
passwordField: 'password',
|
|
session: false,
|
|
passReqToCallback: true,
|
|
},
|
|
passportLogin,
|
|
);
|