mirror of
https://github.com/Silentely/eSIM-Tools.git
synced 2026-09-03 06:24:20 +08:00
fix(sentry): 修复 CSP 内联脚本问题并增强敏感数据脱敏
- 新增 sentry-config.js 外链脚本替代 HTML 内联配置 - 修改 HTML 文件引用外链脚本以符合 CSP 策略 - 重写 inject-sentry-config.js 仅处理配置文件 - 添加 sentry-sdk-loaded 事件触发,修复 SDK 超时覆盖问题 - 增强 beforeSend 脱敏逻辑,覆盖 query_string 和更多敏感参数
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* Sentry 配置注入脚本
|
||||
*
|
||||
* 在构建时将 Sentry 环境变量注入到 HTML 文件中
|
||||
* 在构建时将 Sentry 环境变量注入到 sentry-config.js 文件中
|
||||
* 用法:在 npm run build 中调用此脚本
|
||||
*/
|
||||
|
||||
@@ -14,48 +14,39 @@ const SENTRY_ENVIRONMENT = process.env.SENTRY_ENVIRONMENT || 'production';
|
||||
const SENTRY_RELEASE = process.env.SENTRY_RELEASE ||
|
||||
(process.env.COMMIT_REF ? `esim-tools@${process.env.COMMIT_REF.slice(0, 7)}` : 'esim-tools@unknown');
|
||||
|
||||
// 要处理的 HTML 文件列表
|
||||
const htmlFiles = [
|
||||
'dist/index.html',
|
||||
'dist/src/giffgaff/giffgaff_modular.html',
|
||||
'dist/src/giffgaff/giffgaff_complete_esim.html',
|
||||
'dist/src/simyo/simyo_modular.html',
|
||||
];
|
||||
// 要处理的配置文件(改为处理独立的 JS 配置文件,而非 HTML 内联脚本)
|
||||
const configFile = 'dist/src/js/sentry-config.js';
|
||||
|
||||
console.log('[Sentry Config] 开始注入配置...');
|
||||
console.log(` DSN: ${SENTRY_DSN ? '已配置' : '未配置'}`);
|
||||
console.log(` Environment: ${SENTRY_ENVIRONMENT}`);
|
||||
console.log(` Release: ${SENTRY_RELEASE}`);
|
||||
|
||||
let processedCount = 0;
|
||||
const fullPath = path.join(process.cwd(), configFile);
|
||||
|
||||
htmlFiles.forEach(filePath => {
|
||||
const fullPath = path.join(process.cwd(), filePath);
|
||||
if (!fs.existsSync(fullPath)) {
|
||||
console.error(` ✗ 错误: ${configFile} 不存在`);
|
||||
console.log('[Sentry Config] 失败,请确保构建流程正确复制了 sentry-config.js');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(fullPath)) {
|
||||
console.log(` 跳过: ${filePath} (文件不存在)`);
|
||||
return;
|
||||
}
|
||||
let content = fs.readFileSync(fullPath, 'utf8');
|
||||
|
||||
let content = fs.readFileSync(fullPath, 'utf8');
|
||||
// 替换配置占位符
|
||||
content = content.replace(
|
||||
/window\.SENTRY_DSN\s*=\s*['"][^'"]*['"]/,
|
||||
`window.SENTRY_DSN = '${SENTRY_DSN}'`
|
||||
);
|
||||
content = content.replace(
|
||||
/window\.SENTRY_ENVIRONMENT\s*=\s*['"][^'"]*['"]/,
|
||||
`window.SENTRY_ENVIRONMENT = '${SENTRY_ENVIRONMENT}'`
|
||||
);
|
||||
content = content.replace(
|
||||
/window\.SENTRY_RELEASE\s*=\s*['"][^'"]*['"]/,
|
||||
`window.SENTRY_RELEASE = '${SENTRY_RELEASE}'`
|
||||
);
|
||||
|
||||
// 替换配置占位符
|
||||
content = content.replace(
|
||||
/window\.SENTRY_DSN\s*=\s*['"][^'"]*['"]/,
|
||||
`window.SENTRY_DSN = '${SENTRY_DSN}'`
|
||||
);
|
||||
content = content.replace(
|
||||
/window\.SENTRY_ENVIRONMENT\s*=\s*['"][^'"]*['"]/,
|
||||
`window.SENTRY_ENVIRONMENT = '${SENTRY_ENVIRONMENT}'`
|
||||
);
|
||||
content = content.replace(
|
||||
/window\.SENTRY_RELEASE\s*=\s*['"][^'"]*['"]/,
|
||||
`window.SENTRY_RELEASE = '${SENTRY_RELEASE}'`
|
||||
);
|
||||
fs.writeFileSync(fullPath, content, 'utf8');
|
||||
console.log(` ✓ 已处理: ${configFile}`);
|
||||
|
||||
fs.writeFileSync(fullPath, content, 'utf8');
|
||||
console.log(` ✓ 已处理: ${filePath}`);
|
||||
processedCount++;
|
||||
});
|
||||
|
||||
console.log(`[Sentry Config] 完成,共处理 ${processedCount} 个文件`);
|
||||
console.log('[Sentry Config] 完成');
|
||||
|
||||
@@ -7,12 +7,8 @@
|
||||
<meta name="description" content="Giffgaff eSIM 工具,支持 OAuth 登录、MFA 验证、二维码生成与设备更换。">
|
||||
|
||||
<!-- Sentry 错误监控配置(必须在其他脚本之前) -->
|
||||
<script>
|
||||
// Sentry 配置 - 在 Netlify 部署时会通过环境变量注入
|
||||
window.SENTRY_DSN = ''; // 在 Netlify 环境变量中配置
|
||||
window.SENTRY_ENVIRONMENT = 'production';
|
||||
window.SENTRY_RELEASE = 'esim-tools@unknown';
|
||||
</script>
|
||||
<!-- 使用外链脚本以符合 CSP 策略 -->
|
||||
<script src="/src/js/sentry-config.js"></script>
|
||||
<script src="/src/js/sentry-loader.js"></script>
|
||||
|
||||
<!-- 预连接优化 -->
|
||||
|
||||
11
src/js/sentry-config.js
Normal file
11
src/js/sentry-config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Sentry 配置文件
|
||||
*
|
||||
* 此文件用于设置 Sentry 配置变量,在构建时由 inject-sentry-config.js 注入实际值
|
||||
* 使用外链脚本而非内联脚本,以符合 CSP 策略
|
||||
*/
|
||||
|
||||
// Sentry 配置 - 构建时会被注入实际值
|
||||
window.SENTRY_DSN = '';
|
||||
window.SENTRY_ENVIRONMENT = 'production';
|
||||
window.SENTRY_RELEASE = 'esim-tools@unknown';
|
||||
@@ -113,7 +113,35 @@
|
||||
|
||||
// 敏感数据过滤
|
||||
beforeSend: function(event) {
|
||||
// 脱敏 URL 中的敏感查询参数
|
||||
function sanitizeQueryString(url) {
|
||||
if (!url) return url;
|
||||
var sensitiveParams = ['token', 'key', 'password', 'code', 'state', 'access_token', 'refresh_token', 'auth', 'secret'];
|
||||
try {
|
||||
var urlObj = new URL(url, window.location.origin);
|
||||
sensitiveParams.forEach(function(param) {
|
||||
if (urlObj.searchParams.has(param)) {
|
||||
urlObj.searchParams.set(param, '***');
|
||||
}
|
||||
});
|
||||
return urlObj.toString();
|
||||
} catch (e) {
|
||||
// URL 解析失败,使用正则替换
|
||||
return url.replace(/([?&])(token|key|password|code|state|access_token|refresh_token|auth|secret)=[^&]*/gi, '$1$2=***');
|
||||
}
|
||||
}
|
||||
|
||||
if (event.request) {
|
||||
// 脱敏 query_string
|
||||
if (event.request.query_string) {
|
||||
event.request.query_string = event.request.query_string
|
||||
.replace(/(token|key|password|code|state|access_token|refresh_token|auth|secret)=[^&]*/gi, '$1=***');
|
||||
}
|
||||
// 脱敏 URL
|
||||
if (event.request.url) {
|
||||
event.request.url = sanitizeQueryString(event.request.url);
|
||||
}
|
||||
// 删除敏感 cookies 和 headers
|
||||
delete event.request.cookies;
|
||||
if (event.request.headers) {
|
||||
delete event.request.headers['authorization'];
|
||||
@@ -129,7 +157,11 @@
|
||||
.replace(/token[=:]\s*[^\s,]+/gi, 'token=***')
|
||||
.replace(/key[=:]\s*[^\s,]+/gi, 'key=***')
|
||||
.replace(/password[=:]\s*[^\s,]+/gi, 'password=***')
|
||||
.replace(/cookie[=:]\s*[^\s,]+/gi, 'cookie=***');
|
||||
.replace(/cookie[=:]\s*[^\s,]+/gi, 'cookie=***')
|
||||
.replace(/code[=:]\s*[^\s,]+/gi, 'code=***')
|
||||
.replace(/state[=:]\s*[^\s,]+/gi, 'state=***')
|
||||
.replace(/access_token[=:]\s*[^\s,]+/gi, 'access_token=***')
|
||||
.replace(/refresh_token[=:]\s*[^\s,]+/gi, 'refresh_token=***');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -200,6 +232,8 @@
|
||||
console.log('[Sentry Loader] SDK 加载成功');
|
||||
// 加载成功后立即初始化
|
||||
initSentry();
|
||||
// 触发自定义事件,通知其他模块 SDK 已加载
|
||||
window.dispatchEvent(new Event('sentry-sdk-loaded'));
|
||||
};
|
||||
|
||||
script.onerror = function() {
|
||||
|
||||
@@ -7,12 +7,8 @@
|
||||
<meta name="description" content="Simyo eSIM 工具,支持设备更换、短信验证码、二维码生成与安装确认,帮助您快速管理荷兰 Simyo eSIM。">
|
||||
|
||||
<!-- Sentry 错误监控配置(必须在其他脚本之前) -->
|
||||
<script>
|
||||
// Sentry 配置 - 在 Netlify 部署时会通过环境变量注入
|
||||
window.SENTRY_DSN = ''; // 在 Netlify 环境变量中配置
|
||||
window.SENTRY_ENVIRONMENT = 'production';
|
||||
window.SENTRY_RELEASE = 'esim-tools@unknown';
|
||||
</script>
|
||||
<!-- 使用外链脚本以符合 CSP 策略 -->
|
||||
<script src="/src/js/sentry-config.js"></script>
|
||||
<script src="/src/js/sentry-loader.js"></script>
|
||||
|
||||
<!-- 预连接优化 -->
|
||||
|
||||
Reference in New Issue
Block a user