NODEDC_TASKMANAGER/plane-src/packages/utils/src/auth.ts

374 lines
16 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import type { ReactNode } from "react";
// plane imports
import type { TAuthErrorInfo } from "@plane/constants";
import { E_PASSWORD_STRENGTH, EErrorAlertType, EAuthErrorCodes } from "@plane/constants";
import zxcvbn from "zxcvbn";
/**
* @description Password strength levels
*/
export enum PasswordStrength {
EMPTY = "empty",
WEAK = "weak",
FAIR = "fair",
GOOD = "good",
STRONG = "strong",
}
/**
* Calculate password strength based on various criteria
*/
export const getPasswordStrength = (password: string): E_PASSWORD_STRENGTH => {
if (!password || password === "" || password.length <= 0) {
return E_PASSWORD_STRENGTH.EMPTY;
}
if (password.length < 8) {
return E_PASSWORD_STRENGTH.LENGTH_NOT_VALID;
}
// Check all criteria
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasDigit = /[0-9]/.test(password);
const hasSpecialChar = /[!@#$%^&*()\-_+=\[\]{}|;:'",.<>?/]/.test(password);
const isComplexEnough = hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar;
const isStrongEnough = zxcvbn(password).score >= 3;
if (isComplexEnough && isStrongEnough) {
return E_PASSWORD_STRENGTH.STRENGTH_VALID;
}
return E_PASSWORD_STRENGTH.STRENGTH_NOT_VALID;
};
export type PasswordCriteria = {
key: string;
label: string;
isValid: boolean;
};
/**
* Get password criteria for validation display
*/
export const getPasswordCriteria = (password: string): PasswordCriteria[] => [
{
key: "length",
label: "Минимум 8 символов",
isValid: password.length >= 8,
},
{
key: "uppercase",
label: "Минимум 1 заглавная буква",
isValid: /[A-Z]/.test(password),
},
{
key: "lowercase",
label: "Минимум 1 строчная буква",
isValid: /[a-z]/.test(password),
},
{
key: "number",
label: "Минимум 1 цифра",
isValid: /[0-9]/.test(password),
},
{
key: "special",
label: "Минимум 1 спецсимвол",
isValid: /[!@#$%^&*()\-_+=\[\]{}|;:'",.<>?/]/.test(password),
},
{
key: "predictable",
label: "Избегайте простых и предсказуемых шаблонов",
isValid: password.length >= 8 ? zxcvbn(password).score >= 3 : false,
},
];
// Error code messages
const errorCodeMessages: {
[key in EAuthErrorCodes]: { title: string; message: (email?: string) => ReactNode };
} = {
// global
[EAuthErrorCodes.INSTANCE_NOT_CONFIGURED]: {
title: `Инстанс не настроен`,
message: () => `Инстанс не настроен. Обратитесь к администратору.`,
},
[EAuthErrorCodes.SIGNUP_DISABLED]: {
title: `Регистрация отключена`,
message: () => `Регистрация отключена. Обратитесь к администратору.`,
},
[EAuthErrorCodes.INVALID_PASSWORD]: {
title: `Неверный пароль`,
message: () => `Неверный пароль. Попробуйте снова.`,
},
[EAuthErrorCodes.PASSWORD_TOO_WEAK]: {
title: `Слишком простой пароль`,
message: () =>
`Пароль должен содержать заглавные и строчные буквы, цифру, спецсимвол и не быть предсказуемым.`,
},
[EAuthErrorCodes.SMTP_NOT_CONFIGURED]: {
title: `SMTP не настроен`,
message: () => `SMTP не настроен. Обратитесь к администратору.`,
},
// email check in both sign up and sign in
[EAuthErrorCodes.INVALID_EMAIL]: {
title: `Некорректный e-mail`,
message: () => `Некорректный e-mail. Попробуйте снова.`,
},
[EAuthErrorCodes.EMAIL_REQUIRED]: {
title: `Нужен e-mail`,
message: () => `Укажите e-mail и попробуйте снова.`,
},
// sign up
[EAuthErrorCodes.USER_ALREADY_EXIST]: {
title: `Аккаунт уже существует`,
message: () => `Аккаунт уже зарегистрирован. Выполните вход.`,
},
[EAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP]: {
title: `Нужны e-mail и пароль`,
message: () => `Укажите e-mail и пароль, затем попробуйте снова.`,
},
[EAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_UP]: {
title: `Не удалось выполнить вход`,
message: () => `Не удалось выполнить вход. Проверьте данные и попробуйте снова.`,
},
[EAuthErrorCodes.INVALID_EMAIL_SIGN_UP]: {
title: `Некорректный e-mail`,
message: () => `Некорректный e-mail. Попробуйте снова.`,
},
[EAuthErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED]: {
title: `Нужны e-mail и код`,
message: () => `Укажите e-mail и код подтверждения, затем попробуйте снова.`,
},
[EAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP]: {
title: `Некорректный e-mail`,
message: () => `Некорректный e-mail. Попробуйте снова.`,
},
// sign in
[EAuthErrorCodes.USER_ACCOUNT_DEACTIVATED]: {
title: `Аккаунт деактивирован`,
message: () => `Аккаунт деактивирован. Обратитесь к администратору.`,
},
[EAuthErrorCodes.USER_DOES_NOT_EXIST]: {
title: `Аккаунт не найден`,
message: () => `Аккаунт не найден. Создайте новый для начала работы.`,
},
[EAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN]: {
title: `Нужны e-mail и пароль`,
message: () => `Укажите e-mail и пароль, затем попробуйте снова.`,
},
[EAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_IN]: {
title: `Не удалось выполнить вход`,
message: () => `Не удалось выполнить вход. Проверьте данные и попробуйте снова.`,
},
[EAuthErrorCodes.INVALID_EMAIL_SIGN_IN]: {
title: `Некорректный e-mail`,
message: () => `Некорректный e-mail. Попробуйте снова.`,
},
[EAuthErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED]: {
title: `Нужны e-mail и код`,
message: () => `Укажите e-mail и код подтверждения, затем попробуйте снова.`,
},
[EAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN]: {
title: `Некорректный e-mail`,
message: () => `Некорректный e-mail. Попробуйте снова.`,
},
// Both Sign in and Sign up
[EAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_IN]: {
title: `Неверный код подтверждения`,
message: () => `Неверный код подтверждения. Попробуйте снова.`,
},
[EAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_UP]: {
title: `Неверный код подтверждения`,
message: () => `Неверный код подтверждения. Попробуйте снова.`,
},
[EAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_IN]: {
title: `Код подтверждения истёк`,
message: () => `Код подтверждения истёк. Запросите новый и попробуйте снова.`,
},
[EAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_UP]: {
title: `Код подтверждения истёк`,
message: () => `Код подтверждения истёк. Запросите новый и попробуйте снова.`,
},
[EAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN]: {
title: `Лимит попыток исчерпан`,
message: () => `Лимит попыток ввода кода исчерпан. Запросите новый код.`,
},
[EAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP]: {
title: `Лимит попыток исчерпан`,
message: () => `Лимит попыток ввода кода исчерпан. Запросите новый код.`,
},
// Oauth
[EAuthErrorCodes.OAUTH_NOT_CONFIGURED]: {
title: `OAuth не настроен`,
message: () => `OAuth не настроен. Обратитесь к администратору.`,
},
[EAuthErrorCodes.GOOGLE_NOT_CONFIGURED]: {
title: `Google OAuth не настроен`,
message: () => `Google OAuth не настроен. Обратитесь к администратору.`,
},
[EAuthErrorCodes.GITHUB_NOT_CONFIGURED]: {
title: `GitHub OAuth не настроен`,
message: () => `GitHub OAuth не настроен. Обратитесь к администратору.`,
},
[EAuthErrorCodes.GITLAB_NOT_CONFIGURED]: {
title: `GitLab OAuth не настроен`,
message: () => `GitLab OAuth не настроен. Обратитесь к администратору.`,
},
[EAuthErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR]: {
title: `Ошибка Google OAuth`,
message: () => `Не удалось авторизоваться через Google. Попробуйте снова.`,
},
[EAuthErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR]: {
title: `Ошибка GitHub OAuth`,
message: () => `Не удалось авторизоваться через GitHub. Попробуйте снова.`,
},
[EAuthErrorCodes.GITLAB_OAUTH_PROVIDER_ERROR]: {
title: `Ошибка GitLab OAuth`,
message: () => `Не удалось авторизоваться через GitLab. Попробуйте снова.`,
},
// Reset Password
[EAuthErrorCodes.INVALID_PASSWORD_TOKEN]: {
title: `Некорректный токен`,
message: () => `Некорректный токен восстановления. Попробуйте снова.`,
},
[EAuthErrorCodes.EXPIRED_PASSWORD_TOKEN]: {
title: `Токен истёк`,
message: () => `Токен восстановления истёк. Запросите новый.`,
},
// Change password
[EAuthErrorCodes.MISSING_PASSWORD]: {
title: `Нужен пароль`,
message: () => `Укажите пароль и попробуйте снова.`,
},
[EAuthErrorCodes.INCORRECT_OLD_PASSWORD]: {
title: `Неверный старый пароль`,
message: () => `Старый пароль указан неверно. Попробуйте снова.`,
},
[EAuthErrorCodes.INVALID_NEW_PASSWORD]: {
title: `Некорректный новый пароль`,
message: () => `Новый пароль не соответствует требованиям.`,
},
// set password
[EAuthErrorCodes.PASSWORD_ALREADY_SET]: {
title: `Пароль уже установлен`,
message: () => `Пароль уже установлен. Выполните вход.`,
},
// admin
[EAuthErrorCodes.ADMIN_ALREADY_EXIST]: {
title: `Администратор уже существует`,
message: () => `Администратор уже существует. Попробуйте снова.`,
},
[EAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME]: {
title: `Нужны e-mail, пароль и имя`,
message: () => `Укажите e-mail, пароль и имя, затем попробуйте снова.`,
},
[EAuthErrorCodes.INVALID_ADMIN_EMAIL]: {
title: `Некорректный e-mail администратора`,
message: () => `Некорректный e-mail администратора. Попробуйте снова.`,
},
[EAuthErrorCodes.INVALID_ADMIN_PASSWORD]: {
title: `Некорректный пароль администратора`,
message: () => `Некорректный пароль администратора. Попробуйте снова.`,
},
[EAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD]: {
title: `Нужны e-mail и пароль`,
message: () => `Укажите e-mail и пароль, затем попробуйте снова.`,
},
[EAuthErrorCodes.ADMIN_AUTHENTICATION_FAILED]: {
title: `Не удалось выполнить вход`,
message: () => `Не удалось выполнить вход. Проверьте данные и попробуйте снова.`,
},
[EAuthErrorCodes.ADMIN_USER_ALREADY_EXIST]: {
title: `Администратор уже существует`,
message: () => `Администратор уже существует. Выполните вход.`,
},
[EAuthErrorCodes.ADMIN_USER_DOES_NOT_EXIST]: {
title: `Администратор не найден`,
message: () => `Администратор не найден. Выполните вход.`,
},
[EAuthErrorCodes.MAGIC_LINK_LOGIN_DISABLED]: {
title: `Вход по magic link отключён`,
message: () => `Вход по magic link отключён. Используйте пароль.`,
},
[EAuthErrorCodes.PASSWORD_LOGIN_DISABLED]: {
title: `Вход по паролю отключён`,
message: () => `Вход по паролю отключён. Используйте magic link.`,
},
[EAuthErrorCodes.ADMIN_USER_DEACTIVATED]: {
title: `Администратор деактивирован`,
message: () => `Аккаунт администратора деактивирован. Обратитесь к администратору.`,
},
[EAuthErrorCodes.RATE_LIMIT_EXCEEDED]: {
title: `Слишком много запросов`,
message: () => `Слишком много запросов. Повторите попытку позже.`,
},
};
// Error handler
export const authErrorHandler = (errorCode: EAuthErrorCodes, email?: string): TAuthErrorInfo | undefined => {
const bannerAlertErrorCodes = [
EAuthErrorCodes.INSTANCE_NOT_CONFIGURED,
EAuthErrorCodes.INVALID_EMAIL,
EAuthErrorCodes.EMAIL_REQUIRED,
EAuthErrorCodes.SIGNUP_DISABLED,
EAuthErrorCodes.INVALID_PASSWORD,
EAuthErrorCodes.SMTP_NOT_CONFIGURED,
EAuthErrorCodes.USER_ALREADY_EXIST,
EAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_UP,
EAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP,
EAuthErrorCodes.INVALID_EMAIL_SIGN_UP,
EAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP,
EAuthErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED,
EAuthErrorCodes.USER_DOES_NOT_EXIST,
EAuthErrorCodes.AUTHENTICATION_FAILED_SIGN_IN,
EAuthErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN,
EAuthErrorCodes.INVALID_EMAIL_SIGN_IN,
EAuthErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN,
EAuthErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED,
EAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_IN,
EAuthErrorCodes.INVALID_MAGIC_CODE_SIGN_UP,
EAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_IN,
EAuthErrorCodes.EXPIRED_MAGIC_CODE_SIGN_UP,
EAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN,
EAuthErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP,
EAuthErrorCodes.OAUTH_NOT_CONFIGURED,
EAuthErrorCodes.GOOGLE_NOT_CONFIGURED,
EAuthErrorCodes.GITHUB_NOT_CONFIGURED,
EAuthErrorCodes.GITLAB_NOT_CONFIGURED,
EAuthErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR,
EAuthErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR,
EAuthErrorCodes.GITLAB_OAUTH_PROVIDER_ERROR,
EAuthErrorCodes.INVALID_PASSWORD_TOKEN,
EAuthErrorCodes.EXPIRED_PASSWORD_TOKEN,
EAuthErrorCodes.INCORRECT_OLD_PASSWORD,
EAuthErrorCodes.INVALID_NEW_PASSWORD,
EAuthErrorCodes.PASSWORD_ALREADY_SET,
EAuthErrorCodes.ADMIN_ALREADY_EXIST,
EAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME,
EAuthErrorCodes.INVALID_ADMIN_EMAIL,
EAuthErrorCodes.INVALID_ADMIN_PASSWORD,
EAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD,
EAuthErrorCodes.ADMIN_AUTHENTICATION_FAILED,
EAuthErrorCodes.ADMIN_USER_ALREADY_EXIST,
EAuthErrorCodes.ADMIN_USER_DOES_NOT_EXIST,
EAuthErrorCodes.USER_ACCOUNT_DEACTIVATED,
];
if (bannerAlertErrorCodes.includes(errorCode))
return {
type: EErrorAlertType.BANNER_ALERT,
code: errorCode,
title: errorCodeMessages[errorCode]?.title || "Ошибка",
message: errorCodeMessages[errorCode]?.message(email) || "Что-то пошло не так. Попробуйте снова.",
};
return undefined;
};