thread-master/apps/web/src/lib/passwordPolicy.ts

73 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 密碼政策(與後端 ValidatePasswordPolicy 完全一致):
* - 至少 12 字元
* - 含大寫、小寫、數字、符號
*
* 使用者可見說明(語言包,勿在 UI 另寫一句):
* - zh: password.policy.hint / api.err.400003
* 「密碼須至少 12 碼,且含大寫、小寫、數字與符號」
* - en: 同 key
* 「Password must be at least 12 characters with upper, lower, digit, and symbol」
* 後端 API 400003 message 使用上述英文句FE 依 code 轉語言包。
*/
/** 與後端 domain.PasswordMinLen 一致 */
export const PASSWORD_MIN_LEN = 12;
/** 與後端 domain.PasswordPolicyZH / FE password.policy.hint 一致 */
export const PASSWORD_POLICY_ZH =
"密碼須至少 12 碼,且含大寫、小寫、數字與符號";
/** 與後端 domain.PasswordPolicyEN / API 400003 / FE en password.policy.hint 一致 */
export const PASSWORD_POLICY_EN =
"Password must be at least 12 characters with upper, lower, digit, and symbol";
export type PasswordPolicyResult = {
ok: boolean;
/** i18n key under password.policy.* or empty if ok */
errorKey?: string;
};
const HAS_UPPER = /[A-Z]/;
const HAS_LOWER = /[a-z]/;
const HAS_DIGIT = /[0-9]/;
/** 符號:非字母數字(與後端 unicode.IsPunct/Symbol 大致對齊) */
const HAS_SYMBOL = /[^A-Za-z0-9]/;
export function checkPasswordPolicy(password: string): PasswordPolicyResult {
const p = password ?? "";
// 任一條件不符都回同一句(與後端 400003 / password.policy.hint 一致,不拆多種文案)
const ok =
[...p].length >= PASSWORD_MIN_LEN &&
HAS_UPPER.test(p) &&
HAS_LOWER.test(p) &&
HAS_DIGIT.test(p) &&
HAS_SYMBOL.test(p);
if (!ok) {
return { ok: false, errorKey: "password.policy.hint" };
}
return { ok: true };
}
/** 是否符合政策(提交前 gate */
export function isPasswordPolicyOk(password: string): boolean {
return checkPasswordPolicy(password).ok;
}
/** 產生符合政策的臨時密碼mock admin 用) */
export function generateTempPassword(): string {
const lower = "abcdefghijkmnopqrstuvwxyz";
const upper = "ABCDEFGHJKLMNPQRSTUVWXYZ";
const digits = "23456789";
const symbols = "!@#$%^&*+-=";
const all = lower + upper + digits + symbols;
const pick = (s: string) => s[Math.floor(Math.random() * s.length)]!;
const chars = [pick(lower), pick(upper), pick(digits), pick(symbols)];
while (chars.length < 16) chars.push(pick(all));
for (let i = chars.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[chars[i], chars[j]] = [chars[j]!, chars[i]!];
}
return chars.join("");
}