fix: 全面 QA 审计修复 — 安全加固/代码质量/跨平台一致性/测试覆盖
Phase 0 安全热修复 (CRITICAL): - 外部化微信 appid/secret 到 ERP__WECHAT__APPID/SECRET 环境变量 - 正确连接 HealthCrypto 到 ERP__HEALTH__AES_KEY/HMAC_KEY 环境变量 - 外部化小程序加密密钥到 TARO_APP_ENCRYPTION_KEY 环境变量 - 移除小程序 auth store 中的敏感信息 console.log Phase 1 安全加固: - 微信自动注册 display_name 添加 sanitize 防止 XSS - 测试数据库凭据改为从 TEST_DB_URL 环境变量读取 Phase 2 代码质量: - 提取 useThemeMode hook 消除 22 处重复暗色模式检测 - 提取共享健康常量到 constants/health.ts - 拆分 patient_service.rs 脱敏函数到 masking.rs - 移除未使用的 i18next/react-i18next 依赖 - 移除未使用的 api/errors.ts 和 erp-auth/anyhow 依赖 Phase 3 测试覆盖: - 新增 5 个患者模块集成测试 (CRUD/租户隔离/验证/软删除) Phase 4 跨平台一致性: - 统一小程序 Patient.birthday → birth_date 匹配后端 - 统一小程序 Appointment.time_slot → start_time/end_time 匹配后端 Phase 5 架构: - 微信登录添加多租户 TODO 注释 - 更新 wiki/infrastructure.md 环境变量文档
This commit is contained in:
@@ -1,40 +1,32 @@
|
||||
import Taro from '@tarojs/taro';
|
||||
import CryptoJS from 'crypto-js';
|
||||
|
||||
const XOR_KEY = 'hms_mp_2026_secure_key';
|
||||
const ENCRYPTION_KEY = process.env.TARO_APP_ENCRYPTION_KEY || '';
|
||||
|
||||
function xorTransform(value: string): string {
|
||||
let result = '';
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
result += String.fromCharCode(value.charCodeAt(i) ^ XOR_KEY.charCodeAt(i % XOR_KEY.length));
|
||||
}
|
||||
return result;
|
||||
function encrypt(plaintext: string): string {
|
||||
if (!ENCRYPTION_KEY) return plaintext;
|
||||
return CryptoJS.AES.encrypt(plaintext, ENCRYPTION_KEY).toString();
|
||||
}
|
||||
|
||||
function toBase64(str: string): string {
|
||||
return btoa(unescape(encodeURIComponent(str)));
|
||||
}
|
||||
|
||||
function fromBase64(b64: string): string {
|
||||
function decrypt(ciphertext: string): string {
|
||||
if (!ENCRYPTION_KEY) return ciphertext;
|
||||
try {
|
||||
return decodeURIComponent(escape(atob(b64)));
|
||||
const bytes = CryptoJS.AES.decrypt(ciphertext, ENCRYPTION_KEY);
|
||||
return bytes.toString(CryptoJS.enc.Utf8);
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function secureSet(key: string, value: string): void {
|
||||
const obfuscated = toBase64(xorTransform(value));
|
||||
Taro.setStorageSync(key, obfuscated);
|
||||
const encrypted = encrypt(value);
|
||||
Taro.setStorageSync(key, encrypted);
|
||||
}
|
||||
|
||||
export function secureGet(key: string): string {
|
||||
const raw = Taro.getStorageSync(key);
|
||||
if (!raw || typeof raw !== 'string') return '';
|
||||
try {
|
||||
return xorTransform(fromBase64(raw));
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
return decrypt(raw);
|
||||
}
|
||||
|
||||
export function secureRemove(key: string): void {
|
||||
|
||||
Reference in New Issue
Block a user