mirror of
https://github.com/Silentely/eSIM-Tools.git
synced 2026-09-03 06:24:20 +08:00
- 新增统一的中间件模块,提供鉴权、CORS和错误处理功能 - 重构所有Functions使用withAuth中间件简化代码结构 - 添加安全存储模块替代localStorage,防御XSS攻击 - 引入HTML清理工具,自动转义特殊字符和验证URL安全性 - 创建代码质量检查脚本,验证语法、环境变量和依赖完整性 - 添加构建日志工具和重构脚本,统一替换console.log为Logger - 引入ESLint配置,提升代码质量和一致性 - 重构Giffgaff相关API,统一错误处理和验证逻辑 - 优化构建脚本,添加压缩和图片优化功能 - 新增健康检查端点,用于服务监控和状态报告
239 lines
6.5 KiB
JavaScript
239 lines
6.5 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* 代码质量全面检查脚本
|
|
* 检查所有变更的完整性和代码质量
|
|
*/
|
|
|
|
const BuildLogger = require('./logger.js');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { execSync } = require('child_process');
|
|
|
|
const projectRoot = path.join(__dirname, '..');
|
|
|
|
// 检查项配置
|
|
const checks = {
|
|
// 1. 语法检查
|
|
syntaxCheck: {
|
|
name: '语法检查',
|
|
files: [
|
|
'server.js',
|
|
'webpack.config.js',
|
|
'netlify/functions/_shared/middleware.js',
|
|
'netlify/functions/health.js',
|
|
'netlify/functions/giffgaff-graphql.js',
|
|
'netlify/functions/giffgaff-mfa-challenge.js',
|
|
'netlify/functions/giffgaff-mfa-validation.js',
|
|
'netlify/functions/giffgaff-sms-activate.js',
|
|
'netlify/functions/auto-activate-esim.js',
|
|
'netlify/functions/giffgaff-token-exchange.js',
|
|
'netlify/functions/verify-cookie.js'
|
|
]
|
|
},
|
|
|
|
// 2. 环境变量一致性
|
|
envVarCheck: {
|
|
name: '环境变量一致性',
|
|
required: ['ACCESS_KEY', 'ALLOWED_ORIGIN'],
|
|
deprecated: ['ESIM_ACCESS_KEY', 'COOKIE_SECRET']
|
|
},
|
|
|
|
// 3. 依赖完整性
|
|
dependencyCheck: {
|
|
name: '依赖完整性',
|
|
unused: ['cookie-parser']
|
|
},
|
|
|
|
// 4. 安全配置
|
|
securityCheck: {
|
|
name: '安全配置',
|
|
patterns: {
|
|
weakDefaults: /please_change_me|your-secret-key-here|your-key-here/g,
|
|
hardcodedSecrets: /(?:password|secret|key)\s*=\s*['"][^'"]{10,}['"]/gi,
|
|
consoleLog: /console\.log\(/g
|
|
}
|
|
}
|
|
};
|
|
|
|
let totalChecks = 0;
|
|
let passedChecks = 0;
|
|
let failedChecks = 0;
|
|
|
|
// 辅助函数
|
|
function checkFile(filePath) {
|
|
const fullPath = path.join(projectRoot, filePath);
|
|
if (!fs.existsSync(fullPath)) {
|
|
BuildLogger.error(`文件不存在: ${filePath}`);
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
execSync(`node -c "${fullPath}"`, { stdio: 'pipe' });
|
|
return true;
|
|
} catch (error) {
|
|
BuildLogger.error(`语法错误: ${filePath}`);
|
|
BuildLogger.error(error.message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function checkEnvExample() {
|
|
const envPath = path.join(projectRoot, 'env.example');
|
|
const content = fs.readFileSync(envPath, 'utf8');
|
|
const issues = [];
|
|
|
|
// 检查必需变量
|
|
checks.envVarCheck.required.forEach(varName => {
|
|
if (!content.includes(`${varName}=`)) {
|
|
issues.push(`缺少必需环境变量: ${varName}`);
|
|
}
|
|
});
|
|
|
|
// 检查废弃变量
|
|
checks.envVarCheck.deprecated.forEach(varName => {
|
|
if (content.includes(`${varName}=`)) {
|
|
issues.push(`包含废弃环境变量: ${varName}`);
|
|
}
|
|
});
|
|
|
|
return issues;
|
|
}
|
|
|
|
function searchInFiles(pattern, files, excludeContext = []) {
|
|
const results = [];
|
|
files.forEach(file => {
|
|
const fullPath = path.join(projectRoot, file);
|
|
if (fs.existsSync(fullPath)) {
|
|
const content = fs.readFileSync(fullPath, 'utf8');
|
|
const lines = content.split('\n');
|
|
let matchCount = 0;
|
|
|
|
lines.forEach((line, index) => {
|
|
if (pattern.test(line)) {
|
|
// 检查是否在排除的上下文中(如安全检查代码)
|
|
const isExcluded = excludeContext.some(ctx => {
|
|
const contextLine = lines[index];
|
|
const prevLine = lines[index - 1] || '';
|
|
return contextLine.includes(ctx) || prevLine.includes(ctx);
|
|
});
|
|
|
|
if (!isExcluded) {
|
|
matchCount++;
|
|
}
|
|
}
|
|
});
|
|
|
|
if (matchCount > 0) {
|
|
results.push({ file, matches: matchCount });
|
|
}
|
|
}
|
|
});
|
|
return results;
|
|
}
|
|
|
|
function checkPackageJson() {
|
|
const pkgPath = path.join(projectRoot, 'package.json');
|
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
const issues = [];
|
|
|
|
checks.dependencyCheck.unused.forEach(dep => {
|
|
if (pkg.dependencies && pkg.dependencies[dep]) {
|
|
issues.push(`未使用的依赖: ${dep} (dependencies)`);
|
|
}
|
|
if (pkg.devDependencies && pkg.devDependencies[dep]) {
|
|
issues.push(`未使用的依赖: ${dep} (devDependencies)`);
|
|
}
|
|
});
|
|
|
|
return issues;
|
|
}
|
|
|
|
// 执行检查
|
|
function runChecks() {
|
|
BuildLogger.title('代码质量全面检查');
|
|
|
|
// 1. 语法检查
|
|
BuildLogger.step(1, 4, checks.syntaxCheck.name);
|
|
let syntaxPassed = 0;
|
|
checks.syntaxCheck.files.forEach(file => {
|
|
totalChecks++;
|
|
if (checkFile(file)) {
|
|
BuildLogger.check(true, file);
|
|
syntaxPassed++;
|
|
passedChecks++;
|
|
} else {
|
|
BuildLogger.check(false, file);
|
|
failedChecks++;
|
|
}
|
|
});
|
|
BuildLogger.progress(`${syntaxPassed}/${checks.syntaxCheck.files.length} 文件通过语法检查\n`);
|
|
|
|
// 2. 环境变量检查
|
|
BuildLogger.step(2, 4, checks.envVarCheck.name);
|
|
totalChecks++;
|
|
const envIssues = checkEnvExample();
|
|
if (envIssues.length === 0) {
|
|
BuildLogger.check(true, 'env.example 配置正确');
|
|
passedChecks++;
|
|
} else {
|
|
BuildLogger.check(false, 'env.example 存在问题:');
|
|
envIssues.forEach(issue => BuildLogger.error(` - ${issue}`));
|
|
failedChecks++;
|
|
}
|
|
|
|
// 3. 依赖检查
|
|
BuildLogger.step(3, 4, checks.dependencyCheck.name);
|
|
totalChecks++;
|
|
const depIssues = checkPackageJson();
|
|
if (depIssues.length === 0) {
|
|
BuildLogger.check(true, 'package.json 依赖正确');
|
|
passedChecks++;
|
|
} else {
|
|
BuildLogger.check(false, 'package.json 存在问题:');
|
|
depIssues.forEach(issue => BuildLogger.warn(` - ${issue}`));
|
|
failedChecks++;
|
|
}
|
|
|
|
// 4. 安全配置检查
|
|
BuildLogger.step(4, 4, checks.securityCheck.name);
|
|
|
|
// 检查弱密钥(排除安全检查代码中的引用)
|
|
totalChecks++;
|
|
const weakDefaults = searchInFiles(
|
|
checks.securityCheck.patterns.weakDefaults,
|
|
['env.example', 'netlify/functions/_shared/middleware.js'],
|
|
['if (ACCESS_KEY ===', '安全警告', '警告', '检查']
|
|
);
|
|
if (weakDefaults.length === 0) {
|
|
BuildLogger.check(true, '无弱默认配置');
|
|
passedChecks++;
|
|
} else {
|
|
BuildLogger.check(false, '发现弱默认配置:');
|
|
weakDefaults.forEach(r => BuildLogger.warn(` - ${r.file}: ${r.matches}处`));
|
|
failedChecks++;
|
|
}
|
|
|
|
// 统计报告
|
|
BuildLogger.title('\n检查结果汇总');
|
|
BuildLogger.log(`总检查项: ${totalChecks}`);
|
|
BuildLogger.success(`通过: ${passedChecks}`);
|
|
if (failedChecks > 0) {
|
|
BuildLogger.error(`失败: ${failedChecks}`);
|
|
}
|
|
|
|
const successRate = ((passedChecks / totalChecks) * 100).toFixed(1);
|
|
BuildLogger.log(`\n通过率: ${successRate}%`);
|
|
|
|
if (failedChecks === 0) {
|
|
BuildLogger.success('\n✅ 所有检查通过! 代码质量良好。');
|
|
return 0;
|
|
} else {
|
|
BuildLogger.error('\n❌ 存在质量问题,请修复后重新检查。');
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// 执行
|
|
const exitCode = runChecks();
|
|
process.exit(exitCode);
|