/** * 使用浏览器安全随机源生成密码:至少含小写、大写和数字各一位,排除易混字符。 * 即使要求长度小于 3,三个必选字符也会保留;安全随机源不可用时明确失败,不降级。 */ function e(e = 12) { const source = globalThis.crypto; if (typeof source?.getRandomValues !== `function`) throw Error(`当前环境不支持安全随机密码生成`); const buffer = new Uint32Array(1); // 只接受能均分为 upperBound 份的区间,避免直接取模让某些字符/洗牌位置概率偏高。 function randomIndex(upperBound) { const limit = 2 ** 32 - (2 ** 32 % upperBound); do source.getRandomValues(buffer); while (buffer[0] >= limit); return buffer[0] % upperBound; } let t = (e) => e[randomIndex(e.length)], n = [ t(`abcdefghjkmnpqrstuvwxyz`), t(`ABCDEFGHJKMNPQRSTUVWXYZ`), t(`23456789`), ], r = Array.from( { length: Math.max(0, e - n.length), }, () => t(`abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789`), ), i = [...n, ...r]; for (let e = i.length - 1; e > 0; e--) { // Fisher–Yates 与字符选取共用无偏采样,不能在打乱阶段重新引入非安全随机源。 let t = randomIndex(e + 1); [i[e], i[t]] = [i[t], i[e]]; } return i.join(``); } export { e as t };