From 5817019c171efe268870e8bec871eb9e3356081e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?= Date: Mon, 2 Mar 2026 15:40:46 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=90=9B=20=E4=BF=AE=E5=A4=8D=20include?= =?UTF-8?q?=20*=3F*=20=E8=A1=A8=E8=BE=BE=E5=BC=8F=E5=A4=84=E7=90=86?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20#1271?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/app/repo/resource.ts | 2 +- src/pkg/utils/match.test.ts | 10 ++++++++++ src/pkg/utils/url_matcher.ts | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index fb3929cee..0f11d120e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scriptcat", - "version": "1.3.0-beta.4", + "version": "1.3.0", "description": "脚本猫,一个可以执行用户脚本的浏览器扩展,万物皆可脚本化,让你的浏览器可以做更多的事情!", "author": "CodFrm", "license": "GPLv3", diff --git a/src/app/repo/resource.ts b/src/app/repo/resource.ts index 5aa0889b2..e9eff5aa4 100644 --- a/src/app/repo/resource.ts +++ b/src/app/repo/resource.ts @@ -64,7 +64,7 @@ export class ResourceDAO extends Repo { } // CompiledResource结构变更时,建议修改 CompiledResourceNamespace 以删除旧Cache -export const CompiledResourceNamespace = "a51b9167-fdde-467a-a86f-75e5636adda2"; +export const CompiledResourceNamespace = "57d79c56-231a-42d3-b6e3-d2004ba0866f"; export class CompiledResourceDAO extends Repo { constructor() { diff --git a/src/pkg/utils/match.test.ts b/src/pkg/utils/match.test.ts index eeec35dac..5abf7920d 100644 --- a/src/pkg/utils/match.test.ts +++ b/src/pkg/utils/match.test.ts @@ -889,3 +889,13 @@ describe.concurrent("@include /REGEX/", () => { expect(isUrlIncluded("http://www.hlample.com/", url.rulesMap.get("ok1")!)).toEqual(false); }); }); + +describe.concurrent("invalid or unsupported glob #1271", () => { + const url = new UrlMatch(); + url.addInclude("*://*?*", "ok1"); + url.addInclude("*://*?page*", "ok2"); + it.concurrent("include *://*?*", () => { + expect(url.urlMatch("http://www.example.com/?a=1")).toEqual(["ok1"]); + expect(url.urlMatch("http://www.example.com/?page=1")).toEqual(["ok1", "ok2"]); + }); +}); diff --git a/src/pkg/utils/url_matcher.ts b/src/pkg/utils/url_matcher.ts index 08f5f37f2..70d86160b 100644 --- a/src/pkg/utils/url_matcher.ts +++ b/src/pkg/utils/url_matcher.ts @@ -57,8 +57,8 @@ export function checkUrlMatch(s: string) { } const globSplit = (text: string) => { - text = text.replace(/\*{2,}/g, "*"); // api定义的 glob * 是等价于 glob ** text = text.replace(/\*(\?+)/g, "$1*"); // "*????" 改成 "????*",避免 backward 处理 + text = text.replace(/\*{2,}/g, "*"); // api定义的 glob * 是等价于 glob ** return text.split(/([*?])/g); }; From 961596d8a3c50e1e22b5758f1a8674425dc68215 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Wed, 4 Mar 2026 02:53:16 +0900 Subject: [PATCH 2/5] Added error handling to avoid crash --- src/app/service/content/script_executor.ts | 10 +++++++--- src/pkg/utils/match.ts | 8 ++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/app/service/content/script_executor.ts b/src/app/service/content/script_executor.ts index c231213f6..1d4715b6d 100644 --- a/src/app/service/content/script_executor.ts +++ b/src/app/service/content/script_executor.ts @@ -106,9 +106,13 @@ export class ScriptExecutor { // "@exclude /REGEX/" 的情况下,MV3 UserScripts API 基础匹配范围不会扩大,然后在 earlyScript 把符合 REGEX 的匹配除去 // (Any @exclude = true -> 除去) // 注:如果一早已被除排,根本不会被 MV3 UserScripts API 注入。所以只考虑排除「多余的匹配」。(略过注入) - if (isUrlExcluded(window.location.href, detail.scriptInfo.scriptUrlPatterns)) { - // 「多余的匹配」-> 略过注入 - return; + try { + if (isUrlExcluded(window.location.href, detail.scriptInfo.scriptUrlPatterns)) { + // 「多余的匹配」-> 略过注入 + return; + } + } catch (e) { + console.warn("Unexpected match error", e); } } this.execEarlyScript(scriptFlag, detail.scriptInfo, envInfo); diff --git a/src/pkg/utils/match.ts b/src/pkg/utils/match.ts index a94da8d81..81f3a42dd 100644 --- a/src/pkg/utils/match.ts +++ b/src/pkg/utils/match.ts @@ -18,8 +18,12 @@ export class UrlMatch { if (cacheMap.has(url)) return cacheMap.get(url) as T[]; const res: T[] = []; for (const [uuid, rules] of this.rulesMap) { - if (isUrlIncluded(url, rules)) { - res.push(uuid); + try { + if (isUrlIncluded(url, rules)) { + res.push(uuid); + } + } catch (e) { + console.warn("Unexpected match error", e); } } const sorter = this.sorter; From 886b496c1e71faa5085ef49e1ee565ead447a831 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Wed, 4 Mar 2026 03:12:38 +0900 Subject: [PATCH 3/5] update globSplit --- src/pkg/utils/url_matcher.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pkg/utils/url_matcher.ts b/src/pkg/utils/url_matcher.ts index 70d86160b..22cb1ceec 100644 --- a/src/pkg/utils/url_matcher.ts +++ b/src/pkg/utils/url_matcher.ts @@ -57,8 +57,12 @@ export function checkUrlMatch(s: string) { } const globSplit = (text: string) => { - text = text.replace(/\*(\?+)/g, "$1*"); // "*????" 改成 "????*",避免 backward 处理 - text = text.replace(/\*{2,}/g, "*"); // api定义的 glob * 是等价于 glob ** + let pre; + do { + pre = text; + text = text.replace(/\*+(\?+)/g, "$1*"); // "*????" 改成 "????*",避免 backward 处理 + text = text.replace(/\*{2,}/g, "*"); // api定义的 glob * 是等价于 glob ** + } while (text !== pre); return text.split(/([*?])/g); }; From 4a3fbd793685db534530be987e239954a0cf26b6 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Wed, 4 Mar 2026 03:27:57 +0900 Subject: [PATCH 4/5] update globSplit --- src/pkg/utils/url_matcher.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/pkg/utils/url_matcher.ts b/src/pkg/utils/url_matcher.ts index 22cb1ceec..1d2b0b981 100644 --- a/src/pkg/utils/url_matcher.ts +++ b/src/pkg/utils/url_matcher.ts @@ -57,13 +57,15 @@ export function checkUrlMatch(s: string) { } const globSplit = (text: string) => { - let pre; - do { - pre = text; - text = text.replace(/\*+(\?+)/g, "$1*"); // "*????" 改成 "????*",避免 backward 处理 - text = text.replace(/\*{2,}/g, "*"); // api定义的 glob * 是等价于 glob ** - } while (text !== pre); - return text.split(/([*?])/g); + const split = text.split(/([*?]+)/g); + for (let i = 1; i < split.length; i += 2) { + // "*????" 改成 "????*",避免 backward 处理 + // api定义的 glob * 是等价于 glob ** + const p = split[i]; // **??**??** + const q = p.replace(/\*/g, ""); // ???? + if (p !== q) split[i] = `${q}*`; // ????* + } + return split.join("").split(/([*?])/g); }; export const extractUrlPatterns = (lines: string[]): URLRuleEntry[] => { From 8b0cdda9e15d3d0e8aab7214332d9de757fdb354 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Wed, 4 Mar 2026 03:30:20 +0900 Subject: [PATCH 5/5] update globSplit --- src/pkg/utils/url_matcher.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkg/utils/url_matcher.ts b/src/pkg/utils/url_matcher.ts index 1d2b0b981..e2fb6e218 100644 --- a/src/pkg/utils/url_matcher.ts +++ b/src/pkg/utils/url_matcher.ts @@ -57,7 +57,7 @@ export function checkUrlMatch(s: string) { } const globSplit = (text: string) => { - const split = text.split(/([*?]+)/g); + const split = text.split(/([*?]{2,})/g); for (let i = 1; i < split.length; i += 2) { // "*????" 改成 "????*",避免 backward 处理 // api定义的 glob * 是等价于 glob **