From d8f1344eb9d3954b643dbe52e0debd3869ee007c Mon Sep 17 00:00:00 2001 From: Yao Ding Date: Wed, 21 Aug 2024 08:28:48 -0400 Subject: [PATCH] Add a password strength label (#200) --- packages/features/package.json | 1 + .../components/wallet-info-form.tsx | 32 +++++++++++++++++++ pnpm-lock.yaml | 20 +++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/packages/features/package.json b/packages/features/package.json index 8b9973ab..1dc48b0f 100644 --- a/packages/features/package.json +++ b/packages/features/package.json @@ -43,6 +43,7 @@ "@palladxyz/pallad-core": "workspace:*", "@palladxyz/vault": "workspace:*", "@total-typescript/ts-reset": "0.5.1", + "@zxcvbn-ts/core": "^3.0.4", "array-shuffle": "3.0.0", "class-variance-authority": "0.7.0", "clsx": "2.1.1", diff --git a/packages/features/src/onboarding/components/wallet-info-form.tsx b/packages/features/src/onboarding/components/wallet-info-form.tsx index 41127a99..3dd1ec66 100644 --- a/packages/features/src/onboarding/components/wallet-info-form.tsx +++ b/packages/features/src/onboarding/components/wallet-info-form.tsx @@ -1,4 +1,5 @@ import { zodResolver } from "@hookform/resolvers/zod" +import { zxcvbn } from "@zxcvbn-ts/core" import { ExternalLinkIcon, EyeIcon, EyeOffIcon } from "lucide-react" import { useState } from "react" import { useForm } from "react-hook-form" @@ -20,6 +21,22 @@ const formSchema = z.object({ spendingPassword: passwordSchema, }) +const getPasswordStrengthConfig = (score: number) => { + switch (score) { + case 0: + case 1: + return ["Not the best", "#EB6F92"] + case 2: + return ["Weak", "#F2BEBC"] + case 3: + return ["OK and could be better", "#F2BEBC"] + case 4: + return ["Safe", "#A3DBE4"] + default: + return ["", ""] + } +} + export const WalletInfoForm = ({ title, onSubmit }: WalletInfoFormProps) => { const [showPassword, setShowPassword] = useState(false) const [termsAccepted, setTermsAccepted] = useState(false) @@ -28,6 +45,7 @@ export const WalletInfoForm = ({ title, onSubmit }: WalletInfoFormProps) => { register, handleSubmit, formState: { errors, dirtyFields }, + watch, } = useForm({ defaultValues: { walletName: "", @@ -35,6 +53,10 @@ export const WalletInfoForm = ({ title, onSubmit }: WalletInfoFormProps) => { }, resolver: zodResolver(formSchema), }) + const [strengthLabel, strengthColor] = getPasswordStrengthConfig( + zxcvbn(watch("spendingPassword")).score, + ) + return ( { {showPassword ? : } + {errors.spendingPassword && ( {errors.spendingPassword?.message} )} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9469ee5e..424a0c3a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -248,6 +248,9 @@ importers: '@total-typescript/ts-reset': specifier: 0.5.1 version: 0.5.1 + '@zxcvbn-ts/core': + specifier: ^3.0.4 + version: 3.0.4 array-shuffle: specifier: 3.0.0 version: 3.0.0 @@ -334,7 +337,7 @@ importers: version: 2.4.0 tailwindcss-animate: specifier: 1.0.7 - version: 1.0.7(tailwindcss@3.4.7(ts-node@10.9.2(@swc/core@1.7.3(@swc/helpers@0.5.12))(@types/node@22.0.0)(typescript@5.5.4))) + version: 1.0.7 webext-bridge: specifier: 6.0.1 version: 6.0.1 @@ -2892,6 +2895,9 @@ packages: '@xstate/fsm@1.6.5': resolution: {integrity: sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw==} + '@zxcvbn-ts/core@3.0.4': + resolution: {integrity: sha512-aQeiT0F09FuJaAqNrxynlAwZ2mW/1MdXakKWNmGM1Qp/VaY6CnB/GfnMS2T8gB2231Esp1/maCWd8vTG4OuShw==} + abbrev@2.0.0: resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -4309,6 +4315,10 @@ packages: resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} engines: {node: '>=6'} + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + fastparse@1.1.2: resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==} @@ -10013,6 +10023,10 @@ snapshots: '@xstate/fsm@1.6.5': {} + '@zxcvbn-ts/core@3.0.4': + dependencies: + fastest-levenshtein: 1.0.16 + abbrev@2.0.0: {} abitype@1.0.5(typescript@5.5.4)(zod@3.23.8): @@ -11563,6 +11577,8 @@ snapshots: fast-redact@3.5.0: {} + fastest-levenshtein@1.0.16: {} + fastparse@1.1.2: {} fastq@1.17.1: @@ -14694,6 +14710,8 @@ snapshots: tailwind-merge@2.4.0: {} + tailwindcss-animate@1.0.7: {} + tailwindcss-animate@1.0.7(tailwindcss@3.4.7(ts-node@10.9.2(@swc/core@1.7.3(@swc/helpers@0.5.12))(@types/node@22.0.0)(typescript@5.5.4))): dependencies: tailwindcss: 3.4.7(ts-node@10.9.2(@swc/core@1.7.3(@swc/helpers@0.5.12))(@types/node@22.0.0)(typescript@5.5.4))