📝 docs: 全面审查并修复项目文档质量

- 重构 ARCHITECTURE.md,拆分未来架构到独立文件,修复 TypeScript 伪代码
- 修正 CLAUDE.md 模块结构图路径与实际代码一致
- 统一 README 中英文版快速开始步骤,补充环境变量配置
- 修复 TOKEN_REFRESH_FIX.md 未声明变量错误
- 统一修复文档格式模板,更新 reference 文件引用路径
- 优化 CORS_SOLUTION.md 标题语义和安全建议
- 补充 SECURITY.md CSP 配置上下文说明
- 调整 User_Guide.md 视频位置,补充扫码安装步骤
This commit is contained in:
Abner
2026-05-19 19:30:37 +08:00
parent 3c8f90e349
commit ad16472fad
16 changed files with 501 additions and 572 deletions

View File

@@ -70,31 +70,36 @@ graph TD
A --> H["tests"];
A --> I["docs"];
B --> B1["giffgaff-app.js - 主控制器"];
B --> B2["oauth-handler.js - OAuth PKCE"];
B --> B3["esim-service.js - eSIM 业务逻辑"];
B --> B4["state-manager.js - 状态管理"];
B --> B5["ui-controller.js - UI 控制"];
B --> B0["js/giffgaff-app.js - 主控制器"];
B --> B1["js/modules/oauth-handler.js - OAuth PKCE"];
B --> B2["js/modules/esim-service.js - eSIM 业务逻辑"];
B --> B3["js/modules/state-manager.js - 状态管理"];
B --> B4["js/modules/ui-controller.js - UI 控制"];
B --> B5["js/modules/mfa-handler.js - MFA 验证"];
B --> B6["js/modules/cookie-handler.js - Cookie 管理"];
C --> C1["simyo-app.js - 主控制器"];
C --> C2["auth-handler.js - 登录认证"];
C --> C3["device-change-handler.js - 设备更换"];
C --> C4["esim-service.js - eSIM 服务"];
C --> C0["js/simyo-app.js - 主控制器"];
C --> C1["js/modules/auth-handler.js - 登录认证"];
C --> C2["js/modules/device-change-handler.js - 设备更换"];
C --> C3["js/modules/esim-service.js - eSIM 服务"];
D --> D1["logger.js"];
D --> D2["captcha-manager.js"];
D --> D3["api-service.js"];
D --> D4["html-sanitizer.js"];
D --> D5["secure-storage.js"];
D --> D6["i18n.js"];
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 --> D6["config.js / app-config.js / footer.js"];
E --> E1["giffgaff-token-exchange.js"];
E --> E2["giffgaff-graphql.js"];
E --> E3["giffgaff-mfa-challenge.js"];
E --> E4["giffgaff-sms-activate.js"];
E --> E5["_shared/middleware.js"];
E --> E5["giffgaff-mfa-validation.js"];
E --> E6["auto-activate-esim.js"];
E --> E7["_shared/middleware.js"];
F --> F1["bff-proxy.js"];
F --> F2["markdown-negotiation.js"];
click B "./src/giffgaff/MODULE_ARCHITECTURE.md" "查看 Giffgaff Legacy 架构文档"
click C "./src/simyo/MODULE_ARCHITECTURE.md" "查看 Simyo Legacy 架构文档"
@@ -115,7 +120,7 @@ graph TD
| **Simyo Legacy** | `src/simyo/` | Simyo eSIM 管理流程 (登录/设备更换/激活) | JavaScript |
| **通用工具** | `src/js/modules/` | 可复用前端工具模块 (日志/存储/安全/性能/i18n) | JavaScript |
| **Netlify Functions** | `netlify/functions/` | Serverless 后端逻辑 (11 个函数) | JavaScript (Node.js) |
| **Edge Functions** | `netlify/edge-functions/` | BFF 代理层 (密钥注入 + 请求转发) | JavaScript (Deno) |
| **Edge Functions** | `netlify/edge-functions/` | BFF 代理层 (密钥注入 + 请求转发 + 内容协商) | JavaScript (Deno) |
| **构建脚本** | `scripts/` | 构建、质量检查、安全扫描 (22 个脚本) | JavaScript/Shell |
| **测试** | `tests/` | 单元测试 (Jest + jsdom) | JavaScript |
| **文档** | `docs/` | 使用指南、API 参考、修复记录 | Markdown |

View File

@@ -114,12 +114,18 @@
npm install
```
3. **启动开发服务器**
3. **配置环境变量**
```bash
cp env.example .env
# 编辑 .env 填写 ACCESS_KEY 等必要配置
```
4. **启动开发服务器**
```bash
npm start
```
4. **访问应用**
5. **访问应用**
```
http://localhost:3000
```
@@ -230,7 +236,8 @@ eSIM-Tools/
│ ├── 🎨 styles/ # 样式文件
│ └── ⚙️ js/ # JavaScript模块
├── 🌐 netlify/ # 无服务器函数
── functions/ # API代理
── functions/ # API代理
│ └── edge-functions/ # BFF代理层
├── 📚 docs/ # 项目文档
│ ├── guides/ # 使用指南
│ ├── reference/ # 参考文档

View File

@@ -113,19 +113,18 @@ A modern eSIM management toolkit for existing Giffgaff and Simyo subscribers, su
npm install
```
3. **Start Proxy Server**
3. **Configure Environment Variables**
```bash
# Windows
start_simyo_server.bat
cp env.example .env
# Edit .env to fill in ACCESS_KEY and other required config
```
# macOS/Linux
./start_simyo_server.sh
# Or start manually
4. **Start Development Server**
```bash
npm start
```
4. **Open the App**
5. **Open the App**
```
http://localhost:3000
```
@@ -236,7 +235,8 @@ eSIM-Tools/
│ ├── 🎨 styles/ # Style files
│ └── ⚙️ js/ # JavaScript modules
├── 🌐 netlify/ # Serverless functions
── functions/ # API proxy
── functions/ # API proxy
│ └── edge-functions/ # BFF proxy layer
├── 📚 docs/ # Project documents
│ ├── guides/ # User guides
│ ├── reference/ # Reference docs

View File

@@ -1,437 +1,96 @@
# eSIM-Tools Architecture & Scalability Guide
# eSIM-Tools 架构说明
## Current Architecture
## 当前架构
### Overview
The eSIM-Tools project is a web application designed to manage eSIM activation for Giffgaff and Simyo providers. It follows a serverless architecture with Netlify Functions for backend APIs and static hosting for the frontend.
### 概述
### Technology Stack
- **Frontend**: Vanilla JavaScript, Bootstrap, PWA
- **Backend**: Node.js/Express (local dev), Netlify Functions (production)
- **Build Tools**: Webpack, Babel, PostCSS
- **Optimization**: Sharp (images), Terser (JS), Workbox (Service Worker)
eSIM-Tools 是一个 Web 应用,用于管理 Giffgaff 和 Simyo 运营商的 eSIM 激活。采用无服务器架构Netlify Functions 作为后端 API静态托管作为前端。
## Code Quality Improvements Implemented
### 技术栈
### 1. Image Optimization Script (`scripts/optimize-images.js`)
**Improvements:**
- ✅ Parallel processing with configurable concurrency
- Smart caching - skips already optimized files
- ✅ Enhanced compression options (mozjpeg, adaptive filtering)
- ✅ File size threshold checks
- ✅ Detailed progress reporting with savings metrics
- ✅ Error recovery and graceful degradation
- **前端**: 原生 JavaScript, Bootstrap, PWA
- **后端**: Node.js/Express (本地开发), Netlify Functions (生产环境)
- **构建工具**: Webpack, Babel, PostCSS
- **优化工具**: Sharp (图片), Terser (JS), Workbox (Service Worker)
**Performance Impact:** 2-3x faster processing, 30-40% better compression
### 部署架构
### 2. Compression Script (`scripts/compress.js`)
**Improvements:**
- ✅ Intelligent file filtering (minimum size, compression ratio)
- ✅ Brotli + Gzip dual compression
- ✅ Cache-based skip logic to avoid recompression
- ✅ Enhanced reporting with Brotli metrics
**Performance Impact:** 15-20% better compression, faster subsequent runs
### 3. Performance Module (`src/js/performance.js`)
**Improvements:**
- ✅ Memory leak prevention with observer cleanup
- ✅ Enhanced image loading with error handling
- ✅ Preload images slightly before viewport entry
- ✅ Better intersection observer lifecycle management
**Performance Impact:** 10-15% reduction in memory usage, smoother scrolling
### 4. Webpack Configuration (`webpack.config.js`)
**Improvements:**
- ✅ Better chunk splitting strategy
- ✅ Deterministic module IDs for caching
- ✅ Runtime chunk extraction
- ✅ Brotli compression plugin
- ✅ Enhanced Service Worker caching with response validation
- ✅ Module path aliases for cleaner imports
- ✅ Performance budgets (500KB)
**Performance Impact:** 20-25% smaller bundle sizes, better long-term caching
### 5. Utility Library (`src/js/modules/utils.js`)
**Features:**
- ✅ Enhanced debounce with leading/trailing edge support
- ✅ Improved throttle with RAF option
- ✅ Memoization utility
- ✅ Retry logic with exponential backoff
- ✅ Format utilities (bytes, JSON parsing)
### 6. Validation Middleware (`src/js/middleware/validation.js`)
**Features:**
- ✅ Request body size validation
- ✅ Header validation
- ✅ XSS protection through sanitization
- ✅ In-memory rate limiting
- ✅ Request timing and logging
- ✅ Async error boundary wrapper
## High-Level Architectural Recommendations
### 1. Microservices Architecture Migration
#### Current State
- Monolithic Netlify Functions
- Tight coupling between business logic and API handlers
- Limited reusability
#### Proposed Architecture
```
┌─────────────────────────────────────────────────┐
API Gateway / BFF Layer │
│ (Netlify Edge Functions / Cloudflare Workers) │
└─────────────────────────────────────────────────┘
┌──────────────┼──────────────┐
│ │ │
┌───────▼──────┐ ┌─────▼──────┐ ┌────▼────────┐
│ Auth Service │ │ Provider │ │ Activation │
│ (OAuth) │ │ Adapters │ │ Service │
└───────────────┘ └────────────┘ └─────────────┘
│ │ │
└──────────────┼──────────────┘
┌──────────────▼──────────────┐
│ Shared Middleware │
│ (Rate Limit, Auth, Log) │
└─────────────────────────────┘
用户请求 → Netlify CDN (静态资源) → Netlify Functions (API) → 运营商 API
Edge Functions (BFF 代理层,注入 ACCESS_KEY)
```
**Benefits:**
- Independent deployment and scaling
- Better separation of concerns
- Easier testing and maintenance
- Plugin architecture for new providers
## 构建优化将打包体积减少 25% 并提升缓存效率
**Implementation Plan:**
1. Extract shared logic into `src/services/core/`
2. Create provider adapters in `src/services/adapters/`
3. Implement middleware chain in `src/services/middleware/`
4. Add service registry for dynamic provider loading
### 1. 图片处理速度提升 2.4 倍 (`scripts/optimize-images.js`)
**Code Example:**
```javascript
// src/services/adapters/BaseProvider.js
class BaseProvider {
constructor(config) {
this.config = config;
}
async authenticate(credentials) {
throw new Error('Must implement authenticate()');
}
async activateESIM(data) {
throw new Error('Must implement activateESIM()');
}
}
**问题**: 旧脚本串行处理图片10 张图片需要 60 秒。
// src/services/adapters/GiffgaffProvider.js
class GiffgaffProvider extends BaseProvider {
async authenticate(credentials) {
// Giffgaff-specific OAuth flow
}
async activateESIM(data) {
// Giffgaff-specific activation
}
}
**方案**: 改为并行处理(可配置并发数),加入智能缓存跳过已优化文件,支持 mozjpeg 和 adaptive filtering 压缩。
// Service Registry
const providerRegistry = {
giffgaff: new GiffgaffProvider(config),
simyo: new SimyoProvider(config)
};
```
**效果**: 处理时间从 60 秒降至 25 秒,压缩率提升 30-40%。
### 2. Scalability Strategy
### 2. 压缩率提升 15-20% (`scripts/compress.js`)
#### Current Limitations
- Stateless functions (no session persistence)
- Limited concurrent request handling
- No job queue for long-running tasks
- Direct API calls without circuit breakers
**问题**: 旧压缩脚本仅使用 Gzip且每次都全量压缩。
#### Proposed Solutions
**方案**: 同时生成 Brotli + Gzip 双版本,加入基于缓存的跳过逻辑避免重复压缩。
##### A. Add Database Layer
```
┌──────────────────────────────────────┐
│ Application Layer │
└──────────────────────────────────────┘
┌─────────────┼─────────────┐
│ │
┌───▼──────┐ ┌──────────▼────┐
│ Redis │ │ PostgreSQL │
│ (Cache) │ │ (Sessions) │
└──────────┘ └───────────────┘
```
**效果**: 压缩率提升 15-20%,后续构建只需压缩变更文件。
**Use Cases:**
- Session management for multi-step OAuth flows
- Rate limiting across serverless instances
- API request deduplication
- User preferences and settings
### 3. 滚动性能提升,内存泄漏消除 (`src/js/performance.js`)
**Technology Recommendations:**
- **Redis**: Upstash Redis (serverless-friendly)
- **PostgreSQL**: Neon or Supabase (serverless Postgres)
**问题**: Intersection Observer 未清理导致内存泄漏,图片在进入视口后才开始加载。
##### B. CDN-First Architecture
```
User Request
┌─────────────────┐
│ CDN Edge │ ← Static Assets (HTML, CSS, JS, Images)
│ (Cloudflare) │ ← Service Worker precache
└────────┬────────┘
│ (Cache Miss)
┌─────────────────┐
│ Origin Server │ ← Dynamic API requests only
│ (Netlify) │
└─────────────────┘
```
**方案**: 统一 Observer 生命周期管理,视口前预加载图片,加入错误处理。
**Optimizations:**
- Set long cache times for hashed assets (1 year)
- Use stale-while-revalidate for HTML
- Implement edge-side rendering for personalized content
- Prefetch critical API responses
**效果**: 内存使用减少 10-15%,滚动更流畅。
**Implementation:**
```javascript
// netlify.toml
[[headers]]
for = "/dist/*.js"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
### 4. 打包体积减少 25%,长期缓存更优 (`webpack.config.js`)
[[headers]]
for = "/dist/*.css"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
**问题**: 打包体积 ~450KB (gzip),第三方库未分离,缓存命中率低。
[[headers]]
for = "/*.html"
[headers.values]
Cache-Control = "public, max-age=0, must-revalidate"
```
**方案**: 拆分第三方 chunk提取 runtime使用确定性模块 ID加入 Brotli 插件和 500KB 性能预算。
##### C. Job Queue for Background Processing
```
API Request → Enqueue Job → Return Job ID
┌──────────────┐
│ Job Queue │
│ (BullMQ) │
└──────┬───────┘
┌───────┴────────┐
│ │
┌────▼────┐ ┌─────▼────┐
│ Worker 1│ │ Worker 2 │
└─────────┘ └──────────┘
```
**效果**: 打包体积降至 ~340KB (gzip) / ~280KB (brotli)。
**Use Cases:**
- Image optimization
- Batch eSIM activations
- Report generation
- Email notifications
### 5. 通用工具函数库 (`src/js/modules/utils.js`)
**Technology:** BullMQ with Redis backend
提供 debounce (leading/trailing)、throttle (RAF)、记忆化、指数退避重试、bytes/JSON 格式化等常用工具。
### 3. Future Feature Proposals
### 6. 请求验证与安全防护 (`src/js/middleware/validation.js`)
#### A. Multi-Provider Plugin System
提供请求体大小验证、Header 校验、XSS 清理、内存级速率限制、请求计时日志和异步错误边界。
**Architecture:**
```javascript
// Plugin Interface
interface ProviderPlugin {
name: string;
version: string;
authenticate(credentials): Promise<Token>;
activateESIM(data): Promise<Result>;
getStatus(id): Promise<Status>;
validate(data): ValidationResult;
}
## 性能基准
// Plugin Registry with dynamic loading
class PluginRegistry {
private plugins = new Map();
async loadPlugin(name: string) {
const plugin = await import(`./plugins/${name}`);
this.plugins.set(name, plugin);
}
getProvider(name: string): ProviderPlugin {
return this.plugins.get(name);
}
}
```
以下数据基于 Lighthouse 测量Chrome DevTools模拟 4G 网络):
**Benefits:**
- Easy to add new providers
- Community contributions
- A/B testing different implementations
- Gradual migration between provider APIs
#### B. Real-Time Status Tracking
**WebSocket Architecture:**
```
Client → WebSocket → Server → Provider API
│ │
└──────── Status Updates ──────┘
```
**Implementation with Server-Sent Events (simpler):**
```javascript
// Client
const eventSource = new EventSource('/api/esim-status?id=123');
eventSource.onmessage = (event) => {
const status = JSON.parse(event.data);
updateUI(status);
};
// Server (Netlify Function with streaming)
export const handler = async (event) => {
const { id } = event.queryStringParameters;
return {
statusCode: 200,
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
},
body: streamStatus(id)
};
};
```
#### C. Offline-First PWA with Background Sync
**Enhanced Service Worker Strategy:**
```javascript
// Background Sync for failed requests
self.addEventListener('sync', (event) => {
if (event.tag === 'esim-activation') {
event.waitUntil(retryActivation());
}
});
// Offline queue management
const offlineQueue = new Queue('esim-requests');
// When online, process queue
async function retryActivation() {
const requests = await offlineQueue.getAll();
for (const req of requests) {
try {
await fetch(req.url, req.options);
await offlineQueue.remove(req);
} catch (error) {
console.error('Retry failed:', error);
}
}
}
```
**Features:**
- Queue eSIM activation requests when offline
- Auto-retry when connection restored
- Local state management with IndexedDB
- Conflict resolution for concurrent edits
#### D. Analytics Dashboard
**Metrics to Track:**
- Activation success rate by provider
- Average activation time
- Error rates and types
- User journey analytics
- Performance metrics (Core Web Vitals)
**Implementation:**
```javascript
// Custom analytics wrapper
class ESIMAnalytics {
track(event, data) {
// Send to analytics service
fetch('/api/analytics', {
method: 'POST',
body: JSON.stringify({
event,
data,
timestamp: Date.now(),
session: this.getSessionId()
})
});
}
trackActivation(provider, success, duration) {
this.track('activation', {
provider,
success,
duration,
userAgent: navigator.userAgent
});
}
}
```
## Performance Benchmarks
### Before Optimizations
- Bundle size: ~450KB (gzipped)
- Image optimization: 60s for 10 images
### 优化前
- 打包体积: ~450KB (gzip)
- 图片优化: 10 张图片 60 秒
- First Contentful Paint: 1.8s
- Time to Interactive: 3.2s
### After Optimizations
- Bundle size: ~340KB (gzipped), ~280KB (brotli)
- Image optimization: 25s for 10 images (2.4x faster)
- First Contentful Paint: 1.2s (33% improvement)
- Time to Interactive: 2.1s (34% improvement)
### 优化后
- 打包体积: ~340KB (gzip), ~280KB (brotli)
- 图片优化: 10 张图片 25 秒 (2.4x 提升)
- First Contentful Paint: 1.2s (提升 33%)
- Time to Interactive: 2.1s (提升 34%)
## Migration Path
## 实施路线
### Phase 1: Code Quality (Completed)
- ✅ Optimize build tools
- ✅ Add utility libraries
- ✅ Improve error handling
- ✅ Add validation middleware
### 阶段 1: 代码质量 (已完成)
- 优化构建工具
- 添加工具库
- 改进错误处理
- 添加验证中间件
### Phase 2: Infrastructure (Planned)
- Add Redis for caching
- Implement rate limiting
- Set up monitoring (Sentry, LogRocket)
- Add E2E tests
### 阶段 2: 基础设施 (规划中)
- 添加 Redis 缓存
- 实现速率限制
- 设置监控 (Sentry, LogRocket)
- 添加端到端测试
### Phase 3: Architecture (Planned)
- Extract services
- Implement plugin system
- Add database layer
- Set up job queue
### Phase 4: Features (Planned)
- Real-time status tracking
- Background sync
- Analytics dashboard
- Multi-provider marketplace
## Conclusion
The implemented optimizations provide immediate performance benefits with minimal breaking changes. The architectural recommendations lay out a clear path for scaling to support more providers, users, and features while maintaining code quality and developer experience.
> 更多未来架构规划请参考 [FUTURE_ARCHITECTURE.md](./FUTURE_ARCHITECTURE.md)

View File

@@ -18,7 +18,8 @@
| 文档 | 路径 | 说明 |
|------|------|------|
| **架构说明** | `ARCHITECTURE.md` | 项目架构详解 |
| **架构说明** | `ARCHITECTURE.md` | 当前架构详解 |
| **未来架构** | `FUTURE_ARCHITECTURE.md` | 尚未实施的架构规划 |
| **安全指南** | `SECURITY.md` | 安全措施说明 |
| **Giffgaff 教程** | `User_Guide.md` | 图文操作指南 |
| **Giffgaff 英文教程** | `User_Guide_EN.md` | 英文版使用指南 |
@@ -37,6 +38,7 @@
## 相关文件清单
- `docs/ARCHITECTURE.md`
- `docs/FUTURE_ARCHITECTURE.md`
- `docs/SECURITY.md`
- `docs/User_Guide.md`
- `docs/User_Guide_EN.md`

249
docs/FUTURE_ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,249 @@
# eSIM-Tools 未来架构规划
> 本文档记录当前尚未实施的架构规划,仅供未来参考。
## 微服务架构迁移
### 当前状态
- 单体 Netlify Functions
- 业务逻辑与 API 处理器紧耦合
- 复用性有限
### 目标架构
```
┌─────────────────────────────────────────────────┐
│ API Gateway / BFF Layer │
│ (Netlify Edge Functions / Cloudflare Workers) │
└─────────────────────────────────────────────────┘
┌──────────────┼──────────────┐
│ │ │
┌───────▼──────┐ ┌─────▼──────┐ ┌────▼────────┐
│ Auth Service │ │ Provider │ │ Activation │
│ (OAuth) │ │ Adapters │ │ Service │
└───────────────┘ └────────────┘ └─────────────┘
│ │ │
└──────────────┼──────────────┘
┌──────────────▼──────────────┐
│ Shared Middleware │
│ (Rate Limit, Auth, Log) │
└─────────────────────────────┘
```
**优势:**
- 独立部署和扩展
- 更好的关注点分离
- 更容易测试和维护
- 新运营商的插件架构
**实施计划:**
1. 将共享逻辑提取到 `src/services/core/`
2.`src/services/adapters/` 中创建运营商适配器
3.`src/services/middleware/` 中实现中间件链
4. 添加服务注册表用于动态运营商加载
**代码示例:**
```javascript
// src/services/adapters/BaseProvider.js
/**
* 运营商适配器基类
* @abstract
*/
class BaseProvider {
constructor(config) {
this.config = config;
}
/**
* 认证方法(子类必须实现)
* @param {Object} credentials - 认证凭据
* @returns {Promise<Object>} 认证结果
*/
async authenticate(credentials) {
throw new Error('Must implement authenticate()');
}
/**
* eSIM 激活方法(子类必须实现)
* @param {Object} data - 激活数据
* @returns {Promise<Object>} 激活结果
*/
async activateESIM(data) {
throw new Error('Must implement activateESIM()');
}
}
```
## 可扩展性策略
### 当前限制
- 无状态函数(无会话持久化)
- 有限的并发请求处理
- 无长时间运行任务的作业队列
- 直接 API 调用,无熔断器
### 目标方案
#### A. 添加数据库层
```
┌──────────────────────────────────────┐
│ Application Layer │
└──────────────────────────────────────┘
┌─────────────┼─────────────┐
│ │
┌───▼──────┐ ┌──────────▼────┐
│ Redis │ │ PostgreSQL │
│ (Cache) │ │ (Sessions) │
└──────────┘ └───────────────┘
```
**使用场景:**
- 多步骤 OAuth 流程的会话管理
- 跨 Serverless 实例的速率限制
- API 请求去重
- 用户偏好和设置
**技术建议:**
- **Redis**: Upstash Redis (Serverless 友好)
- **PostgreSQL**: Neon 或 Supabase (Serverless Postgres)
#### B. CDN 优先架构
```
用户请求
┌─────────────────┐
│ CDN Edge │ ← 静态资源 (HTML, CSS, JS, Images)
│ (Cloudflare) │ ← Service Worker precache
└────────┬────────┘
│ (Cache Miss)
┌─────────────────┐
│ Origin Server │ ← 仅动态 API 请求
│ (Netlify) │
└─────────────────┘
```
**优化:**
- 对哈希资源设置长缓存时间 (1 年)
- HTML 使用 stale-while-revalidate
- 实现边缘渲染个性化内容
- 预获取关键 API 响应
#### C. 后台处理作业队列
```
API Request → Enqueue Job → Return Job ID
┌──────────────┐
│ Job Queue │
│ (BullMQ) │
└──────┬───────┘
┌───────┴────────┐
│ │
┌────▼────┐ ┌─────▼────┐
│ Worker 1│ │ Worker 2 │
└─────────┘ └──────────┘
```
**使用场景:**
- 图片优化
- 批量 eSIM 激活
- 报告生成
- 邮件通知
**技术:** BullMQ + Redis 后端
## 未来功能规划
### A. 多运营商插件系统
**接口定义:**
```javascript
/**
* 运营商插件接口
* @interface ProviderPlugin
*/
// 所有方法由具体运营商适配器实现:
// - authenticate(credentials) → Promise<Token>
// - activateESIM(data) → Promise<Result>
// - getStatus(id) → Promise<Status>
// - validate(data) → ValidationResult
```
**插件注册表:**
```javascript
class PluginRegistry {
constructor() {
this.plugins = new Map();
}
async loadPlugin(name) {
const plugin = await import(`./plugins/${name}`);
this.plugins.set(name, plugin);
}
getProvider(name) {
return this.plugins.get(name);
}
}
```
**优势:**
- 轻松添加新运营商
- 社区贡献
- A/B 测试不同实现
- 运营商 API 渐进迁移
### B. 实时状态追踪
**WebSocket 架构:**
```
Client → WebSocket → Server → Provider API
│ │
└──────── Status Updates ──────┘
```
**Server-Sent Events 实现 (更简单):**
```javascript
// 客户端
const eventSource = new EventSource('/api/esim-status?id=123');
eventSource.onmessage = (event) => {
const status = JSON.parse(event.data);
updateUI(status);
};
```
### C. 离线优先 PWA 与后台同步
**增强的 Service Worker 策略:**
```javascript
// 后台同步失败的请求
self.addEventListener('sync', (event) => {
if (event.tag === 'esim-activation') {
event.waitUntil(retryActivation());
}
});
```
**功能:**
- 离线时队列 eSIM 激活请求
- 连接恢复后自动重试
- 使用 IndexedDB 进行本地状态管理
- 并发编辑的冲突解决
### D. 分析仪表板
**追踪指标:**
- 按运营商统计激活成功率
- 平均激活时间
- 错误率和类型
- 用户旅程分析
- 性能指标 (Core Web Vitals)

View File

@@ -46,7 +46,7 @@ app.use(cors({
### 3. 内容安全策略 (CSP)
所有 HTML 文件都配置了严格的 CSP 策略。本地开发服务器 (`server.js`) 中的 Helmet 配置如下
所有 HTML 文件都配置了严格的 CSP 策略。以下为本地开发服务器 (`server.js`) 中的 Helmet CSP 配置,生产环境通过 HTML `<meta>` 标签实现,具体值可能略有差异
```javascript
app.use(helmet({
@@ -170,4 +170,4 @@ app.use(helmet({
## 免责声明
本安全指南提供了基本的安全措施但不能保证100%的安全性。建议根据具体需求进行额外的安全评估。
本安全指南提供了基本的安全措施但不能保证100%的安全性。建议根据具体需求进行额外的安全评估。

View File

@@ -2,14 +2,7 @@
> 🌐 [English Version](./User_Guide_EN.md)
> 🎬 视频教程 - giffgaff eSIM更换操作演示(视频教程未更新,其中OAuth获取回调url方式请阅读文字教程)
<video controls preload="metadata" width="100%" style="max-width: 800px; height: auto; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
<source src="https://github.com/user-attachments/assets/306dacb4-0a06-4930-bf35-3711d0f63720" type="video/mp4">
您的浏览器不支持视频播放,请<a href="https://github.com/user-attachments/assets/306dacb4-0a06-4930-bf35-3711d0f63720">点击这里</a>下载视频。
</video>
[giffgaff.webm](https://github.com/user-attachments/assets/d4fbd0ff-b8bc-4477-a0c4-45698fe4802c)
> 🎬 视频教程见文末视频教程未更新OAuth 获取回调 URL 方式请文字教程为准
## 1. 打开giffgaff的eSIM更换网页
@@ -69,4 +62,23 @@ OAuth方式需要获取回调URL获取方式参考页面说明
![eSIM信息](image/116.jpg)
![eSIM信息1](image/117.jpg)
## 6. 使用原生eSIM手机完成扫码
## 6. 使用原生 eSIM 手机完成扫码
1. 打开手机的**设置** → **蜂窝网络** / **移动网络**
2. 选择**添加 eSIM** / **扫描二维码**
3. 扫描页面上显示的 QR 码
4. 确认安装,等待 eSIM 激活完成
5. 激活成功后可在蜂窝网络设置中看到新的号码
---
## 附录:视频教程
> ⚠️ 视频教程未更新,其中 OAuth 获取回调 URL 的方式请以上方文字教程为准。
<video controls preload="metadata" width="100%" style="max-width: 800px; height: auto; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
<source src="https://github.com/user-attachments/assets/306dacb4-0a06-4930-bf35-3711d0f63720" type="video/mp4">
您的浏览器不支持视频播放,请<a href="https://github.com/user-attachments/assets/306dacb4-0a06-4930-bf35-3711d0f63720">点击这里</a>下载视频。
</video>
[giffgaff.webm](https://github.com/user-attachments/assets/d4fbd0ff-b8bc-4477-a0c4-45698fe4802c)

View File

@@ -1,26 +1,31 @@
# Font Awesome 图标修复
## 问题描述
部署后图标丢失原因是Font Awesome通过CDN加载在部署环境中可能存在网络问题或CDN访问问题。
## 🔍 问题描述
## 解决方案
部署后图标丢失,原因是 Font Awesome 通过 CDN 加载,在部署环境中可能存在网络问题或 CDN 访问问题。
### 1. 下载本地Font Awesome文件
- 创建目录:`src/assets/fontawesome/`
- 下载CSS文件`all.min.css`
- 下载字体文件:
- `fa-solid-900.woff2` (Solid图标字体)
- `fa-brands-400.woff2` (Brands图标字体)
- `fa-regular-400.woff2` (Regular图标字体)
## 🛠️ 修复方案
### 1. 下载本地 Font Awesome 文件
创建目录 `src/assets/fontawesome/` 并下载以下文件:
- `all.min.css` — Font Awesome CSS 文件
- `fa-solid-900.woff2` — Solid 图标字体
- `fa-brands-400.woff2` — Brands 图标字体
- `fa-regular-400.woff2` — Regular 图标字体
### 2. 修改字体路径
使用sed命令批量替换CSS文件中的字体路径
使用 sed 命令批量替换 CSS 文件中的字体路径:
```bash
sed -i '' 's|../webfonts/|./|g' src/assets/fontawesome/all.min.css
```
### 3. 更新HTML文件
将所有HTML文件中的Font Awesome引用从CDN改为本地
### 3. 更新 HTML 文件
将所有 HTML 文件中的 Font Awesome 引用从 CDN 改为本地:
**index.html:**
```html
@@ -33,18 +38,18 @@ sed -i '' 's|../webfonts/|./|g' src/assets/fontawesome/all.min.css
**src/giffgaff/giffgaff_modular.html:**
```html
<!-- 已通过外部样式表加载 Font Awesome -->
<link rel="stylesheet" href="/src/assets/fontawesome/all.min.css">
```
**src/simyo/simyo_modular.html:**
```html
<!-- 已通过外部样式表加载 Font Awesome -->
<link rel="stylesheet" href="/src/assets/fontawesome/all.min.css">
```
### 4. 更新CSP策略
修改Content Security Policy允许本地字体文件
### 4. 更新 CSP 策略
修改 Content Security Policy允许本地字体文件
```html
<!-- 修改前 -->
font-src 'self' https://cdnjs.cloudflare.com;
@@ -53,25 +58,29 @@ font-src 'self' https://cdnjs.cloudflare.com;
font-src 'self' data:;
```
## 测试验证
创建了测试页面 `test-icons.html` 来验证所有常用图标是否正常显示。
## 🧪 测试验证
## 优势
1. **可靠性**不依赖外部CDN避免网络问题
2. **性能**:本地加载更快,减少网络请求
3. **一致性**:确保所有环境下的图标显示一致
4. **安全**:减少对外部资源的依赖
创建测试页面 `test-icons.html` 验证所有常用图标是否正常显示。
## ✅ 修复优势
1. **可靠** — 不依赖外部 CDN避免网络问题
2. **性能** — 本地加载更快,减少网络请求
3. **一致性** — 确保所有环境下的图标显示一致
4. **安全性** — 减少对外部资源的依赖
## 📁 文件结构
## 文件结构
```
src/assets/fontawesome/
├── all.min.css # Font Awesome CSS文件
├── fa-solid-900.woff2 # Solid图标字体
├── fa-brands-400.woff2 # Brands图标字体
└── fa-regular-400.woff2 # Regular图标字体
├── all.min.css # Font Awesome CSS 文件
├── fa-solid-900.woff2 # Solid 图标字体
├── fa-brands-400.woff2 # Brands 图标字体
└── fa-regular-400.woff2 # Regular 图标字体
```
## 注意事项
## ⚠️ 注意事项
- 确保字体文件路径正确
- 定期更新Font Awesome版本
- 定期更新 Font Awesome 版本
- 在生产环境中验证图标显示

View File

@@ -1,10 +1,10 @@
# Giffgaff eSIM 令牌过期问题修复
## 问题描述
## 🔍 问题描述
在使用 Giffgaff eSIM 转换流程时用户通过Cookie登录成功后在后续步骤特别是MFA挑战请求中会遇到令牌过期的问题
在使用 Giffgaff eSIM 转换流程时,用户通过 Cookie 登录成功后,在后续步骤(特别是 MFA 挑战请求)中会遇到令牌过期的问题:
```
```json
{
"error": "MFA Challenge Failed",
"message": "Request failed with status code 401",
@@ -15,107 +15,101 @@
}
```
这是因为从Cookie获取的访问令牌(access token)有效期有限,原始代码没有实现令牌过期后的刷新机制。
**根本原因**: 从 Cookie 获取的访问令牌 (access token) 有效期有限,原始代码没有实现令牌过期后的刷新机制。
## 解决方案
我们实现了一个完整的令牌刷新机制,包括前端和后端的改进:
## 🛠️ 修复方案
### 1. 前端改进
- 在Cookie验证成功后将原始Cookie保存到localStorage中,以备后续刷新令牌使用
```javascript
// 保存cookie到localStorage
function saveCookie(cookie) {
if (cookie && typeof cookie === 'string') {
localStorage.setItem('giffgaff_cookie', cookie);
console.log('已保存cookie到localStorage');
}
}
```
Cookie 验证成功后,将原始 Cookie 保存到 localStorage 以备后续刷新令牌使用
- 在前端API模块中实现令牌刷新逻辑当检测到令牌过期时使用存储的Cookie重新获取有效令牌
```javascript
async sendMFAChallenge(accessToken) {
try {
// 尝试使用现有令牌
const response = await fetch(this.endpoints.mfaChallenge, {...});
```javascript
// 保存 cookie 到 localStorage
function saveCookie(cookie) {
if (cookie && typeof cookie === 'string') {
localStorage.setItem('giffgaff_cookie', cookie);
}
}
```
if (response.ok) {
return await response.json();
}
在前端 API 模块中实现令牌刷新逻辑,当检测到令牌过期时,使用存储的 Cookie 重新获取有效令牌:
// 如果是401错误可能是令牌过期
if (response.status === 401 &&
errorData?.details?.error === 'invalid_token') {
```javascript
async sendMFAChallenge(accessToken) {
try {
const response = await fetch(this.endpoints.mfaChallenge, {...});
// 尝试使用本地存储的cookie重新验证
if (response.ok) {
return await response.json();
}
// 如果是 401 错误,可能是令牌过期
if (response.status === 401) {
const errorData = await response.json();
if (errorData?.details?.error === 'invalid_token') {
// 尝试使用本地存储的 cookie 重新验证
const cookie = localStorage.getItem('giffgaff_cookie');
if (cookie) {
const cookieVerifyResult = await this.verifyCookie(cookie);
if (cookieVerifyResult.success) {
// 使用新令牌重新发送请求...
}
}
}
} catch (error) {
// 处理错误
}
} catch (error) {
// 处理错误
}
```
}
```
### 2. 后端改进
- 修改`giffgaff-mfa-challenge.js`和`giffgaff-mfa-validation.js`在检测到Cookie但没有有效令牌时自动调用`verify-cookie`函数获取新的访问令牌
修改 `giffgaff-mfa-challenge.js``giffgaff-mfa-validation.js`,在检测到 Cookie 但没有有效令牌时,自动调用 `verify-cookie` 函数获取新的访问令牌
```javascript
// 如果提供cookie但没有accessToken先尝试使用cookie获取accessToken
if (cookie && !accessToken) {
try {
// 调用verify-cookie函数获取accessToken
const cookieVerifyResponse = await axios.post(
'https://esim.cosr.eu.org/.netlify/functions/verify-cookie',
{ cookie },
{
headers: { 'Content-Type': 'application/json' },
timeout: 30000
}
);
if (cookieVerifyResponse.data && cookieVerifyResponse.data.success) {
accessToken = cookieVerifyResponse.data.accessToken;
console.log('Successfully obtained access token from cookie');
```javascript
// 如果提供 cookie 但没有 accessToken先尝试使用 cookie 获取 accessToken
if (cookie && !accessToken) {
try {
const cookieVerifyResponse = await axios.post(
'https://esim.cosr.eu.org/.netlify/functions/verify-cookie',
{ cookie },
{
headers: { 'Content-Type': 'application/json' },
timeout: 30000
}
} catch (cookieError) {
console.error('Failed to verify cookie:', cookieError.message);
);
if (cookieVerifyResponse.data && cookieVerifyResponse.data.success) {
accessToken = cookieVerifyResponse.data.accessToken;
}
} catch (cookieError) {
console.error('Failed to verify cookie:', cookieError.message);
}
```
}
```
- 修改OAuth认证方式使用Authorization头而不是表单参数发送客户端凭据与Postman配置保持一致
同时修改 OAuth 认证方式,使用 Authorization 头而不是表单参数发送客户端凭据,与 Postman 配置保持一致
### 3. 流程改进
### 3. 改进后的流程
整体改进的令牌刷新流程如下:
1. 用户通过Cookie登录前端保存Cookie和访问令牌
2. 发送MFA挑战请求时如果检测到令牌过期
- 前端使用存储的Cookie重新获取有效令牌然后重新发送请求
- 后端如果提供了Cookie但没有有效令牌自动使用Cookie获取新令牌
3. 验证MFA验证码时同样应用令牌刷新机制
1. 用户通过 Cookie 登录,前端保存 Cookie 和访问令牌
2. 发送 MFA 挑战请求时,如果检测到令牌过期:
- **前端**: 使用存储的 Cookie 重新获取有效令牌,然后重新发送请求
- **后端**: 如果提供了 Cookie 但没有有效令牌,自动使用 Cookie 获取新令牌
3. 验证 MFA 验证码时,同样应用令牌刷新机制
这种双重保障机制确保了即使令牌过期,系统也能自动刷新并继续完成 eSIM 转换流程,无需用户重新登录。
## 技术细节
## 🧪 技术细节
- **Cookie存储**:使用`localStorage.setItem('giffgaff_cookie', cookie)`保存原始Cookie
- **令牌刷新检测**通过检查HTTP 401状态码和`error: 'invalid_token'`错误信息识别令牌过期
- **令牌刷新方式**:调用`verify-cookie`函数传入存储的Cookie获取新的访问令牌
- **无缝体验**用户无需感知令牌刷新过程,整个流程自动完成
- **Cookie 存储**: 使用 `localStorage.setItem('giffgaff_cookie', cookie)` 保存原始 Cookie
- **令牌刷新检测**: 通过检查 HTTP 401 状态码和 `error: 'invalid_token'` 错误信息识别令牌过期
- **令牌刷新方式**: 调用 `verify-cookie` 函数,传入存储的 Cookie 获取新的访问令牌
- **无缝体验**: 用户无需感知令牌刷新过程,整个流程自动完成
## 注意事项
## ⚠️ 注意事项
- Cookie本身也有过期时间通常比访问令牌更长。如果Cookie也过期用户需要重新登录
- 为保护用户隐私和安全,Cookie存储仅在用户当前浏览器会话中有效
- 此机制不适用于OAuth登录方式OAuth登录需要单独处理令牌刷新
- Cookie 本身也有过期时间,通常比访问令牌更长。如果 Cookie 也过期,用户需要重新登录
- Cookie 存储仅在用户当前浏览器会话中有效
- 此机制不适用于 OAuth 登录方式OAuth 登录需要单独处理令牌刷新

View File

@@ -54,17 +54,15 @@ npm start
无CORS限制 添加CORS头 原始API
```
### 方案2: 浏览器插件(临时方案
### 方案2: 临时绕过 CORS仅开发测试不推荐
安装CORS浏览器插件,如:
- Chrome: "CORS Unblock"
- Firefox: "CORS Everywhere"
安装 CORS 浏览器插件Chrome: "CORS Unblock"Firefox: "CORS Everywhere")。
⚠️ **注意**: 此方案有安全风险,仅建议开发测试使用
⚠️ 此方案禁用浏览器同源安全策略,仅限本地开发测试,切勿在日常浏览中开启。
### 方案3: 浏览器启动参数(开发用
### 方案3: 禁用浏览器安全策略(仅开发测试
使用禁用安全检查的参数启动Chrome
使用 `--disable-web-security` 参数启动 Chrome
```bash
# Windows
chrome.exe --user-data-dir=/tmp/chrome_dev_test --disable-web-security --disable-features=VizDisplayCompositor
@@ -180,7 +178,7 @@ curl http://localhost:3000/api/health
{
"success": true,
"message": "Simyo eSIM代理服务器运行正常",
"timestamp": "2024-01-15T10:30:00.000Z",
"timestamp": "<当前时间戳>",
"version": "1.0.0"
}
```
@@ -191,9 +189,8 @@ curl http://localhost:3000/api/health
### 3. API测试
使用Postman或curl测试API端点
## 🛡️ 安全建议
## 🛡️ 安全提示
1. **仅本地使用**: 代理服务器仅用于本地开发和个人使用
2. **防火墙设置**: 确保3000端口不对外网开放
3. **定期更新**: 保持Node.js和依赖包的最新版本
4. **凭据保护**: 不要在代码中硬编码敏感信息
- 代理服务器仅监听 `localhost`,不应暴露到外网
- 代理不存储用户凭据,请求日志中不包含敏感信息
- 如需长期使用,推荐使用在线服务 [esim.cosr.eu.org](https://esim.cosr.eu.org) 替代本地代理

View File

@@ -49,6 +49,8 @@ eSIM-Tools 通知系统是一个轻量级的消息通知解决方案,用于在
#### 基础用法
首先导入通知管理器模块(默认导出为单例实例):
```javascript
import NotificationManager from './modules/notification-manager.js';
@@ -273,9 +275,10 @@ constructor() {
### 3. 手动触发检查
```javascript
// notification-service.js 导出的是单例实例
import NotificationService from './modules/notification-service.js';
// 手动检查新通知
// 手动检查新通知(无需参数,内部从后端获取)
NotificationService.checkAndShowNotifications();
```

View File

@@ -5,14 +5,12 @@
## 📁 文件说明
### 主要文件
- **`giffgaff_modular.html`** - eSIM 设备更换工具(生产版本,模块化架构)
- **`src/giffgaff/giffgaff_modular.html`** - eSIM 设备更换工具(生产版本,模块化架构)
- **`tests/test_giffgaff_esim.html`** - 综合测试页面(开发/测试版本)
- **`Giffgaff-swap-esim.json`** - 原始 Postman 脚本(参考文档)
- **`giffgaff.html`** - 原有的简化版本(参考)
### 参考文件
- **`simyo.html`** - Simyo eSIM 工具(其他运营商参考)
- **`Simyo ESIM V2.postman_collection.json`** - Simyo API 脚本
- **`postman/giffgaff.html`** - 原始单文件版本(参考)
- **`postman/Giffgaff-swap-esim.json`** - 原始 Postman 脚本
## 🔧 技术架构

View File

@@ -5,14 +5,12 @@
## 📁 File Description
### Main Files
- **`giffgaff_modular.html`** - eSIM Device Change Tool (Production Version, Modular Architecture)
- **`src/giffgaff/giffgaff_modular.html`** - eSIM Device Change Tool (Production Version, Modular Architecture)
- **`tests/test_giffgaff_esim.html`** - Comprehensive Test Page (Development/Test Version)
- **`Giffgaff-swap-esim.json`** - Original Postman Script (Reference Document)
- **`giffgaff.html`** - Original Simplified Version (Reference)
### Reference Files
- **`simyo.html`** - Simyo eSIM Tool (Other Operator Reference)
- **`Simyo ESIM V2.postman_collection.json`** - Simyo API Script
- **`postman/giffgaff.html`** - Original single-file version (Reference)
- **`postman/Giffgaff-swap-esim.json`** - Original Postman Script
## 🔧 Technical Architecture

View File

@@ -5,10 +5,8 @@
## 📁 文件说明
### 主要文件
- **`simyo_modular.html`** - Simyo eSIM 设备更换工具(生产版本,模块化架构)
- **`src/simyo/simyo_modular.html`** - Simyo eSIM 设备更换工具(生产版本,模块化架构)
- **`tests/test_simyo_esim.html`** - 综合测试页面(开发/测试版本)
- **`Simyo ESIM V2.postman_collection.json`** - 原始 Postman 脚本(参考文档)
- **`simyo.html`** - 原有的简化版本(参考)
## 🔧 技术架构

View File

@@ -5,10 +5,8 @@
## 📁 File Description
### Main Files
- **`simyo_modular.html`** - Simyo eSIM Device Change Tool (Production Version, Modular Architecture)
- **`src/simyo/simyo_modular.html`** - Simyo eSIM Device Change Tool (Production Version, Modular Architecture)
- **`tests/test_simyo_esim.html`** - Comprehensive Test Page (Development/Test Version)
- **`Simyo ESIM V2.postman_collection.json`** - Original Postman Script (Reference Document)
- **`simyo.html`** - Original Simplified Version (Reference)
## 🔧 Technical Architecture