From 00a0e58d81b0ffdaf73adcac300067777beb3bac Mon Sep 17 00:00:00 2001 From: Abner <22141172+Silentely@users.noreply.github.com> Date: Tue, 2 Jun 2026 22:50:26 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20docs:=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=E4=B8=8E=E5=AE=89=E5=85=A8=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E5=B9=B6=E6=89=A9=E5=B1=95=E6=B5=8B=E8=AF=95=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=B8=85=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新 CLAUDE.md、docs/ARCHITECTURE.md 中的模块与阶段状态,补充 verify-cookie/health/public-config/notifications 等新节点,并将基础设施阶段由规划中标注为进行中 - 完善 docs/SECURITY.md 的 BFF 代理层与 withAuth 中间件说明,明确 x-esim-key 注入、函数白名单校验以及 CORS/体验验证的统一错误格式化策略 - 更新 src/giffgaff/MODULE_ARCHITECTURE.md 的安全考虑条目,补充 cookie 有效性检查间隔、CSP/Helmet 策略、HTML sanitization(escapeHtml/escapeAttr)以及通过 BFF 代理转发的传输层防护细则 - 扩展 tests/CLAUDE.md 测试范围与表格结构,新增 modules、giffgaff、security 三类的独立测试文件清单,并补充 tests/setup.js 的全局初始化说明 - 调整脚本与模块文档:scripts/CLAUDE.md 新增部署与构建相关脚本清单;src/js/modules/CLAUDE.md 更新 CaptchaManager 集成说明与模块覆盖状态,补充 notification-service/browser-utils 等相关条目 --- CLAUDE.md | 16 ++++++--- docs/ARCHITECTURE.md | 11 ++++--- docs/SECURITY.md | 10 ++++++ scripts/CLAUDE.md | 12 +++++++ src/giffgaff/MODULE_ARCHITECTURE.md | 51 ++++++++++++++++------------- src/js/modules/CLAUDE.md | 6 ++-- tests/CLAUDE.md | 33 +++++++++++++++---- 7 files changed, 99 insertions(+), 40 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 0fef290..f6376bc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -87,8 +87,8 @@ graph TD D --> D1["logger.js / api-service.js"]; D --> D2["notification-manager.js / notification-service.js"]; D --> D3["html-sanitizer.js / secure-storage.js"]; - D --> D4["captcha-manager.js / i18n.js"]; - D --> D5["utils.js / performance-monitor.js"]; + D --> D4["captcha-manager.js / i18n.js / i18n-data.js"]; + D --> D5["utils.js / performance-monitor.js / browser-utils.js"]; D --> D6["config.js / app-config.js / footer.js"]; E --> E1["giffgaff-token-exchange.js"]; @@ -97,7 +97,13 @@ graph TD E --> E4["giffgaff-sms-activate.js"]; E --> E5["giffgaff-mfa-validation.js"]; E --> E6["auto-activate-esim.js"]; - E --> E7["_shared/middleware.js"]; + E --> E7["verify-cookie.js"]; + E --> E8["health.js"]; + E --> E9["public-config.js"]; + E --> E10["notifications.js"]; + E --> E11["notifications-internal.js"]; + E --> E12["_shared/middleware.js"]; + E --> E13["_shared/internal-headers.js"]; F --> F1["bff-proxy.js"]; F --> F2["markdown-negotiation.js"]; @@ -122,7 +128,7 @@ graph TD | **通用工具** | `src/js/modules/` | 可复用前端工具模块 (日志/存储/安全/性能/i18n) | JavaScript | | **Netlify Functions** | `netlify/functions/` | Serverless 后端逻辑 (11 个函数) | JavaScript (Node.js) | | **Edge Functions** | `netlify/edge-functions/` | BFF 代理层 (密钥注入 + 请求转发 + 内容协商) | JavaScript (Deno) | -| **构建脚本** | `scripts/` | 构建、质量检查、安全扫描 (22 个脚本) | JavaScript/Shell | +| **构建脚本** | `scripts/` | 构建、质量检查、安全扫描 (23 个脚本) | JavaScript/Shell | | **测试** | `tests/` | 单元测试 (Jest + jsdom) | JavaScript | | **文档** | `docs/` | 使用指南、API 参考、修复记录 | Markdown | @@ -187,7 +193,7 @@ npm run test:coverage # 生成覆盖率报告 - **框架**: Jest 30.3.0 + jsdom 环境 - **覆盖率阈值**: 60% (branches/functions/lines/statements) -- **测试文件**: `tests/giffgaff/` 和 `tests/simyo/` +- **测试文件**: `tests/modules/`、`tests/giffgaff/`、`tests/simyo/` 和 `tests/security/` - **Mock**: `tests/__mocks__/` (styleMock, fileMock) - **运行**: `npm test` / `npm run test:coverage` diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index fc7cda3..a1da51d 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -45,7 +45,10 @@ eSIM-Tools 是一个 Web 应用,用于管理 Giffgaff 和 Simyo 运营商的 e │ giffgaff-token-exchange.js giffgaff-graphql.js │ │ giffgaff-mfa-challenge.js giffgaff-sms-activate.js │ │ giffgaff-mfa-validation.js auto-activate-esim.js │ -│ _shared/middleware.js │ +│ verify-cookie.js health.js │ +│ public-config.js notifications.js │ +│ notifications-internal.js │ +│ _shared/middleware.js _shared/internal-headers.js │ └─────────────────────────────────────────────────────────┘ ``` @@ -128,10 +131,10 @@ eSIM-Tools 是一个 Web 应用,用于管理 Giffgaff 和 Simyo 运营商的 e - 改进错误处理 - 添加验证中间件 -### 阶段 2: 基础设施 (规划中) +### 阶段 2: 基础设施 (进行中) +- ✅ Sentry 监控 (前后端) +- ✅ 内存级速率限制 (`_shared/rate-limiter.js`) - 添加 Redis 缓存 -- 实现速率限制 -- 设置监控 (Sentry, LogRocket) - 添加端到端测试 > 更多未来架构规划请参考 [FUTURE_ARCHITECTURE.md](./FUTURE_ARCHITECTURE.md) diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 4cca8e2..95ecb40 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -23,6 +23,16 @@ ### 2. 服务器安全 +#### BFF 代理层 (Edge Functions) +- 所有前端 `/bff/*` 请求经过 Edge Functions 代理 +- ACCESS_KEY 在服务端注入 (`x-esim-key` 头),前端不接触密钥 +- 目标函数白名单校验,仅允许转发到 `/.netlify/functions/*` + +#### withAuth 中间件 +- 所有受保护的 Netlify Functions 通过 `withAuth` 包装 +- 统一处理 CORS 来源校验、请求体验证、错误格式化 +- 内部函数互调通过 `x-esim-key` 或 `x-app-key` 头传递密钥 + #### Helmet安全头 ```javascript const helmet = require('helmet'); diff --git a/scripts/CLAUDE.md b/scripts/CLAUDE.md index 2082507..f713a80 100644 --- a/scripts/CLAUDE.md +++ b/scripts/CLAUDE.md @@ -55,6 +55,7 @@ | `logger.js` | 构建日志模块 (彩色输出) | | `replace-console-log.js` | 替换 console.log | | `update-script-logging.js` | 更新脚本日志 | +| `generate-agent-metadata.js` | 生成 AI Agent 元数据 | | `apply-middleware.sh` | 应用中间件 | | `start_simyo_server.sh/.bat` | 启动 Simyo 代理服务器 | @@ -72,13 +73,24 @@ npm run compress # 资源压缩 ## 相关文件清单 - `scripts/build-static.js` +- `scripts/transpile-dist-js.js` +- `scripts/inject-sentry-config.js` - `scripts/quality-check.js` - `scripts/security-check.js` - `scripts/deploy-prepare.js` +- `scripts/deploy-analyze.js` - `scripts/test-deploy-config.js` +- `scripts/deploy.sh` - `scripts/optimize-images.js` - `scripts/compress.js` - `scripts/logger.js` +- `scripts/replace-console-log.js` +- `scripts/update-script-logging.js` - `scripts/pre-commit-check.js` - `scripts/pre-push-check.js` - `scripts/commit-msg-lint.js` +- `scripts/prepare-commit-msg.js` +- `scripts/generate-agent-metadata.js` +- `scripts/apply-middleware.sh` +- `scripts/start_simyo_server.sh` +- `scripts/start_simyo_server.bat` diff --git a/src/giffgaff/MODULE_ARCHITECTURE.md b/src/giffgaff/MODULE_ARCHITECTURE.md index 44ca793..9651087 100644 --- a/src/giffgaff/MODULE_ARCHITECTURE.md +++ b/src/giffgaff/MODULE_ARCHITECTURE.md @@ -438,19 +438,24 @@ API调用 (原始错误) ## 🔐 安全考虑 ### 1. 敏感数据处理 -- Access Token仅存储在内存和localStorage -- Cookie不在代码中硬编码 -- 定期检查Cookie有效性 +- Access Token 仅存储在内存和 localStorage +- Cookie 不在代码中硬编码 +- 定期检查 Cookie 有效性 (cookie-handler.js 5 分钟间隔) -### 2. XSS防护 +### 2. XSS 防护 - 使用 `textContent` 而非 `innerHTML`(除非必要) -- CSP策略限制脚本来源 -- 用户输入验证 +- CSP 策略限制脚本来源 (HTML meta 标签 + server.js Helmet) +- 通用工具模块 `html-sanitizer.js` 提供 `escapeHtml` / `escapeAttr` -### 3. CSRF防护 -- 使用PKCE流程 -- State参数验证 -- Turnstile人机验证 +### 3. CSRF 防护 +- 使用 PKCE 流程 +- State 参数验证 +- reCAPTCHA 人机验证 (可选,通过 `captcha-manager.js` 集成) + +### 4. 传输层防护 +- 所有 API 请求通过 BFF 代理层 (Edge Functions) 转发 +- ACCESS_KEY 仅在服务端注入,前端不接触密钥 +- `withAuth` 中间件统一处理鉴权和 CORS 校验 ## 📈 扩展性设计 @@ -511,35 +516,35 @@ import { StateManager } from './state-manager.js'; describe('StateManager', () => { let manager; - + beforeEach(() => { manager = new StateManager(); localStorage.clear(); }); - + test('应该正确保存和恢复会话', () => { manager.setState({ accessToken: 'test-token' }); manager.saveSession(); - + const newManager = new StateManager(); const restored = newManager.loadSession(); - + expect(restored).toBe(true); expect(newManager.get('accessToken')).toBe('test-token'); }); - + test('应该在超时后清除会话', () => { manager.setState({ accessToken: 'test-token' }); manager.saveSession(); - + // 模拟超时 const sessionData = JSON.parse(localStorage.getItem('giffgaff_session')); sessionData.timestamp = Date.now() - (3 * 60 * 60 * 1000); // 3小时前 localStorage.setItem('giffgaff_session', JSON.stringify(sessionData)); - + const newManager = new StateManager(); const restored = newManager.loadSession(); - + expect(restored).toBe(false); }); }); @@ -558,11 +563,11 @@ describe('OAuth Flow', () => { const loginResult = await oauthHandler.startOAuthLogin(); expect(loginResult.success).toBe(true); expect(stateManager.get('codeVerifier')).toBeTruthy(); - + // 2. 模拟回调 const mockCallback = 'giffgaff://auth/callback/?code=TEST&state=STATE'; const callbackResult = await oauthHandler.processCallback(mockCallback); - + expect(callbackResult.success).toBe(true); expect(stateManager.get('accessToken')).toBeTruthy(); }); @@ -615,6 +620,6 @@ try { --- -**文档版本:** 1.0.0 -**最后更新:** 2025-10-31 -**维护者:** eSIM Tools Team \ No newline at end of file +**文档版本:** 1.0.0 +**最后更新:** 2025-10-31 +**维护者:** eSIM Tools Team diff --git a/src/js/modules/CLAUDE.md b/src/js/modules/CLAUDE.md index b9511bb..3155b50 100644 --- a/src/js/modules/CLAUDE.md +++ b/src/js/modules/CLAUDE.md @@ -11,7 +11,7 @@ | 模块 | 文件 | 职责 | |------|------|------| | **Logger** | `logger.js` | 环境感知日志 (生产环境自动禁用 console.log) | -| **CaptchaManager** | `captcha-manager.js` | 验证码集成 (Turnstile/reCAPTCHA),自动刷新 | +| **CaptchaManager** | `captcha-manager.js` | 验证码集成 (reCAPTCHA),自动刷新 | | **API Service** | `api-service.js` | 统一 HTTP 客户端 (重试/缓存/去重) | | **HTML Sanitizer** | `html-sanitizer.js` | XSS 防护 (escapeHtml/escapeAttr) | | **Secure Storage** | `secure-storage.js` | 加密 localStorage (TTL 过期) | @@ -54,7 +54,7 @@ element.innerHTML = sanitizeHTML(userInput); ## 测试与质量 - 所有模块设计为可测试 (ES6 import/export) -- 无独立测试文件,通过业务模块测试间接覆盖 +- 已有独立测试: `tests/modules/` 覆盖 logger、utils、html-sanitizer、secure-storage、api-service、app-config ## 相关文件清单 @@ -72,4 +72,6 @@ element.innerHTML = sanitizeHTML(userInput); - `src/js/modules/sentry-init.js` - `src/js/modules/utils.js` - `src/js/modules/config.js` +- `src/js/modules/notification-service.js` +- `src/js/modules/browser-utils.js` - `src/js/middleware/validation.js` diff --git a/tests/CLAUDE.md b/tests/CLAUDE.md index ece0ae0..c5ca6df 100644 --- a/tests/CLAUDE.md +++ b/tests/CLAUDE.md @@ -4,7 +4,7 @@ ## 模块职责 -提供单元测试,覆盖 Giffgaff 和 Simyo 前端模块的核心逻辑。 +提供单元测试,覆盖通用工具模块、Giffgaff/Simyo 业务模块和安全校验逻辑。 ## 测试框架 @@ -16,11 +16,21 @@ ## 测试文件 -| 文件 | 覆盖模块 | 测试项 | -|------|----------|--------| -| `simyo/help.test.js` | Simyo 帮助文档 | 帮助内容渲染 | -| `simyo/simyo-app-device-change.test.js` | `SimyoApp` | 设备更换流程 | -| `simyo/device-change-handler.test.js` | 设备更换处理 | 设备更换逻辑 | +| 目录 | 文件 | 覆盖模块 | 测试项 | +|------|------|----------|--------| +| **modules/** | `app-config.test.js` | App Config | 环境配置管理 | +| | `logger.test.js` | Logger | 日志输出与脱敏 | +| | `utils.test.js` | Utils | 工具函数 (debounce/throttle 等) | +| | `html-sanitizer.test.js` | HTML Sanitizer | XSS 防护 (escapeHtml/escapeAttr) | +| | `secure-storage.test.js` | Secure Storage | 加密 localStorage (TTL 过期) | +| | `api-service.test.js` | API Service | HTTP 客户端 (重试/缓存/去重) | +| **simyo/** | `help.test.js` | Simyo 帮助文档 | 帮助内容渲染 | +| | `simyo-app-device-change.test.js` | `SimyoApp` | 设备更换流程 | +| | `device-change-handler.test.js` | 设备更换处理 | 设备更换逻辑 | +| **giffgaff/** | `direct-fetch.test.js` | Giffgaff 直接请求 | Fetch 调用逻辑 | +| **security/** | `bff-proxy.test.js` | BFF Proxy | Edge Function 安全校验 | +| | `functions-auth.test.js` | Functions Auth | withAuth 中间件鉴权 | +| | `server-routes.test.js` | Server Routes | 本地开发服务器路由 | ## 运行方式 @@ -41,6 +51,7 @@ npm run test:coverage # 生成覆盖率报告 - `styleMock.js`: CSS 导入 mock (返回空对象) - `fileMock.js`: 静态文件导入 mock (返回文件名字符串) +- `setup.js`: 全局 setup 文件,在每个测试前初始化 jsdom 环境 ## 相关文件清单 @@ -48,6 +59,16 @@ npm run test:coverage # 生成覆盖率报告 - `tests/setup.js` - 测试设置 - `tests/__mocks__/styleMock.js` - `tests/__mocks__/fileMock.js` +- `tests/modules/app-config.test.js` +- `tests/modules/logger.test.js` +- `tests/modules/utils.test.js` +- `tests/modules/html-sanitizer.test.js` +- `tests/modules/secure-storage.test.js` +- `tests/modules/api-service.test.js` - `tests/simyo/help.test.js` - `tests/simyo/simyo-app-device-change.test.js` - `tests/simyo/device-change-handler.test.js` +- `tests/giffgaff/direct-fetch.test.js` +- `tests/security/bff-proxy.test.js` +- `tests/security/functions-auth.test.js` +- `tests/security/server-routes.test.js`