[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:
Jayash Tripathy
2026-02-13 18:51:33 +05:30
committed by GitHub
parent bf521b7b03
commit 53b3358a63
11 changed files with 45 additions and 23 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -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),

View File

@@ -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)

View File

@@ -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)

View File

@@ -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,

View File

@@ -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")}

View File

@@ -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,
];

View File

@@ -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",

View File

@@ -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;

View File

@@ -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.`,