📧 feat: email verification (#2344)

* feat: verification email

* chore: email verification invalid; localize: update

* fix: redirect to login when signup: fix: save emailVerified correctly

* docs: update ALLOW_UNVERIFIED_EMAIL_LOGIN; fix: don't accept login only when ALLOW_UNVERIFIED_EMAIL_LOGIN = true

* fix: user needs to be authenticated

* style: update

* fix: registration success message and redirect logic

* refactor: use `isEnabled` in ALLOW_UNVERIFIED_EMAIL_LOGIN

* refactor: move checkEmailConfig to server/utils

* refactor: use req as param for verifyEmail function

* chore: jsdoc

* chore: remove console log

* refactor: rename `createNewUser` to `createSocialUser`

* refactor: update typing and add expiresAt field to userSchema

* refactor: begin use of user methods over direct model access for User

* refactor: initial email verification rewrite

* chore: typing

* refactor: registration flow rewrite

* chore: remove help center text

* refactor: update getUser to getUserById and add findUser methods. general fixes from recent changes

* refactor: Update updateUser method to remove expiresAt field and use $set and $unset operations, createUser now returns Id only

* refactor: Update openidStrategy to use optional chaining for avatar check, move saveBuffer init to buffer condition

* refactor: logout on deleteUser mutatation

* refactor: Update openidStrategy login success message format

* refactor: Add emailVerified field to Discord and Facebook profile details

* refactor: move limiters to separate middleware dir

* refactor: Add limiters for email verification and password reset

* refactor: Remove getUserController and update routes and controllers accordingly

* refactor: Update getUserById method to exclude password and version fields

* refactor: move verification to user route, add resend verification option

* refactor: Improve email verification process and resend option

* refactor: remove more direct model access of User and remove unused code

* refactor: replace user authentication methods and token generation

* fix: add user.id to jwt user

* refactor: Update AuthContext to include setError function, add resend link to Login Form, make registration redirect shorter

* fix(updateUserPluginsService): ensure userPlugins variable is defined

* refactor: Delete all shared links for a specific user

* fix: remove use of direct User.save() in handleExistingUser

* fix(importLibreChatConvo): handle missing createdAt field in messages

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
Marco Beretta 2024-06-07 21:06:47 +02:00 committed by GitHub
parent b7fef6958b
commit ee673d682e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
67 changed files with 1863 additions and 1117 deletions

View file

@ -1,6 +1,6 @@
const { ErrorTypes } = require('librechat-data-provider');
const { encrypt, decrypt } = require('~/server/utils');
const { User, Key } = require('~/models');
const { updateUser, Key } = require('~/models');
const { logger } = require('~/config');
/**
@ -16,16 +16,13 @@ const { logger } = require('~/config');
*/
const updateUserPluginsService = async (user, pluginKey, action) => {
try {
const userPlugins = user.plugins || [];
if (action === 'install') {
return await User.updateOne(
{ _id: user._id },
{ $set: { plugins: [...user.plugins, pluginKey] } },
);
return await updateUser(user._id, { plugins: [...userPlugins, pluginKey] });
} else if (action === 'uninstall') {
return await User.updateOne(
{ _id: user._id },
{ $set: { plugins: user.plugins.filter((plugin) => plugin !== pluginKey) } },
);
return await updateUser(user._id, {
plugins: userPlugins.filter((plugin) => plugin !== pluginKey),
});
}
} catch (err) {
logger.error('[updateUserPluginsService]', err);
@ -166,30 +163,12 @@ const checkUserKeyExpiry = (expiresAt, endpoint) => {
}
};
/**
* Retrieves a user document from the database based on the provided email.
* @async
* @param {string} email - The email of the user to find.
* @returns {Promise<Object|null>} The user document if found, otherwise null.
* @throws {Error} Throws an error if there is a problem during user retrieval.
*/
const findUserByEmail = async (email) => {
try {
const user = await User.findOne({ email });
return user;
} catch (error) {
logger.error(`[findUserByEmail] Error occurred while finding user by email: ${email}`, error);
throw error;
}
};
module.exports = {
updateUserPluginsService,
getUserKey,
getUserKeyValues,
getUserKeyExpiry,
updateUserKey,
deleteUserKey,
getUserKeyValues,
getUserKeyExpiry,
checkUserKeyExpiry,
findUserByEmail,
updateUserPluginsService,
};