diff --git a/e2e/onboarding.spec.ts b/e2e/onboarding.spec.ts index 887382ea5..7e709f425 100644 --- a/e2e/onboarding.spec.ts +++ b/e2e/onboarding.spec.ts @@ -42,37 +42,6 @@ describe("Onboarding", () => { await homarrContainer.stop(); }, 60_000); - test("Credentials onboarding with special character password should be successful", async () => { - const { db, localMountPath } = await createSqliteDbFileAsync(); - const homarrContainer = await createHomarrContainer({ - mounts: { - "/appdata": localMountPath, - }, - }).start(); - - const browser = await chromium.launch(); - const context = await browser.newContext(); - const page = await context.newPage(); - const actions = new OnboardingActions(page, db); - const assertions = new OnboardingAssertions(page, db); - - await page.goto(`http://${homarrContainer.getHost()}:${homarrContainer.getMappedPort(7575)}`); - await actions.startOnboardingAsync("scratch"); - await actions.processUserStepAsync({ - username: "admin", - password: "LoveHomarr<3", - confirmPassword: "LoveHomarr<3", - }); - await actions.processSettingsStepAsync(); - - await assertions.assertFinishStepVisibleAsync(); - await assertions.assertUserAndAdminGroupInsertedAsync("admin"); - await assertions.assertDbOnboardingStepAsync("finish"); - - await browser.close(); - await homarrContainer.stop(); - }, 60_000); - test("External provider onboarding setup should be successful", async () => { // Arrange const { db, localMountPath } = await createSqliteDbFileAsync(); diff --git a/packages/auth/test/security.spec.ts b/packages/auth/test/security.spec.ts index 7b3ffd82e..fee34ec7f 100644 --- a/packages/auth/test/security.spec.ts +++ b/packages/auth/test/security.spec.ts @@ -53,12 +53,4 @@ describe("comparePasswordsAsync should compare passwords correctly", () => { // Assert expect(result).toBe(false); }); - it("should return true for passwords with special characters like LoveHomarr<3", async () => { - const password = "LoveHomarr<3"; - const hash = await hashPasswordAsync(password); - - const result = await comparePasswordsAsync(password, hash); - - expect(result).toBe(true); - }); }); diff --git a/packages/translation/src/lang/ca.json b/packages/translation/src/lang/ca.json index 6cbd7acf6..4ccc82522 100644 --- a/packages/translation/src/lang/ca.json +++ b/packages/translation/src/lang/ca.json @@ -132,7 +132,7 @@ }, "password": { "label": "Contrasenya", - "requirement": { + "suggestion": { "length": "Inclou com a mínim 8 caràcters", "lowercase": "Inclou minúscules", "uppercase": "Inclou majúscules", diff --git a/packages/translation/src/lang/cn.json b/packages/translation/src/lang/cn.json index 3a10e9210..88f801a3f 100644 --- a/packages/translation/src/lang/cn.json +++ b/packages/translation/src/lang/cn.json @@ -132,7 +132,7 @@ }, "password": { "label": "密码", - "requirement": { + "suggestion": { "length": "至少包含 8 个字符", "lowercase": "包含小写字母", "uppercase": "包含大写字母", diff --git a/packages/translation/src/lang/cr.json b/packages/translation/src/lang/cr.json index 27a4588a8..a4b260b83 100644 --- a/packages/translation/src/lang/cr.json +++ b/packages/translation/src/lang/cr.json @@ -132,7 +132,7 @@ }, "password": { "label": "crwdns26:0crwdne26:0", - "requirement": { + "suggestion": { "length": "crwdns28:0crwdne28:0", "lowercase": "crwdns30:0crwdne30:0", "uppercase": "crwdns32:0crwdne32:0", diff --git a/packages/translation/src/lang/cs.json b/packages/translation/src/lang/cs.json index 46d284ee5..30969a03d 100644 --- a/packages/translation/src/lang/cs.json +++ b/packages/translation/src/lang/cs.json @@ -132,7 +132,7 @@ }, "password": { "label": "Heslo", - "requirement": { + "suggestion": { "length": "Obsahuje alespoň 8 znaků", "lowercase": "Obsahuje malé písmeno", "uppercase": "Obsahuje velké písmeno", diff --git a/packages/translation/src/lang/da.json b/packages/translation/src/lang/da.json index 09d071783..044f7b747 100644 --- a/packages/translation/src/lang/da.json +++ b/packages/translation/src/lang/da.json @@ -132,7 +132,7 @@ }, "password": { "label": "Adgangskode", - "requirement": { + "suggestion": { "length": "Inkluderer mindst 8 tegn", "lowercase": "Inkluderer små bogstaver", "uppercase": "Inkluderer store bogstaver", diff --git a/packages/translation/src/lang/de-CH.json b/packages/translation/src/lang/de-CH.json index 024e95740..abdca6525 100644 --- a/packages/translation/src/lang/de-CH.json +++ b/packages/translation/src/lang/de-CH.json @@ -132,7 +132,7 @@ }, "password": { "label": "Passwort", - "requirement": { + "suggestion": { "length": "Enthält mindestens 8 Zeichen", "lowercase": "Enthält Kleinbuchstaben", "uppercase": "Enthält Großbuchstaben", diff --git a/packages/translation/src/lang/de.json b/packages/translation/src/lang/de.json index db0479ba6..0110618f4 100644 --- a/packages/translation/src/lang/de.json +++ b/packages/translation/src/lang/de.json @@ -132,7 +132,7 @@ }, "password": { "label": "Passwort", - "requirement": { + "suggestion": { "length": "Enthält mindestens 8 Zeichen", "lowercase": "Enthält Kleinbuchstaben", "uppercase": "Enthält Großbuchstaben", diff --git a/packages/translation/src/lang/el.json b/packages/translation/src/lang/el.json index 9c9b49876..904ac0714 100644 --- a/packages/translation/src/lang/el.json +++ b/packages/translation/src/lang/el.json @@ -132,7 +132,7 @@ }, "password": { "label": "Κωδικός", - "requirement": { + "suggestion": { "length": "", "lowercase": "Περιλαμβάνει πεζό γράμμα", "uppercase": "Περιλαμβάνει κεφαλαίο γράμμα", diff --git a/packages/translation/src/lang/en-gb.json b/packages/translation/src/lang/en-gb.json index ae6870d90..e201c1c38 100644 --- a/packages/translation/src/lang/en-gb.json +++ b/packages/translation/src/lang/en-gb.json @@ -132,7 +132,7 @@ }, "password": { "label": "Password", - "requirement": { + "suggestion": { "length": "Includes a minimum of 8 characters", "lowercase": "Includes a lower-case letter", "uppercase": "Includes an upper-case letter", diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index 5e742c7c4..788132aeb 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -133,12 +133,12 @@ "password": { "label": "Password", "suggestionsTitle": "Password suggestions", - "requirement": { + "suggestion": { "length": "At least 8 characters", - "lowercase": "Suggested: includes lowercase letter", - "uppercase": "Suggested: includes uppercase letter", - "number": "Suggested: includes number", - "special": "Suggested: includes special symbol" + "lowercase": "Includes lowercase letter", + "uppercase": "Includes uppercase letter", + "number": "Includes number", + "special": "Includes special symbol" } }, "passwordConfirm": { diff --git a/packages/translation/src/lang/es.json b/packages/translation/src/lang/es.json index cbbb17abd..23121af37 100644 --- a/packages/translation/src/lang/es.json +++ b/packages/translation/src/lang/es.json @@ -132,7 +132,7 @@ }, "password": { "label": "Contraseña", - "requirement": { + "suggestion": { "length": "Incluye al menos 8 caracteres", "lowercase": "Incluye al menos una letra minúscula", "uppercase": "Incluye al menos una letra mayúscula", diff --git a/packages/translation/src/lang/et.json b/packages/translation/src/lang/et.json index d48280e5c..987bf58db 100644 --- a/packages/translation/src/lang/et.json +++ b/packages/translation/src/lang/et.json @@ -132,7 +132,7 @@ }, "password": { "label": "", - "requirement": { + "suggestion": { "length": "", "lowercase": "", "uppercase": "", diff --git a/packages/translation/src/lang/fr.json b/packages/translation/src/lang/fr.json index a28b4718b..ae93e9622 100644 --- a/packages/translation/src/lang/fr.json +++ b/packages/translation/src/lang/fr.json @@ -132,7 +132,7 @@ }, "password": { "label": "Mot de passe", - "requirement": { + "suggestion": { "length": "Contient au moins 8 caractères", "lowercase": "Inclut une lettre minuscule", "uppercase": "Inclut une lettre majuscule", diff --git a/packages/translation/src/lang/he.json b/packages/translation/src/lang/he.json index b23563ce9..afa95ee97 100644 --- a/packages/translation/src/lang/he.json +++ b/packages/translation/src/lang/he.json @@ -132,7 +132,7 @@ }, "password": { "label": "סיסמה", - "requirement": { + "suggestion": { "length": "כולל לפחות 8 תווים", "lowercase": "אפשר אותיות קטנות", "uppercase": "אפשר אותיות גדולות", diff --git a/packages/translation/src/lang/hr.json b/packages/translation/src/lang/hr.json index 9558b4bfa..b794745df 100644 --- a/packages/translation/src/lang/hr.json +++ b/packages/translation/src/lang/hr.json @@ -132,7 +132,7 @@ }, "password": { "label": "Lozinka", - "requirement": { + "suggestion": { "length": "", "lowercase": "Uključuje mala slova", "uppercase": "Uključuje veliko slovo", diff --git a/packages/translation/src/lang/hu.json b/packages/translation/src/lang/hu.json index 44f4a8575..ef8cee25f 100644 --- a/packages/translation/src/lang/hu.json +++ b/packages/translation/src/lang/hu.json @@ -132,7 +132,7 @@ }, "password": { "label": "Jelszó", - "requirement": { + "suggestion": { "length": "Tartalmazzon legalább 8 karaktert", "lowercase": "Tartalmazzon kisbetűt", "uppercase": "Tartalmazzon nagybetűt", diff --git a/packages/translation/src/lang/it.json b/packages/translation/src/lang/it.json index 60720ad7c..1e578c856 100644 --- a/packages/translation/src/lang/it.json +++ b/packages/translation/src/lang/it.json @@ -132,7 +132,7 @@ }, "password": { "label": "Password", - "requirement": { + "suggestion": { "length": "Include almeno 8 caratteri", "lowercase": "Include lettera minuscola", "uppercase": "Include lettera maiuscola", diff --git a/packages/translation/src/lang/ja.json b/packages/translation/src/lang/ja.json index 752a3a529..73df36f45 100644 --- a/packages/translation/src/lang/ja.json +++ b/packages/translation/src/lang/ja.json @@ -132,7 +132,7 @@ }, "password": { "label": "パスワード", - "requirement": { + "suggestion": { "length": "少なくとも 8 文字以上を含む", "lowercase": "小文字を含む", "uppercase": "大文字を含む", diff --git a/packages/translation/src/lang/ko.json b/packages/translation/src/lang/ko.json index 868611bd4..09276585a 100644 --- a/packages/translation/src/lang/ko.json +++ b/packages/translation/src/lang/ko.json @@ -132,7 +132,7 @@ }, "password": { "label": "비밀번호", - "requirement": { + "suggestion": { "length": "", "lowercase": "소문자 포함", "uppercase": "대문자 포함", diff --git a/packages/translation/src/lang/lt.json b/packages/translation/src/lang/lt.json index 5b165bb86..ad5eded2c 100644 --- a/packages/translation/src/lang/lt.json +++ b/packages/translation/src/lang/lt.json @@ -132,7 +132,7 @@ }, "password": { "label": "Slaptažodis", - "requirement": { + "suggestion": { "length": "", "lowercase": "", "uppercase": "", diff --git a/packages/translation/src/lang/lv.json b/packages/translation/src/lang/lv.json index 762f7bff7..7af9291e0 100644 --- a/packages/translation/src/lang/lv.json +++ b/packages/translation/src/lang/lv.json @@ -132,7 +132,7 @@ }, "password": { "label": "Parole", - "requirement": { + "suggestion": { "length": "", "lowercase": "Ietver mazo burtu", "uppercase": "Ietver lielo burtu", diff --git a/packages/translation/src/lang/nl.json b/packages/translation/src/lang/nl.json index c8fb6c654..5cc03d9f1 100644 --- a/packages/translation/src/lang/nl.json +++ b/packages/translation/src/lang/nl.json @@ -132,7 +132,7 @@ }, "password": { "label": "Wachtwoord", - "requirement": { + "suggestion": { "length": "Bevat ten minste 8 tekens", "lowercase": "Inclusief kleine letter", "uppercase": "Inclusief hoofdletter", diff --git a/packages/translation/src/lang/no.json b/packages/translation/src/lang/no.json index 224f8c0a0..f0cfbb301 100644 --- a/packages/translation/src/lang/no.json +++ b/packages/translation/src/lang/no.json @@ -132,7 +132,7 @@ }, "password": { "label": "Passord", - "requirement": { + "suggestion": { "length": "Inkluderer minst 8 tegn", "lowercase": "Inkluderer liten bokstav", "uppercase": "Inkluderer stor bokstav", diff --git a/packages/translation/src/lang/pl.json b/packages/translation/src/lang/pl.json index c93bb30d8..de8334117 100644 --- a/packages/translation/src/lang/pl.json +++ b/packages/translation/src/lang/pl.json @@ -132,7 +132,7 @@ }, "password": { "label": "Hasło", - "requirement": { + "suggestion": { "length": "Zawiera co najmniej 8 znaków", "lowercase": "Zawiera małą literę", "uppercase": "Zawiera wielką literę", diff --git a/packages/translation/src/lang/pt-br.json b/packages/translation/src/lang/pt-br.json index 0e130afac..a505b039b 100644 --- a/packages/translation/src/lang/pt-br.json +++ b/packages/translation/src/lang/pt-br.json @@ -132,7 +132,7 @@ }, "password": { "label": "Senha", - "requirement": { + "suggestion": { "length": "Inclua pelo menos 8 caracteres", "lowercase": "Inclui letras minúsculas", "uppercase": "Inclui letras maiúsculas", diff --git a/packages/translation/src/lang/pt.json b/packages/translation/src/lang/pt.json index 4d6cbd7f0..e730bd84b 100644 --- a/packages/translation/src/lang/pt.json +++ b/packages/translation/src/lang/pt.json @@ -132,7 +132,7 @@ }, "password": { "label": "", - "requirement": { + "suggestion": { "length": "", "lowercase": "", "uppercase": "", diff --git a/packages/translation/src/lang/ro.json b/packages/translation/src/lang/ro.json index 559f78e58..fcba7b068 100644 --- a/packages/translation/src/lang/ro.json +++ b/packages/translation/src/lang/ro.json @@ -132,7 +132,7 @@ }, "password": { "label": "Parola", - "requirement": { + "suggestion": { "length": "", "lowercase": "Să includă litere mici", "uppercase": "Să includă litere mari", diff --git a/packages/translation/src/lang/ru.json b/packages/translation/src/lang/ru.json index 11d073d13..9f5b6f6e1 100644 --- a/packages/translation/src/lang/ru.json +++ b/packages/translation/src/lang/ru.json @@ -132,7 +132,7 @@ }, "password": { "label": "Пароль", - "requirement": { + "suggestion": { "length": "Содержит не менее 8 символов", "lowercase": "Содержит строчную букву", "uppercase": "Содержит заглавную букву", diff --git a/packages/translation/src/lang/sk.json b/packages/translation/src/lang/sk.json index 576aa56a3..47a41923e 100644 --- a/packages/translation/src/lang/sk.json +++ b/packages/translation/src/lang/sk.json @@ -132,7 +132,7 @@ }, "password": { "label": "Heslo", - "requirement": { + "suggestion": { "length": "Obsahuje aspoň 8 znakov", "lowercase": "Zahŕňa malé písmeno", "uppercase": "Zahŕňa veľké písmená", diff --git a/packages/translation/src/lang/sl.json b/packages/translation/src/lang/sl.json index 186e79151..112ecb12f 100644 --- a/packages/translation/src/lang/sl.json +++ b/packages/translation/src/lang/sl.json @@ -132,7 +132,7 @@ }, "password": { "label": "Geslo", - "requirement": { + "suggestion": { "length": "", "lowercase": "Vključuje male črke", "uppercase": "Vključuje velike tiskane črke", diff --git a/packages/translation/src/lang/sv.json b/packages/translation/src/lang/sv.json index 83fb869fb..b99a318a7 100644 --- a/packages/translation/src/lang/sv.json +++ b/packages/translation/src/lang/sv.json @@ -132,7 +132,7 @@ }, "password": { "label": "Lösenord", - "requirement": { + "suggestion": { "length": "Använd minst 8 tecken", "lowercase": "Använd liten bokstav", "uppercase": "Använd stor bokstav", diff --git a/packages/translation/src/lang/tr.json b/packages/translation/src/lang/tr.json index 35e29f18e..f05911e1d 100644 --- a/packages/translation/src/lang/tr.json +++ b/packages/translation/src/lang/tr.json @@ -132,7 +132,7 @@ }, "password": { "label": "Şifre", - "requirement": { + "suggestion": { "length": "En az 8 karakter içermeli", "lowercase": "Küçük harf içermeli", "uppercase": "Büyük harf içermeli", diff --git a/packages/translation/src/lang/uk.json b/packages/translation/src/lang/uk.json index c573c65ba..23a3fb284 100644 --- a/packages/translation/src/lang/uk.json +++ b/packages/translation/src/lang/uk.json @@ -132,7 +132,7 @@ }, "password": { "label": "Пароль", - "requirement": { + "suggestion": { "length": "Включає принаймні 8 символів", "lowercase": "Включає малу літеру", "uppercase": "Включає велику літеру", diff --git a/packages/translation/src/lang/vi.json b/packages/translation/src/lang/vi.json index f8f8823e1..b9a038efa 100644 --- a/packages/translation/src/lang/vi.json +++ b/packages/translation/src/lang/vi.json @@ -132,7 +132,7 @@ }, "password": { "label": "Mật khẩu", - "requirement": { + "suggestion": { "length": "Bao gồm ít nhất 8 kí tự", "lowercase": "Bao gồm chữ thường", "uppercase": "Bao gồm chữ in hoa", diff --git a/packages/translation/src/lang/zh.json b/packages/translation/src/lang/zh.json index 147db32f0..9cdd5bbbf 100644 --- a/packages/translation/src/lang/zh.json +++ b/packages/translation/src/lang/zh.json @@ -132,7 +132,7 @@ }, "password": { "label": "密碼", - "requirement": { + "suggestion": { "length": "至少包含 8 個字符", "lowercase": "包含小寫字母", "uppercase": "包含大寫字母", diff --git a/packages/ui/src/components/password-input/password-input.tsx b/packages/ui/src/components/password-input/password-input.tsx index 13141d39a..22d4a75dc 100644 --- a/packages/ui/src/components/password-input/password-input.tsx +++ b/packages/ui/src/components/password-input/password-input.tsx @@ -20,16 +20,15 @@ export const CustomPasswordInput = ({ withPasswordRequirements, ...props }: Cust }; const WithPasswordRequirements = (props: PasswordInputProps) => { - const [internalValue, setInternalValue] = useState(""); - const password = props.value ?? internalValue; + const [password, setPassword] = useState(""); const onChange = (event: ChangeEvent) => { - setInternalValue(event.currentTarget.value); + setPassword(event.currentTarget.value); props.onChange?.(event); }; return ( - + ); diff --git a/packages/ui/src/components/password-input/password-requirement.tsx b/packages/ui/src/components/password-input/password-requirement.tsx index 5031bf5c8..99d694d31 100644 --- a/packages/ui/src/components/password-input/password-requirement.tsx +++ b/packages/ui/src/components/password-input/password-requirement.tsx @@ -1,18 +1,14 @@ import { rem, Text } from "@mantine/core"; import { IconCheck, IconPoint } from "@tabler/icons-react"; -const requirementDisplay = { - met: { color: "teal", Icon: IconCheck }, - unmet: { color: "dimmed", Icon: IconPoint }, -} as const; - -const displayKey = { - true: "met", - false: "unmet", -} as const; +const getRequirementDisplay = (meets: boolean) => + ({ + true: { color: "teal", Icon: IconCheck }, + false: { color: "dimmed", Icon: IconPoint }, + })[String(meets) as "true" | "false"]; export function PasswordRequirement({ meets, label }: { meets: boolean; label: string }) { - const display = requirementDisplay[displayKey[String(meets) as "true" | "false"]]; + const display = getRequirementDisplay(meets); const Icon = display.Icon; return ( diff --git a/packages/ui/src/components/password-input/password-requirements-popover.tsx b/packages/ui/src/components/password-input/password-requirements-popover.tsx index 8ee545fb3..33cb30e42 100644 --- a/packages/ui/src/components/password-input/password-requirements-popover.tsx +++ b/packages/ui/src/components/password-input/password-requirements-popover.tsx @@ -46,7 +46,7 @@ export const PasswordRequirementsPopover = ({ password, children }: PropsWithChi }; const useRequirements = () => { - const t = useScopedI18n("user.field.password.requirement"); + const t = useScopedI18n("user.field.password.suggestion"); return passwordRequirements.map(({ check, value }) => ({ check, label: t(value) })); }; diff --git a/packages/validation/src/user.ts b/packages/validation/src/user.ts index b94e65015..824567fa6 100644 --- a/packages/validation/src/user.ts +++ b/packages/validation/src/user.ts @@ -19,7 +19,7 @@ export const passwordRequirements = [ { check: regexCheck(/[$&+,:;=?@#|'<>.^*()%!\-~`"_/\\[\]{}]/), value: "special" }, ] satisfies { check: (value: string) => boolean; - value: keyof TranslationObject["user"]["field"]["password"]["requirement"]; + value: keyof TranslationObject["user"]["field"]["password"]["suggestion"]; }[]; export const userPasswordSchema = z.string().min(8).max(255);