mirror of
https://github.com/makeplane/plane.git
synced 2026-02-24 04:00:14 +01:00
[GIT-44] refactor(auth): add PASSWORD_TOO_WEAK error code (#8522)
* refactor(auth): add PASSWORD_TOO_WEAK error code and update related error handling in password change flow * fix(auth): update import to use type for EAuthenticationErrorCodes in security page * Update apps/web/app/(all)/profile/security/page.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/security/page.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: updated auth error exception accross zxcvbn usages * fix: improve error handling for password strength validation and update error messages * i18n(ru): update Russian translations for stickies and automation description Added translation for 'stickies' and improved formatting of the automation description in Russian locale. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -85,8 +85,8 @@ class Adapter:
|
||||
results = zxcvbn(self.code)
|
||||
if results["score"] < 3:
|
||||
raise AuthenticationException(
|
||||
error_code=AUTHENTICATION_ERROR_CODES["INVALID_PASSWORD"],
|
||||
error_message="INVALID_PASSWORD",
|
||||
error_code=AUTHENTICATION_ERROR_CODES["PASSWORD_TOO_WEAK"],
|
||||
error_message="PASSWORD_TOO_WEAK",
|
||||
payload={"email": email},
|
||||
)
|
||||
return
|
||||
|
||||
@@ -13,6 +13,7 @@ AUTHENTICATION_ERROR_CODES = {
|
||||
"USER_ACCOUNT_DEACTIVATED": 5019,
|
||||
# Password strength
|
||||
"INVALID_PASSWORD": 5020,
|
||||
"PASSWORD_TOO_WEAK": 5021,
|
||||
"SMTP_NOT_CONFIGURED": 5025,
|
||||
# Sign Up
|
||||
"USER_ALREADY_EXIST": 5030,
|
||||
|
||||
@@ -145,8 +145,8 @@ class ResetPasswordEndpoint(View):
|
||||
results = zxcvbn(password)
|
||||
if results["score"] < 3:
|
||||
exc = AuthenticationException(
|
||||
error_code=AUTHENTICATION_ERROR_CODES["INVALID_PASSWORD"],
|
||||
error_message="INVALID_PASSWORD",
|
||||
error_code=AUTHENTICATION_ERROR_CODES["PASSWORD_TOO_WEAK"],
|
||||
error_message="PASSWORD_TOO_WEAK",
|
||||
)
|
||||
url = urljoin(
|
||||
base_host(request=request, is_app=True),
|
||||
|
||||
@@ -83,8 +83,8 @@ class ChangePasswordEndpoint(APIView):
|
||||
results = zxcvbn(new_password)
|
||||
if results["score"] < 3:
|
||||
exc = AuthenticationException(
|
||||
error_code=AUTHENTICATION_ERROR_CODES["INVALID_NEW_PASSWORD"],
|
||||
error_message="INVALID_NEW_PASSWORD",
|
||||
error_code=AUTHENTICATION_ERROR_CODES["PASSWORD_TOO_WEAK"],
|
||||
error_message="PASSWORD_TOO_WEAK",
|
||||
)
|
||||
return Response(exc.get_error_dict(), status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
@@ -139,8 +139,8 @@ class ResetPasswordSpaceEndpoint(View):
|
||||
results = zxcvbn(password)
|
||||
if results["score"] < 3:
|
||||
exc = AuthenticationException(
|
||||
error_code=AUTHENTICATION_ERROR_CODES["INVALID_PASSWORD"],
|
||||
error_message="INVALID_PASSWORD",
|
||||
error_code=AUTHENTICATION_ERROR_CODES["PASSWORD_TOO_WEAK"],
|
||||
error_message="PASSWORD_TOO_WEAK",
|
||||
)
|
||||
url = f"{base_host(request=request, is_space=True)}/accounts/reset-password/?{urlencode(exc.get_error_dict())}" # noqa: E501
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@@ -191,8 +191,8 @@ class InstanceAdminSignUpEndpoint(View):
|
||||
results = zxcvbn(password)
|
||||
if results["score"] < 3:
|
||||
exc = AuthenticationException(
|
||||
error_code=AUTHENTICATION_ERROR_CODES["INVALID_ADMIN_PASSWORD"],
|
||||
error_message="INVALID_ADMIN_PASSWORD",
|
||||
error_code=AUTHENTICATION_ERROR_CODES["PASSWORD_TOO_WEAK"],
|
||||
error_message="PASSWORD_TOO_WEAK",
|
||||
payload={
|
||||
"email": email,
|
||||
"first_name": first_name,
|
||||
|
||||
@@ -18,8 +18,7 @@ import { getPasswordStrength } from "@plane/utils";
|
||||
// components
|
||||
import { ProfileSettingsHeading } from "@/components/settings/profile/heading";
|
||||
// helpers
|
||||
import { authErrorHandler } from "@/helpers/authentication.helper";
|
||||
import type { EAuthenticationErrorCodes } from "@/helpers/authentication.helper";
|
||||
import { authErrorHandler, EAuthenticationErrorCodes, passwordErrors } from "@/helpers/authentication.helper";
|
||||
// hooks
|
||||
import { useUser } from "@/hooks/store/user";
|
||||
// services
|
||||
@@ -58,6 +57,7 @@ export const SecurityProfileSettings = observer(function SecurityProfileSettings
|
||||
control,
|
||||
handleSubmit,
|
||||
watch,
|
||||
setError,
|
||||
formState: { errors, isSubmitting },
|
||||
reset,
|
||||
} = useForm<FormValues>({ defaultValues });
|
||||
@@ -93,11 +93,9 @@ export const SecurityProfileSettings = observer(function SecurityProfileSettings
|
||||
message: t("auth.common.password.toast.change_password.success.message"),
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
let errorInfo = undefined;
|
||||
if (error instanceof Error) {
|
||||
const code = "error_code" in error ? error.error_code?.toString() : undefined;
|
||||
errorInfo = code ? authErrorHandler(code as EAuthenticationErrorCodes) : undefined;
|
||||
}
|
||||
const err = error as Error & { error_code?: string };
|
||||
const code = err.error_code?.toString();
|
||||
const errorInfo = code ? authErrorHandler(code as EAuthenticationErrorCodes) : undefined;
|
||||
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
@@ -105,6 +103,13 @@ export const SecurityProfileSettings = observer(function SecurityProfileSettings
|
||||
message:
|
||||
typeof errorInfo?.message === "string" ? errorInfo.message : t("auth.common.password.toast.error.message"),
|
||||
});
|
||||
|
||||
if (code && passwordErrors.includes(code as EAuthenticationErrorCodes)) {
|
||||
setError("new_password", {
|
||||
type: "manual",
|
||||
message: errorInfo?.message?.toString() || t("auth.common.password.toast.error.message"),
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -204,6 +209,9 @@ export const SecurityProfileSettings = observer(function SecurityProfileSettings
|
||||
)}
|
||||
</div>
|
||||
{passwordSupport}
|
||||
{errors.new_password && (
|
||||
<span className="text-11 text-danger-primary">{errors.new_password.message}</span>
|
||||
)}
|
||||
{isNewPasswordSameAsOldPassword && !isPasswordInputFocused && (
|
||||
<span className="text-11 text-danger-primary">
|
||||
{t("new_password_must_be_different_from_old_password")}
|
||||
|
||||
@@ -47,6 +47,7 @@ export enum EAuthenticationErrorCodes {
|
||||
USER_ACCOUNT_DEACTIVATED = "5019",
|
||||
// Password strength
|
||||
INVALID_PASSWORD = "5020",
|
||||
PASSWORD_TOO_WEAK = "5021",
|
||||
SMTP_NOT_CONFIGURED = "5025",
|
||||
// Sign Up
|
||||
USER_ALREADY_EXIST = "5030",
|
||||
@@ -107,6 +108,7 @@ export type TAuthErrorInfo = {
|
||||
message: ReactNode;
|
||||
};
|
||||
|
||||
// TODO: move all error messages to translation files
|
||||
const errorCodeMessages: {
|
||||
[key in EAuthenticationErrorCodes]: { title: string; message: (email?: string) => ReactNode };
|
||||
} = {
|
||||
@@ -143,6 +145,10 @@ const errorCodeMessages: {
|
||||
title: `Invalid password`,
|
||||
message: () => `Invalid password. Please try again.`,
|
||||
},
|
||||
[EAuthenticationErrorCodes.PASSWORD_TOO_WEAK]: {
|
||||
title: `Password too weak`,
|
||||
message: () => `Please use a stronger password.`,
|
||||
},
|
||||
[EAuthenticationErrorCodes.SMTP_NOT_CONFIGURED]: {
|
||||
title: `SMTP not configured`,
|
||||
message: () => `SMTP not configured. Please contact your administrator.`,
|
||||
@@ -418,6 +424,7 @@ export const authErrorHandler = (errorCode: EAuthenticationErrorCodes, email?: s
|
||||
EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST,
|
||||
EAuthenticationErrorCodes.ADMIN_USER_DEACTIVATED,
|
||||
EAuthenticationErrorCodes.RATE_LIMIT_EXCEEDED,
|
||||
EAuthenticationErrorCodes.PASSWORD_TOO_WEAK,
|
||||
];
|
||||
|
||||
if (bannerAlertErrorCodes.includes(errorCode))
|
||||
@@ -430,3 +437,8 @@ export const authErrorHandler = (errorCode: EAuthenticationErrorCodes, email?: s
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const passwordErrors = [
|
||||
EAuthenticationErrorCodes.PASSWORD_TOO_WEAK,
|
||||
EAuthenticationErrorCodes.INVALID_NEW_PASSWORD,
|
||||
];
|
||||
|
||||
@@ -114,6 +114,7 @@ export enum EAuthErrorCodes {
|
||||
USER_ACCOUNT_DEACTIVATED = "5019",
|
||||
// Password strength
|
||||
INVALID_PASSWORD = "5020",
|
||||
PASSWORD_TOO_WEAK = "5021",
|
||||
SMTP_NOT_CONFIGURED = "5025",
|
||||
// Sign Up
|
||||
USER_ALREADY_EXIST = "5030",
|
||||
|
||||
@@ -23,6 +23,7 @@ export default {
|
||||
favorites: "Избранное",
|
||||
pro: "Pro",
|
||||
upgrade: "Обновить",
|
||||
stickies: "Стикеры",
|
||||
},
|
||||
auth: {
|
||||
common: {
|
||||
@@ -2002,8 +2003,7 @@ export default {
|
||||
automations: {
|
||||
label: "Автоматизация",
|
||||
heading: "Автоматизация",
|
||||
description:
|
||||
"Настройте автоматические действия для оптимизации рабочего процесса и сокращения ручных задач.",
|
||||
description: "Настройте автоматические действия для оптимизации рабочего процесса и сокращения ручных задач.",
|
||||
"auto-archive": {
|
||||
title: "Автоархивация закрытых рабочих элементов",
|
||||
description: "Plane будет автоматически архивировать рабочие элементы, которые были завершены или отменены.",
|
||||
@@ -2921,8 +2921,4 @@ export default {
|
||||
enter_number_of_projects: "Введите количество проектов",
|
||||
pin: "Закрепить",
|
||||
unpin: "Открепить",
|
||||
sidebar: {
|
||||
stickies: "Стикеры",
|
||||
your_work: "Ваша работа",
|
||||
},
|
||||
} as const;
|
||||
|
||||
@@ -99,6 +99,10 @@ const errorCodeMessages: {
|
||||
title: `Invalid password`,
|
||||
message: () => `Invalid password. Please try again.`,
|
||||
},
|
||||
[EAuthErrorCodes.PASSWORD_TOO_WEAK]: {
|
||||
title: `Password too weak`,
|
||||
message: () => `Please use a stronger password.`,
|
||||
},
|
||||
[EAuthErrorCodes.SMTP_NOT_CONFIGURED]: {
|
||||
title: `SMTP not configured`,
|
||||
message: () => `SMTP not configured. Please contact your administrator.`,
|
||||
|
||||
Reference in New Issue
Block a user