@h-ai/kit 0.1.0-alpha.10 → 0.1.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +2 -2
- package/dist/{chunk-6TMSXG7J.js → chunk-BRZK7V5O.js} +4 -2
- package/dist/chunk-BRZK7V5O.js.map +1 -0
- package/dist/{chunk-PHS7ZD5L.js → chunk-GRYHRXVC.js} +4 -4
- package/dist/chunk-GRYHRXVC.js.map +1 -0
- package/dist/{chunk-AD6S473Y.js → chunk-XTZUGWBY.js} +3 -3
- package/dist/{chunk-AD6S473Y.js.map → chunk-XTZUGWBY.js.map} +1 -1
- package/dist/client/index.js +2 -2
- package/dist/index.js +3 -3
- package/dist/modules/crypto/index.js +3 -3
- package/package.json +3 -3
- package/dist/chunk-6TMSXG7J.js.map +0 -1
- package/dist/chunk-PHS7ZD5L.js.map +0 -1
package/dist/browser.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineCrud } from './chunk-FRYJMRTP.js';
|
|
2
|
-
import { createHandleFetch, createTokenStore, clearBrowserToken, setBrowserToken, createKitClient } from './chunk-
|
|
3
|
-
import { setAllModulesLocale } from './chunk-
|
|
2
|
+
import { createHandleFetch, createTokenStore, clearBrowserToken, setBrowserToken, createKitClient } from './chunk-GRYHRXVC.js';
|
|
3
|
+
import { setAllModulesLocale } from './chunk-BRZK7V5O.js';
|
|
4
4
|
|
|
5
5
|
// src/browser.ts
|
|
6
6
|
var kit = {
|
|
@@ -7,6 +7,7 @@ var en_US_default = {
|
|
|
7
7
|
$schema: "https://inlang.com/schema/inlang-message-format",
|
|
8
8
|
kit_unauthorized: "Unauthorized",
|
|
9
9
|
kit_forbidden: "Forbidden: missing {permission} permission",
|
|
10
|
+
kit_authNotConfigured: "kit.auth is not configured: pass auth.operations in kit.createHandle()",
|
|
10
11
|
kit_csrfTokenFailed: "Failed to generate CSRF token",
|
|
11
12
|
kit_csrfVerifyFailed: "CSRF token verification failed",
|
|
12
13
|
kit_csrfValidationFailed: "Invalid CSRF token",
|
|
@@ -40,6 +41,7 @@ var zh_CN_default = {
|
|
|
40
41
|
$schema: "https://inlang.com/schema/inlang-message-format",
|
|
41
42
|
kit_unauthorized: "\u672A\u6388\u6743",
|
|
42
43
|
kit_forbidden: "\u6743\u9650\u4E0D\u8DB3\uFF1A\u7F3A\u5C11 {permission} \u6743\u9650",
|
|
44
|
+
kit_authNotConfigured: "kit.auth \u672A\u914D\u7F6E\uFF1A\u8BF7\u5728 kit.createHandle() \u4E2D\u4F20\u5165 auth.operations",
|
|
43
45
|
kit_csrfTokenFailed: "\u751F\u6210 CSRF Token \u5931\u8D25",
|
|
44
46
|
kit_csrfVerifyFailed: "CSRF Token \u9A8C\u8BC1\u5931\u8D25",
|
|
45
47
|
kit_csrfValidationFailed: "CSRF Token \u65E0\u6548",
|
|
@@ -165,5 +167,5 @@ function isValidEncryptedPayload(payload) {
|
|
|
165
167
|
}
|
|
166
168
|
|
|
167
169
|
export { createKeyExchangeHandler, createTransportEncryption, isValidEncryptedPayload, kitM, setAllModulesLocale };
|
|
168
|
-
//# sourceMappingURL=chunk-
|
|
169
|
-
//# sourceMappingURL=chunk-
|
|
170
|
+
//# sourceMappingURL=chunk-BRZK7V5O.js.map
|
|
171
|
+
//# sourceMappingURL=chunk-BRZK7V5O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../messages/en-US.json","../messages/zh-CN.json","../src/kit-i18n.ts","../src/modules/crypto/kit-transport-encryption.ts"],"names":[],"mappings":"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","file":"chunk-BRZK7V5O.js","sourcesContent":["{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"kit_unauthorized\": \"Unauthorized\",\n \"kit_forbidden\": \"Forbidden: missing {permission} permission\",\n \"kit_authNotConfigured\": \"kit.auth is not configured: pass auth.operations in kit.createHandle()\",\n \"kit_csrfTokenFailed\": \"Failed to generate CSRF token\",\n \"kit_csrfVerifyFailed\": \"CSRF token verification failed\",\n \"kit_csrfValidationFailed\": \"Invalid CSRF token\",\n \"kit_rateLimitExceeded\": \"Too many requests, please try again later\",\n \"kit_unsupportedContentType\": \"Unsupported content type\",\n \"kit_parseBodyFailed\": \"Failed to parse request body\",\n \"kit_encryptFailed\": \"Encryption failed\",\n \"kit_transportKeyGenerationFailed\": \"Transport encryption key generation failed\",\n \"kit_transportClientKeyNotFound\": \"Client key not found\",\n \"kit_transportEncryptFailed\": \"Transport encryption failed\",\n \"kit_transportEncryptKeyFailed\": \"Symmetric key encryption failed\",\n \"kit_transportDecryptKeyFailed\": \"Symmetric key decryption failed\",\n \"kit_transportDecryptFailed\": \"Transport decryption failed\",\n \"kit_transportInvalidPayload\": \"Invalid encrypted payload\",\n \"kit_transportKeyExchangeFailed\": \"Key exchange failed\",\n \"kit_transportClientIdRequired\": \"Missing X-Client-Id header, key exchange is required for transport encryption\",\n \"kit_signFailed\": \"Request signing failed\",\n \"kit_authRequired\": \"Authentication required\",\n \"kit_accessDenied\": \"Access denied\",\n \"kit_resourceNotFound\": \"Resource not found\",\n \"kit_internalError\": \"Internal server error\",\n \"kit_validationFailed\": \"Validation failed\",\n \"kit_noGuardsPassed\": \"No guards passed\",\n \"kit_requiredRoles\": \"Required roles: {roles}\",\n \"kit_requiredPermissions\": \"Required permissions: {permissions}\",\n \"kit_idRequired\": \"ID is required\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"kit_unauthorized\": \"未授权\",\n \"kit_forbidden\": \"权限不足:缺少 {permission} 权限\",\n \"kit_authNotConfigured\": \"kit.auth 未配置:请在 kit.createHandle() 中传入 auth.operations\",\n \"kit_csrfTokenFailed\": \"生成 CSRF Token 失败\",\n \"kit_csrfVerifyFailed\": \"CSRF Token 验证失败\",\n \"kit_csrfValidationFailed\": \"CSRF Token 无效\",\n \"kit_rateLimitExceeded\": \"请求过于频繁,请稍后再试\",\n \"kit_unsupportedContentType\": \"不支持的内容类型\",\n \"kit_parseBodyFailed\": \"请求体解析失败\",\n \"kit_encryptFailed\": \"加密失败\",\n \"kit_transportKeyGenerationFailed\": \"传输加密密钥对生成失败\",\n \"kit_transportClientKeyNotFound\": \"客户端密钥未找到\",\n \"kit_transportEncryptFailed\": \"传输加密失败\",\n \"kit_transportEncryptKeyFailed\": \"对称密钥加密失败\",\n \"kit_transportDecryptKeyFailed\": \"对称密钥解密失败\",\n \"kit_transportDecryptFailed\": \"传输解密失败\",\n \"kit_transportInvalidPayload\": \"无效的加密载荷\",\n \"kit_transportKeyExchangeFailed\": \"密钥交换失败\",\n \"kit_transportClientIdRequired\": \"缺少 X-Client-Id 请求头,传输加密必须先完成密钥交换\",\n \"kit_signFailed\": \"请求签名失败\",\n \"kit_authRequired\": \"需要身份认证\",\n \"kit_accessDenied\": \"拒绝访问\",\n \"kit_resourceNotFound\": \"资源未找到\",\n \"kit_internalError\": \"内部服务器错误\",\n \"kit_validationFailed\": \"数据验证失败\",\n \"kit_noGuardsPassed\": \"没有守卫通过\",\n \"kit_requiredRoles\": \"需要角色:{roles}\",\n \"kit_requiredPermissions\": \"需要权限:{permissions}\",\n \"kit_idRequired\": \"ID 不能为空\"\n}\n","/**\n * @h-ai/kit — i18n 工具\n *\n * Kit 模块的国际化消息工具,从 @h-ai/core 调用 i18n API。\n * @module kit-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\ntype KitMessageKey = keyof typeof messagesZhCN\n\n/** 获取 Kit 模块的 i18n 消息 */\nexport const kitM\n = core.i18n.createMessageGetter<KitMessageKey>({ 'zh-CN': messagesZhCN, 'en-US': messagesEnUS })\n\n/**\n * 统一设置所有 hai 模块的默认语言\n *\n * 通过 @h-ai/core 的集中式 locale 管理器,一次调用即可同步所有模块。\n * 各模块的 createMessageGetter 会读取全局 locale。\n *\n * @example\n * ```ts\n * import { kit } from '@h-ai/kit'\n *\n * // 在 i18n handle 中\n * const locale = event.cookies.get('PARAGLIDE_LOCALE') ?? 'zh-CN'\n * kit.i18n.setLocale(locale)\n * ```\n */\nexport function setAllModulesLocale(locale: string): void {\n core.i18n.setGlobalLocale(locale)\n}\n","/**\n * @h-ai/kit — 传输加密核心\n *\n * 基于非对称 + 对称的混合传输加密。\n * @module kit-transport-encryption\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type {\n EncryptedPayload,\n TransportCryptoServiceLike,\n TransportEncryptionManager,\n TransportKeyPair,\n} from './kit-crypto-types.js'\nimport { err, ok } from '@h-ai/core'\nimport { kitM } from '../../kit-i18n.js'\n\n/**\n * 创建传输加密管理器\n *\n * 启动时生成服务端非对称密钥对,通过 clientId → publicKey 的内存 Map 管理客户端密钥。\n * 内置 LRU 淘汰机制,超过 maxClients 上限时自动移除最早注册的客户端。\n *\n * 注意:clientKeys 存储在进程内存中,多节点部署时各节点状态独立。\n * 客户端密钥交换后的后续请求必须路由到同一节点(如使用 sticky session),\n * 否则传输加密功能不可用。\n *\n * @param cryptoService - 传输加密服务实例(非对称 + 对称)\n * @param maxClients - 最大客户端数量(默认 10000),超过时淘汰最早注册的\n * @returns 成功返回传输加密管理器,密钥对生成失败时返回错误\n */\nexport function createTransportEncryption(\n cryptoService: TransportCryptoServiceLike,\n maxClients = 10000,\n): HaiResult<TransportEncryptionManager> {\n // 生成服务端密钥对\n const keyPairResult = cryptoService.asymmetric.generateKeyPair()\n if (!keyPairResult.success || !keyPairResult.data) {\n return err({ code: 'KIT_TRANSPORT_KEY_GENERATION_FAILED', message: kitM('kit_transportKeyGenerationFailed') })\n }\n const serverKeyPair: TransportKeyPair = keyPairResult.data\n\n // 客户端公钥存储:clientId → publicKey(Map 保持插入顺序,用于 LRU 淘汰)\n const clientKeys = new Map<string, string>()\n let clientIdCounter = 0\n\n return ok({\n getServerPublicKey(): string {\n return serverKeyPair.publicKey\n },\n\n registerClientKey(clientPublicKey: string): string {\n clientIdCounter++\n const clientId = `client_${clientIdCounter}_${Date.now()}`\n\n // LRU 淘汰:超过上限时移除最早注册的客户端\n if (clientKeys.size >= maxClients) {\n const oldestKey = clientKeys.keys().next().value\n if (oldestKey !== undefined) {\n clientKeys.delete(oldestKey)\n }\n }\n\n clientKeys.set(clientId, clientPublicKey)\n return clientId\n },\n\n getClientPublicKey(clientId: string): string | undefined {\n return clientKeys.get(clientId)\n },\n\n encryptResponse(clientId: string, data: string): EncryptedPayload {\n const clientPublicKey = clientKeys.get(clientId)\n if (!clientPublicKey) {\n throw new Error(kitM('kit_transportClientKeyNotFound'))\n }\n\n // 1. 生成随机对称密钥\n const symmetricKey = cryptoService.symmetric.generateKey()\n\n // 2. 对称加密内容\n const encResult = cryptoService.symmetric.encryptWithIV(data, symmetricKey)\n if (!encResult.success || !encResult.data) {\n throw new Error(kitM('kit_transportEncryptFailed'))\n }\n\n // 3. 非对称加密对称密钥(使用客户端公钥)\n const keyEncResult = cryptoService.asymmetric.encrypt(symmetricKey, clientPublicKey)\n if (!keyEncResult.success || !keyEncResult.data) {\n throw new Error(kitM('kit_transportEncryptKeyFailed'))\n }\n\n return {\n encryptedKey: keyEncResult.data,\n ciphertext: encResult.data.ciphertext,\n iv: encResult.data.iv,\n }\n },\n\n decryptRequest(payload: EncryptedPayload): string {\n // 1. 非对称解密对称密钥(使用服务端私钥)\n const keyDecResult = cryptoService.asymmetric.decrypt(payload.encryptedKey, serverKeyPair.privateKey)\n if (!keyDecResult.success || !keyDecResult.data) {\n throw new Error(kitM('kit_transportDecryptKeyFailed'))\n }\n\n // 2. 对称解密内容\n const decResult = cryptoService.symmetric.decryptWithIV(payload.ciphertext, keyDecResult.data, payload.iv)\n if (!decResult.success || typeof decResult.data !== 'string') {\n throw new Error(kitM('kit_transportDecryptFailed'))\n }\n\n return decResult.data\n },\n })\n}\n\n/**\n * 创建密钥交换端点处理器\n *\n * 返回一个标准的 POST 处理函数,用于接收客户端公钥并返回服务端公钥与 clientId。\n *\n * @param manager - 传输加密管理器\n * @returns POST 处理函数,可直接用于 SvelteKit +server.ts\n *\n * @example\n * ```ts\n * // src/routes/api/kit/key-exchange/+server.ts\n * import { keyExchangeHandler } from '$lib/server/transport'\n * export const POST = keyExchangeHandler\n * ```\n */\nexport function createKeyExchangeHandler(\n manager: TransportEncryptionManager,\n): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n try {\n const body = await request.json() as { clientPublicKey?: string }\n\n if (!body.clientPublicKey || typeof body.clientPublicKey !== 'string') {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportInvalidPayload') }),\n { status: 400, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n const clientId = manager.registerClientKey(body.clientPublicKey)\n const serverPublicKey = manager.getServerPublicKey()\n\n return new Response(\n JSON.stringify({ serverPublicKey, clientId }),\n { status: 200, headers: { 'Content-Type': 'application/json' } },\n )\n }\n catch {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportKeyExchangeFailed') }),\n { status: 500, headers: { 'Content-Type': 'application/json' } },\n )\n }\n }\n}\n\n/**\n * 校验加密载荷格式是否合法\n *\n * @param payload - 待校验对象\n * @returns 是否为合法的 EncryptedPayload\n */\nexport function isValidEncryptedPayload(payload: unknown): payload is EncryptedPayload {\n if (typeof payload !== 'object' || payload === null)\n return false\n const p = payload as Record<string, unknown>\n return (\n typeof p.encryptedKey === 'string'\n && typeof p.ciphertext === 'string'\n && typeof p.iv === 'string'\n && p.encryptedKey.length > 0\n && p.ciphertext.length > 0\n && p.iv.length > 0\n )\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isValidEncryptedPayload } from './chunk-
|
|
1
|
+
import { kitM, isValidEncryptedPayload } from './chunk-BRZK7V5O.js';
|
|
2
2
|
import process from 'process';
|
|
3
3
|
|
|
4
4
|
var DEFAULT_TOKEN_COOKIE_NAME = "hai_access_token";
|
|
@@ -42,7 +42,7 @@ function clearToken(cookies) {
|
|
|
42
42
|
}
|
|
43
43
|
function getAuthOperations() {
|
|
44
44
|
if (!authState.operations) {
|
|
45
|
-
throw new Error(
|
|
45
|
+
throw new Error(kitM("kit_authNotConfigured"));
|
|
46
46
|
}
|
|
47
47
|
return typeof authState.operations === "function" ? authState.operations() : authState.operations;
|
|
48
48
|
}
|
|
@@ -270,5 +270,5 @@ function createKitClient(config = {}) {
|
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
export { clearBrowserToken, configureAuth, createHandleFetch, createKitClient, createTokenStore, getAccessToken, login, loginWithApiKey, loginWithLdap, loginWithOtp, logout, registerAndLogin, setBrowserToken };
|
|
273
|
-
//# sourceMappingURL=chunk-
|
|
274
|
-
//# sourceMappingURL=chunk-
|
|
273
|
+
//# sourceMappingURL=chunk-GRYHRXVC.js.map
|
|
274
|
+
//# sourceMappingURL=chunk-GRYHRXVC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/kit-auth.ts","../src/client/kit-client.ts"],"names":["fetch","response"],"mappings":"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","file":"chunk-GRYHRXVC.js","sourcesContent":["/**\n * @h-ai/kit — Bearer 认证工具\n *\n * 提供服务端认证 Cookie 管理(login / logout)与浏览器端 Token 存储工具。\n * @module kit-auth\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ApiKeyCredentials, AuthResult, LdapCredentials, OtpCredentials, PasswordCredentials, RegisterOptions } from '@h-ai/iam'\nimport type { HandleFetch } from '@sveltejs/kit'\nimport type { AuthOperations, AuthOperationsProvider } from './kit-types.js'\nimport process from 'node:process'\nimport { kitM } from './kit-i18n.js'\n\n/** 默认 Token Cookie 名 */\nconst DEFAULT_TOKEN_COOKIE_NAME = 'hai_access_token'\n\n/**\n * 应用级认证配置(由 createHandle 一次性初始化,生命周期同进程)\n *\n * 此状态非请求级:仅在 createHandle() 时写入一次,后续所有请求只读访问。\n */\nconst authState = {\n cookieName: DEFAULT_TOKEN_COOKIE_NAME,\n operations: null as AuthOperationsProvider | null,\n}\n\n/**\n * 配置认证参数\n *\n * 通常由 `createHandle` 在初始化时自动调用,无需手动调用。\n */\nexport function configureAuth(config: { cookieName?: string, operations?: AuthOperationsProvider }): void {\n if (config.cookieName)\n authState.cookieName = config.cookieName\n if (config.operations)\n authState.operations = config.operations\n}\n\n/**\n * 获取当前配置的 Token Cookie 名\n */\nexport function getTokenCookieName(): string {\n return authState.cookieName\n}\n\ninterface CookieReader {\n get: (name: string) => string | undefined\n}\n\ninterface CookieWriter {\n set: (name: string, value: string, options: {\n path: string\n httpOnly: boolean\n sameSite: 'lax' | 'strict' | 'none'\n secure: boolean\n maxAge?: number\n }) => void\n delete: (name: string, options: { path: string }) => void\n}\n\n/** 浏览器 Token 存储器 */\nexport interface BrowserTokenStore {\n get: () => string | null\n set: (token: string) => void\n clear: () => void\n}\n\nconst defaultBrowserTokenStore = createTokenStore()\n\n// ─── 内部工具(仅 kit 包内使用) ───\n\n/**\n * 从请求 Authorization 头提取 Bearer Token。\n */\nexport function getBearerTokenFromRequest(request: Request): string | null {\n const authorization = request.headers.get('authorization')\n if (!authorization)\n return null\n\n const [scheme, token] = authorization.split(' ')\n if (!scheme || !token)\n return null\n\n if (scheme.toLowerCase() !== 'bearer')\n return null\n\n const trimmed = token.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\n/**\n * 从请求中统一提取 Access Token(Bearer 优先,其次配置的 Cookie 名)。\n */\nexport function getAccessToken(request: Request, cookies?: CookieReader): string | null {\n return getBearerTokenFromRequest(request) ?? cookies?.get(authState.cookieName) ?? null\n}\n\n// ─── 服务端认证 Cookie 管理 ───\n\n/**\n * 写入 Access Token Cookie(内部使用,由 login 自动调用)。\n */\nfunction setToken(cookies: CookieWriter, token: string, maxAge?: number): void {\n cookies.set(authState.cookieName, token, {\n path: '/',\n httpOnly: true,\n sameSite: 'lax',\n secure: process.env.NODE_ENV === 'production',\n maxAge,\n })\n}\n\n/**\n * 清除 Access Token Cookie(内部使用,由 logout 自动调用)。\n */\nfunction clearToken(cookies: CookieWriter): void {\n cookies.delete(authState.cookieName, { path: '/' })\n}\n\n// ─── 服务端高级认证 API(通过 kit.auth 暴露) ───\n\n/**\n * 获取已注入的认证操作(未配置时抛出编程错误)\n */\nfunction getAuthOperations(): AuthOperations {\n if (!authState.operations) {\n throw new Error(kitM('kit_authNotConfigured'))\n }\n return typeof authState.operations === 'function'\n ? authState.operations()\n : authState.operations\n}\n\n/**\n * 内部工具:执行认证操作并在成功时写入 Token Cookie。\n */\nasync function executeLogin(\n cookies: CookieWriter,\n authPromise: Promise<HaiResult<AuthResult>>,\n): Promise<HaiResult<AuthResult>> {\n const result = await authPromise\n if (result.success) {\n setToken(cookies, result.data.tokens.accessToken, result.data.tokens.expiresIn)\n }\n return result\n}\n\n/**\n * 服务端登录(密码):内部调用 iam.auth.login,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - 密码凭证(identifier + password)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.login(cookies, { identifier, password })\n * if (!result.success) return kit.response.fromError(result.error, IamErrorHttpStatus)\n * const { user, roles, permissions } = result.data\n * ```\n */\nexport async function login(\n cookies: CookieWriter,\n credentials: PasswordCredentials,\n): Promise<HaiResult<AuthResult>> {\n return executeLogin(cookies, getAuthOperations().login(credentials))\n}\n\n/**\n * 服务端登录(OTP 验证码):内部调用 iam.auth.loginWithOtp,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - OTP 凭证(identifier + code)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithOtp(cookies, { identifier, code })\n * ```\n */\nexport async function loginWithOtp(\n cookies: CookieWriter,\n credentials: OtpCredentials,\n): Promise<HaiResult<AuthResult>> {\n return executeLogin(cookies, getAuthOperations().loginWithOtp(credentials))\n}\n\n/**\n * 服务端登录(LDAP):内部调用 iam.auth.loginWithLdap,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - LDAP 凭证(username + password)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithLdap(cookies, { username, password })\n * ```\n */\nexport async function loginWithLdap(\n cookies: CookieWriter,\n credentials: LdapCredentials,\n): Promise<HaiResult<AuthResult>> {\n return executeLogin(cookies, getAuthOperations().loginWithLdap(credentials))\n}\n\n/**\n * 服务端登录(API Key):内部调用 iam.auth.loginWithApiKey,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - API Key 凭证(key)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithApiKey(cookies, { key: apiKey })\n * if (!result.success) return kit.response.fromError(result.error, IamErrorHttpStatus)\n * ```\n */\nexport async function loginWithApiKey(\n cookies: CookieWriter,\n credentials: ApiKeyCredentials,\n): Promise<HaiResult<AuthResult>> {\n return executeLogin(cookies, getAuthOperations().loginWithApiKey(credentials))\n}\n\n/**\n * 服务端注册并登录:内部调用 iam.auth.registerAndLogin,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param options - 注册选项(username、password、email 等)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.registerAndLogin(cookies, { username, email, password })\n * ```\n */\nexport async function registerAndLogin(\n cookies: CookieWriter,\n options: RegisterOptions,\n): Promise<HaiResult<AuthResult>> {\n return executeLogin(cookies, getAuthOperations().registerAndLogin(options))\n}\n\n/**\n * 服务端登出:内部调用 iam.auth.logout 使会话失效,并清除 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param accessToken - 访问令牌(为 null/undefined 时仅清除 Cookie)\n *\n * @example\n * ```ts\n * await kit.auth.logout(cookies, locals.accessToken)\n * return kit.response.ok(null)\n * ```\n */\nexport async function logout(\n cookies: CookieWriter,\n accessToken?: string | null,\n): Promise<void> {\n if (accessToken) {\n await getAuthOperations().logout(accessToken)\n }\n clearToken(cookies)\n}\n\n// ─── 浏览器端 Token 存储(通过 kit.auth 暴露) ───\n\n/**\n * 创建浏览器端 Token 存储器(localStorage)。\n *\n * @param key - localStorage 键名,默认 `'hai_access_token'`\n */\nexport function createTokenStore(key = DEFAULT_TOKEN_COOKIE_NAME): BrowserTokenStore {\n return {\n get(): string | null {\n if (typeof window === 'undefined') {\n return null\n }\n return window.localStorage.getItem(key)\n },\n set(token: string): void {\n if (typeof window === 'undefined') {\n return\n }\n window.localStorage.setItem(key, token)\n },\n clear(): void {\n if (typeof window === 'undefined') {\n return\n }\n window.localStorage.removeItem(key)\n },\n }\n}\n\n/**\n * 写入浏览器端 Access Token。\n */\nexport function setBrowserToken(token: string): void {\n defaultBrowserTokenStore.set(token)\n}\n\n/**\n * 清除浏览器端 Access Token。\n */\nexport function clearBrowserToken(): void {\n defaultBrowserTokenStore.clear()\n}\n\n// ─── HandleFetch 工厂(通过 kit.auth 暴露) ───\n\n/**\n * 创建浏览器端同源请求自动附加 Access Token 的 HandleFetch。\n */\nexport function createHandleFetch(tokenStore: BrowserTokenStore = createTokenStore()): HandleFetch {\n return async ({ event, request, fetch }) => {\n const requestUrl = new URL(request.url)\n if (requestUrl.origin !== event.url.origin)\n return fetch(request)\n\n const token = tokenStore.get()\n if (!token)\n return fetch(request)\n\n const headers = new Headers(request.headers)\n headers.set('Authorization', `Bearer ${token}`)\n\n return fetch(new Request(request, { headers }))\n }\n}\n","/**\n * @h-ai/kit — 统一客户端\n *\n * 将 CSRF Token 附加与可选传输加密封装为统一 `apiFetch`。\n * 应用层只需调用一次 `createKitClient()`,后续 API 调用即可复用同一套安全能力。\n * @module kit-client\n */\n\nimport type { BrowserTokenStore } from '../kit-auth.js'\nimport type { EncryptedPayload, TransportCryptoServiceLike, TransportKeyPair } from '../modules/crypto/kit-crypto-types.js'\nimport { createTokenStore } from '../kit-auth.js'\nimport { isValidEncryptedPayload } from '../modules/crypto/kit-transport-encryption.js'\n\n// ─── 类型 ───\n\n/**\n * 传输加密客户端配置\n */\nexport interface ClientTransportConfig {\n /** 传输加密服务实例(@h-ai/crypto 的 asymmetric + symmetric) */\n crypto: TransportCryptoServiceLike\n /** 密钥交换端点 URL(默认 `'/api/kit/key-exchange'`) */\n keyExchangeUrl?: string\n}\n\n/**\n * Kit 客户端配置\n */\nexport interface KitClientConfig {\n /**\n * 传输加密配置。\n * - 不提供 / undefined:不启用传输加密,仅 CSRF\n * - 提供对象:启用传输加密\n */\n transport?: ClientTransportConfig\n /** CSRF Cookie 名称(默认 `'hai_csrf'`) */\n csrfCookieName?: string\n /** CSRF Header 名称(默认 `'X-CSRF-Token'`) */\n csrfHeaderName?: string\n /**\n * 认证配置:自动从浏览器存储读取 Access Token 并注入请求头。\n * - `true`:使用默认 localStorage 存储(key = `hai_access_token`)\n * - `BrowserTokenStore`:使用自定义存储\n * - 不提供 / `false`:不自动注入\n */\n auth?: boolean | BrowserTokenStore\n}\n\n/**\n * Kit 客户端实例\n */\nexport interface KitClient {\n /** 统一 API fetch(写请求自动附加 CSRF,启用 transport 时自动加解密) */\n apiFetch: (url: string, init?: RequestInit) => Promise<Response>\n /** 传输加密是否就绪(未启用传输加密时始终为 true) */\n readonly ready: boolean\n /** 手动触发密钥交换(transport 启用时) */\n init: () => Promise<void>\n /** 销毁密钥状态 */\n destroy: () => void\n}\n\n// ─── 工具函数 ───\n\n/**\n * 从 document.cookie 中读取指定名称的 Cookie 值\n *\n * @param name - Cookie 名称\n * @returns Cookie 值;不存在或运行在服务端时返回 undefined\n */\nfunction getCookie(name: string): string | undefined {\n if (typeof document === 'undefined')\n return undefined\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`))\n return match?.[1]\n}\n\n// ─── 主函数 ───\n\n/**\n * 创建 Kit 客户端\n *\n * 返回统一的 `apiFetch`,内部自动完成:\n * 1. CSRF Token 附加(写方法自动读取 Cookie + 设置 Header)\n * 2. 密钥交换(首次写请求时 lazy init,transport 启用时)\n * 3. 请求体加密(transport 启用时)\n * 4. 响应体解密(transport 启用时)\n *\n * @param config - 客户端配置\n * @returns KitClient 实例\n *\n * @example\n * ```ts\n * const client = createKitClient({ transport: { crypto } })\n * const res = await client.apiFetch('/api/users', { method: 'POST', body: '{}' })\n * ```\n */\nexport function createKitClient(config: KitClientConfig = {}): KitClient {\n const {\n transport: transportConfig,\n csrfCookieName = 'hai_csrf',\n csrfHeaderName = 'X-CSRF-Token',\n auth: authConfig,\n } = config\n\n // ── Auth token store ──\n const authStore: BrowserTokenStore | null = authConfig\n ? (authConfig === true ? createTokenStore() : authConfig)\n : null\n\n // ── 传输加密状态 ──\n let transportReady = false\n let clientKeyPair: TransportKeyPair | null = null\n let serverPublicKey: string | null = null\n let clientId: string | null = null\n /** 密钥交换锁,防止并发 init */\n let initPromise: Promise<void> | null = null\n\n /**\n * 执行密钥交换\n */\n async function doKeyExchange(): Promise<void> {\n if (!transportConfig)\n return\n\n const { crypto: cryptoService, keyExchangeUrl = '/api/kit/key-exchange' } = transportConfig\n\n // 1. 生成客户端非对称密钥对\n const keyPairResult = cryptoService.asymmetric.generateKeyPair()\n if (!keyPairResult.success || !keyPairResult.data) {\n throw new Error('Failed to generate client key pair')\n }\n clientKeyPair = keyPairResult.data\n\n // 2. 与服务端交换公钥\n const response = await fetch(keyExchangeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ clientPublicKey: clientKeyPair.publicKey }),\n })\n\n if (!response.ok) {\n throw new Error(`Key exchange failed: ${response.status}`)\n }\n\n const data = await response.json() as { serverPublicKey?: string, clientId?: string }\n if (!data.serverPublicKey || !data.clientId) {\n throw new Error('Invalid key exchange response')\n }\n\n serverPublicKey = data.serverPublicKey\n clientId = data.clientId\n transportReady = true\n }\n\n /**\n * 确保密钥交换完成(lazy init + 单例锁)\n */\n async function ensureTransportReady(): Promise<void> {\n if (transportReady)\n return\n if (!initPromise) {\n initPromise = doKeyExchange().finally(() => {\n initPromise = null\n })\n }\n await initPromise\n }\n\n /**\n * 加密请求体\n */\n function encryptBody(bodyText: string): string {\n if (!transportConfig || !serverPublicKey)\n return bodyText\n\n const { crypto: cryptoService } = transportConfig\n\n // 1. 生成随机对称密钥\n const symmetricKey = cryptoService.symmetric.generateKey()\n\n // 2. 对称加密内容\n const encResult = cryptoService.symmetric.encryptWithIV(bodyText, symmetricKey)\n if (!encResult.success || !encResult.data) {\n throw new Error('Request body encryption failed')\n }\n\n // 3. 非对称加密对称密钥\n const keyEncResult = cryptoService.asymmetric.encrypt(symmetricKey, serverPublicKey)\n if (!keyEncResult.success || !keyEncResult.data) {\n throw new Error('Symmetric key encryption failed')\n }\n\n const payload: EncryptedPayload = {\n encryptedKey: keyEncResult.data,\n ciphertext: encResult.data.ciphertext,\n iv: encResult.data.iv,\n }\n\n return JSON.stringify(payload)\n }\n\n /**\n * 解密响应体\n */\n async function decryptResponse(response: Response): Promise<Response> {\n if (!clientKeyPair || !transportConfig)\n return response\n\n const encryptedBody = await response.json() as unknown\n if (!isValidEncryptedPayload(encryptedBody))\n return response\n\n const { crypto: cryptoService } = transportConfig\n\n // 1. 非对称解密对称密钥\n const keyDecResult = cryptoService.asymmetric.decrypt(encryptedBody.encryptedKey, clientKeyPair.privateKey)\n if (!keyDecResult.success || !keyDecResult.data) {\n throw new Error('Response key decryption failed')\n }\n\n // 2. 对称解密内容\n const decResult = cryptoService.symmetric.decryptWithIV(encryptedBody.ciphertext, keyDecResult.data, encryptedBody.iv)\n if (!decResult.success || typeof decResult.data !== 'string') {\n throw new Error('Response body decryption failed')\n }\n\n return new Response(decResult.data, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n }\n\n /**\n * 统一 API fetch\n */\n async function apiFetch(url: string, init: RequestInit = {}): Promise<Response> {\n const method = (init.method ?? 'GET').toUpperCase()\n const isWriteMethod = !['GET', 'HEAD', 'OPTIONS'].includes(method)\n\n const headers = new Headers(init.headers)\n\n // ── Auth ──\n if (authStore) {\n const token = authStore.get()\n if (token) {\n headers.set('Authorization', `Bearer ${token}`)\n }\n }\n\n // ── CSRF ──\n if (isWriteMethod) {\n const csrfToken = getCookie(csrfCookieName)\n if (csrfToken) {\n headers.set(csrfHeaderName, csrfToken)\n }\n }\n\n // ── 传输加密 ──\n if (transportConfig) {\n await ensureTransportReady()\n\n if (clientId) {\n headers.set('X-Client-Id', clientId)\n }\n\n // 加密请求体(写方法且有 body 时)\n if (init.body !== undefined && init.body !== null) {\n const bodyText = typeof init.body === 'string' ? init.body : JSON.stringify(init.body)\n const encrypted = encryptBody(bodyText)\n headers.set('Content-Type', 'application/json')\n\n let response = await fetch(url, { ...init, headers, body: encrypted })\n\n // 解密响应\n if (response.headers.get('X-Encrypted') === 'true') {\n response = await decryptResponse(response)\n }\n\n return response\n }\n }\n\n // ── 发送 ──\n let response = await fetch(url, { ...init, headers })\n\n // ── 解密响应(GET/无 body 写请求也可能有加密响应) ──\n if (transportConfig && response.headers.get('X-Encrypted') === 'true') {\n response = await decryptResponse(response)\n }\n\n return response\n }\n\n return {\n apiFetch,\n get ready() { return !transportConfig || transportReady },\n async init() {\n if (transportConfig)\n await ensureTransportReady()\n },\n destroy() {\n clientKeyPair = null\n serverPublicKey = null\n clientId = null\n transportReady = false\n initPromise = null\n },\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createTransportEncryption, kitM, isValidEncryptedPayload } from './chunk-
|
|
1
|
+
import { createTransportEncryption, kitM, isValidEncryptedPayload } from './chunk-BRZK7V5O.js';
|
|
2
2
|
|
|
3
3
|
// src/modules/crypto/kit-transport-middleware.ts
|
|
4
4
|
function transportEncryptionMiddleware(config) {
|
|
@@ -133,5 +133,5 @@ function hasBody(method) {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
export { transportEncryptionMiddleware };
|
|
136
|
-
//# sourceMappingURL=chunk-
|
|
137
|
-
//# sourceMappingURL=chunk-
|
|
136
|
+
//# sourceMappingURL=chunk-XTZUGWBY.js.map
|
|
137
|
+
//# sourceMappingURL=chunk-XTZUGWBY.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/modules/crypto/kit-transport-middleware.ts"],"names":[],"mappings":"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","file":"chunk-AD6S473Y.js","sourcesContent":["/**\n * @h-ai/kit — 传输加密中间件\n *\n * SvelteKit 中间件,自动对请求/响应进行传输加密解密。\n * @module kit-transport-middleware\n */\n\nimport type { Middleware } from '../../kit-types.js'\nimport type { TransportEncryptionConfig, TransportEncryptionManager } from './kit-crypto-types.js'\nimport { kitM } from '../../kit-i18n.js'\nimport { createTransportEncryption, isValidEncryptedPayload } from './kit-transport-encryption.js'\n\n/**\n * 创建传输加密中间件\n *\n * @param config - 传输加密配置\n * @returns SvelteKit 中间件\n *\n * @example\n * ```ts\n * import { crypto } from '@h-ai/crypto'\n * import { kit } from '@h-ai/kit'\n *\n * // 传输加密通过 createHandle 的 crypto 配置自动启用:\n * export const handle = kit.createHandle({\n * crypto: { crypto, transport: true },\n * })\n * ```\n */\nexport function transportEncryptionMiddleware(config: TransportEncryptionConfig): Middleware {\n // 未启用时直接透传\n if (!config.enabled) {\n return async (_context, next) => next()\n }\n\n const keyExchangePath = config.keyExchangePath ?? '/api/kit/key-exchange'\n const excludePaths = config.excludePaths ?? []\n const encryptResponse = config.encryptResponse ?? true\n const requireEncryption = config.requireEncryption ?? true\n\n // 初始化传输加密管理器\n const result = createTransportEncryption(config.crypto)\n if (!result.success) {\n // 密钥生成失败时降级为透传\n return async (_context, next) => next()\n }\n const manager = result.data\n\n return async (context, next) => {\n const { event } = context\n const pathname = event.url.pathname\n\n // 密钥交换端点:委托给 keyExchangeHandler\n if (pathname === keyExchangePath && event.request.method === 'POST') {\n return handleKeyExchange(manager, event.request)\n }\n\n // 排除路径不做加解密\n if (shouldExclude(pathname, excludePaths, keyExchangePath)) {\n return next()\n }\n\n // 请求头中无 X-Client-Id 时的处理\n const clientId = event.request.headers.get('X-Client-Id')\n if (!clientId) {\n if (requireEncryption) {\n // 强制加密模式:缺少 X-Client-Id 说明未完成密钥交换,拒绝请求\n return new Response(\n JSON.stringify({ error: kitM('kit_transportClientIdRequired') }),\n { status: 400, headers: { 'Content-Type': 'application/json' } },\n )\n }\n // 非强制模式:透传明文(渐进式迁移兼容)\n return next()\n }\n\n // 检查客户端是否已注册\n const clientPublicKey = manager.getClientPublicKey(clientId)\n if (!clientPublicKey) {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportClientKeyNotFound') }),\n { status: 400, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n // ── 解密请求 ──\n try {\n if (hasBody(event.request.method)) {\n const bodyText = await event.request.text()\n if (bodyText) {\n const payload = JSON.parse(bodyText) as unknown\n if (isValidEncryptedPayload(payload)) {\n const plaintext = manager.decryptRequest(payload)\n // 重建请求,替换为解密后的明文\n const newRequest = new Request(event.request.url, {\n method: event.request.method,\n headers: new Headers(event.request.headers),\n body: plaintext,\n })\n // 将解密后的请求注入 locals,供后续中间件/端点使用\n Object.defineProperty(event, 'request', {\n value: newRequest,\n writable: true,\n configurable: true,\n })\n }\n }\n }\n }\n catch {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportDecryptFailed') }),\n { status: 400, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n // ── 执行后续中间件/端点 ──\n const response = await next()\n\n // ── 加密响应 ──\n if (!encryptResponse) {\n return response\n }\n\n // 跳过非 JSON 响应和大体积响应(>1MB),避免内存问题\n const contentType = response.headers.get('Content-Type') ?? ''\n if (!contentType.includes('application/json')) {\n return response\n }\n const contentLength = response.headers.get('Content-Length')\n if (contentLength && Number.parseInt(contentLength, 10) > 1_048_576) {\n return response\n }\n\n try {\n const responseBody = await response.text()\n if (!responseBody) {\n return response\n }\n\n const encryptedPayload = manager.encryptResponse(clientId, responseBody)\n return new Response(\n JSON.stringify(encryptedPayload),\n {\n status: response.status,\n statusText: response.statusText,\n headers: {\n ...Object.fromEntries(response.headers.entries()),\n 'Content-Type': 'application/json',\n 'X-Encrypted': 'true',\n },\n },\n )\n }\n catch {\n // 加密失败时返回原始响应\n return response\n }\n }\n}\n\n/**\n * 处理密钥交换 POST 请求\n *\n * 接收客户端公钥,注册并返回服务端公钥与 clientId。\n *\n * @param manager - 传输加密管理器\n * @param request - 原始 Request\n * @returns JSON Response\n */\nasync function handleKeyExchange(\n manager: TransportEncryptionManager,\n request: Request,\n): Promise<Response> {\n try {\n const body = await request.json() as { clientPublicKey?: string }\n\n if (!body.clientPublicKey || typeof body.clientPublicKey !== 'string') {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportInvalidPayload') }),\n { status: 400, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n const clientId = manager.registerClientKey(body.clientPublicKey)\n const serverPublicKey = manager.getServerPublicKey()\n\n return new Response(\n JSON.stringify({ serverPublicKey, clientId }),\n { status: 200, headers: { 'Content-Type': 'application/json' } },\n )\n }\n catch {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportKeyExchangeFailed') }),\n { status: 500, headers: { 'Content-Type': 'application/json' } },\n )\n }\n}\n\n/**\n * 判断路径是否应排除传输加解密\n *\n * @param pathname - 当前请求路径\n * @param excludePaths - 配置的排除列表\n * @param keyExchangePath - 密钥交换端点路径\n * @returns 是否排除\n */\nfunction shouldExclude(pathname: string, excludePaths: string[], keyExchangePath: string): boolean {\n if (pathname === keyExchangePath)\n return true\n return excludePaths.some(p => pathname === p || pathname.startsWith(`${p}/`))\n}\n\n/**\n * 判断 HTTP 方法是否可能携带请求体\n *\n * @param method - HTTP 方法字符串\n * @returns `true` 表示 POST / PUT / PATCH / DELETE\n */\nfunction hasBody(method: string): boolean {\n return ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method.toUpperCase())\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/modules/crypto/kit-transport-middleware.ts"],"names":[],"mappings":"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","file":"chunk-XTZUGWBY.js","sourcesContent":["/**\n * @h-ai/kit — 传输加密中间件\n *\n * SvelteKit 中间件,自动对请求/响应进行传输加密解密。\n * @module kit-transport-middleware\n */\n\nimport type { Middleware } from '../../kit-types.js'\nimport type { TransportEncryptionConfig, TransportEncryptionManager } from './kit-crypto-types.js'\nimport { kitM } from '../../kit-i18n.js'\nimport { createTransportEncryption, isValidEncryptedPayload } from './kit-transport-encryption.js'\n\n/**\n * 创建传输加密中间件\n *\n * @param config - 传输加密配置\n * @returns SvelteKit 中间件\n *\n * @example\n * ```ts\n * import { crypto } from '@h-ai/crypto'\n * import { kit } from '@h-ai/kit'\n *\n * // 传输加密通过 createHandle 的 crypto 配置自动启用:\n * export const handle = kit.createHandle({\n * crypto: { crypto, transport: true },\n * })\n * ```\n */\nexport function transportEncryptionMiddleware(config: TransportEncryptionConfig): Middleware {\n // 未启用时直接透传\n if (!config.enabled) {\n return async (_context, next) => next()\n }\n\n const keyExchangePath = config.keyExchangePath ?? '/api/kit/key-exchange'\n const excludePaths = config.excludePaths ?? []\n const encryptResponse = config.encryptResponse ?? true\n const requireEncryption = config.requireEncryption ?? true\n\n // 初始化传输加密管理器\n const result = createTransportEncryption(config.crypto)\n if (!result.success) {\n // 密钥生成失败时降级为透传\n return async (_context, next) => next()\n }\n const manager = result.data\n\n return async (context, next) => {\n const { event } = context\n const pathname = event.url.pathname\n\n // 密钥交换端点:委托给 keyExchangeHandler\n if (pathname === keyExchangePath && event.request.method === 'POST') {\n return handleKeyExchange(manager, event.request)\n }\n\n // 排除路径不做加解密\n if (shouldExclude(pathname, excludePaths, keyExchangePath)) {\n return next()\n }\n\n // 请求头中无 X-Client-Id 时的处理\n const clientId = event.request.headers.get('X-Client-Id')\n if (!clientId) {\n if (requireEncryption) {\n // 强制加密模式:缺少 X-Client-Id 说明未完成密钥交换,拒绝请求\n return new Response(\n JSON.stringify({ error: kitM('kit_transportClientIdRequired') }),\n { status: 400, headers: { 'Content-Type': 'application/json' } },\n )\n }\n // 非强制模式:透传明文(渐进式迁移兼容)\n return next()\n }\n\n // 检查客户端是否已注册\n const clientPublicKey = manager.getClientPublicKey(clientId)\n if (!clientPublicKey) {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportClientKeyNotFound') }),\n { status: 400, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n // ── 解密请求 ──\n try {\n if (hasBody(event.request.method)) {\n const bodyText = await event.request.text()\n if (bodyText) {\n const payload = JSON.parse(bodyText) as unknown\n if (isValidEncryptedPayload(payload)) {\n const plaintext = manager.decryptRequest(payload)\n // 重建请求,替换为解密后的明文\n const newRequest = new Request(event.request.url, {\n method: event.request.method,\n headers: new Headers(event.request.headers),\n body: plaintext,\n })\n // 将解密后的请求注入 locals,供后续中间件/端点使用\n Object.defineProperty(event, 'request', {\n value: newRequest,\n writable: true,\n configurable: true,\n })\n }\n }\n }\n }\n catch {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportDecryptFailed') }),\n { status: 400, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n // ── 执行后续中间件/端点 ──\n const response = await next()\n\n // ── 加密响应 ──\n if (!encryptResponse) {\n return response\n }\n\n // 跳过非 JSON 响应和大体积响应(>1MB),避免内存问题\n const contentType = response.headers.get('Content-Type') ?? ''\n if (!contentType.includes('application/json')) {\n return response\n }\n const contentLength = response.headers.get('Content-Length')\n if (contentLength && Number.parseInt(contentLength, 10) > 1_048_576) {\n return response\n }\n\n try {\n const responseBody = await response.text()\n if (!responseBody) {\n return response\n }\n\n const encryptedPayload = manager.encryptResponse(clientId, responseBody)\n return new Response(\n JSON.stringify(encryptedPayload),\n {\n status: response.status,\n statusText: response.statusText,\n headers: {\n ...Object.fromEntries(response.headers.entries()),\n 'Content-Type': 'application/json',\n 'X-Encrypted': 'true',\n },\n },\n )\n }\n catch {\n // 加密失败时返回原始响应\n return response\n }\n }\n}\n\n/**\n * 处理密钥交换 POST 请求\n *\n * 接收客户端公钥,注册并返回服务端公钥与 clientId。\n *\n * @param manager - 传输加密管理器\n * @param request - 原始 Request\n * @returns JSON Response\n */\nasync function handleKeyExchange(\n manager: TransportEncryptionManager,\n request: Request,\n): Promise<Response> {\n try {\n const body = await request.json() as { clientPublicKey?: string }\n\n if (!body.clientPublicKey || typeof body.clientPublicKey !== 'string') {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportInvalidPayload') }),\n { status: 400, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n const clientId = manager.registerClientKey(body.clientPublicKey)\n const serverPublicKey = manager.getServerPublicKey()\n\n return new Response(\n JSON.stringify({ serverPublicKey, clientId }),\n { status: 200, headers: { 'Content-Type': 'application/json' } },\n )\n }\n catch {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportKeyExchangeFailed') }),\n { status: 500, headers: { 'Content-Type': 'application/json' } },\n )\n }\n}\n\n/**\n * 判断路径是否应排除传输加解密\n *\n * @param pathname - 当前请求路径\n * @param excludePaths - 配置的排除列表\n * @param keyExchangePath - 密钥交换端点路径\n * @returns 是否排除\n */\nfunction shouldExclude(pathname: string, excludePaths: string[], keyExchangePath: string): boolean {\n if (pathname === keyExchangePath)\n return true\n return excludePaths.some(p => pathname === p || pathname.startsWith(`${p}/`))\n}\n\n/**\n * 判断 HTTP 方法是否可能携带请求体\n *\n * @param method - HTTP 方法字符串\n * @returns `true` 表示 POST / PUT / PATCH / DELETE\n */\nfunction hasBody(method: string): boolean {\n return ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method.toUpperCase())\n}\n"]}
|
package/dist/client/index.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { defineCrud } from './chunk-FRYJMRTP.js';
|
|
2
2
|
export { defineCrud, resolveOptions, resolveText } from './chunk-FRYJMRTP.js';
|
|
3
|
-
import { createHandleFetch, createTokenStore, clearBrowserToken, setBrowserToken, logout, registerAndLogin, loginWithApiKey, loginWithLdap, loginWithOtp, login, createKitClient, configureAuth, getAccessToken } from './chunk-
|
|
3
|
+
import { createHandleFetch, createTokenStore, clearBrowserToken, setBrowserToken, logout, registerAndLogin, loginWithApiKey, loginWithLdap, loginWithOtp, login, createKitClient, configureAuth, getAccessToken } from './chunk-GRYHRXVC.js';
|
|
4
4
|
import { resolveA2AConfig, handleA2ARequest } from './chunk-475WECWK.js';
|
|
5
|
-
import { transportEncryptionMiddleware } from './chunk-
|
|
6
|
-
import { kitM, setAllModulesLocale } from './chunk-
|
|
5
|
+
import { transportEncryptionMiddleware } from './chunk-XTZUGWBY.js';
|
|
6
|
+
import { kitM, setAllModulesLocale } from './chunk-BRZK7V5O.js';
|
|
7
7
|
import { core } from '@h-ai/core';
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { transportEncryptionMiddleware } from '../../chunk-
|
|
2
|
-
import { kitM } from '../../chunk-
|
|
3
|
-
export { createKeyExchangeHandler, createTransportEncryption, isValidEncryptedPayload } from '../../chunk-
|
|
1
|
+
export { transportEncryptionMiddleware } from '../../chunk-XTZUGWBY.js';
|
|
2
|
+
import { kitM } from '../../chunk-BRZK7V5O.js';
|
|
3
|
+
export { createKeyExchangeHandler, createTransportEncryption, isValidEncryptedPayload } from '../../chunk-BRZK7V5O.js';
|
|
4
4
|
|
|
5
5
|
// src/modules/crypto/kit-crypto-helpers.ts
|
|
6
6
|
async function verifyWebhookSignature(config) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-ai/kit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.11",
|
|
5
5
|
"description": "Hai Framework SvelteKit integration module.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"exports": {
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"zod": "^4.3.6",
|
|
59
|
-
"@h-ai/core": "0.1.0-alpha.
|
|
60
|
-
"@h-ai/iam": "0.1.0-alpha.
|
|
59
|
+
"@h-ai/core": "0.1.0-alpha.11",
|
|
60
|
+
"@h-ai/iam": "0.1.0-alpha.11"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@sveltejs/kit": "^2.57.1",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../messages/en-US.json","../messages/zh-CN.json","../src/kit-i18n.ts","../src/modules/crypto/kit-transport-encryption.ts"],"names":[],"mappings":";;;;;AAAA,IAAA,aAAA,GAAA;AAAA,EACE,OAAA,EAAW,iDAAA;AAAA,EACX,gBAAA,EAAoB,cAAA;AAAA,EACpB,aAAA,EAAiB,4CAAA;AAAA,EACjB,mBAAA,EAAuB,+BAAA;AAAA,EACvB,oBAAA,EAAwB,gCAAA;AAAA,EACxB,wBAAA,EAA4B,oBAAA;AAAA,EAC5B,qBAAA,EAAyB,2CAAA;AAAA,EACzB,0BAAA,EAA8B,0BAAA;AAAA,EAC9B,mBAAA,EAAuB,8BAAA;AAAA,EACvB,iBAAA,EAAqB,mBAAA;AAAA,EACrB,gCAAA,EAAoC,4CAAA;AAAA,EACpC,8BAAA,EAAkC,sBAAA;AAAA,EAClC,0BAAA,EAA8B,6BAAA;AAAA,EAC9B,6BAAA,EAAiC,iCAAA;AAAA,EACjC,6BAAA,EAAiC,iCAAA;AAAA,EACjC,0BAAA,EAA8B,6BAAA;AAAA,EAC9B,2BAAA,EAA+B,2BAAA;AAAA,EAC/B,8BAAA,EAAkC,qBAAA;AAAA,EAClC,6BAAA,EAAiC,+EAAA;AAAA,EACjC,cAAA,EAAkB,wBAAA;AAAA,EAClB,gBAAA,EAAoB,yBAAA;AAAA,EACpB,gBAAA,EAAoB,eAAA;AAAA,EACpB,oBAAA,EAAwB,oBAAA;AAAA,EACxB,iBAAA,EAAqB,uBAAA;AAAA,EACrB,oBAAA,EAAwB,mBAAA;AAAA,EACxB,kBAAA,EAAsB,kBAAA;AAAA,EACtB,iBAAA,EAAqB,yBAAA;AAAA,EACrB,uBAAA,EAA2B,qCAAA;AAAA,EAC3B,cAAA,EAAkB;AACpB,CAAA;;;AC9BA,IAAA,aAAA,GAAA;AAAA,EACE,OAAA,EAAW,iDAAA;AAAA,EACX,gBAAA,EAAoB,oBAAA;AAAA,EACpB,aAAA,EAAiB,sEAAA;AAAA,EACjB,mBAAA,EAAuB,sCAAA;AAAA,EACvB,oBAAA,EAAwB,qCAAA;AAAA,EACxB,wBAAA,EAA4B,yBAAA;AAAA,EAC5B,qBAAA,EAAyB,0EAAA;AAAA,EACzB,0BAAA,EAA8B,kDAAA;AAAA,EAC9B,mBAAA,EAAuB,4CAAA;AAAA,EACvB,iBAAA,EAAqB,0BAAA;AAAA,EACrB,gCAAA,EAAoC,oEAAA;AAAA,EACpC,8BAAA,EAAkC,kDAAA;AAAA,EAClC,0BAAA,EAA8B,sCAAA;AAAA,EAC9B,6BAAA,EAAiC,kDAAA;AAAA,EACjC,6BAAA,EAAiC,kDAAA;AAAA,EACjC,0BAAA,EAA8B,sCAAA;AAAA,EAC9B,2BAAA,EAA+B,4CAAA;AAAA,EAC/B,8BAAA,EAAkC,sCAAA;AAAA,EAClC,6BAAA,EAAiC,iIAAA;AAAA,EACjC,cAAA,EAAkB,sCAAA;AAAA,EAClB,gBAAA,EAAoB,sCAAA;AAAA,EACpB,gBAAA,EAAoB,0BAAA;AAAA,EACpB,oBAAA,EAAwB,gCAAA;AAAA,EACxB,iBAAA,EAAqB,4CAAA;AAAA,EACrB,oBAAA,EAAwB,sCAAA;AAAA,EACxB,kBAAA,EAAsB,sCAAA;AAAA,EACtB,iBAAA,EAAqB,uCAAA;AAAA,EACrB,uBAAA,EAA2B,6CAAA;AAAA,EAC3B,cAAA,EAAkB;AACpB,CAAA;;;AChBO,IAAM,IAAA,GACT,KAAK,IAAA,CAAK,mBAAA,CAAmC,EAAE,OAAA,EAAS,aAAA,EAAc,OAAA,EAAS,aAAA,EAAc;AAiB1F,SAAS,oBAAoB,MAAA,EAAsB;AACxD,EAAA,IAAA,CAAK,IAAA,CAAK,gBAAgB,MAAM,CAAA;AAClC;ACHO,SAAS,yBAAA,CACd,aAAA,EACA,UAAA,GAAa,GAAA,EAC0B;AAEvC,EAAA,MAAM,aAAA,GAAgB,aAAA,CAAc,UAAA,CAAW,eAAA,EAAgB;AAC/D,EAAA,IAAI,CAAC,aAAA,CAAc,OAAA,IAAW,CAAC,cAAc,IAAA,EAAM;AACjD,IAAA,OAAO,GAAA,CAAI,EAAE,IAAA,EAAM,qCAAA,EAAuC,SAAS,IAAA,CAAK,kCAAkC,GAAG,CAAA;AAAA,EAC/G;AACA,EAAA,MAAM,gBAAkC,aAAA,CAAc,IAAA;AAGtD,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAoB;AAC3C,EAAA,IAAI,eAAA,GAAkB,CAAA;AAEtB,EAAA,OAAO,EAAA,CAAG;AAAA,IACR,kBAAA,GAA6B;AAC3B,MAAA,OAAO,aAAA,CAAc,SAAA;AAAA,IACvB,CAAA;AAAA,IAEA,kBAAkB,eAAA,EAAiC;AACjD,MAAA,eAAA,EAAA;AACA,MAAA,MAAM,WAAW,CAAA,OAAA,EAAU,eAAe,CAAA,CAAA,EAAI,IAAA,CAAK,KAAK,CAAA,CAAA;AAGxD,MAAA,IAAI,UAAA,CAAW,QAAQ,UAAA,EAAY;AACjC,QAAA,MAAM,SAAA,GAAY,UAAA,CAAW,IAAA,EAAK,CAAE,MAAK,CAAE,KAAA;AAC3C,QAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,UAAA,UAAA,CAAW,OAAO,SAAS,CAAA;AAAA,QAC7B;AAAA,MACF;AAEA,MAAA,UAAA,CAAW,GAAA,CAAI,UAAU,eAAe,CAAA;AACxC,MAAA,OAAO,QAAA;AAAA,IACT,CAAA;AAAA,IAEA,mBAAmB,QAAA,EAAsC;AACvD,MAAA,OAAO,UAAA,CAAW,IAAI,QAAQ,CAAA;AAAA,IAChC,CAAA;AAAA,IAEA,eAAA,CAAgB,UAAkB,IAAA,EAAgC;AAChE,MAAA,MAAM,eAAA,GAAkB,UAAA,CAAW,GAAA,CAAI,QAAQ,CAAA;AAC/C,MAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,QAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,gCAAgC,CAAC,CAAA;AAAA,MACxD;AAGA,MAAA,MAAM,YAAA,GAAe,aAAA,CAAc,SAAA,CAAU,WAAA,EAAY;AAGzD,MAAA,MAAM,SAAA,GAAY,aAAA,CAAc,SAAA,CAAU,aAAA,CAAc,MAAM,YAAY,CAAA;AAC1E,MAAA,IAAI,CAAC,SAAA,CAAU,OAAA,IAAW,CAAC,UAAU,IAAA,EAAM;AACzC,QAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,4BAA4B,CAAC,CAAA;AAAA,MACpD;AAGA,MAAA,MAAM,YAAA,GAAe,aAAA,CAAc,UAAA,CAAW,OAAA,CAAQ,cAAc,eAAe,CAAA;AACnF,MAAA,IAAI,CAAC,YAAA,CAAa,OAAA,IAAW,CAAC,aAAa,IAAA,EAAM;AAC/C,QAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,+BAA+B,CAAC,CAAA;AAAA,MACvD;AAEA,MAAA,OAAO;AAAA,QACL,cAAc,YAAA,CAAa,IAAA;AAAA,QAC3B,UAAA,EAAY,UAAU,IAAA,CAAK,UAAA;AAAA,QAC3B,EAAA,EAAI,UAAU,IAAA,CAAK;AAAA,OACrB;AAAA,IACF,CAAA;AAAA,IAEA,eAAe,OAAA,EAAmC;AAEhD,MAAA,MAAM,eAAe,aAAA,CAAc,UAAA,CAAW,QAAQ,OAAA,CAAQ,YAAA,EAAc,cAAc,UAAU,CAAA;AACpG,MAAA,IAAI,CAAC,YAAA,CAAa,OAAA,IAAW,CAAC,aAAa,IAAA,EAAM;AAC/C,QAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,+BAA+B,CAAC,CAAA;AAAA,MACvD;AAGA,MAAA,MAAM,SAAA,GAAY,cAAc,SAAA,CAAU,aAAA,CAAc,QAAQ,UAAA,EAAY,YAAA,CAAa,IAAA,EAAM,OAAA,CAAQ,EAAE,CAAA;AACzG,MAAA,IAAI,CAAC,SAAA,CAAU,OAAA,IAAW,OAAO,SAAA,CAAU,SAAS,QAAA,EAAU;AAC5D,QAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,4BAA4B,CAAC,CAAA;AAAA,MACpD;AAEA,MAAA,OAAO,SAAA,CAAU,IAAA;AAAA,IACnB;AAAA,GACD,CAAA;AACH;AAiBO,SAAS,yBACd,OAAA,EACyC;AACzC,EAAA,OAAO,OAAO,OAAA,KAAwC;AACpD,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,IAAA,EAAK;AAEhC,MAAA,IAAI,CAAC,IAAA,CAAK,eAAA,IAAmB,OAAO,IAAA,CAAK,oBAAoB,QAAA,EAAU;AACrE,QAAA,OAAO,IAAI,QAAA;AAAA,UACT,KAAK,SAAA,CAAU,EAAE,OAAO,IAAA,CAAK,6BAA6B,GAAG,CAAA;AAAA,UAC7D,EAAE,MAAA,EAAQ,GAAA,EAAK,SAAS,EAAE,cAAA,EAAgB,oBAAmB;AAAE,SACjE;AAAA,MACF;AAEA,MAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,iBAAA,CAAkB,IAAA,CAAK,eAAe,CAAA;AAC/D,MAAA,MAAM,eAAA,GAAkB,QAAQ,kBAAA,EAAmB;AAEnD,MAAA,OAAO,IAAI,QAAA;AAAA,QACT,IAAA,CAAK,SAAA,CAAU,EAAE,eAAA,EAAiB,UAAU,CAAA;AAAA,QAC5C,EAAE,MAAA,EAAQ,GAAA,EAAK,SAAS,EAAE,cAAA,EAAgB,oBAAmB;AAAE,OACjE;AAAA,IACF,CAAA,CAAA,MACM;AACJ,MAAA,OAAO,IAAI,QAAA;AAAA,QACT,KAAK,SAAA,CAAU,EAAE,OAAO,IAAA,CAAK,gCAAgC,GAAG,CAAA;AAAA,QAChE,EAAE,MAAA,EAAQ,GAAA,EAAK,SAAS,EAAE,cAAA,EAAgB,oBAAmB;AAAE,OACjE;AAAA,IACF;AAAA,EACF,CAAA;AACF;AAQO,SAAS,wBAAwB,OAAA,EAA+C;AACrF,EAAA,IAAI,OAAO,OAAA,KAAY,QAAA,IAAY,OAAA,KAAY,IAAA;AAC7C,IAAA,OAAO,KAAA;AACT,EAAA,MAAM,CAAA,GAAI,OAAA;AACV,EAAA,OACE,OAAO,EAAE,YAAA,KAAiB,QAAA,IACvB,OAAO,CAAA,CAAE,UAAA,KAAe,QAAA,IACxB,OAAO,CAAA,CAAE,EAAA,KAAO,YAChB,CAAA,CAAE,YAAA,CAAa,SAAS,CAAA,IACxB,CAAA,CAAE,WAAW,MAAA,GAAS,CAAA,IACtB,CAAA,CAAE,EAAA,CAAG,MAAA,GAAS,CAAA;AAErB","file":"chunk-6TMSXG7J.js","sourcesContent":["{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"kit_unauthorized\": \"Unauthorized\",\n \"kit_forbidden\": \"Forbidden: missing {permission} permission\",\n \"kit_csrfTokenFailed\": \"Failed to generate CSRF token\",\n \"kit_csrfVerifyFailed\": \"CSRF token verification failed\",\n \"kit_csrfValidationFailed\": \"Invalid CSRF token\",\n \"kit_rateLimitExceeded\": \"Too many requests, please try again later\",\n \"kit_unsupportedContentType\": \"Unsupported content type\",\n \"kit_parseBodyFailed\": \"Failed to parse request body\",\n \"kit_encryptFailed\": \"Encryption failed\",\n \"kit_transportKeyGenerationFailed\": \"Transport encryption key generation failed\",\n \"kit_transportClientKeyNotFound\": \"Client key not found\",\n \"kit_transportEncryptFailed\": \"Transport encryption failed\",\n \"kit_transportEncryptKeyFailed\": \"Symmetric key encryption failed\",\n \"kit_transportDecryptKeyFailed\": \"Symmetric key decryption failed\",\n \"kit_transportDecryptFailed\": \"Transport decryption failed\",\n \"kit_transportInvalidPayload\": \"Invalid encrypted payload\",\n \"kit_transportKeyExchangeFailed\": \"Key exchange failed\",\n \"kit_transportClientIdRequired\": \"Missing X-Client-Id header, key exchange is required for transport encryption\",\n \"kit_signFailed\": \"Request signing failed\",\n \"kit_authRequired\": \"Authentication required\",\n \"kit_accessDenied\": \"Access denied\",\n \"kit_resourceNotFound\": \"Resource not found\",\n \"kit_internalError\": \"Internal server error\",\n \"kit_validationFailed\": \"Validation failed\",\n \"kit_noGuardsPassed\": \"No guards passed\",\n \"kit_requiredRoles\": \"Required roles: {roles}\",\n \"kit_requiredPermissions\": \"Required permissions: {permissions}\",\n \"kit_idRequired\": \"ID is required\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"kit_unauthorized\": \"未授权\",\n \"kit_forbidden\": \"权限不足:缺少 {permission} 权限\",\n \"kit_csrfTokenFailed\": \"生成 CSRF Token 失败\",\n \"kit_csrfVerifyFailed\": \"CSRF Token 验证失败\",\n \"kit_csrfValidationFailed\": \"CSRF Token 无效\",\n \"kit_rateLimitExceeded\": \"请求过于频繁,请稍后再试\",\n \"kit_unsupportedContentType\": \"不支持的内容类型\",\n \"kit_parseBodyFailed\": \"请求体解析失败\",\n \"kit_encryptFailed\": \"加密失败\",\n \"kit_transportKeyGenerationFailed\": \"传输加密密钥对生成失败\",\n \"kit_transportClientKeyNotFound\": \"客户端密钥未找到\",\n \"kit_transportEncryptFailed\": \"传输加密失败\",\n \"kit_transportEncryptKeyFailed\": \"对称密钥加密失败\",\n \"kit_transportDecryptKeyFailed\": \"对称密钥解密失败\",\n \"kit_transportDecryptFailed\": \"传输解密失败\",\n \"kit_transportInvalidPayload\": \"无效的加密载荷\",\n \"kit_transportKeyExchangeFailed\": \"密钥交换失败\",\n \"kit_transportClientIdRequired\": \"缺少 X-Client-Id 请求头,传输加密必须先完成密钥交换\",\n \"kit_signFailed\": \"请求签名失败\",\n \"kit_authRequired\": \"需要身份认证\",\n \"kit_accessDenied\": \"拒绝访问\",\n \"kit_resourceNotFound\": \"资源未找到\",\n \"kit_internalError\": \"内部服务器错误\",\n \"kit_validationFailed\": \"数据验证失败\",\n \"kit_noGuardsPassed\": \"没有守卫通过\",\n \"kit_requiredRoles\": \"需要角色:{roles}\",\n \"kit_requiredPermissions\": \"需要权限:{permissions}\",\n \"kit_idRequired\": \"ID 不能为空\"\n}\n","/**\n * @h-ai/kit — i18n 工具\n *\n * Kit 模块的国际化消息工具,从 @h-ai/core 调用 i18n API。\n * @module kit-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\ntype KitMessageKey = keyof typeof messagesZhCN\n\n/** 获取 Kit 模块的 i18n 消息 */\nexport const kitM\n = core.i18n.createMessageGetter<KitMessageKey>({ 'zh-CN': messagesZhCN, 'en-US': messagesEnUS })\n\n/**\n * 统一设置所有 hai 模块的默认语言\n *\n * 通过 @h-ai/core 的集中式 locale 管理器,一次调用即可同步所有模块。\n * 各模块的 createMessageGetter 会读取全局 locale。\n *\n * @example\n * ```ts\n * import { kit } from '@h-ai/kit'\n *\n * // 在 i18n handle 中\n * const locale = event.cookies.get('PARAGLIDE_LOCALE') ?? 'zh-CN'\n * kit.i18n.setLocale(locale)\n * ```\n */\nexport function setAllModulesLocale(locale: string): void {\n core.i18n.setGlobalLocale(locale)\n}\n","/**\n * @h-ai/kit — 传输加密核心\n *\n * 基于非对称 + 对称的混合传输加密。\n * @module kit-transport-encryption\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type {\n EncryptedPayload,\n TransportCryptoServiceLike,\n TransportEncryptionManager,\n TransportKeyPair,\n} from './kit-crypto-types.js'\nimport { err, ok } from '@h-ai/core'\nimport { kitM } from '../../kit-i18n.js'\n\n/**\n * 创建传输加密管理器\n *\n * 启动时生成服务端非对称密钥对,通过 clientId → publicKey 的内存 Map 管理客户端密钥。\n * 内置 LRU 淘汰机制,超过 maxClients 上限时自动移除最早注册的客户端。\n *\n * 注意:clientKeys 存储在进程内存中,多节点部署时各节点状态独立。\n * 客户端密钥交换后的后续请求必须路由到同一节点(如使用 sticky session),\n * 否则传输加密功能不可用。\n *\n * @param cryptoService - 传输加密服务实例(非对称 + 对称)\n * @param maxClients - 最大客户端数量(默认 10000),超过时淘汰最早注册的\n * @returns 成功返回传输加密管理器,密钥对生成失败时返回错误\n */\nexport function createTransportEncryption(\n cryptoService: TransportCryptoServiceLike,\n maxClients = 10000,\n): HaiResult<TransportEncryptionManager> {\n // 生成服务端密钥对\n const keyPairResult = cryptoService.asymmetric.generateKeyPair()\n if (!keyPairResult.success || !keyPairResult.data) {\n return err({ code: 'KIT_TRANSPORT_KEY_GENERATION_FAILED', message: kitM('kit_transportKeyGenerationFailed') })\n }\n const serverKeyPair: TransportKeyPair = keyPairResult.data\n\n // 客户端公钥存储:clientId → publicKey(Map 保持插入顺序,用于 LRU 淘汰)\n const clientKeys = new Map<string, string>()\n let clientIdCounter = 0\n\n return ok({\n getServerPublicKey(): string {\n return serverKeyPair.publicKey\n },\n\n registerClientKey(clientPublicKey: string): string {\n clientIdCounter++\n const clientId = `client_${clientIdCounter}_${Date.now()}`\n\n // LRU 淘汰:超过上限时移除最早注册的客户端\n if (clientKeys.size >= maxClients) {\n const oldestKey = clientKeys.keys().next().value\n if (oldestKey !== undefined) {\n clientKeys.delete(oldestKey)\n }\n }\n\n clientKeys.set(clientId, clientPublicKey)\n return clientId\n },\n\n getClientPublicKey(clientId: string): string | undefined {\n return clientKeys.get(clientId)\n },\n\n encryptResponse(clientId: string, data: string): EncryptedPayload {\n const clientPublicKey = clientKeys.get(clientId)\n if (!clientPublicKey) {\n throw new Error(kitM('kit_transportClientKeyNotFound'))\n }\n\n // 1. 生成随机对称密钥\n const symmetricKey = cryptoService.symmetric.generateKey()\n\n // 2. 对称加密内容\n const encResult = cryptoService.symmetric.encryptWithIV(data, symmetricKey)\n if (!encResult.success || !encResult.data) {\n throw new Error(kitM('kit_transportEncryptFailed'))\n }\n\n // 3. 非对称加密对称密钥(使用客户端公钥)\n const keyEncResult = cryptoService.asymmetric.encrypt(symmetricKey, clientPublicKey)\n if (!keyEncResult.success || !keyEncResult.data) {\n throw new Error(kitM('kit_transportEncryptKeyFailed'))\n }\n\n return {\n encryptedKey: keyEncResult.data,\n ciphertext: encResult.data.ciphertext,\n iv: encResult.data.iv,\n }\n },\n\n decryptRequest(payload: EncryptedPayload): string {\n // 1. 非对称解密对称密钥(使用服务端私钥)\n const keyDecResult = cryptoService.asymmetric.decrypt(payload.encryptedKey, serverKeyPair.privateKey)\n if (!keyDecResult.success || !keyDecResult.data) {\n throw new Error(kitM('kit_transportDecryptKeyFailed'))\n }\n\n // 2. 对称解密内容\n const decResult = cryptoService.symmetric.decryptWithIV(payload.ciphertext, keyDecResult.data, payload.iv)\n if (!decResult.success || typeof decResult.data !== 'string') {\n throw new Error(kitM('kit_transportDecryptFailed'))\n }\n\n return decResult.data\n },\n })\n}\n\n/**\n * 创建密钥交换端点处理器\n *\n * 返回一个标准的 POST 处理函数,用于接收客户端公钥并返回服务端公钥与 clientId。\n *\n * @param manager - 传输加密管理器\n * @returns POST 处理函数,可直接用于 SvelteKit +server.ts\n *\n * @example\n * ```ts\n * // src/routes/api/kit/key-exchange/+server.ts\n * import { keyExchangeHandler } from '$lib/server/transport'\n * export const POST = keyExchangeHandler\n * ```\n */\nexport function createKeyExchangeHandler(\n manager: TransportEncryptionManager,\n): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n try {\n const body = await request.json() as { clientPublicKey?: string }\n\n if (!body.clientPublicKey || typeof body.clientPublicKey !== 'string') {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportInvalidPayload') }),\n { status: 400, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n const clientId = manager.registerClientKey(body.clientPublicKey)\n const serverPublicKey = manager.getServerPublicKey()\n\n return new Response(\n JSON.stringify({ serverPublicKey, clientId }),\n { status: 200, headers: { 'Content-Type': 'application/json' } },\n )\n }\n catch {\n return new Response(\n JSON.stringify({ error: kitM('kit_transportKeyExchangeFailed') }),\n { status: 500, headers: { 'Content-Type': 'application/json' } },\n )\n }\n }\n}\n\n/**\n * 校验加密载荷格式是否合法\n *\n * @param payload - 待校验对象\n * @returns 是否为合法的 EncryptedPayload\n */\nexport function isValidEncryptedPayload(payload: unknown): payload is EncryptedPayload {\n if (typeof payload !== 'object' || payload === null)\n return false\n const p = payload as Record<string, unknown>\n return (\n typeof p.encryptedKey === 'string'\n && typeof p.ciphertext === 'string'\n && typeof p.iv === 'string'\n && p.encryptedKey.length > 0\n && p.ciphertext.length > 0\n && p.iv.length > 0\n )\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/kit-auth.ts","../src/client/kit-client.ts"],"names":["fetch","response"],"mappings":"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","file":"chunk-PHS7ZD5L.js","sourcesContent":["/**\n * @h-ai/kit — Bearer 认证工具\n *\n * 提供服务端认证 Cookie 管理(login / logout)与浏览器端 Token 存储工具。\n * @module kit-auth\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ApiKeyCredentials, AuthResult, LdapCredentials, OtpCredentials, PasswordCredentials, RegisterOptions } from '@h-ai/iam'\nimport type { HandleFetch } from '@sveltejs/kit'\nimport type { AuthOperations, AuthOperationsProvider } from './kit-types.js'\nimport process from 'node:process'\n\n/** 默认 Token Cookie 名 */\nconst DEFAULT_TOKEN_COOKIE_NAME = 'hai_access_token'\n\n/**\n * 应用级认证配置(由 createHandle 一次性初始化,生命周期同进程)\n *\n * 此状态非请求级:仅在 createHandle() 时写入一次,后续所有请求只读访问。\n */\nconst authState = {\n cookieName: DEFAULT_TOKEN_COOKIE_NAME,\n operations: null as AuthOperationsProvider | null,\n}\n\n/**\n * 配置认证参数\n *\n * 通常由 `createHandle` 在初始化时自动调用,无需手动调用。\n */\nexport function configureAuth(config: { cookieName?: string, operations?: AuthOperationsProvider }): void {\n if (config.cookieName)\n authState.cookieName = config.cookieName\n if (config.operations)\n authState.operations = config.operations\n}\n\n/**\n * 获取当前配置的 Token Cookie 名\n */\nexport function getTokenCookieName(): string {\n return authState.cookieName\n}\n\ninterface CookieReader {\n get: (name: string) => string | undefined\n}\n\ninterface CookieWriter {\n set: (name: string, value: string, options: {\n path: string\n httpOnly: boolean\n sameSite: 'lax' | 'strict' | 'none'\n secure: boolean\n maxAge?: number\n }) => void\n delete: (name: string, options: { path: string }) => void\n}\n\n/** 浏览器 Token 存储器 */\nexport interface BrowserTokenStore {\n get: () => string | null\n set: (token: string) => void\n clear: () => void\n}\n\nconst defaultBrowserTokenStore = createTokenStore()\n\n// ─── 内部工具(仅 kit 包内使用) ───\n\n/**\n * 从请求 Authorization 头提取 Bearer Token。\n */\nexport function getBearerTokenFromRequest(request: Request): string | null {\n const authorization = request.headers.get('authorization')\n if (!authorization)\n return null\n\n const [scheme, token] = authorization.split(' ')\n if (!scheme || !token)\n return null\n\n if (scheme.toLowerCase() !== 'bearer')\n return null\n\n const trimmed = token.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\n/**\n * 从请求中统一提取 Access Token(Bearer 优先,其次配置的 Cookie 名)。\n */\nexport function getAccessToken(request: Request, cookies?: CookieReader): string | null {\n return getBearerTokenFromRequest(request) ?? cookies?.get(authState.cookieName) ?? null\n}\n\n// ─── 服务端认证 Cookie 管理 ───\n\n/**\n * 写入 Access Token Cookie(内部使用,由 login 自动调用)。\n */\nfunction setToken(cookies: CookieWriter, token: string, maxAge?: number): void {\n cookies.set(authState.cookieName, token, {\n path: '/',\n httpOnly: true,\n sameSite: 'lax',\n secure: process.env.NODE_ENV === 'production',\n maxAge,\n })\n}\n\n/**\n * 清除 Access Token Cookie(内部使用,由 logout 自动调用)。\n */\nfunction clearToken(cookies: CookieWriter): void {\n cookies.delete(authState.cookieName, { path: '/' })\n}\n\n// ─── 服务端高级认证 API(通过 kit.auth 暴露) ───\n\n/**\n * 获取已注入的认证操作(未配置时抛出编程错误)\n */\nfunction getAuthOperations(): AuthOperations {\n if (!authState.operations) {\n throw new Error('kit.auth 未配置:请在 kit.createHandle() 中传入 auth.operations')\n }\n return typeof authState.operations === 'function'\n ? authState.operations()\n : authState.operations\n}\n\n/**\n * 内部工具:执行认证操作并在成功时写入 Token Cookie。\n */\nasync function executeLogin(\n cookies: CookieWriter,\n authPromise: Promise<HaiResult<AuthResult>>,\n): Promise<HaiResult<AuthResult>> {\n const result = await authPromise\n if (result.success) {\n setToken(cookies, result.data.tokens.accessToken, result.data.tokens.expiresIn)\n }\n return result\n}\n\n/**\n * 服务端登录(密码):内部调用 iam.auth.login,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - 密码凭证(identifier + password)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.login(cookies, { identifier, password })\n * if (!result.success) return kit.response.fromError(result.error, IamErrorHttpStatus)\n * const { user, roles, permissions } = result.data\n * ```\n */\nexport async function login(\n cookies: CookieWriter,\n credentials: PasswordCredentials,\n): Promise<HaiResult<AuthResult>> {\n return executeLogin(cookies, getAuthOperations().login(credentials))\n}\n\n/**\n * 服务端登录(OTP 验证码):内部调用 iam.auth.loginWithOtp,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - OTP 凭证(identifier + code)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithOtp(cookies, { identifier, code })\n * ```\n */\nexport async function loginWithOtp(\n cookies: CookieWriter,\n credentials: OtpCredentials,\n): Promise<HaiResult<AuthResult>> {\n return executeLogin(cookies, getAuthOperations().loginWithOtp(credentials))\n}\n\n/**\n * 服务端登录(LDAP):内部调用 iam.auth.loginWithLdap,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - LDAP 凭证(username + password)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithLdap(cookies, { username, password })\n * ```\n */\nexport async function loginWithLdap(\n cookies: CookieWriter,\n credentials: LdapCredentials,\n): Promise<HaiResult<AuthResult>> {\n return executeLogin(cookies, getAuthOperations().loginWithLdap(credentials))\n}\n\n/**\n * 服务端登录(API Key):内部调用 iam.auth.loginWithApiKey,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - API Key 凭证(key)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithApiKey(cookies, { key: apiKey })\n * if (!result.success) return kit.response.fromError(result.error, IamErrorHttpStatus)\n * ```\n */\nexport async function loginWithApiKey(\n cookies: CookieWriter,\n credentials: ApiKeyCredentials,\n): Promise<HaiResult<AuthResult>> {\n return executeLogin(cookies, getAuthOperations().loginWithApiKey(credentials))\n}\n\n/**\n * 服务端注册并登录:内部调用 iam.auth.registerAndLogin,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param options - 注册选项(username、password、email 等)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.registerAndLogin(cookies, { username, email, password })\n * ```\n */\nexport async function registerAndLogin(\n cookies: CookieWriter,\n options: RegisterOptions,\n): Promise<HaiResult<AuthResult>> {\n return executeLogin(cookies, getAuthOperations().registerAndLogin(options))\n}\n\n/**\n * 服务端登出:内部调用 iam.auth.logout 使会话失效,并清除 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param accessToken - 访问令牌(为 null/undefined 时仅清除 Cookie)\n *\n * @example\n * ```ts\n * await kit.auth.logout(cookies, locals.accessToken)\n * return kit.response.ok(null)\n * ```\n */\nexport async function logout(\n cookies: CookieWriter,\n accessToken?: string | null,\n): Promise<void> {\n if (accessToken) {\n await getAuthOperations().logout(accessToken)\n }\n clearToken(cookies)\n}\n\n// ─── 浏览器端 Token 存储(通过 kit.auth 暴露) ───\n\n/**\n * 创建浏览器端 Token 存储器(localStorage)。\n *\n * @param key - localStorage 键名,默认 `'hai_access_token'`\n */\nexport function createTokenStore(key = DEFAULT_TOKEN_COOKIE_NAME): BrowserTokenStore {\n return {\n get(): string | null {\n if (typeof window === 'undefined') {\n return null\n }\n return window.localStorage.getItem(key)\n },\n set(token: string): void {\n if (typeof window === 'undefined') {\n return\n }\n window.localStorage.setItem(key, token)\n },\n clear(): void {\n if (typeof window === 'undefined') {\n return\n }\n window.localStorage.removeItem(key)\n },\n }\n}\n\n/**\n * 写入浏览器端 Access Token。\n */\nexport function setBrowserToken(token: string): void {\n defaultBrowserTokenStore.set(token)\n}\n\n/**\n * 清除浏览器端 Access Token。\n */\nexport function clearBrowserToken(): void {\n defaultBrowserTokenStore.clear()\n}\n\n// ─── HandleFetch 工厂(通过 kit.auth 暴露) ───\n\n/**\n * 创建浏览器端同源请求自动附加 Access Token 的 HandleFetch。\n */\nexport function createHandleFetch(tokenStore: BrowserTokenStore = createTokenStore()): HandleFetch {\n return async ({ event, request, fetch }) => {\n const requestUrl = new URL(request.url)\n if (requestUrl.origin !== event.url.origin)\n return fetch(request)\n\n const token = tokenStore.get()\n if (!token)\n return fetch(request)\n\n const headers = new Headers(request.headers)\n headers.set('Authorization', `Bearer ${token}`)\n\n return fetch(new Request(request, { headers }))\n }\n}\n","/**\n * @h-ai/kit — 统一客户端\n *\n * 将 CSRF Token 附加与可选传输加密封装为统一 `apiFetch`。\n * 应用层只需调用一次 `createKitClient()`,后续 API 调用即可复用同一套安全能力。\n * @module kit-client\n */\n\nimport type { BrowserTokenStore } from '../kit-auth.js'\nimport type { EncryptedPayload, TransportCryptoServiceLike, TransportKeyPair } from '../modules/crypto/kit-crypto-types.js'\nimport { createTokenStore } from '../kit-auth.js'\nimport { isValidEncryptedPayload } from '../modules/crypto/kit-transport-encryption.js'\n\n// ─── 类型 ───\n\n/**\n * 传输加密客户端配置\n */\nexport interface ClientTransportConfig {\n /** 传输加密服务实例(@h-ai/crypto 的 asymmetric + symmetric) */\n crypto: TransportCryptoServiceLike\n /** 密钥交换端点 URL(默认 `'/api/kit/key-exchange'`) */\n keyExchangeUrl?: string\n}\n\n/**\n * Kit 客户端配置\n */\nexport interface KitClientConfig {\n /**\n * 传输加密配置。\n * - 不提供 / undefined:不启用传输加密,仅 CSRF\n * - 提供对象:启用传输加密\n */\n transport?: ClientTransportConfig\n /** CSRF Cookie 名称(默认 `'hai_csrf'`) */\n csrfCookieName?: string\n /** CSRF Header 名称(默认 `'X-CSRF-Token'`) */\n csrfHeaderName?: string\n /**\n * 认证配置:自动从浏览器存储读取 Access Token 并注入请求头。\n * - `true`:使用默认 localStorage 存储(key = `hai_access_token`)\n * - `BrowserTokenStore`:使用自定义存储\n * - 不提供 / `false`:不自动注入\n */\n auth?: boolean | BrowserTokenStore\n}\n\n/**\n * Kit 客户端实例\n */\nexport interface KitClient {\n /** 统一 API fetch(写请求自动附加 CSRF,启用 transport 时自动加解密) */\n apiFetch: (url: string, init?: RequestInit) => Promise<Response>\n /** 传输加密是否就绪(未启用传输加密时始终为 true) */\n readonly ready: boolean\n /** 手动触发密钥交换(transport 启用时) */\n init: () => Promise<void>\n /** 销毁密钥状态 */\n destroy: () => void\n}\n\n// ─── 工具函数 ───\n\n/**\n * 从 document.cookie 中读取指定名称的 Cookie 值\n *\n * @param name - Cookie 名称\n * @returns Cookie 值;不存在或运行在服务端时返回 undefined\n */\nfunction getCookie(name: string): string | undefined {\n if (typeof document === 'undefined')\n return undefined\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`))\n return match?.[1]\n}\n\n// ─── 主函数 ───\n\n/**\n * 创建 Kit 客户端\n *\n * 返回统一的 `apiFetch`,内部自动完成:\n * 1. CSRF Token 附加(写方法自动读取 Cookie + 设置 Header)\n * 2. 密钥交换(首次写请求时 lazy init,transport 启用时)\n * 3. 请求体加密(transport 启用时)\n * 4. 响应体解密(transport 启用时)\n *\n * @param config - 客户端配置\n * @returns KitClient 实例\n *\n * @example\n * ```ts\n * const client = createKitClient({ transport: { crypto } })\n * const res = await client.apiFetch('/api/users', { method: 'POST', body: '{}' })\n * ```\n */\nexport function createKitClient(config: KitClientConfig = {}): KitClient {\n const {\n transport: transportConfig,\n csrfCookieName = 'hai_csrf',\n csrfHeaderName = 'X-CSRF-Token',\n auth: authConfig,\n } = config\n\n // ── Auth token store ──\n const authStore: BrowserTokenStore | null = authConfig\n ? (authConfig === true ? createTokenStore() : authConfig)\n : null\n\n // ── 传输加密状态 ──\n let transportReady = false\n let clientKeyPair: TransportKeyPair | null = null\n let serverPublicKey: string | null = null\n let clientId: string | null = null\n /** 密钥交换锁,防止并发 init */\n let initPromise: Promise<void> | null = null\n\n /**\n * 执行密钥交换\n */\n async function doKeyExchange(): Promise<void> {\n if (!transportConfig)\n return\n\n const { crypto: cryptoService, keyExchangeUrl = '/api/kit/key-exchange' } = transportConfig\n\n // 1. 生成客户端非对称密钥对\n const keyPairResult = cryptoService.asymmetric.generateKeyPair()\n if (!keyPairResult.success || !keyPairResult.data) {\n throw new Error('Failed to generate client key pair')\n }\n clientKeyPair = keyPairResult.data\n\n // 2. 与服务端交换公钥\n const response = await fetch(keyExchangeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ clientPublicKey: clientKeyPair.publicKey }),\n })\n\n if (!response.ok) {\n throw new Error(`Key exchange failed: ${response.status}`)\n }\n\n const data = await response.json() as { serverPublicKey?: string, clientId?: string }\n if (!data.serverPublicKey || !data.clientId) {\n throw new Error('Invalid key exchange response')\n }\n\n serverPublicKey = data.serverPublicKey\n clientId = data.clientId\n transportReady = true\n }\n\n /**\n * 确保密钥交换完成(lazy init + 单例锁)\n */\n async function ensureTransportReady(): Promise<void> {\n if (transportReady)\n return\n if (!initPromise) {\n initPromise = doKeyExchange().finally(() => {\n initPromise = null\n })\n }\n await initPromise\n }\n\n /**\n * 加密请求体\n */\n function encryptBody(bodyText: string): string {\n if (!transportConfig || !serverPublicKey)\n return bodyText\n\n const { crypto: cryptoService } = transportConfig\n\n // 1. 生成随机对称密钥\n const symmetricKey = cryptoService.symmetric.generateKey()\n\n // 2. 对称加密内容\n const encResult = cryptoService.symmetric.encryptWithIV(bodyText, symmetricKey)\n if (!encResult.success || !encResult.data) {\n throw new Error('Request body encryption failed')\n }\n\n // 3. 非对称加密对称密钥\n const keyEncResult = cryptoService.asymmetric.encrypt(symmetricKey, serverPublicKey)\n if (!keyEncResult.success || !keyEncResult.data) {\n throw new Error('Symmetric key encryption failed')\n }\n\n const payload: EncryptedPayload = {\n encryptedKey: keyEncResult.data,\n ciphertext: encResult.data.ciphertext,\n iv: encResult.data.iv,\n }\n\n return JSON.stringify(payload)\n }\n\n /**\n * 解密响应体\n */\n async function decryptResponse(response: Response): Promise<Response> {\n if (!clientKeyPair || !transportConfig)\n return response\n\n const encryptedBody = await response.json() as unknown\n if (!isValidEncryptedPayload(encryptedBody))\n return response\n\n const { crypto: cryptoService } = transportConfig\n\n // 1. 非对称解密对称密钥\n const keyDecResult = cryptoService.asymmetric.decrypt(encryptedBody.encryptedKey, clientKeyPair.privateKey)\n if (!keyDecResult.success || !keyDecResult.data) {\n throw new Error('Response key decryption failed')\n }\n\n // 2. 对称解密内容\n const decResult = cryptoService.symmetric.decryptWithIV(encryptedBody.ciphertext, keyDecResult.data, encryptedBody.iv)\n if (!decResult.success || typeof decResult.data !== 'string') {\n throw new Error('Response body decryption failed')\n }\n\n return new Response(decResult.data, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n }\n\n /**\n * 统一 API fetch\n */\n async function apiFetch(url: string, init: RequestInit = {}): Promise<Response> {\n const method = (init.method ?? 'GET').toUpperCase()\n const isWriteMethod = !['GET', 'HEAD', 'OPTIONS'].includes(method)\n\n const headers = new Headers(init.headers)\n\n // ── Auth ──\n if (authStore) {\n const token = authStore.get()\n if (token) {\n headers.set('Authorization', `Bearer ${token}`)\n }\n }\n\n // ── CSRF ──\n if (isWriteMethod) {\n const csrfToken = getCookie(csrfCookieName)\n if (csrfToken) {\n headers.set(csrfHeaderName, csrfToken)\n }\n }\n\n // ── 传输加密 ──\n if (transportConfig) {\n await ensureTransportReady()\n\n if (clientId) {\n headers.set('X-Client-Id', clientId)\n }\n\n // 加密请求体(写方法且有 body 时)\n if (init.body !== undefined && init.body !== null) {\n const bodyText = typeof init.body === 'string' ? init.body : JSON.stringify(init.body)\n const encrypted = encryptBody(bodyText)\n headers.set('Content-Type', 'application/json')\n\n let response = await fetch(url, { ...init, headers, body: encrypted })\n\n // 解密响应\n if (response.headers.get('X-Encrypted') === 'true') {\n response = await decryptResponse(response)\n }\n\n return response\n }\n }\n\n // ── 发送 ──\n let response = await fetch(url, { ...init, headers })\n\n // ── 解密响应(GET/无 body 写请求也可能有加密响应) ──\n if (transportConfig && response.headers.get('X-Encrypted') === 'true') {\n response = await decryptResponse(response)\n }\n\n return response\n }\n\n return {\n apiFetch,\n get ready() { return !transportConfig || transportReady },\n async init() {\n if (transportConfig)\n await ensureTransportReady()\n },\n destroy() {\n clientKeyPair = null\n serverPublicKey = null\n clientId = null\n transportReady = false\n initPromise = null\n },\n }\n}\n"]}
|