From 4267e201488100b6283ff4c0897035220922a62d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E8=89=AF?= <841369634@qq.com> Date: Tue, 16 Apr 2024 16:09:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=87=8D=E6=9E=84=EF=BC=9A?= =?UTF-8?q?=E5=B0=86=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90script=E6=8B=A6?= =?UTF-8?q?=E6=88=AA=E5=99=A8=E9=85=8D=E7=BD=AE=E7=9A=84=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E8=BD=AC=E7=A7=BB=E5=88=B0=20script.js=20=E4=B8=AD?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/lib/interceptor/impl/res/script.js | 96 ++++++++++++++++++- packages/mitmproxy/src/options.js | 91 +----------------- 2 files changed, 98 insertions(+), 89 deletions(-) diff --git a/packages/mitmproxy/src/lib/interceptor/impl/res/script.js b/packages/mitmproxy/src/lib/interceptor/impl/res/script.js index 784398c..43cbfae 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/res/script.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/res/script.js @@ -1,8 +1,14 @@ -const contextPath = '/____ds_script____/' const monkey = require('../../../monkey') const CryptoJs = require('crypto-js') +const lodash = require('lodash') +const log = require('../../../../utils/util.log') + +const SCRIPT_URL_PRE = '/____ds_script____/' // 内置脚本的请求地址前缀 +const SCRIPT_PROXY_URL_PRE = '/____ds_script_proxy____/' // 绝对地址脚本的伪脚本地址前缀 +const REMOVE = '[remove]' // 标记需要移除的头信息 + function getScript (key, script) { - const scriptUrl = contextPath + key + const scriptUrl = SCRIPT_URL_PRE + key const hash = CryptoJs.SHA256(script).toString(CryptoJs.enc.Base64) return `` @@ -60,5 +66,91 @@ module.exports = { }, is (interceptOpt) { return interceptOpt.script + }, + // 处理拦截配置:自动生成script拦截器所需的辅助配置,降低使用`script拦截器`配置绝对地址和相对地址时的门槛 + handleScriptInterceptConfig (intercepts) { + // 为了简化 script 拦截器配置脚本绝对地址,这里特殊处理一下 + for (const hostnamePattern in intercepts) { + const hostnameConfig = intercepts[hostnamePattern] + + const scriptProxy = {} + for (const pathPattern in hostnameConfig) { + const pathConfig = hostnameConfig[pathPattern] + if (typeof pathConfig.script === 'object' && pathConfig.script.length > 0) { + for (let i = 0; i < pathConfig.script.length; i++) { + const script = pathConfig.script[i] + if (script.indexOf('https:') === 0 || script.indexOf('http:') === 0) { + // 绝对地址 + const scriptKey = SCRIPT_PROXY_URL_PRE + script.replace('.js', '').replace(/\W/g, '') + '.js' // 伪脚本地址:移除 script 中可能存在的特殊字符,并转为相对地址 + scriptProxy[scriptKey] = script + log.info(`替换script配置值:'${pathConfig.script[i]}' -> '${scriptKey}'`) + pathConfig.script[i] = scriptKey + } else if (script.indexOf('/') === 0) { + // 相对地址 + scriptProxy[script] = script + } + } + } + } + + // 自动创建脚本 + if (!lodash.isEmpty(scriptProxy)) { + for (const scriptKey in scriptProxy) { + if (scriptKey.indexOf(SCRIPT_PROXY_URL_PRE) === 0) { + // 绝对地址:新增代理配置 + const scriptUrl = scriptProxy[scriptKey] + + const pathPattern = `^${scriptKey.replace(/\./g, '\\.')}$` + if (hostnameConfig[pathPattern]) { + continue // 配置已经存在,按自定义配置优先 + } + hostnameConfig[pathPattern] = { + proxy: scriptUrl, + // 移除部分请求头,避免触发目标站点的拦截策略 + requestReplace: { + headers: { + host: REMOVE, + referer: REMOVE, + cookie: REMOVE + } + }, + // 替换和移除部分响应头,避免触发目标站点的阻止脚本加载策略 + responseReplace: { + headers: { + 'content-type': 'application/javascript; charset=utf-8', + 'set-cookie': REMOVE, + server: REMOVE + } + }, + cacheDays: 7, + desc: "为伪脚本文件设置代理地址,并设置响应头 `content-type: 'application/javascript; charset=utf-8'`,同时缓存7天。" + } + + const obj = {} + obj[pathPattern] = hostnameConfig[pathPattern] + log.info(`域名 '${hostnamePattern}' 拦截配置中,新增伪脚本地址的代理配置:`, obj) + } else { + // 相对地址:新增响应头Content-Type替换配置 + if (hostnameConfig[scriptKey]) { + continue // 配置已经存在,按自定义配置优先 + } + + hostnameConfig[scriptKey] = { + responseReplace: { + headers: { + 'content-type': 'application/javascript; charset=utf-8' + } + }, + cacheDays: 7, + desc: "为脚本设置响应头 `content-type: 'application/javascript; charset=utf-8'`,同时缓存7天。" + } + + const obj = {} + obj[scriptKey] = hostnameConfig[scriptKey] + log.info(`域名 '${hostnamePattern}' 拦截配置中,新增目标脚本地址的响应头替换配置:`, obj) + } + } + } + } } } diff --git a/packages/mitmproxy/src/options.js b/packages/mitmproxy/src/options.js index e5305a1..7799891 100644 --- a/packages/mitmproxy/src/options.js +++ b/packages/mitmproxy/src/options.js @@ -3,97 +3,14 @@ const dnsUtil = require('./lib/dns') const log = require('./utils/util.log') const matchUtil = require('./utils/util.match') const path = require('path') -const lodash = require('lodash') -const SCRIPT_URL_PRE = '/____ds_script_proxy____/' -const REMOVE = '[remove]' +const scriptInterceptor = require('./lib/interceptor/impl/res/script') const createOverwallMiddleware = require('./lib/proxy/middleware/overwall') -// 处理拦截配置:目前,只自动生成了script拦截器所需的辅助配置,降低script拦截器配置绝对地址和相对地址的门槛 +// 处理拦截配置 function buildIntercepts (intercepts) { - // 为了简化 script 拦截器配置脚本绝对地址,这里特殊处理一下 - for (const hostnamePattern in intercepts) { - const hostnameConfig = intercepts[hostnamePattern] - - const scriptProxy = {} - for (const pathPattern in hostnameConfig) { - const pathConfig = hostnameConfig[pathPattern] - if (typeof pathConfig.script === 'object' && pathConfig.script.length > 0) { - for (let i = 0; i < pathConfig.script.length; i++) { - const script = pathConfig.script[i] - if (script.indexOf('https:') === 0 || script.indexOf('http:') === 0) { - // 绝对地址 - const scriptKey = SCRIPT_URL_PRE + script.replace('.js', '').replace(/\W/g, '') + '.js' // 伪脚本地址:移除 script 中可能存在的特殊字符,并转为相对地址 - scriptProxy[scriptKey] = script - log.info(`替换script配置值:'${pathConfig.script[i]}' -> '${scriptKey}'`) - pathConfig.script[i] = scriptKey - } else if (script.indexOf('/') === 0) { - // 相对地址 - scriptProxy[script] = script - } - } - } - } - - // 自动创建脚本 - if (!lodash.isEmpty(scriptProxy)) { - for (const scriptKey in scriptProxy) { - if (scriptKey.indexOf(SCRIPT_URL_PRE) === 0) { - // 绝对地址:新增代理配置 - const scriptUrl = scriptProxy[scriptKey] - - const pathPattern = `^${scriptKey.replace(/\./g, '\\.')}$` - if (hostnameConfig[pathPattern]) { - continue // 配置已经存在,按自定义配置优先 - } - hostnameConfig[pathPattern] = { - proxy: scriptUrl, - // 移除部分请求头,避免触发目标站点的拦截策略 - requestReplace: { - headers: { - host: REMOVE, - referer: REMOVE, - cookie: REMOVE - } - }, - // 替换和移除部分响应头,避免触发目标站点的阻止脚本加载策略 - responseReplace: { - headers: { - 'content-type': 'application/javascript; charset=utf-8', - 'set-cookie': REMOVE, - server: REMOVE - } - }, - cacheDays: 7, - desc: "为伪脚本文件设置代理地址,并设置响应头 `content-type: 'application/javascript; charset=utf-8'`,同时缓存7天。" - } - - const obj = {} - obj[pathPattern] = hostnameConfig[pathPattern] - log.info(`域名 '${hostnamePattern}' 拦截配置中,新增伪脚本地址的代理配置:`, obj) - } else { - // 相对地址:新增响应头Content-Type替换配置 - if (hostnameConfig[scriptKey]) { - continue // 配置已经存在,按自定义配置优先 - } - - hostnameConfig[scriptKey] = { - responseReplace: { - headers: { - 'content-type': 'application/javascript; charset=utf-8' - } - }, - cacheDays: 7, - desc: "为脚本设置响应头 `content-type: 'application/javascript; charset=utf-8'`,同时缓存7天。" - } - - const obj = {} - obj[scriptKey] = hostnameConfig[scriptKey] - log.info(`域名 '${hostnamePattern}' 拦截配置中,新增目标脚本地址的响应头替换配置:`, obj) - } - } - } - } + // 自动生成script拦截器所需的辅助配置,降低使用`script拦截器`配置绝对地址和相对地址时的门槛 + scriptInterceptor.handleScriptInterceptConfig(intercepts) return intercepts }