ShaoLOWu 21fb080530
fix(frontend): allow non-ASCII local parts in auth password forms (#7488) (#7498)
* fix(frontend): allow non-ASCII local parts in auth password forms (#7488)

The sign-in, register, admin-setup and change-password forms relied on the
browser's type="email" constraint validation, which rejects any non-ASCII
local part before the submit handler runs. The backend identity schema
deliberately accepts such addresses (see emailSchema in @/core/auth/types),
so an account created via the API, an administrator or OIDC could never sign
in through the password form.

Forms are now noValidate, and the permissive isValidEmail helper (one @,
non-empty local part and domain, no whitespace) runs in the handlers instead,
staying strictly weaker than what the backend accepts.

* fix(auth): normalize emails and restore form password checks

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-10-25 22:09:58 +08:00

37 lines
1.5 KiB
TypeScript

import { describe, expect, test } from "@rstest/core";
import { isValidEmail } from "@/core/auth/email";
// The backend identity schema deliberately accepts addresses stricter
// validators reject (`emailSchema` in @/core/auth/types is a bare
// `z.string().min(1)`). The auth forms used to hand the decision to the
// browser's `type="email"` constraint instead, which rejects any non-ASCII
// local part before the submit handler runs — an account like
// `用户@example.com` (creatable via the API, an admin, or OIDC) could never
// sign in through the password form (#7488).
describe("auth email validation", () => {
test("accepts addresses the backend accepts, including non-ASCII local parts", () => {
expect(isValidEmail("用户@example.com")).toBe(true);
expect(isValidEmail("wíérd@name.example")).toBe(true);
expect(isValidEmail("someone@example.com")).toBe(true);
expect(isValidEmail("a@b")).toBe(true);
});
test("accepts surrounding whitespace (trimmed before the check)", () => {
expect(isValidEmail(" user@example.com ")).toBe(true);
});
test("rejects values without a usable local@domain shape", () => {
expect(isValidEmail("not-an-email")).toBe(false);
expect(isValidEmail("@example.com")).toBe(false);
expect(isValidEmail("user@")).toBe(false);
expect(isValidEmail("a@b@c.example")).toBe(false);
expect(isValidEmail("a b@example.com")).toBe(false);
});
test("rejects empty and blank input", () => {
expect(isValidEmail("")).toBe(false);
expect(isValidEmail(" ")).toBe(false);
});
});