📧 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

@ -83,6 +83,10 @@ export const requestPasswordReset = () => '/api/auth/requestPasswordReset';
export const resetPassword = () => '/api/auth/resetPassword';
export const verifyEmail = () => '/api/user/verify';
export const resendVerificationEmail = () => '/api/user/verify/resend';
export const plugins = () => '/api/plugins';
export const config = () => '/api/config';

View file

@ -677,6 +677,14 @@ export enum ViolationTypes {
* STT Request Limit Violation.
*/
STT_LIMIT = 'stt_limit',
/**
* Reset Password Limit Violation.
*/
RESET_PASSWORD_LIMIT = 'reset_password_limit',
/**
* Verify Email Limit Violation.
*/
VERIFY_EMAIL_LIMIT = 'verify_email_limit',
}
/**

View file

@ -142,6 +142,16 @@ export const resetPassword = (payload: t.TResetPassword) => {
return request.post(endpoints.resetPassword(), payload);
};
export const verifyEmail = (payload: t.TVerifyEmail): Promise<t.VerifyEmailResponse> => {
return request.post(endpoints.verifyEmail(), payload);
};
export const resendVerificationEmail = (
payload: t.TResendVerificationEmail,
): Promise<t.VerifyEmailResponse> => {
return request.post(endpoints.resendVerificationEmail(), payload);
};
export const getAvailablePlugins = (): Promise<s.TPlugin[]> => {
return request.get(endpoints.plugins());
};

View file

@ -322,16 +322,17 @@ export const useLoginUserMutation = (): UseMutationResult<
});
};
export const useRegisterUserMutation = (): UseMutationResult<
unknown,
unknown,
t.TRegisterUser,
unknown
> => {
export const useRegisterUserMutation = (
options?: m.RegistrationOptions,
): UseMutationResult<t.TError, unknown, t.TRegisterUser, unknown> => {
const queryClient = useQueryClient();
return useMutation((payload: t.TRegisterUser) => dataService.register(payload), {
onSuccess: () => {
...options,
onSuccess: (...args) => {
queryClient.invalidateQueries([QueryKeys.user]);
if (options?.onSuccess) {
options.onSuccess(...args);
}
},
});
};

View file

@ -215,6 +215,10 @@ export type TSearchMessage = object;
export type TSearchMessageTreeNode = object;
export type TRegisterUserResponse = {
message: string;
};
export type TRegisterUser = {
name: string;
email: string;
@ -244,6 +248,15 @@ export type TResetPassword = {
confirm_password?: string;
};
export type VerifyEmailResponse = { message: string };
export type TVerifyEmail = {
email: string;
token: string;
};
export type TResendVerificationEmail = Omit<TVerifyEmail, 'token'>;
export type TInterfaceConfig = {
privacyPolicy?: {
externalUrl?: string;

View file

@ -109,3 +109,16 @@ export type UpdateSharedLinkOptions = MutationOptions<
Partial<types.TSharedLink>
>;
export type DeleteSharedLinkOptions = MutationOptions<types.TSharedLink, { shareId: string }>;
/* Auth mutations */
export type VerifyEmailOptions = MutationOptions<types.VerifyEmailResponse, types.TVerifyEmail>;
export type ResendVerifcationOptions = MutationOptions<
types.VerifyEmailResponse,
types.TResendVerificationEmail
>;
export type RegistrationOptions = MutationOptions<
types.TRegisterUserResponse,
types.TRegisterUser,
unknown,
types.TError
>;