From ae99fe41374d7158348194f00f778af6ec659796 Mon Sep 17 00:00:00 2001 From: CC11001100 Date: Wed, 8 Jan 2025 01:13:10 +0800 Subject: [PATCH 1/9] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E6=97=A7?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E7=9A=84=E8=80=81=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script-request-response-hook.js | 56 ----------------------------- 1 file changed, 56 deletions(-) delete mode 100644 src/script-request-response-hook.js diff --git a/src/script-request-response-hook.js b/src/script-request-response-hook.js deleted file mode 100644 index ef89240..0000000 --- a/src/script-request-response-hook.js +++ /dev/null @@ -1,56 +0,0 @@ -// ==UserScript== -// @name script request/response hook -// @namespace https://github.com/JSREI/js-script-hook -// @version 0.1 -// @description 用来给script类型的请求打断点 -// @author CC11001100 -// @match *://*/* -// @run-at document-start -// @grant none -// ==/UserScript== - -(() => { - - /** - * 使用说明: - * 用来hook通过script发请求和服务器交互的(多为jsonp),这种打xhr断点没用 - * - * 使用方式: - * urlContainsHook: 用来在请求发送之前hook,请求的url中随便复制一点可标识的部分粘贴在这里即可, - * 只要检测到script发出的请求的url包含给定的字符串就会hook住进入断点, - * 使用场景是url中有加密参数的话就可以往前追溯定位参数怎么来的 - * - * debuggerBeforeRequestSend: 是否在发送请求前进入断点,如果只需要打response断点的话则手动置为false即可 - * - * jsonpCallbackFunctionNameParam: 注意服务器的响应内容,如果服务器是返回的callback({foo: bar})形式的, - * 就将callback函数的名字粘贴到这里,适用场景是jsonp回调函数的名字不变 - * - * jsonpCallbackFunctionNameParam: 用来在接收到服务器响应时进入断点,如果是以jsonp形式交互的,则服务器返回的是一个函数调用的形式, - * 具体调用哪个函数是请求参数传递的,这里指定的就是这个参数的名字,会把函数名字替掉添加response断点, - * 用于jsonp回调函数每次都会变的,典型的就是jsonp函数名称总有时间戳 - * 使用场景是如果响应体是加密的可以跟进去看解密逻辑 - * - */ - - const urlContainsHook = "localhost"; - - // 如果为true则在请求发送前进入断点,否则请求发送前不进入断点 - // 如果请求参数比较明确,但是返回内容是加密的,这个时候只关注响应是如何处理的,则可以将这个选项置为false - const debuggerBeforeRequestSend = true; - - // 如果jsonp的回调不是通过参数传递的,而是服务端返回时写死的,看一眼函数的名字,配置在这里,会把这个函数替换掉以插入断点 - const jsonpCallbackFunctionName = ""; - - // 如果每次都会变,则只能从参数中取名字 - const jsonpCallbackFunctionNameParam = ""; - - const scriptDebugger = [ - // 请求的Url中包含给定的字符串时进入断点 - "", - { - "urlPattern": " { string | Regexp | null } ", - "jsonpCallbackFunctionName": " { string | Regexp | null }" - } - ] - -})(); From 1a1bd83d4b120b5ba3f86d99bb89d23503341ec9 Mon Sep 17 00:00:00 2001 From: CC11001100 Date: Wed, 8 Jan 2025 01:17:47 +0800 Subject: [PATCH 2/9] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=E8=B7=B3=E8=BD=AC?= =?UTF-8?q?=E6=89=93=E5=BC=80=E6=97=B6=E6=A0=B7=E5=BC=8F=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/ui/menu.js | 3 ++- src/init/init.js | 13 +++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/config/ui/menu.js b/src/config/ui/menu.js index c036dc8..bae4180 100644 --- a/src/config/ui/menu.js +++ b/src/config/ui/menu.js @@ -38,6 +38,7 @@ function currentInProjectRepo() { } module.exports = { - registerMenu + registerMenu, + show } diff --git a/src/init/init.js b/src/init/init.js index 971a010..f2ccec2 100644 --- a/src/init/init.js +++ b/src/init/init.js @@ -1,5 +1,4 @@ -const {registerMenu} = require("../config/ui/menu"); -const {Debugger} = require("../debugger/debugger"); +const {registerMenu, show} = require("../config/ui/menu"); const {getUnsafeWindow} = require("../utils/scope-util"); const {DocumentHook} = require("../hook/document-hook"); const {initConfig, getGlobalConfig} = require("../config/config"); @@ -16,18 +15,12 @@ function init() { // 增加可视化的配置 registerMenu(); - // 增加一个测试断点 - // const jsonpDebugger = new Debugger("test", true, "match-regexp", /xxxxx/); - // getGlobalConfig().addDebugger(jsonpDebugger); - // 为document增加hook点 - const unsafeWindow = getUnsafeWindow(); - new DocumentHook(unsafeWindow.document).addHook(); + new DocumentHook(getUnsafeWindow().document).addHook(); if (GM_getValue("js-script-hook-open-configuration")) { GM_setValue("js-script-hook-open-configuration", false); - const configurationComponent = new ConfigurationComponent(); - configurationComponent.show(); + show(); } } From 73dabe06176bb8d1c340bd19f3fc721dd07f128b Mon Sep 17 00:00:00 2001 From: CC11001100 Date: Wed, 8 Jan 2025 01:48:59 +0800 Subject: [PATCH 3/9] fix: hook --- src/analyzer/param-encryption-analyzer.js | 107 +++++++++--------- src/analyzer/request-analyzer.js | 11 +- .../ui/component/configuration-component.js | 2 +- src/context/request/param.js | 2 + src/context/request/request-context.js | 1 + src/formatter/request-formatter.js | 26 +++-- src/hook/jsonp-callback-hook.js | 5 +- src/hook/object-function-hook.js | 3 +- src/hook/script-hook.js | 8 +- 9 files changed, 89 insertions(+), 76 deletions(-) diff --git a/src/analyzer/param-encryption-analyzer.js b/src/analyzer/param-encryption-analyzer.js index 477a401..5d533e1 100644 --- a/src/analyzer/param-encryption-analyzer.js +++ b/src/analyzer/param-encryption-analyzer.js @@ -1,105 +1,104 @@ /** - * 分析参数加密 + * 参数加密分析器类,用于检测输入参数的加密类型。 */ class ParamEncryptionAnalyzer { /** - * - * @param param {Param} + * 分析参数的加密类型。 + * @param {Param} param - 需要分析的参数对象,包含一个 `value` 属性。 + * @returns {string|null} 返回检测到的加密类型,如果无法识别则返回 `null`。 */ analyze(param) { return this.detectEncryptionType(param.value); } + /** + * 检测输入字符串的加密类型。 + * @param {string} input - 需要检测的输入字符串。 + * @returns {string|null} 返回检测到的加密类型,如果无法识别则返回 `null`。 + */ detectEncryptionType(input) { - // Base64 - const base64Regex = /^[A-Za-z0-9+/]+={0,2}$/; - if (base64Regex.test(input) && input.length % 4 === 0) { - return "Base64"; + + // 如果输入为空,直接返回 null + if (!input) { + return null; } - // MD5 + // // Base64 编码检测 + // const base64Regex = /^[A-Za-z0-9+/]+={0,2}$/; + // if (base64Regex.test(input) && input.length % 4 === 0) { + // return "Base64"; + // } + + // MD5 哈希检测 const md5Regex = /^[a-f0-9]{32}$/i; if (md5Regex.test(input)) { return "MD5"; } - // SHA-1 + // SHA-1 哈希检测 const sha1Regex = /^[a-f0-9]{40}$/i; if (sha1Regex.test(input)) { return "SHA-1"; } - // SHA-256 + // SHA-256 哈希检测 const sha256Regex = /^[a-f0-9]{64}$/i; if (sha256Regex.test(input)) { return "SHA-256"; } - // SHA-512 + // SHA-512 哈希检测 const sha512Regex = /^[a-f0-9]{128}$/i; if (sha512Regex.test(input)) { return "SHA-512"; } - // bcrypt + // bcrypt 哈希检测 const bcryptRegex = /^\$2[aby]\$\d{2}\$[.\/A-Za-z0-9]{53}$/; if (bcryptRegex.test(input)) { return "bcrypt"; } - // URL编码 - const urlEncodedRegex = /%[0-9A-Fa-f]{2}/; - if (urlEncodedRegex.test(input)) { - return "URL Encoded"; - } - - // Hex编码 - const hexRegex = /^[0-9A-Fa-f]+$/; - if (hexRegex.test(input) && input.length % 2 === 0) { - return "Hex Encoded"; - } - - // ROT13 - const rot13Regex = /^[A-Za-z]+$/; - if (rot13Regex.test(input) && input === input.replace(/[A-Za-z]/g, function (c) { - return String.fromCharCode(c.charCodeAt(0) + (c.toLowerCase() < 'n' ? 13 : -13)); - })) { - return "ROT13"; - } - - // JWT - const jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/; - if (jwtRegex.test(input)) { - return "JWT"; - } - - // UUID + // // URL 编码检测 + // const urlEncodedRegex = /%[0-9A-Fa-f]{2}/; + // if (urlEncodedRegex.test(input)) { + // return "URL Encoded"; + // } + // + // // Hex 编码检测 + // const hexRegex = /^[0-9A-Fa-f]+$/; + // if (hexRegex.test(input) && input.length % 2 === 0) { + // return "Hex Encoded"; + // } + + // // ROT13 编码检测 + // const rot13Regex = /^[A-Za-z]+$/; + // if (rot13Regex.test(input) && input === input.replace(/[A-Za-z]/g, function (c) { + // return String.fromCharCode(c.charCodeAt(0) + (c.toLowerCase() < 'n' ? 13 : -13)); + // })) { + // return "ROT13"; + // } + + // // JWT (JSON Web Token) 检测 + // const jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/; + // if (jwtRegex.test(input)) { + // return "JWT"; + // } + + // UUID 检测 const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; if (uuidRegex.test(input)) { return "UUID"; } - // 如果都不匹配,返回未知 + // 如果以上所有加密类型都不匹配,返回 null 表示未知加密类型 return null; } -// // 测试示例 -// console.log(detectEncryptionType("SGVsbG8gV29ybGQ=")); // Base64 -// console.log(detectEncryptionType("5d41402abc4b2a76b9719d911017c592")); // MD5 -// console.log(detectEncryptionType("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12")); // SHA-1 -// console.log(detectEncryptionType("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); // SHA-256 -// console.log(detectEncryptionType("$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy")); // bcrypt -// console.log(detectEncryptionType("Hello%20World")); // URL Encoded -// console.log(detectEncryptionType("48656c6c6f20576f726c64")); // Hex Encoded -// console.log(detectEncryptionType("Uryyb Jbeyq")); // ROT13 -// console.log(detectEncryptionType("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c")); // JWT -// console.log(detectEncryptionType("550e8400-e29b-41d4-a716-446655440000")); // UUID -// console.log(detectEncryptionType("randomstring")); // Unknown Encryption Type - } - +// 导出 ParamEncryptionAnalyzer 类 module.exports = { ParamEncryptionAnalyzer } \ No newline at end of file diff --git a/src/analyzer/request-analyzer.js b/src/analyzer/request-analyzer.js index 86e281d..d769b6b 100644 --- a/src/analyzer/request-analyzer.js +++ b/src/analyzer/request-analyzer.js @@ -1,4 +1,5 @@ const {getUnsafeWindow} = require("../utils/scope-util"); +const {ParamEncryptionAnalyzer} = require("./param-encryption-analyzer"); /** * 分析请求中的jsonp情况,主要是看一下是否存在jsonp参数,并将其识别出来 @@ -10,16 +11,24 @@ class RequestAnalyzer { * @param requestContext {RequestContext} */ analyze(requestContext) { + if (!requestContext.params) { return null; } - requestContext.params = this.computeParamsJsonpCallbackScore(requestContext.params); + // 自动推断出jsonp参数 + requestContext.params = this.computeParamsJsonpCallbackScore(requestContext.params); // 选出其中可能性最大的一个参数作为jsonp callback参数 if (requestContext.params && requestContext.params.length && requestContext.params[0].jsonpCallbackScore > 0) { requestContext.params[0].isJsonpCallback = true; } + // 推断参数加密方式 + const paramEncryptionAnalyzer = new ParamEncryptionAnalyzer(); + for (let param of requestContext.params) { + param.encryptType = paramEncryptionAnalyzer.analyze(param); + } + } /** diff --git a/src/config/ui/component/configuration-component.js b/src/config/ui/component/configuration-component.js index 8b711c3..7023db8 100644 --- a/src/config/ui/component/configuration-component.js +++ b/src/config/ui/component/configuration-component.js @@ -4,7 +4,7 @@ const {getGlobalConfig} = require("../../config"); const {getLanguage} = require("./language"); /** - * 使用之前要签署用户协议 + * 配置组件 */ class ConfigurationComponent { diff --git a/src/context/request/param.js b/src/context/request/param.js index 2f92c3b..30ba513 100644 --- a/src/context/request/param.js +++ b/src/context/request/param.js @@ -24,6 +24,8 @@ class Param { // 此参数是 JSONP 的 callback 参数的可能性有多大(用于评分) this.jsonpCallbackScore = 0; + // 参数的加密类型 + this.encryptType = null; } /** diff --git a/src/context/request/request-context.js b/src/context/request/request-context.js index f0c24da..1516d54 100644 --- a/src/context/request/request-context.js +++ b/src/context/request/request-context.js @@ -1,4 +1,5 @@ const {repeat} = require("../../utils/string-util"); +const {Param} = require("./param"); /** * 用于封装请求的上下文,包含从 URL 中解析出的各种信息。 diff --git a/src/formatter/request-formatter.js b/src/formatter/request-formatter.js index db25661..31747c0 100644 --- a/src/formatter/request-formatter.js +++ b/src/formatter/request-formatter.js @@ -70,24 +70,32 @@ class RequestFormatter { // 示例数据 const data = [ - ['名称', '值'], - [language.console.time, new Date().toLocaleString()], - [language.console.requestId, scriptContext.requestId], - [language.console.isJsonpRequest, scriptContext.isJsonp()], - [language.console.hostname, requestContext.hostname], - [language.console.path, requestContext.path], - [language.console.hash, requestContext.hash], + // TODO 2025-01-08 01:28:26 国际化 + ["名称", "值", "备注"], + [language.console.time, new Date().toLocaleString(), ""], + [language.console.requestId, scriptContext.requestId, ""], + [language.console.isJsonpRequest, scriptContext.isJsonp(), ""], + [language.console.hostname, requestContext.hostname, ""], + [language.console.path, requestContext.path, ""], + [language.console.hash, requestContext.hash, ""], // [language.console.param, requestContext.params.length], ]; let index = 1; for (let param of requestContext.params) { + const name = `${language.console.param}(${index++}) ${param.name}`; + let value = `${param.value}`; + + let attribute = ""; if (param.isJsonpCallback) { - value += "(jsonp callback)" + attribute = "jsonp callback"; + } else if (param.encryptType) { + attribute = param.encryptType; } - data.push([name, value]); + + data.push([name, value, attribute]); } // 示例样式 diff --git a/src/hook/jsonp-callback-hook.js b/src/hook/jsonp-callback-hook.js index b85f72e..72cd533 100644 --- a/src/hook/jsonp-callback-hook.js +++ b/src/hook/jsonp-callback-hook.js @@ -46,10 +46,11 @@ class JsonpCallbackHook { const hook = new ObjectFunctionHook(getUnsafeWindow(), jsonpCallbackFunctionName); if (getGlobalConfig().hookType === "use-redeclare-function") { hook.hookType = hookTypeUseDeclareFunction; - hook.addHook(this.callbackForDeclareFunction(_this), true); + hook.addHook(this.callbackForDeclareFunction(_this)); } else if (getGlobalConfig().hookType === "use-proxy-function") { hook.hookType = hookTypeUseProxyFunction; - hook.addHook(this.callbackForProxyFunction(_this), true); + hook.callByHookCallbackFunction = true; + hook.addHook(this.callbackForProxyFunction(_this)); } } diff --git a/src/hook/object-function-hook.js b/src/hook/object-function-hook.js index bf3c4ad..0f0f256 100644 --- a/src/hook/object-function-hook.js +++ b/src/hook/object-function-hook.js @@ -32,9 +32,8 @@ class ObjectFunctionHook { /** * * @param hookCallbackFunction - * @param callByHookCallbackFunction {boolean} */ - addHook(hookCallbackFunction, callByHookCallbackFunction = false) { + addHook(hookCallbackFunction) { // 要Hook的函数必须存在 const functionHolder = this.object[this.functionName]; diff --git a/src/hook/script-hook.js b/src/hook/script-hook.js index 713e317..4266784 100644 --- a/src/hook/script-hook.js +++ b/src/hook/script-hook.js @@ -1,14 +1,8 @@ -const Debugger = require("../debugger/debugger"); -const {JsonpCallbackFunctionAnalyzer} = require("../analyzer/response-analyzer"); const {ScriptContext} = require("../context/script/script-context"); const {RequestContext} = require("../context/request/request-context"); const {RequestAnalyzer} = require("../analyzer/request-analyzer"); const {getGlobalConfig} = require("../config/config"); const {RequestFormatter} = require("../formatter/request-formatter"); -const {getUnsafeWindow} = require("../utils/scope-util"); -const {ObjectFunctionHook} = require("./object-function-hook"); -const {ResponseContext} = require("../context/response/response-context"); -const {ResponseFormatter} = require("../formatter/response-formatter"); const {JsonpCallbackHook} = require("./jsonp-callback-hook"); const {formatScriptSrcToUrl} = require("../utils/url-util"); const {DebuggerTester} = require("../debugger/debugger-tester"); @@ -51,7 +45,7 @@ class ScriptHook { // 在请求发送之前测试断点 if (new DebuggerTester().isNeedPrintToConsole(getGlobalConfig(), scriptContext)) { const requestFormatter = new RequestFormatter(); - console.log(requestFormatter.format(scriptContext)); + requestFormatter.format(scriptContext) } const hitDebuggers = getGlobalConfig().testAll(scriptContext); From 6294b972778e703901f6070231518e5214ae000a Mon Sep 17 00:00:00 2001 From: CC11001100 Date: Wed, 8 Jan 2025 01:49:31 +0800 Subject: [PATCH 4/9] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4request=20formatte?= =?UTF-8?q?r=E7=9A=84=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/formatter/request-formatter.js | 46 ------------------------------ 1 file changed, 46 deletions(-) diff --git a/src/formatter/request-formatter.js b/src/formatter/request-formatter.js index 31747c0..470f0aa 100644 --- a/src/formatter/request-formatter.js +++ b/src/formatter/request-formatter.js @@ -18,52 +18,6 @@ class RequestFormatter { const requestContext = scriptContext.requestContext; const language = getLanguage(getGlobalConfig().language); - // 提示词: - // 我需要写一些console.log的样式打印在控制台上,接下来会陆陆续续给你一些写样式的任务,球球你帮帮我 - - const valueStyle = `color: black; background: #E50000; font-size: 12px; font-weight: bold;`; - const normalStyle = `color: black; background: #FF6766; font-size: 12px;`; - - const titleStyle = 'font-weight: bold; font-size: 16px; background: green; color: white; padding: 5px; border-radius: 3px;'; - - const length = 200; - - const message = [ - normalStyle, fillToLength(`-------------------------------------------------- Script Hook Captured Request --------------------------------------------------`, length) + "\n", - normalStyle, fillToLength(`${language.console.time}: ${new Date().toLocaleString()}`, length) + "\n", - normalStyle, fillToLength(`${language.console.requestId}: ${scriptContext.requestId}`, length) + "\n", - normalStyle, fillToLength(`${language.console.isJsonpRequest}: ${scriptContext.isJsonp()}`, length) + "\n", - normalStyle, fillToLength(`${language.console.hostname}: ${requestContext.hostname}`, length) + "\n", - normalStyle, fillToLength(`${language.console.path}: ${requestContext.path}`, length) + "\n", - normalStyle, fillToLength(`${language.console.hash}: ${requestContext.hash}`, length) + "\n", - normalStyle, fillToLength((() => { - const paramTitle = `${language.console.param}(${requestContext.params.length})`; - return paramTitle; - })(), length) + "\n", - - - // (() => { - // - // let paramTitle = `${indentSpace}`; - // if (!this.params.length) { - // paramTitle += " do not have param."; - // } - // msgs.push(paramTitle); - // for (let param of this.params) { - // msgs.push(param.toHumanReadable(indent + 4)); - // } - // - // - // if (this.hash) { - // msgs.push() - // } - // - // return msgs.join("\n\n"); - // })() - - ]; - console.log(genFormatArray(message), ...message); - // 把参数以表格的形式打印 // const data = this.convertParamsToTableData(language, requestContext.params); // console.table(data); From 11fdf64a6770916bbcc2edf3fd89c2e4f572f48e Mon Sep 17 00:00:00 2001 From: CC11001100 Date: Wed, 8 Jan 2025 21:08:59 +0800 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20=E5=B0=BD=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E9=99=8D=E4=BD=8E=E4=B8=AA=E4=BA=BA=E7=97=95=E8=BF=B9=EF=BC=8C?= =?UTF-8?q?=E5=BC=BA=E5=8C=96=E7=BB=84=E7=BB=87=E7=9A=84=E7=97=95=E8=BF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/config.js | 2 +- src/config/ui/component/configuration-component.js | 10 +++++----- src/config/ui/component/language.js | 2 +- src/hook/object-function-hook.js | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/config/config.js b/src/config/config.js index ebd3db0..d52db03 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -13,7 +13,7 @@ class Config { this.language = "english"; // 让用户能够自己指定前缀,也许会有一些拥有感?之前ast hook好像就有个哥们喜欢这样干... - this.prefix = "CC11001100"; + this.prefix = "JSREI"; this.hookType = "use-proxy-function"; diff --git a/src/config/ui/component/configuration-component.js b/src/config/ui/component/configuration-component.js index 7023db8..898c998 100644 --- a/src/config/ui/component/configuration-component.js +++ b/src/config/ui/component/configuration-component.js @@ -10,9 +10,9 @@ class ConfigurationComponent { constructor() { this.modalHTML = ` -
+
- +
@@ -39,15 +39,15 @@ class ConfigurationComponent { $("#js-script-hook-configuration-content").append(debuggerManager.render(language, getGlobalConfig().debuggers)); // 关闭按钮事件处理 - document.getElementById("cc11001100-js-script-hook-configuration-close-btn").addEventListener('click', this.closeModalWindow); - document.getElementById("cc11001100-js-script-hook-configuration-modal-window").style.display = 'flex'; + document.getElementById("jsrei-js-script-hook-configuration-close-btn").addEventListener('click', this.closeModalWindow); + document.getElementById("jsrei-js-script-hook-configuration-modal-window").style.display = 'flex'; } /** * 隐藏模态框的函数 */ closeModalWindow() { - const element = document.getElementById("cc11001100-js-script-hook-configuration-modal-window"); + const element = document.getElementById("jsrei-js-script-hook-configuration-modal-window"); if (element) { element.parentNode.removeChild(element); } diff --git a/src/config/ui/component/language.js b/src/config/ui/component/language.js index 28c3a1f..e9ad562 100644 --- a/src/config/ui/component/language.js +++ b/src/config/ui/component/language.js @@ -9,7 +9,7 @@ const chinese = { flagPrefix: "Hook Flag前缀:", flagPrefixTips: "在Hook的时候会设置一些全局唯一的标志位,你可以个性化修改为自定义的前缀", - flagPrefixPlaceholder: "可自定义全局前缀,未设置默认为 CC11001100_js_script_hook", + flagPrefixPlaceholder: "可自定义全局前缀,未设置默认为 JSREI_js_script_hook", responseDebuggerHookType: "响应断点Hook方式:", responseDebuggerHookTypeTips: "此选项刷新页面后生效", diff --git a/src/hook/object-function-hook.js b/src/hook/object-function-hook.js index 0f0f256..56022b7 100644 --- a/src/hook/object-function-hook.js +++ b/src/hook/object-function-hook.js @@ -45,8 +45,8 @@ class ObjectFunctionHook { // 如果已经Hook过了则不重复hook,也就是说一次addHook只生效一次 // TODO 2025-01-06 03:19:19 修改为读取配置中的前缀 - // const prefix = getGlobalConfig().prefix || "CC11001100_js_script_hook" - const prefix = "CC11001100_js_script_hook" + // const prefix = getGlobalConfig().prefix || "JSREI_js_script_hook" + const prefix = "JSREI_js_script_hook" const hookDoneFlag = prefix + "_hookDoneFlag"; if (functionHolder[hookDoneFlag]) { return; From f13959a97e670a7697cf23ec6a382d40a1d4283f Mon Sep 17 00:00:00 2001 From: CC11001100 Date: Wed, 8 Jan 2025 21:35:49 +0800 Subject: [PATCH 6/9] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E7=94=A8=E6=88=B7=E4=BB=A3=E7=A0=81=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/ui/component/language.js | 1 + src/formatter/request-formatter.js | 4 ++++ src/hook/watch-hook.js | 12 ++++++++++++ src/utils/code-util.js | 22 ++++++++++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 src/hook/watch-hook.js diff --git a/src/config/ui/component/language.js b/src/config/ui/component/language.js index e9ad562..e08d21c 100644 --- a/src/config/ui/component/language.js +++ b/src/config/ui/component/language.js @@ -74,6 +74,7 @@ const chinese = { paramName: "参数名称", paramValue: "参数值", isJsonpCallback: "是否是jsonp回调函数", + codeLocation: "代码位置", } }; diff --git a/src/formatter/request-formatter.js b/src/formatter/request-formatter.js index 470f0aa..50ebd54 100644 --- a/src/formatter/request-formatter.js +++ b/src/formatter/request-formatter.js @@ -3,6 +3,7 @@ const {repeat, fillToLength} = require("../utils/string-util"); const {getLanguage} = require("../config/ui/component/language"); const {getGlobalConfig} = require("../config/config"); const {printStyledTable} = require("./table-formatter"); +const {getUserCodeLocation} = require("../utils/code-util"); /** * 用于第请求进行格式化 @@ -15,6 +16,8 @@ class RequestFormatter { */ format(scriptContext) { + const codeLocation = getUserCodeLocation(); + const requestContext = scriptContext.requestContext; const language = getLanguage(getGlobalConfig().language); @@ -32,6 +35,7 @@ class RequestFormatter { [language.console.hostname, requestContext.hostname, ""], [language.console.path, requestContext.path, ""], [language.console.hash, requestContext.hash, ""], + [language.console.codeLocation, codeLocation, ""], // [language.console.param, requestContext.params.length], ]; diff --git a/src/hook/watch-hook.js b/src/hook/watch-hook.js new file mode 100644 index 0000000..e6809ad --- /dev/null +++ b/src/hook/watch-hook.js @@ -0,0 +1,12 @@ +/** + * 监控对象 + */ +class WatchHook { + + watch(object) { + + return new Proxy(); + + } + +} \ No newline at end of file diff --git a/src/utils/code-util.js b/src/utils/code-util.js index bd8f842..1f46db0 100644 --- a/src/utils/code-util.js +++ b/src/utils/code-util.js @@ -68,8 +68,30 @@ function generateRandomFunctionName(length = 8) { return result; } +const tampermonkeyChromeExtensionId = "dhdgffkkebhmkfjojejmpbldmpobfkfo"; + +/** + * 获取用户代码的位置,用户代码的定义就是调用栈里从用户的代码进入到插件代码的第一行代码 + */ +function getUserCodeLocation() { + + // 把调用栈一个栈帧一个栈帧的弹掉 + const stack = new Error().stack.split("\n"); + let index = stack.length - 1; + while (index >= 0) { + const frame = stack[index]; + if (frame.includes(tampermonkeyChromeExtensionId) && index < stack.length) { + return stack[index + 1].trim(); + } else { + index--; + } + } + return null; +} + module.exports = { getFunctionBody, getParameterNames, generateRandomFunctionName, + getUserCodeLocation, }; \ No newline at end of file From fafd14821e7984914b916b392ed536395774062b Mon Sep 17 00:00:00 2001 From: CC11001100 Date: Wed, 8 Jan 2025 22:32:50 +0800 Subject: [PATCH 7/9] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E5=8F=B0=E6=89=93=E5=8D=B0=E7=9A=84=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/formatter/request-formatter.js | 8 +-- src/formatter/response-formatter.js | 80 +++++++++++------------------ src/formatter/table-formatter.js | 56 +++++++++++++++++--- 3 files changed, 79 insertions(+), 65 deletions(-) diff --git a/src/formatter/request-formatter.js b/src/formatter/request-formatter.js index 50ebd54..63c3c77 100644 --- a/src/formatter/request-formatter.js +++ b/src/formatter/request-formatter.js @@ -21,11 +21,6 @@ class RequestFormatter { const requestContext = scriptContext.requestContext; const language = getLanguage(getGlobalConfig().language); - // 把参数以表格的形式打印 - // const data = this.convertParamsToTableData(language, requestContext.params); - // console.table(data); - - // 示例数据 const data = [ // TODO 2025-01-08 01:28:26 国际化 ["名称", "值", "备注"], @@ -65,7 +60,8 @@ class RequestFormatter { }; // 打印表格 - printStyledTable(data, styles); + const title = language.console.titleRequest; + printStyledTable(data, styles, title); } diff --git a/src/formatter/response-formatter.js b/src/formatter/response-formatter.js index 000adc2..28e7005 100644 --- a/src/formatter/response-formatter.js +++ b/src/formatter/response-formatter.js @@ -3,6 +3,8 @@ const {fillToLength} = require("../utils/string-util"); const {genFormatArray} = require("../utils/log-util"); const {getGlobalConfig} = require("../config/config"); const {highlightJSON} = require("./json-formatter"); +const {getUserCodeLocation} = require("../utils/code-util"); +const {printStyledTable} = require("./table-formatter"); /** * 用于对响应进行格式化 @@ -15,63 +17,39 @@ class ResponseFormatter { */ format(scriptContext) { + const codeLocation = getUserCodeLocation(); + const responseContext = scriptContext.responseContext; + const requestContext = scriptContext.requestContext; // const language = getLanguage(getGlobalConfig().language); const language = chinese; - // 提示词: - // 我需要写一些console.log的样式打印在控制台上,接下来会陆陆续续给你一些写样式的任务,球球你帮帮我 - - const valueStyle = `color: black; background: #E50000; font-size: 12px; font-weight: bold;`; - const normalStyle = `color: black; background: #FF6766; font-size: 12px;`; - - const titleStyle = 'font-weight: bold; font-size: 16px; background: green; color: white; padding: 5px; border-radius: 3px;'; - - const length = 200; - - // const msgs = []; - // msgs.push() - // msgs.push("Time: " + new Date().toLocaleString() + "\n"); - // msgs.push(`Request ID: ${scriptContext.requestId} \n`); - // msgs.push(`${scriptContext.responseContext.toHumanReadable(0)}`); - // return msgs.join("\n"); - - const message = [ - normalStyle, fillToLength(`-------------------------------------------------- Script Hook Captured Response --------------------------------------------------`, length) + "\n", - normalStyle, fillToLength(`${language.console.time}: ${new Date().toLocaleString()}`, length) + "\n", - normalStyle, fillToLength(`${language.console.requestId}: ${scriptContext.requestId}`, length) + "\n", - // normalStyle, fillToLength(`${language.console.isJsonpRequest}: ${scriptContext.isJsonp()}`, length) + "\n", - // normalStyle, fillToLength(`${language.console.hostname}: ${requestContext.hostname}`, length) + "\n", - // normalStyle, fillToLength(`${language.console.path}: ${requestContext.path}`, length) + "\n", - // normalStyle, fillToLength((() => { - // const paramTitle = `${language.console.param}(${requestContext.params.length})`; - // return paramTitle; - // })(), length) + "\n", - // normalStyle, fillToLength(`${language.console.hash}: ${requestContext.hash}`, length) + "\n", - - // (() => { - // - // let paramTitle = `${indentSpace}`; - // if (!this.params.length) { - // paramTitle += " do not have param."; - // } - // msgs.push(paramTitle); - // for (let param of this.params) { - // msgs.push(param.toHumanReadable(indent + 4)); - // } - // - // - // if (this.hash) { - // msgs.push() - // } - // - // return msgs.join("\n\n"); - // })() - + const data = [ + // TODO 2025-01-08 01:28:26 国际化 + ["名称", "值", "备注"], + [language.console.time, new Date().toLocaleString(), ""], + [language.console.requestId, scriptContext.requestId, ""], + [language.console.isJsonpRequest, scriptContext.isJsonp(), ""], + [language.console.hostname, requestContext.hostname, ""], + [language.console.path, requestContext.path, ""], + [language.console.hash, requestContext.hash, ""], + [language.console.codeLocation, codeLocation, ""], + // [language.console.param, requestContext.params.length], ]; - console.log(genFormatArray(message), ...message); + // 示例样式 + const styles = { + borderColor: '#000', + cellBackgroundColor: '#f0f0f0', + fontSize: '14px', + fontColor: '#333' + }; + + // 打印表格 + const title = language.console.titleResponse; + printStyledTable(data, styles, title); + const msgs = highlightJSON(responseContext.jsonpCallbackArguments); + console.log(msgs); - highlightJSON(responseContext.jsonpCallbackArguments); } diff --git a/src/formatter/table-formatter.js b/src/formatter/table-formatter.js index 3e2738c..35891b3 100644 --- a/src/formatter/table-formatter.js +++ b/src/formatter/table-formatter.js @@ -1,11 +1,23 @@ -function printStyledTable(data, styles) { - const { borderColor, cellBackgroundColor, fontSize, fontColor } = styles; +function printStyledTable(data, styles, title = '') { + const { borderColor, cellBackgroundColor, fontSize, fontColor, titleFontSize = '20px' } = styles; + + // 计算字符串的实际宽度(中文字符宽度为2,英文字符宽度为1) + function getStringWidth(str) { + let width = 0; + for (const char of str) { + width += /[\u4e00-\u9fa5]/.test(char) ? 2 : 1; // 判断是否为中文字符 + } + return width; + } // 计算每列的最大宽度 let colWidths = data[0].map((_, colIndex) => - Math.max(...data.map(row => String(row[colIndex]).length)) + Math.max(...data.map(row => getStringWidth(String(row[colIndex])))) ); + // 计算表格的总宽度 + const totalWidth = colWidths.reduce((sum, width) => sum + width + 3, 0) - 1; + // 定义表格的样式 const tableStyle = ` padding: 5px; @@ -17,26 +29,54 @@ function printStyledTable(data, styles) { white-space: pre; // 保留空格和换行 `; + // 定义标题的样式(背景色和边框与表格一致) + const titleStyle = ` + font-size: ${titleFontSize}; + font-weight: bold; + text-align: center; + background-color: ${cellBackgroundColor}; + border: 1px solid ${borderColor}; + padding: 5px; + `; + + // 根据实际宽度填充字符串 + function padString(str, width) { + const strWidth = getStringWidth(str); + if (strWidth >= width) return str; // 如果字符串宽度已经足够,直接返回 + const padding = ' '.repeat(width - strWidth); // 计算需要填充的空格 + return str + padding; + } + // 构建表格内容 let tableContent = ''; + // 如果有标题,添加标题行 + if (title) { + const titlePadding = Math.floor((totalWidth - getStringWidth(title)) / 2); + const paddedTitle = padString(title, totalWidth); + tableContent += '%c' + paddedTitle + '\n'; + } + // 表头 tableContent += data[0] - .map((cell, index) => cell.padEnd(colWidths[index])) + .map((cell, index) => padString(String(cell), colWidths[index])) .join(' │ '); // 表格内容 for (let i = 1; i < data.length; i++) { tableContent += '\n' + data[i] - .map((cell, index) => String(cell).padEnd(colWidths[index])) + .map((cell, index) => padString(String(cell), colWidths[index])) .join(' │ '); } // 打印表格 - console.log('%c' + tableContent, tableStyle); + if (title) { + console.log('%c' + tableContent, titleStyle, tableStyle); + } else { + console.log('%c' + tableContent, tableStyle); + } } - module.exports = { printStyledTable -} \ No newline at end of file +}; \ No newline at end of file From 8e40281d71ba13330d2ca8ca1b7ef0081838caa8 Mon Sep 17 00:00:00 2001 From: CC11001100 Date: Wed, 8 Jan 2025 22:39:50 +0800 Subject: [PATCH 8/9] =?UTF-8?q?feat:=20=E6=90=9E=E4=BA=86=E4=B8=8B?= =?UTF-8?q?=E5=9B=BD=E9=99=85=E5=8C=96=EF=BC=8CAI=E7=BF=BB=E8=AF=91?= =?UTF-8?q?=E8=B4=BC=E6=8B=89=E7=89=9B=E9=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/config.js | 4 +- src/config/ui/component/language.js | 125 +++++++++++++++++++--------- src/formatter/request-formatter.js | 6 +- src/formatter/response-formatter.js | 7 +- 4 files changed, 92 insertions(+), 50 deletions(-) diff --git a/src/config/config.js b/src/config/config.js index d52db03..ccdda57 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -18,10 +18,10 @@ class Config { this.hookType = "use-proxy-function"; // 是否忽略.js后缀的请求 - this.isIgnoreJsSuffixRequest = true; + this.isIgnoreJsSuffixRequest = false; // 是否忽略不是jsonp的请求 - this.isIgnoreNotJsonpRequest = true; + this.isIgnoreNotJsonpRequest = false; // 在打开配置页面的时候自动跳转到项目主页 this.autoJumpProjectSiteOnConfiguraion = true; diff --git a/src/config/ui/component/language.js b/src/config/ui/component/language.js index e08d21c..bf314a5 100644 --- a/src/config/ui/component/language.js +++ b/src/config/ui/component/language.js @@ -1,20 +1,21 @@ // 中文菜单 +const {getGlobalConfig} = require("../../config"); const chinese = { global_settings: { title: "全局设置", language: "界面语言:", - languageTips: "你可以修改此配置界面的语言,修改后下次进入生效!", + languageTips: "你可以修改此配置界面的语言,修改后下次进入生效!
You can modify the language of this configuration interface, and the changes will take effect the next time you enter!", flagPrefix: "Hook Flag前缀:", flagPrefixTips: "在Hook的时候会设置一些全局唯一的标志位,你可以个性化修改为自定义的前缀", flagPrefixPlaceholder: "可自定义全局前缀,未设置默认为 JSREI_js_script_hook", responseDebuggerHookType: "响应断点Hook方式:", - responseDebuggerHookTypeTips: "此选项刷新页面后生效", + responseDebuggerHookTypeTips: "当Hook jsonp的callback函数的时候,有两种方式实现Hook:

一种是替换掉callback方法的引用,相当于是一个代理函数,这种需要在命中断点后再点一下跟进去callback函数的实现,这种方式兼容性比较好,绝大多数网站都可以丝滑兼容;

还有一种方式是直接改写callback函数的函数体,相当于是对函数的代码实现进行编辑后重新声明,这样子可以直接把断点打在callback函数体中,但此种方式可能会有一些作用域的兼容性问题,如有遇到报错,请调整为代理方式实现Hook;

注意,此选项修改后刷新页面后生效", responseDebuggerHookTypeUseProxyFunction: "使用代理函数实现Hook", - responseDebuggerHookTypeUseRedeclareFunction: "直接修改网站callback函数体(注意可能会有作用域问题)", + responseDebuggerHookTypeUseRedeclareFunction: "直接修改网站callback函数体(注意可能会有兼容性问题)", isIgnoreJsSuffixRequest: "是否忽略.js后缀的请求:", isIgnoreJsSuffixRequestTips: "大多数时候.js后缀的请求都是单纯的加载JavaScript资源文件,可以选择忽略掉这类请求,当勾选的时候,控制台上也不会再打印.js请求", @@ -23,7 +24,7 @@ const chinese = { isIgnoreNotJsonpRequestTips: "如果只关注jsonp类型的请求,可以选择忽略掉其它请求,当勾选的时候,控制台上也不会再打印非jsonp请求", autoJumpProjectSiteOnConfiguraion: "跳转到项目主页打开此界面以防样式错乱:", - autoJumpProjectSiteOnConfiguraionTips: "油猴脚本注入的界面可能会跟网页中原有的样式发生冲突或者污染,从而导致样式错乱,跳转到经过测试的项目主页打开设置界面可以有效防止布局错乱", + autoJumpProjectSiteOnConfiguraionTips: "油猴脚本注入的界面可能会跟网页中原有的样式发生冲突或者污染,从而导致样式错乱,跳转到经过测试的项目主页打开设置界面可以有效防止布局错乱,推荐勾选此选项", }, debugger_config: { @@ -64,6 +65,11 @@ const chinese = { commentPlaceholder: "好记性不如烂笔头", }, console: { + tableKey: "键", + tableValue: "值", + tableComment: "备注", + titleRequest: "Script Hook 捕捉到请求", + titleResponse: "Script Hook 捕捉到响应", time: "时间", requestId: "请求ID", isJsonpRequest: "是否是jsonp请求", @@ -80,61 +86,97 @@ const chinese = { // 英文菜单 const english = { - global_settings: { + "global_settings": { + + "title": "Global Settings", - title: "Global Settings", + "language": "Interface Language:", + "languageTips": "你可以修改此配置界面的语言,修改后下次进入生效!
You can modify the language of this configuration interface, and the changes will take effect the next time you enter!", - language: "语言", - languageTips: "语言", + "flagPrefix": "Hook Flag Prefix:", + "flagPrefixTips": "When hooking, some globally unique flags will be set. You can customize the prefix.", + "flagPrefixPlaceholder": "You can customize the global prefix. If not set, the default is JSREI_js_script_hook.", - flagPrefix: "Flag前缀", - flagPrefixTips: "Flag前缀", - flagPrefixPlaceholder: "xxx", + "responseDebuggerHookType": "Response Breakpoint Hook Method:", + "responseDebuggerHookTypeTips": "When hooking the callback function of JSONP, there are two ways to implement the hook:

One is to replace the reference of the callback function, which acts as a proxy function. This requires stepping into the callback function implementation after hitting the breakpoint. This method has better compatibility and works smoothly on most websites.

The other method is to directly rewrite the function body of the callback function, which is equivalent to editing and redeclaring the function's code. This allows you to place the breakpoint directly in the callback function body, but there may be some scope compatibility issues. If you encounter errors, please switch to the proxy method.

Note: This option takes effect after refreshing the page.", + "responseDebuggerHookTypeUseProxyFunction": "Use Proxy Function to Implement Hook", + "responseDebuggerHookTypeUseRedeclareFunction": "Directly Modify the Callback Function Body (Note: There May Be Compatibility Issues)", - isIgnoreJsSuffixRequest: "忽略.js后缀的请求", - isIgnoreJsSuffixRequestTips: "忽略.js后缀的请求", + "isIgnoreJsSuffixRequest": "Ignore .js Suffix Requests:", + "isIgnoreJsSuffixRequestTips": "Most of the time, requests with a .js suffix are simply loading JavaScript resource files. You can choose to ignore such requests. When checked, .js requests will not be printed on the console.", - isIgnoreNotJsonpRequest: "忽略不是jsonp的请求", - isIgnoreNotJsonpRequestTips: "忽略不是jsonp的请求", + "isIgnoreNotJsonpRequest": "Ignore Non-JSONP Requests:", + "isIgnoreNotJsonpRequestTips": "If you are only concerned with JSONP-type requests, you can choose to ignore other requests. When checked, non-JSONP requests will not be printed on the console.", - autoJumpProjectSiteOnConfiguraion: "打开此界面时自动跳转到项目主页以防样式错乱", - autoJumpProjectSiteOnConfiguraionTips: "打开此界面时自动跳转到项目主页以防样式错乱", + "autoJumpProjectSiteOnConfiguraion": "Jump to the Project Homepage to Open This Interface to Prevent Style Issues:", + "autoJumpProjectSiteOnConfiguraionTips": "The interface injected by the Tampermonkey script may conflict with or pollute the original styles of the webpage, causing style issues. Jumping to the tested project homepage to open the settings interface can effectively prevent layout issues. It is recommended to check this option." }, - debugger_config: { - enable: "是否启用", - enableTips: "是否启用此断点,仅当断点处于启用状态的时候才会生效,取消勾选可以暂时禁用断点而无需删除。", + "debugger_config": { - urlPattern: "URL匹配方式", - urlPatternTips: "", + "debuggerTitle": "Breakpoint Configuration", - urlPatternTypeTips: "", - urlPatternType_EqualsThisString: "Equals This String", - urlPatternType_ContainsThisString: "Contains This String", - urlPatternType_MatchThisRegexp: "Match This Regexp", - urlPatternType_MatchALL: "Match ALL", + "enable": "Enable This Breakpoint:", + "enableTips": "Whether to enable this breakpoint. It will only take effect when the breakpoint is enabled. Unchecking it can temporarily disable the breakpoint without deleting it.", - urlPatternTextTips: "", - urlPatternTextPlaceholder: "关键字或正则表达式", + "urlPattern": "URL Matching Method:", + "urlPatternTips": "The URL matching method is used to specify when the script's URL meets certain conditions to hit this breakpoint.", - urlPatternTest: "测试", - urlPatternTestTips: "你可以输入一个script url测试此断点对其命中情况", + "urlPatternTypeTips": "Specify how to match the Script URL:", + "urlPatternType_EqualsThisString": "The Script URL must exactly match the given string.", + "urlPatternType_ContainsThisString": "The Script URL contains the given string.", + "urlPatternType_MatchThisRegexp": "The Script URL matches the given regular expression.", + "urlPatternType_MatchALL": "Directly match all Script URLs.", - enableRequestDebugger: "是否启动请求断点", - enableRequestDebuggerTips: "启动请求断点后,在script请求发出之前进入断点", + "urlPatternTextTips": "Enter a keyword or expression.", + "urlPatternTextPlaceholder": "Enter a keyword or expression.", - enableResponseDebugger: "是否启用响应断点", - enableResponseDebuggerTips: "启动响应断点之后,在jsonp请求的回调函数中命中断点", + "urlPatternTest": "Test", + "urlPatternTestTips": "You can enter a script URL to test whether this breakpoint hits it.", + "urlPatternTestPrompt": "Please enter the URL to test:", + "urlPatternTestResult": "Test Result:", - callbackFunctionParamName: "jsonp回调函数参数名称", - callbackFunctionParamNameTips: "", - callbackFunctionParamNamePlaceholder: "", + "enableRequestDebugger": "Enable Request Breakpoint:", + "enableRequestDebuggerTips": "After enabling the request breakpoint, the breakpoint will be triggered before the script request is sent.", - comment: "备注", - commentTips: "你可以输入一些备注,或者相关信息的一些上下文,以防止时间长了之后忘记。", - commentPlaceholder: "好记性不如烂笔头", + "enableResponseDebugger": "Enable Response Breakpoint:", + "enableResponseDebuggerTips": "After enabling the response breakpoint, the breakpoint will be triggered in the callback function of the JSONP request.", + + "callbackFunctionParamName": "JSONP Callback Function Parameter Name:", + "callbackFunctionParamNameTips": "If not specified, the built-in engine will automatically infer the JSONP parameter name. If the inference fails, you can manually specify it.", + "callbackFunctionParamNamePlaceholder": "If not specified, the built-in engine will automatically infer the JSONP parameter name.", + + "comment": "Comment:", + "commentTips": "You can enter some comments or contextual information to avoid forgetting it over time.", + "commentPlaceholder": "A good memory is not as good as a written record." + }, + "console": { + tableKey: "key", + tableValue: "value", + tableComment: "comment", + "titleRequest": "Script Hook Captured Request", + "titleResponse": "Script Hook Captured Response", + "time": "Time", + "requestId": "Request ID", + "isJsonpRequest": "Is JSONP Request", + "hostname": "Request Hostname", + "path": "Request Path", + "param": "Request Parameters", + "hash": "Request #hash", + "paramName": "Parameter Name", + "paramValue": "Parameter Value", + "isJsonpCallback": "Is JSONP Callback Function", + "codeLocation": "Code Location" } }; +/** + * + * @return {{debugger_config: {urlPatternTest: string, urlPatternTestTips: string, enableTips: string, commentPlaceholder: string, debuggerTitle: string, enableRequestDebuggerTips: string, enableResponseDebugger: string, enableRequestDebugger: string, callbackFunctionParamName: string, urlPatternTypeTips: string, urlPatternTips: string, urlPatternType_MatchThisRegexp: string, urlPatternType_MatchALL: string, urlPatternType_EqualsThisString: string, urlPatternTextPlaceholder: string, enable: string, commentTips: string, urlPatternTextTips: string, enableResponseDebuggerTips: string, callbackFunctionParamNameTips: string, callbackFunctionParamNamePlaceholder: string, comment: string, urlPattern: string, urlPatternType_ContainsThisString: string}, global_settings: {languageTips: string, autoJumpProjectSiteOnConfiguraionTips: string, flagPrefix: string, flagPrefixTips: string, isIgnoreJsSuffixRequestTips: string, autoJumpProjectSiteOnConfiguraion: string, isIgnoreJsSuffixRequest: string, language: string, isIgnoreNotJsonpRequestTips: string, title: string, flagPrefixPlaceholder: string, isIgnoreNotJsonpRequest: string}}|{debugger_config: {urlPatternTest: string, urlPatternTestTips: string, enableTips: string, commentPlaceholder: string, enableRequestDebuggerTips: string, enableResponseDebugger: string, enableRequestDebugger: string, callbackFunctionParamName: string, urlPatternTypeTips: string, urlPatternTips: string, urlPatternType_MatchThisRegexp: string, urlPatternType_MatchALL: string, urlPatternType_EqualsThisString: string, urlPatternTextPlaceholder: string, enable: string, commentTips: string, urlPatternTextTips: string, enableResponseDebuggerTips: string, callbackFunctionParamNameTips: string, callbackFunctionParamNamePlaceholder: string, comment: string, urlPattern: string, urlPatternType_ContainsThisString: string}, global_settings: {languageTips: string, autoJumpProjectSiteOnConfiguraionTips: string, flagPrefix: string, flagPrefixTips: string, isIgnoreJsSuffixRequestTips: string, autoJumpProjectSiteOnConfiguraion: string, isIgnoreJsSuffixRequest: string, language: string, isIgnoreNotJsonpRequestTips: string, title: string, flagPrefixPlaceholder: string, isIgnoreNotJsonpRequest: string}}} + */ +function getLanguageByGlobalConfig() { + return getLanguage(getGlobalConfig().language); +} + /** * * @param language @@ -153,6 +195,7 @@ function getLanguage(language) { module.exports = { getLanguage, + getLanguageByGlobalConfig, chinese, english } diff --git a/src/formatter/request-formatter.js b/src/formatter/request-formatter.js index 63c3c77..7a3610a 100644 --- a/src/formatter/request-formatter.js +++ b/src/formatter/request-formatter.js @@ -1,6 +1,6 @@ const {genFormatArray} = require("../utils/log-util"); const {repeat, fillToLength} = require("../utils/string-util"); -const {getLanguage} = require("../config/ui/component/language"); +const {getLanguage, getLanguageByGlobalConfig} = require("../config/ui/component/language"); const {getGlobalConfig} = require("../config/config"); const {printStyledTable} = require("./table-formatter"); const {getUserCodeLocation} = require("../utils/code-util"); @@ -19,11 +19,11 @@ class RequestFormatter { const codeLocation = getUserCodeLocation(); const requestContext = scriptContext.requestContext; - const language = getLanguage(getGlobalConfig().language); + const language = getLanguageByGlobalConfig(); const data = [ // TODO 2025-01-08 01:28:26 国际化 - ["名称", "值", "备注"], + [language.console.tableKey, language.console.tableValue, language.console.tableComment], [language.console.time, new Date().toLocaleString(), ""], [language.console.requestId, scriptContext.requestId, ""], [language.console.isJsonpRequest, scriptContext.isJsonp(), ""], diff --git a/src/formatter/response-formatter.js b/src/formatter/response-formatter.js index 28e7005..388ec92 100644 --- a/src/formatter/response-formatter.js +++ b/src/formatter/response-formatter.js @@ -1,4 +1,4 @@ -const {getLanguage, chinese} = require("../config/ui/component/language"); +const {getLanguage, chinese, getLanguageByGlobalConfig} = require("../config/ui/component/language"); const {fillToLength} = require("../utils/string-util"); const {genFormatArray} = require("../utils/log-util"); const {getGlobalConfig} = require("../config/config"); @@ -21,12 +21,11 @@ class ResponseFormatter { const responseContext = scriptContext.responseContext; const requestContext = scriptContext.requestContext; - // const language = getLanguage(getGlobalConfig().language); - const language = chinese; + const language = getLanguageByGlobalConfig(); const data = [ // TODO 2025-01-08 01:28:26 国际化 - ["名称", "值", "备注"], + [language.console.tableKey, language.console.tableValue, language.console.tableComment], [language.console.time, new Date().toLocaleString(), ""], [language.console.requestId, scriptContext.requestId, ""], [language.console.isJsonpRequest, scriptContext.isJsonp(), ""], From a97385509978cb737c1b0a4718b1e49df45f6ed3 Mon Sep 17 00:00:00 2001 From: CC11001100 Date: Wed, 8 Jan 2025 22:48:10 +0800 Subject: [PATCH 9/9] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E8=A1=A8?= =?UTF-8?q?=E6=A0=BC=E6=89=93=E5=8D=B0=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/formatter/response-formatter.js | 3 +-- src/formatter/table-formatter.js | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/formatter/response-formatter.js b/src/formatter/response-formatter.js index 388ec92..ca1bfdf 100644 --- a/src/formatter/response-formatter.js +++ b/src/formatter/response-formatter.js @@ -47,8 +47,7 @@ class ResponseFormatter { const title = language.console.titleResponse; printStyledTable(data, styles, title); const msgs = highlightJSON(responseContext.jsonpCallbackArguments); - console.log(msgs); - + // console.log(msgs); } diff --git a/src/formatter/table-formatter.js b/src/formatter/table-formatter.js index 35891b3..52d4a1e 100644 --- a/src/formatter/table-formatter.js +++ b/src/formatter/table-formatter.js @@ -52,8 +52,10 @@ function printStyledTable(data, styles, title = '') { // 如果有标题,添加标题行 if (title) { - const titlePadding = Math.floor((totalWidth - getStringWidth(title)) / 2); - const paddedTitle = padString(title, totalWidth); + const titleWidth = getStringWidth(title); + const leftPadding = Math.floor((totalWidth - titleWidth) / 2); + const rightPadding = totalWidth - titleWidth - leftPadding; + const paddedTitle = ' '.repeat(leftPadding) + title + ' '.repeat(rightPadding); tableContent += '%c' + paddedTitle + '\n'; }