55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
import { readFileSync } from "node:fs";
|
||
import { env } from "./env.js";
|
||
|
||
/**
|
||
* JWT RS256 密钥对加载(president §2.15:本地文件密钥)。
|
||
*
|
||
* - 私钥:IAM 签发 access_token / refresh_token
|
||
* - 公钥:api-gateway 通过 JWKS 或 gRPC GetPublicKey 拉取验签
|
||
*
|
||
* 启动时一次性加载到内存,避免每次签名/验签的 IO 开销。
|
||
* kid(Key ID)用于 JWKS 端点多密钥轮换场景下标识密钥。
|
||
*/
|
||
export interface JwtKeyPair {
|
||
privateKey: string;
|
||
publicKey: string;
|
||
kid: string;
|
||
alg: "RS256";
|
||
}
|
||
|
||
let keyPair: JwtKeyPair | null = null;
|
||
|
||
export function getJwtKeyPair(): JwtKeyPair {
|
||
if (!keyPair) {
|
||
const privateKey = readFileSync(env.IAM_PRIVATE_KEY_PATH, "utf-8");
|
||
const publicKey = readFileSync(env.IAM_PUBLIC_KEY_PATH, "utf-8");
|
||
keyPair = {
|
||
privateKey,
|
||
publicKey,
|
||
kid: env.JWT_KEY_ID,
|
||
alg: "RS256",
|
||
};
|
||
}
|
||
return keyPair;
|
||
}
|
||
|
||
/**
|
||
* TTL 计算:将 "15m" / "7d" 等字符串转为秒数。
|
||
* 用于 JWT expiresIn 配置与响应中的 expires_in 字段。
|
||
*/
|
||
export function ttlToSeconds(ttl: string): number {
|
||
const match = /^(\d+)([smhd])$/.exec(ttl);
|
||
if (!match || match[1] === undefined || match[2] === undefined) {
|
||
throw new Error(`Invalid TTL format: ${ttl}`);
|
||
}
|
||
const value = Number.parseInt(match[1], 10);
|
||
const unit = match[2] as "s" | "m" | "h" | "d";
|
||
const multipliers: Record<"s" | "m" | "h" | "d", number> = {
|
||
s: 1,
|
||
m: 60,
|
||
h: 3600,
|
||
d: 86400,
|
||
};
|
||
return value * multipliers[unit];
|
||
}
|