fix: 加固认证撤销与运行配置

This commit is contained in:
root
2026-09-14 20:05:40 +08:00
parent c708205084
commit 6b453af364
13 changed files with 397 additions and 26 deletions
+42
View File
@@ -26,6 +26,31 @@ const REQUIRED_KEYS = [
] as const;
type AuthSecrets = Record<(typeof REQUIRED_KEYS)[number], Buffer>;
let secrets: AuthSecrets | undefined;
let configuredWebOrigin: string | undefined;
function parseWebOrigin(): string {
const raw = process.env.WEB_ORIGIN;
if (!raw) throw new Error("WEB_ORIGIN is required");
let url: URL;
try {
url = new URL(raw);
} catch {
throw new Error("WEB_ORIGIN must be an absolute HTTP(S) origin");
}
if (
!["http:", "https:"].includes(url.protocol) ||
url.username ||
url.password ||
url.pathname !== "/" ||
url.search ||
url.hash ||
url.origin !== raw
)
throw new Error(
"WEB_ORIGIN must be one absolute HTTP(S) origin without credentials or path",
);
return url.origin;
}
export function validateAuthEnvironment(): void {
const loaded = Object.fromEntries(
@@ -38,18 +63,35 @@ export function validateAuthEnvironment(): void {
);
if (new Set(fingerprints).size !== fingerprints.length)
throw new Error("Auth secrets must be independent");
const origin = parseWebOrigin();
if (process.env.DEMO_SMS_CODE_ENABLED === "true" && !demoEnvironmentAllowed())
throw new Error(
"DEMO_SMS_CODE_ENABLED is forbidden outside test or local development",
);
secrets = loaded;
configuredWebOrigin = origin;
}
export function resetAuthEnvironmentForTests(): void {
if (process.env.NODE_ENV !== "test")
throw new Error("Auth environment reset is test-only");
secrets = undefined;
configuredWebOrigin = undefined;
}
function authSecrets(): AuthSecrets {
if (!secrets) validateAuthEnvironment();
return secrets!;
}
export const jwtSecret = (): Buffer => authSecrets().JWT_SECRET;
export const webOrigin = (): string => {
if (!configuredWebOrigin) validateAuthEnvironment();
return configuredWebOrigin!;
};
const demoEnvironmentAllowed = (): boolean =>
process.env.NODE_ENV === "test" ||
process.env.NODE_ENV === "development" ||
process.env.APP_ENV === "local";
export const demoSmsCodeEnabled = (): boolean =>
process.env.DEMO_SMS_CODE_ENABLED === "true" && demoEnvironmentAllowed();
export const phoneHmac = (phone: string): string =>
createHmac("sha256", authSecrets().PHONE_HMAC_KEY)
.update(phone)