diff --git a/api/models/Token.js b/api/models/Token.js index a9affbb638..6f130eb2c4 100644 --- a/api/models/Token.js +++ b/api/models/Token.js @@ -1,8 +1,6 @@ -const mongoose = require('mongoose'); +const { findToken, updateToken, createToken } = require('~/models'); const { encryptV2 } = require('~/server/utils/crypto'); -const Token = require('~/db/models').Token; - /** * Handles the OAuth token by creating or updating the token. * @param {object} fields @@ -31,11 +29,11 @@ async function handleOAuthToken({ expiresIn: parseInt(expiresIn, 10) || 3600, }; - const existingToken = await Token.findToken({ userId, identifier }); + const existingToken = await findToken({ userId, identifier }); if (existingToken) { - return await Token.updateToken({ identifier }, tokenData); + return await updateToken({ identifier }, tokenData); } else { - return await Token.createToken(tokenData); + return await createToken(tokenData); } } diff --git a/api/models/inviteUser.js b/api/models/inviteUser.js index 1263e3091c..295cdff87f 100644 --- a/api/models/inviteUser.js +++ b/api/models/inviteUser.js @@ -1,8 +1,7 @@ const mongoose = require('mongoose'); const { logger } = require('@librechat/data-schemas'); const { getRandomValues, hashToken } = require('~/server/utils/crypto'); - -const Token = require('~/db/models').Token; +const { createToken, findToken } = require('~/models'); /** * @module inviteUser @@ -24,7 +23,7 @@ const createInvite = async (email) => { const fakeUserId = new mongoose.Types.ObjectId(); - await Token.createToken({ + await createToken({ userId: fakeUserId, email, token: hash, @@ -51,7 +50,7 @@ const getInvite = async (encodedToken, email) => { try { const token = decodeURIComponent(encodedToken); const hash = await hashToken(token); - const invite = await Token.findToken({ token: hash, email }); + const invite = await findToken({ token: hash, email }); if (!invite) { throw new Error('Invite not found or email does not match'); diff --git a/api/server/controllers/AuthController.js b/api/server/controllers/AuthController.js index 3b19494330..0f8152de3e 100644 --- a/api/server/controllers/AuthController.js +++ b/api/server/controllers/AuthController.js @@ -9,12 +9,10 @@ const { requestPasswordReset, setOpenIDAuthTokens, } = require('~/server/services/AuthService'); -const { findUser, getUserById } = require('~/models'); +const { findUser, getUserById, deleteAllUserSessions, findSession } = require('~/models'); const { getOpenIdConfig } = require('~/strategies'); const { isEnabled } = require('~/server/utils'); -const Session = require('~/db/models').Session; - const registrationController = async (req, res) => { try { const response = await registerUser(req.body); @@ -50,7 +48,7 @@ const resetPasswordController = async (req, res) => { if (resetPasswordService instanceof Error) { return res.status(400).json(resetPasswordService); } else { - await Session.deleteAllUserSessions({ userId: req.body.userId }); + await deleteAllUserSessions({ userId: req.body.userId }); return res.status(200).json(resetPasswordService); } } catch (e) { @@ -98,7 +96,7 @@ const refreshController = async (req, res) => { } // Find the session with the hashed refresh token - const session = await Session.findSession({ + const session = await findSession({ userId: userId, refreshToken: refreshToken, }); diff --git a/api/server/controllers/TwoFactorController.js b/api/server/controllers/TwoFactorController.js index a8db894ff5..6e22db2e5c 100644 --- a/api/server/controllers/TwoFactorController.js +++ b/api/server/controllers/TwoFactorController.js @@ -1,16 +1,15 @@ -const mongoose = require('mongoose'); const { logger } = require('@librechat/data-schemas'); const { + verifyTOTP, + getTOTPSecret, + verifyBackupCode, generateTOTPSecret, generateBackupCodes, - verifyTOTP, - verifyBackupCode, - getTOTPSecret, } = require('~/server/services/twoFactorService'); +const { getUserById, updateUser } = require('~/models'); const { encryptV3 } = require('~/server/utils/crypto'); -const safeAppTitle = (process.env.APP_TITLE || 'LibreChat').replace(/\s+/g, ''); -const User = require('~/db/models').User; +const safeAppTitle = (process.env.APP_TITLE || 'LibreChat').replace(/\s+/g, ''); /** * Enable 2FA for the user by generating a new TOTP secret and backup codes. @@ -26,7 +25,7 @@ const enable2FA = async (req, res) => { const encryptedSecret = encryptV3(secret); // Update the user record: store the secret & backup codes and set twoFactorEnabled to false. - const user = await User.updateUser(userId, { + const user = await updateUser(userId, { totpSecret: encryptedSecret, backupCodes: codeObjects, twoFactorEnabled: false, @@ -48,7 +47,7 @@ const verify2FA = async (req, res) => { try { const userId = req.user.id; const { token, backupCode } = req.body; - const user = await User.getUserById(userId); + const user = await getUserById(userId); if (!user || !user.totpSecret) { return res.status(400).json({ message: '2FA not initiated' }); @@ -80,7 +79,7 @@ const confirm2FA = async (req, res) => { try { const userId = req.user.id; const { token } = req.body; - const user = await User.getUserById(userId); + const user = await getUserById(userId); if (!user || !user.totpSecret) { return res.status(400).json({ message: '2FA not initiated' }); @@ -88,7 +87,7 @@ const confirm2FA = async (req, res) => { const secret = await getTOTPSecret(user.totpSecret); if (await verifyTOTP(secret, token)) { - await User.updateUser(userId, { twoFactorEnabled: true }); + await updateUser(userId, { twoFactorEnabled: true }); return res.status(200).json(); } return res.status(400).json({ message: 'Invalid token.' }); @@ -104,7 +103,7 @@ const confirm2FA = async (req, res) => { const disable2FA = async (req, res) => { try { const userId = req.user.id; - await User.updateUser(userId, { totpSecret: null, backupCodes: [], twoFactorEnabled: false }); + await updateUser(userId, { totpSecret: null, backupCodes: [], twoFactorEnabled: false }); return res.status(200).json(); } catch (err) { logger.error('[disable2FA]', err); @@ -119,7 +118,7 @@ const regenerateBackupCodes = async (req, res) => { try { const userId = req.user.id; const { plainCodes, codeObjects } = await generateBackupCodes(); - await User.updateUser(userId, { backupCodes: codeObjects }); + await updateUser(userId, { backupCodes: codeObjects }); return res.status(200).json({ backupCodes: plainCodes, backupCodesHash: codeObjects, diff --git a/api/server/controllers/UserController.js b/api/server/controllers/UserController.js index 09460be5ec..43c1fcb57f 100644 --- a/api/server/controllers/UserController.js +++ b/api/server/controllers/UserController.js @@ -4,9 +4,17 @@ const { webSearchKeys, extractWebSearchEnvVars, } = require('librechat-data-provider'); -const mongoose = require('mongoose'); const { logger } = require('@librechat/data-schemas'); -const { getFiles, deleteFiles, deleteConvos, deletePresets, deleteMessages } = require('~/models'); +const { + getFiles, + updateUser, + deleteFiles, + deleteConvos, + deletePresets, + deleteMessages, + deleteUserById, + deleteAllUserSessions, +} = require('~/models'); const { updateUserPluginAuth, deleteUserPluginAuth } = require('~/server/services/PluginService'); const { updateUserPluginsService, deleteUserKey } = require('~/server/services/UserService'); const { verifyEmail, resendVerificationEmail } = require('~/server/services/AuthService'); @@ -16,7 +24,6 @@ const { deleteAllSharedLinks } = require('~/models/Share'); const { deleteToolCalls } = require('~/models/ToolCall'); const Transaction = require('~/db/models').Transaction; -const Session = require('~/db/models').Session; const Balance = require('~/db/models').Balance; const User = require('~/db/models').User; @@ -32,7 +39,7 @@ const getUserController = async (req, res) => { const originalAvatar = userData.avatar; try { userData.avatar = await getNewS3URL(userData.avatar); - await User.updateUser(userData.id, { avatar: userData.avatar }); + await updateUser(userData.id, { avatar: userData.avatar }); } catch (error) { userData.avatar = originalAvatar; logger.error('Error getting new S3 URL for avatar:', error); @@ -153,7 +160,7 @@ const deleteUserController = async (req, res) => { try { await deleteMessages({ user: user.id }); // delete user messages - await Session.deleteAllUserSessions({ userId: user.id }); // delete user sessions + await deleteAllUserSessions({ userId: user.id }); // delete user sessions await Transaction.deleteMany({ user: user.id }); // delete user transactions await deleteUserKey({ userId: user.id, all: true }); // delete user keys await Balance.deleteMany({ user: user._id }); // delete user balances @@ -161,7 +168,7 @@ const deleteUserController = async (req, res) => { /* TODO: Delete Assistant Threads */ await deleteConvos(user.id); // delete user convos await deleteUserPluginAuth(user.id, null, true); // delete user plugin auth - await User.deleteUserById(user.id); // delete user + await deleteUserById(user.id); // delete user await deleteAllSharedLinks(user.id); // delete user shared links await deleteUserFiles(req); // delete user files await deleteFiles(null, user.id); // delete database files in case of orphaned files from previous steps diff --git a/api/server/controllers/auth/TwoFactorAuthController.js b/api/server/controllers/auth/TwoFactorAuthController.js index d3c14b9a83..b37c89a998 100644 --- a/api/server/controllers/auth/TwoFactorAuthController.js +++ b/api/server/controllers/auth/TwoFactorAuthController.js @@ -1,14 +1,12 @@ const jwt = require('jsonwebtoken'); -const mongoose = require('mongoose'); +const { logger } = require('@librechat/data-schemas'); const { verifyTOTP, - verifyBackupCode, getTOTPSecret, + verifyBackupCode, } = require('~/server/services/twoFactorService'); const { setAuthTokens } = require('~/server/services/AuthService'); -const { logger } = require('@librechat/data-schemas'); - -const User = require('~/db/models').User; +const { getUserById } = require('~/models'); /** * Verifies the 2FA code during login using a temporary token. @@ -27,7 +25,7 @@ const verify2FAWithTempToken = async (req, res) => { return res.status(401).json({ message: 'Invalid or expired temporary token' }); } - const user = await User.getUserById(payload.userId); + const user = await getUserById(payload.userId); if (!user || !user.twoFactorEnabled) { return res.status(400).json({ message: '2FA is not enabled for this user' }); } diff --git a/api/server/services/twoFactorService.js b/api/server/services/twoFactorService.js index b12cecdaf3..0274842367 100644 --- a/api/server/services/twoFactorService.js +++ b/api/server/services/twoFactorService.js @@ -1,8 +1,6 @@ -const mongoose = require('mongoose'); const { webcrypto } = require('node:crypto'); const { hashBackupCode, decryptV3, decryptV2 } = require('~/server/utils/crypto'); - -const User = require('~/db/models').User; +const { updateUser } = require('~/models'); // Base32 alphabet for TOTP secret encoding. const BASE32_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; @@ -174,7 +172,7 @@ const verifyBackupCode = async ({ user, backupCode }) => { : codeObj, ); // Update the user record with the marked backup code. - await User.updateUser(user._id, { backupCodes: updatedBackupCodes }); + await updateUser(user._id, { backupCodes: updatedBackupCodes }); return true; } return false; diff --git a/api/strategies/jwtStrategy.js b/api/strategies/jwtStrategy.js index 86f2ff7147..6793873ee8 100644 --- a/api/strategies/jwtStrategy.js +++ b/api/strategies/jwtStrategy.js @@ -1,9 +1,7 @@ -const mongoose = require('mongoose'); const { logger } = require('@librechat/data-schemas'); const { SystemRoles } = require('librechat-data-provider'); const { Strategy: JwtStrategy, ExtractJwt } = require('passport-jwt'); - -const User = require('~/db/models').User; +const { getUserById, updateUser } = require('~/models'); // JWT strategy const jwtLogin = () => @@ -14,12 +12,12 @@ const jwtLogin = () => }, async (payload, done) => { try { - const user = await User.getUserById(payload?.id, '-password -__v -totpSecret'); + const user = await getUserById(payload?.id, '-password -__v -totpSecret'); if (user) { user.id = user._id.toString(); if (!user.role) { user.role = SystemRoles.USER; - await User.updateUser(user.id, { role: user.role }); + await updateUser(user.id, { role: user.role }); } done(null, user); } else { diff --git a/api/strategies/ldapStrategy.js b/api/strategies/ldapStrategy.js index 48abf57d36..434534c264 100644 --- a/api/strategies/ldapStrategy.js +++ b/api/strategies/ldapStrategy.js @@ -1,14 +1,11 @@ const fs = require('fs'); -const mongoose = require('mongoose'); const LdapStrategy = require('passport-ldapauth'); const { SystemRoles } = require('librechat-data-provider'); const { logger } = require('@librechat/data-schemas'); -const { createUser, findUser, updateUser } = require('~/models'); +const { createUser, findUser, updateUser, countUsers } = require('~/models'); const { getBalanceConfig } = require('~/server/services/Config'); const { isEnabled } = require('~/server/utils'); -const User = require('~/db/models').User; - const { LDAP_URL, LDAP_BIND_DN, @@ -117,7 +114,7 @@ const ldapLogin = new LdapStrategy(ldapOptions, async (userinfo, done) => { } if (!user) { - const isFirstRegisteredUser = (await User.countUsers()) === 0; + const isFirstRegisteredUser = (await countUsers()) === 0; user = { provider: 'ldap', ldapId, diff --git a/api/strategies/localStrategy.js b/api/strategies/localStrategy.js index a8859028e5..edc749ee9e 100644 --- a/api/strategies/localStrategy.js +++ b/api/strategies/localStrategy.js @@ -2,11 +2,9 @@ const { logger } = require('@librechat/data-schemas'); const { errorsToString } = require('librechat-data-provider'); const { Strategy: PassportLocalStrategy } = require('passport-local'); const { isEnabled, checkEmailConfig } = require('~/server/utils'); -const { findUser, comparePassword } = require('~/models'); +const { findUser, comparePassword, updateUser } = require('~/models'); const { loginSchema } = require('./validators'); -const User = require('~/db/models').User; - // Unix timestamp for 2024-06-07 15:20:18 Eastern Time const verificationEnabledTimestamp = 1717788018; @@ -46,13 +44,13 @@ async function passportLogin(req, email, password, done) { !user.emailVerified && userCreatedAtTimestamp < verificationEnabledTimestamp ) { - await User.updateUser(user._id, { emailVerified: true }); + await updateUser(user._id, { emailVerified: true }); user.emailVerified = true; } const unverifiedAllowed = isEnabled(process.env.ALLOW_UNVERIFIED_EMAIL_LOGIN); if (user.expiresAt && unverifiedAllowed) { - await User.updateUser(user._id, {}); + await updateUser(user._id, {}); } if (!user.emailVerified && !unverifiedAllowed) {