mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
🪪 fix: Preserve Trusted Registration Provider Overrides (#13307)
This commit is contained in:
parent
d75d26164d
commit
b01d34abe2
3 changed files with 82 additions and 9 deletions
|
|
@ -191,13 +191,13 @@ const verifyEmail = async (req) => {
|
|||
/**
|
||||
* Register a new user.
|
||||
* @param {IUser} user <email, password, name, username>
|
||||
* @param {Partial<IUser>} [additionalData={}]
|
||||
* @param {Partial<IUser>} [additionalData={}] Trusted server-provided fields, such as CLI overrides.
|
||||
* @returns {Promise<{status: number, message: string, user?: IUser}>}
|
||||
*/
|
||||
const registerUser = async (user, additionalData = {}) => {
|
||||
const { error } = registerSchema.safeParse(user);
|
||||
if (error) {
|
||||
const errorMessage = errorsToString(error.errors);
|
||||
const result = registerSchema.safeParse(user);
|
||||
if (!result.success) {
|
||||
const errorMessage = errorsToString(result.error.errors);
|
||||
logger.info(
|
||||
'Route: register - Validation Error',
|
||||
{ name: 'Request params:', value: user },
|
||||
|
|
@ -207,7 +207,8 @@ const registerUser = async (user, additionalData = {}) => {
|
|||
return { status: 404, message: errorMessage };
|
||||
}
|
||||
|
||||
const { email, password, name, username, provider } = user;
|
||||
const { email, password, name, username } = result.data;
|
||||
const { provider, ...trustedAdditionalData } = additionalData ?? {};
|
||||
|
||||
let newUserId;
|
||||
try {
|
||||
|
|
@ -245,7 +246,7 @@ const registerUser = async (user, additionalData = {}) => {
|
|||
avatar: null,
|
||||
role: isFirstRegisteredUser ? SystemRoles.ADMIN : SystemRoles.USER,
|
||||
password: bcrypt.hashSync(password, salt),
|
||||
...additionalData,
|
||||
...trustedAdditionalData,
|
||||
};
|
||||
|
||||
const emailEnabled = checkEmailConfig();
|
||||
|
|
|
|||
|
|
@ -42,11 +42,25 @@ jest.mock('~/models', () => ({
|
|||
deleteUserById: jest.fn(),
|
||||
generateRefreshToken: jest.fn(),
|
||||
}));
|
||||
jest.mock('~/strategies/validators', () => ({ registerSchema: { parse: jest.fn() } }));
|
||||
jest.mock('~/strategies/validators', () => ({
|
||||
registerSchema: {
|
||||
safeParse: jest.fn((user) => ({
|
||||
success: true,
|
||||
data: {
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
password: user.password,
|
||||
confirm_password: user.confirm_password,
|
||||
},
|
||||
})),
|
||||
},
|
||||
}));
|
||||
jest.mock('~/server/services/Config', () => ({ getAppConfig: jest.fn() }));
|
||||
jest.mock('~/server/utils', () => ({ sendEmail: jest.fn() }));
|
||||
|
||||
const {
|
||||
checkEmailConfig,
|
||||
shouldUseSecureCookie,
|
||||
isEmailDomainAllowed,
|
||||
resolveAppConfigForUser,
|
||||
|
|
@ -58,6 +72,9 @@ const jwt = require('jsonwebtoken');
|
|||
const { logger } = require('@librechat/data-schemas');
|
||||
const {
|
||||
findUser,
|
||||
createUser,
|
||||
updateUser,
|
||||
countUsers,
|
||||
getUserById,
|
||||
generateToken,
|
||||
generateRefreshToken,
|
||||
|
|
@ -67,6 +84,7 @@ const { getAppConfig } = require('~/server/services/Config');
|
|||
const {
|
||||
setOpenIDAuthTokens,
|
||||
requestPasswordReset,
|
||||
registerUser,
|
||||
setAuthTokens,
|
||||
setCloudFrontAuthCookies,
|
||||
} = require('./AuthService');
|
||||
|
|
@ -381,6 +399,59 @@ describe('setOpenIDAuthTokens', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('registerUser', () => {
|
||||
const registrationPayload = {
|
||||
name: 'Test User',
|
||||
username: 'testuser',
|
||||
email: 'test@example.com',
|
||||
password: 'Password123!',
|
||||
confirm_password: 'Password123!',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
process.env.ALLOW_UNVERIFIED_EMAIL_LOGIN = 'false';
|
||||
checkEmailConfig.mockReturnValue(false);
|
||||
isEmailDomainAllowed.mockReturnValue(true);
|
||||
getAppConfig.mockResolvedValue({
|
||||
balance: { enabled: false },
|
||||
registration: { allowedDomains: [] },
|
||||
});
|
||||
findUser.mockResolvedValue(null);
|
||||
countUsers.mockResolvedValue(1);
|
||||
createUser.mockResolvedValue({ _id: 'new-user-id' });
|
||||
updateUser.mockResolvedValue({ _id: 'new-user-id' });
|
||||
});
|
||||
|
||||
it('ignores provider values from the public registration payload', async () => {
|
||||
const result = await registerUser({ ...registrationPayload, provider: 'google' });
|
||||
|
||||
expect(result.status).toBe(200);
|
||||
expect(createUser.mock.calls[0][0]).toEqual(
|
||||
expect.objectContaining({
|
||||
email: registrationPayload.email,
|
||||
provider: 'local',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('allows trusted callers to set provider through additional data', async () => {
|
||||
const result = await registerUser(registrationPayload, {
|
||||
emailVerified: true,
|
||||
provider: 'google',
|
||||
});
|
||||
|
||||
expect(result.status).toBe(200);
|
||||
expect(createUser.mock.calls[0][0]).toEqual(
|
||||
expect.objectContaining({
|
||||
email: registrationPayload.email,
|
||||
emailVerified: true,
|
||||
provider: 'google',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('requestPasswordReset', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
|
|
|||
|
|
@ -103,10 +103,11 @@ or the user will need to attempt logging in to have a verification link sent to
|
|||
silentExit(1);
|
||||
}
|
||||
|
||||
const user = { email, password, name, username, confirm_password: password, provider };
|
||||
const user = { email, password, name, username, confirm_password: password };
|
||||
const additionalData = { emailVerified, ...(provider !== undefined ? { provider } : {}) };
|
||||
let result;
|
||||
try {
|
||||
result = await registerUser(user, { emailVerified });
|
||||
result = await registerUser(user, additionalData);
|
||||
} catch (error) {
|
||||
console.red('Error: ' + error.message);
|
||||
silentExit(1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue