From 65068df5dddb4220f7a52e828a13cbc4c0c71f88 Mon Sep 17 00:00:00 2001 From: Abner <22141172+Silentely@users.noreply.github.com> Date: Sat, 13 Dec 2025 23:36:44 +0800 Subject: [PATCH] =?UTF-8?q?fix(sentry):=20=E4=BF=AE=E5=A4=8D=20CSP=20?= =?UTF-8?q?=E5=86=85=E8=81=94=E8=84=9A=E6=9C=AC=E9=97=AE=E9=A2=98=E5=B9=B6?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E6=95=8F=E6=84=9F=E6=95=B0=E6=8D=AE=E8=84=B1?= =?UTF-8?q?=E6=95=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 sentry-config.js 外链脚本替代 HTML 内联配置 - 修改 HTML 文件引用外链脚本以符合 CSP 策略 - 重写 inject-sentry-config.js 仅处理配置文件 - 添加 sentry-sdk-loaded 事件触发,修复 SDK 超时覆盖问题 - 增强 beforeSend 脱敏逻辑,覆盖 query_string 和更多敏感参数 --- scripts/inject-sentry-config.js | 61 +++++++++++++----------------- src/giffgaff/giffgaff_modular.html | 8 +--- src/js/sentry-config.js | 11 ++++++ src/js/sentry-loader.js | 36 +++++++++++++++++- src/simyo/simyo_modular.html | 8 +--- 5 files changed, 76 insertions(+), 48 deletions(-) create mode 100644 src/js/sentry-config.js diff --git a/scripts/inject-sentry-config.js b/scripts/inject-sentry-config.js index 5fadab5..c517a76 100644 --- a/scripts/inject-sentry-config.js +++ b/scripts/inject-sentry-config.js @@ -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] 完成'); diff --git a/src/giffgaff/giffgaff_modular.html b/src/giffgaff/giffgaff_modular.html index 85a3aa3..14e8a79 100644 --- a/src/giffgaff/giffgaff_modular.html +++ b/src/giffgaff/giffgaff_modular.html @@ -7,12 +7,8 @@ - + + diff --git a/src/js/sentry-config.js b/src/js/sentry-config.js new file mode 100644 index 0000000..9241738 --- /dev/null +++ b/src/js/sentry-config.js @@ -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'; diff --git a/src/js/sentry-loader.js b/src/js/sentry-loader.js index 0d70605..2a987bf 100644 --- a/src/js/sentry-loader.js +++ b/src/js/sentry-loader.js @@ -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() { diff --git a/src/simyo/simyo_modular.html b/src/simyo/simyo_modular.html index e87aead..3556561 100644 --- a/src/simyo/simyo_modular.html +++ b/src/simyo/simyo_modular.html @@ -7,12 +7,8 @@ - + +