mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-31 23:58:50 +01:00
* fix: social login provider crossover * feat: Enhance OpenID login handling and add tests for provider validation * refactor: authentication error handling to use ErrorTypes.AUTH_FAILED enum * refactor: update authentication error handling in LDAP and SAML strategies to use ErrorTypes.AUTH_FAILED enum * ci: Add validation for login with existing email and different provider in SAML strategy chore: Add logging for existing users with different providers in LDAP, SAML, and Social Login strategies
83 lines
2.9 KiB
TypeScript
83 lines
2.9 KiB
TypeScript
import { logger } from '@librechat/data-schemas';
|
|
import { ErrorTypes } from 'librechat-data-provider';
|
|
import type { NextFunction, Request, Response } from 'express';
|
|
import type { MongoServerError, ValidationError, CustomError } from '~/types';
|
|
|
|
const handleDuplicateKeyError = (err: MongoServerError, res: Response) => {
|
|
logger.warn('Duplicate key error: ' + (err.errmsg || err.message));
|
|
const field = err.keyValue ? `${JSON.stringify(Object.keys(err.keyValue))}` : 'unknown';
|
|
const code = 409;
|
|
res
|
|
.status(code)
|
|
.send({ messages: `An document with that ${field} already exists.`, fields: field });
|
|
};
|
|
|
|
const handleValidationError = (err: ValidationError, res: Response) => {
|
|
logger.error('Validation error:', err.errors);
|
|
const errorMessages = Object.values(err.errors).map((el) => el.message);
|
|
const fields = `${JSON.stringify(Object.values(err.errors).map((el) => el.path))}`;
|
|
const code = 400;
|
|
const messages =
|
|
errorMessages.length > 1
|
|
? `${JSON.stringify(errorMessages.join(' '))}`
|
|
: `${JSON.stringify(errorMessages)}`;
|
|
|
|
res.status(code).send({ messages, fields });
|
|
};
|
|
|
|
/** Type guard for ValidationError */
|
|
function isValidationError(err: unknown): err is ValidationError {
|
|
return err !== null && typeof err === 'object' && 'name' in err && err.name === 'ValidationError';
|
|
}
|
|
|
|
/** Type guard for MongoServerError (duplicate key) */
|
|
function isMongoServerError(err: unknown): err is MongoServerError {
|
|
return err !== null && typeof err === 'object' && 'code' in err && err.code === 11000;
|
|
}
|
|
|
|
/** Type guard for CustomError with statusCode and body */
|
|
function isCustomError(err: unknown): err is CustomError {
|
|
return err !== null && typeof err === 'object' && 'statusCode' in err && 'body' in err;
|
|
}
|
|
|
|
export const ErrorController = (
|
|
err: Error | CustomError,
|
|
req: Request,
|
|
res: Response,
|
|
next: NextFunction,
|
|
): Response | void => {
|
|
try {
|
|
if (!err) {
|
|
return next();
|
|
}
|
|
const error = err as CustomError;
|
|
|
|
if (
|
|
(error.message === ErrorTypes.AUTH_FAILED || error.code === ErrorTypes.AUTH_FAILED) &&
|
|
req.originalUrl &&
|
|
req.originalUrl.includes('/oauth/') &&
|
|
req.originalUrl.includes('/callback')
|
|
) {
|
|
const domain = process.env.DOMAIN_CLIENT || 'http://localhost:3080';
|
|
return res.redirect(`${domain}/login?redirect=false&error=${ErrorTypes.AUTH_FAILED}`);
|
|
}
|
|
|
|
if (isValidationError(error)) {
|
|
return handleValidationError(error, res);
|
|
}
|
|
|
|
if (isMongoServerError(error)) {
|
|
return handleDuplicateKeyError(error, res);
|
|
}
|
|
|
|
if (isCustomError(error) && error.statusCode && error.body) {
|
|
return res.status(error.statusCode).send(error.body);
|
|
}
|
|
|
|
logger.error('ErrorController => error', err);
|
|
return res.status(500).send('An unknown error occurred.');
|
|
} catch (processingError) {
|
|
logger.error('ErrorController => processing error', processingError);
|
|
return res.status(500).send('Processing error in ErrorController.');
|
|
}
|
|
};
|