diff --git a/apps/admin/core/components/common/password-strength-meter.tsx b/apps/admin/core/components/common/password-strength-meter.tsx deleted file mode 100644 index f4349b24ad0..00000000000 --- a/apps/admin/core/components/common/password-strength-meter.tsx +++ /dev/null @@ -1,89 +0,0 @@ -"use client"; - -import { FC, useMemo } from "react"; -// plane internal packages -import { E_PASSWORD_STRENGTH } from "@plane/constants"; -import { cn, getPasswordStrength } from "@plane/utils"; - -type TPasswordStrengthMeter = { - password: string; - isFocused?: boolean; -}; - -export const PasswordStrengthMeter: FC = (props) => { - const { password, isFocused = false } = props; - // derived values - const strength = useMemo(() => getPasswordStrength(password), [password]); - const strengthBars = useMemo(() => { - switch (strength) { - case E_PASSWORD_STRENGTH.EMPTY: { - return { - bars: [`bg-custom-text-100`, `bg-custom-text-100`, `bg-custom-text-100`], - text: "Please enter your password.", - textColor: "text-custom-text-100", - }; - } - case E_PASSWORD_STRENGTH.LENGTH_NOT_VALID: { - return { - bars: [`bg-red-500`, `bg-custom-text-100`, `bg-custom-text-100`], - text: "Password length should me more than 8 characters.", - textColor: "text-red-500", - }; - } - case E_PASSWORD_STRENGTH.STRENGTH_NOT_VALID: { - return { - bars: [`bg-red-500`, `bg-custom-text-100`, `bg-custom-text-100`], - text: "Password is weak.", - textColor: "text-red-500", - }; - } - case E_PASSWORD_STRENGTH.STRENGTH_VALID: { - return { - bars: [`bg-green-500`, `bg-green-500`, `bg-green-500`], - text: "Password is strong.", - textColor: "text-green-500", - }; - } - default: { - return { - bars: [`bg-custom-text-100`, `bg-custom-text-100`, `bg-custom-text-100`], - text: "Please enter your password.", - textColor: "text-custom-text-100", - }; - } - } - }, [strength]); - - const isPasswordMeterVisible = isFocused ? true : strength === E_PASSWORD_STRENGTH.STRENGTH_VALID ? false : true; - - if (!isPasswordMeterVisible) return <>; - return ( -
-
-
- {strengthBars?.bars.map((color, index) => ( -
- ))} -
-
- {strengthBars?.text} -
-
- - {/*
- {PASSWORD_CRITERIA.map((criteria) => ( -
- - {criteria.label} -
- ))} -
*/} -
- ); -}; diff --git a/apps/admin/core/components/instance/setup-form.tsx b/apps/admin/core/components/instance/setup-form.tsx index 4e771e91be8..e3169ed63e6 100644 --- a/apps/admin/core/components/instance/setup-form.tsx +++ b/apps/admin/core/components/instance/setup-form.tsx @@ -7,11 +7,10 @@ import { Eye, EyeOff } from "lucide-react"; // plane internal packages import { API_BASE_URL, E_PASSWORD_STRENGTH } from "@plane/constants"; import { AuthService } from "@plane/services"; -import { Button, Checkbox, Input, Spinner } from "@plane/ui"; +import { Button, Checkbox, Input, PasswordStrengthIndicator, Spinner } from "@plane/ui"; import { getPasswordStrength } from "@plane/utils"; // components import { Banner } from "@/components/common/banner"; -import { PasswordStrengthMeter } from "@/components/common/password-strength-meter"; // service initialization const authService = new AuthService(); @@ -274,7 +273,7 @@ export const InstanceSetupForm: FC = (props) => { {errorData.type && errorData.type === EErrorCodes.INVALID_PASSWORD && errorData.message && (

{errorData.message}

)} - +
diff --git a/apps/admin/package.json b/apps/admin/package.json index f4c293977b3..e8ef3549739 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -40,8 +40,7 @@ "react-dom": "^18.3.1", "react-hook-form": "7.51.5", "swr": "^2.2.4", - "uuid": "^9.0.1", - "zxcvbn": "^4.4.2" + "uuid": "^9.0.1" }, "devDependencies": { "@plane/eslint-config": "*", @@ -51,7 +50,6 @@ "@types/react": "^18.3.11", "@types/react-dom": "^18.2.18", "@types/uuid": "^9.0.8", - "@types/zxcvbn": "^4.4.4", "typescript": "5.8.3" } } diff --git a/apps/space/core/components/account/auth-forms/password.tsx b/apps/space/core/components/account/auth-forms/password.tsx index 08db783e394..1dbae80a3fc 100644 --- a/apps/space/core/components/account/auth-forms/password.tsx +++ b/apps/space/core/components/account/auth-forms/password.tsx @@ -4,13 +4,10 @@ import React, { useEffect, useMemo, useRef, useState } from "react"; import { observer } from "mobx-react"; import { Eye, EyeOff, XCircle } from "lucide-react"; // plane imports -import { API_BASE_URL } from "@plane/constants"; +import { API_BASE_URL, E_PASSWORD_STRENGTH } from "@plane/constants"; import { AuthService } from "@plane/services"; -import { Button, Input, Spinner } from "@plane/ui"; -// components -import { PasswordStrengthMeter } from "@/components/account"; -// helpers -import { E_PASSWORD_STRENGTH, getPasswordStrength } from "@/helpers/password.helper"; +import { Button, Input, Spinner, PasswordStrengthIndicator } from "@plane/ui"; +import { getPasswordStrength } from "@plane/utils"; // types import { EAuthModes, EAuthSteps } from "@/types/auth"; @@ -72,7 +69,7 @@ export const AuthPasswordForm: React.FC = observer((props: Props) => { const passwordSupport = passwordFormData.password.length > 0 && mode === EAuthModes.SIGN_UP && getPasswordStrength(passwordFormData.password) != E_PASSWORD_STRENGTH.STRENGTH_VALID && ( - + ); const isButtonDisabled = useMemo( diff --git a/apps/space/core/components/account/helpers/index.ts b/apps/space/core/components/account/helpers/index.ts deleted file mode 100644 index e3e821656ad..00000000000 --- a/apps/space/core/components/account/helpers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./password-strength-meter"; diff --git a/apps/space/core/components/account/helpers/password-strength-meter.tsx b/apps/space/core/components/account/helpers/password-strength-meter.tsx deleted file mode 100644 index 611067355c1..00000000000 --- a/apps/space/core/components/account/helpers/password-strength-meter.tsx +++ /dev/null @@ -1,94 +0,0 @@ -"use client"; - -import { FC, useMemo } from "react"; -// import { CircleCheck } from "lucide-react"; -// helpers -import { cn } from "@plane/utils"; -import { - E_PASSWORD_STRENGTH, - // PASSWORD_CRITERIA, - getPasswordStrength, -} from "@/helpers/password.helper"; - -type TPasswordStrengthMeter = { - password: string; - isFocused?: boolean; -}; - -export const PasswordStrengthMeter: FC = (props) => { - const { password, isFocused = false } = props; - // derived values - const strength = useMemo(() => getPasswordStrength(password), [password]); - const strengthBars = useMemo(() => { - switch (strength) { - case E_PASSWORD_STRENGTH.EMPTY: { - return { - bars: [`bg-custom-text-100`, `bg-custom-text-100`, `bg-custom-text-100`], - text: "Please enter your password.", - textColor: "text-custom-text-100", - }; - } - case E_PASSWORD_STRENGTH.LENGTH_NOT_VALID: { - return { - bars: [`bg-red-500`, `bg-custom-text-100`, `bg-custom-text-100`], - text: "Password length should me more than 8 characters.", - textColor: "text-red-500", - }; - } - case E_PASSWORD_STRENGTH.STRENGTH_NOT_VALID: { - return { - bars: [`bg-red-500`, `bg-custom-text-100`, `bg-custom-text-100`], - text: "Password is weak.", - textColor: "text-red-500", - }; - } - case E_PASSWORD_STRENGTH.STRENGTH_VALID: { - return { - bars: [`bg-green-500`, `bg-green-500`, `bg-green-500`], - text: "Password is strong.", - textColor: "text-green-500", - }; - } - default: { - return { - bars: [`bg-custom-text-100`, `bg-custom-text-100`, `bg-custom-text-100`], - text: "Please enter your password.", - textColor: "text-custom-text-100", - }; - } - } - }, [strength]); - - const isPasswordMeterVisible = isFocused ? true : strength === E_PASSWORD_STRENGTH.STRENGTH_VALID ? false : true; - - if (!isPasswordMeterVisible) return <>; - return ( -
-
-
- {strengthBars?.bars.map((color, index) => ( -
- ))} -
-
- {strengthBars?.text} -
-
- - {/*
- {PASSWORD_CRITERIA.map((criteria) => ( -
- - {criteria.label} -
- ))} -
*/} -
- ); -}; diff --git a/apps/space/core/components/account/index.ts b/apps/space/core/components/account/index.ts index cf1b7d8cdcb..bfa38e89586 100644 --- a/apps/space/core/components/account/index.ts +++ b/apps/space/core/components/account/index.ts @@ -1,5 +1,4 @@ export * from "./auth-forms"; export * from "./oauth"; export * from "./terms-and-conditions"; -export * from "./helpers"; export * from "./user-logged-in"; diff --git a/apps/space/helpers/password.helper.ts b/apps/space/helpers/password.helper.ts deleted file mode 100644 index dfe9a5c65fb..00000000000 --- a/apps/space/helpers/password.helper.ts +++ /dev/null @@ -1,67 +0,0 @@ -import zxcvbn from "zxcvbn"; - -export enum E_PASSWORD_STRENGTH { - EMPTY = "empty", - LENGTH_NOT_VALID = "length_not_valid", - STRENGTH_NOT_VALID = "strength_not_valid", - STRENGTH_VALID = "strength_valid", -} - -const PASSWORD_MIN_LENGTH = 8; -// const PASSWORD_NUMBER_REGEX = /\d/; -// const PASSWORD_CHAR_CAPS_REGEX = /[A-Z]/; -// const PASSWORD_SPECIAL_CHAR_REGEX = /[`!@#$%^&*()_\-+=\[\]{};':"\\|,.<>\/?~ ]/; - -export const PASSWORD_CRITERIA = [ - { - key: "min_8_char", - label: "Min 8 characters", - isCriteriaValid: (password: string) => password.length >= PASSWORD_MIN_LENGTH, - }, - // { - // key: "min_1_upper_case", - // label: "Min 1 upper-case letter", - // isCriteriaValid: (password: string) => PASSWORD_NUMBER_REGEX.test(password), - // }, - // { - // key: "min_1_number", - // label: "Min 1 number", - // isCriteriaValid: (password: string) => PASSWORD_CHAR_CAPS_REGEX.test(password), - // }, - // { - // key: "min_1_special_char", - // label: "Min 1 special character", - // isCriteriaValid: (password: string) => PASSWORD_SPECIAL_CHAR_REGEX.test(password), - // }, -]; - -export const getPasswordStrength = (password: string): E_PASSWORD_STRENGTH => { - let passwordStrength: E_PASSWORD_STRENGTH = E_PASSWORD_STRENGTH.EMPTY; - - if (!password || password === "" || password.length <= 0) { - return passwordStrength; - } - - if (password.length >= PASSWORD_MIN_LENGTH) { - passwordStrength = E_PASSWORD_STRENGTH.STRENGTH_NOT_VALID; - } else { - passwordStrength = E_PASSWORD_STRENGTH.LENGTH_NOT_VALID; - return passwordStrength; - } - - const passwordCriteriaValidation = PASSWORD_CRITERIA.map((criteria) => criteria.isCriteriaValid(password)).every( - (criterion) => criterion - ); - const passwordStrengthScore = zxcvbn(password).score; - - if (passwordCriteriaValidation === false || passwordStrengthScore <= 2) { - passwordStrength = E_PASSWORD_STRENGTH.STRENGTH_NOT_VALID; - return passwordStrength; - } - - if (passwordCriteriaValidation === true && passwordStrengthScore >= 3) { - passwordStrength = E_PASSWORD_STRENGTH.STRENGTH_VALID; - } - - return passwordStrength; -}; diff --git a/apps/space/package.json b/apps/space/package.json index 77b43042548..d0fe8c6a69b 100644 --- a/apps/space/package.json +++ b/apps/space/package.json @@ -49,8 +49,7 @@ "react-popper": "^2.3.0", "swr": "^2.2.2", "tailwind-merge": "^2.0.0", - "uuid": "^9.0.0", - "zxcvbn": "^4.4.2" + "uuid": "^9.0.0" }, "devDependencies": { "@plane/eslint-config": "*", @@ -63,7 +62,6 @@ "@types/react": "^18.3.11", "@types/react-dom": "^18.2.18", "@types/uuid": "^9.0.1", - "@types/zxcvbn": "^4.4.4", "@typescript-eslint/eslint-plugin": "^8.36.0", "typescript": "5.8.3" } diff --git a/apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/security/page.tsx b/apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/security/page.tsx index 4e1b23ba96e..2a405e0b015 100644 --- a/apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/security/page.tsx +++ b/apps/web/app/(all)/[workspaceSlug]/(settings)/settings/account/security/page.tsx @@ -7,10 +7,9 @@ import { Eye, EyeOff } from "lucide-react"; // plane imports import { E_PASSWORD_STRENGTH } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; -import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui"; +import { Button, Input, PasswordStrengthIndicator, TOAST_TYPE, setToast } from "@plane/ui"; import { getPasswordStrength } from "@plane/utils"; // components -import { PasswordStrengthMeter } from "@/components/account"; import { PageHead } from "@/components/core"; import { ProfileSettingContentHeader } from "@/components/profile"; // helpers @@ -114,7 +113,7 @@ const SecurityPage = observer(() => { const passwordSupport = password.length > 0 && getPasswordStrength(password) != E_PASSWORD_STRENGTH.STRENGTH_VALID && ( - + ); const renderPasswordMatchError = !isRetryPasswordInputFocused || confirmPassword.length >= password.length; diff --git a/apps/web/app/(all)/accounts/reset-password/page.tsx b/apps/web/app/(all)/accounts/reset-password/page.tsx index 388e7a02da2..bf6980e9b4d 100644 --- a/apps/web/app/(all)/accounts/reset-password/page.tsx +++ b/apps/web/app/(all)/accounts/reset-password/page.tsx @@ -11,10 +11,10 @@ import { Eye, EyeOff } from "lucide-react"; // ui import { API_BASE_URL, E_PASSWORD_STRENGTH } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; -import { Button, Input } from "@plane/ui"; +import { Button, Input, PasswordStrengthIndicator } from "@plane/ui"; // components import { getPasswordStrength } from "@plane/utils"; -import { AuthBanner, PasswordStrengthMeter } from "@/components/account"; +import { AuthBanner } from "@/components/account"; // helpers import { EAuthenticationErrorCodes, @@ -192,7 +192,7 @@ const ResetPasswordPage = observer(() => { /> )}
- +
- +