更大范围的脚本匹配

This commit is contained in:
王一之 2025-04-29 11:28:01 +08:00
parent 14baa176d9
commit ddd3219bae
4 changed files with 40 additions and 22 deletions

View File

@ -257,7 +257,7 @@ export class ResourceService {
return fetch(u.url)
.then(async (resp) => {
if (resp.status !== 200) {
throw new Error(`resource response status not 200:${resp.status}`);
throw new Error(`resource response status not 200: ${resp.status}`);
}
return {
data: await resp.blob(),

View File

@ -15,20 +15,17 @@ import { subscribeScriptDelete, subscribeScriptEnable, subscribeScriptInstall }
import { ScriptService } from "./script";
import { runScript, stopScript } from "../offscreen/client";
import { getRunAt } from "./utils";
import { InfoNotification, isUserScriptsAvailable, randomString } from "@App/pkg/utils/utils";
import { isUserScriptsAvailable, randomString } from "@App/pkg/utils/utils";
import Cache from "@App/app/cache";
import { dealPatternMatches, UrlMatch } from "@App/pkg/utils/match";
import { ExtensionContentMessageSend } from "@Packages/message/extension_message";
import { sendMessage } from "@Packages/message/client";
import { compileInjectScript } from "../content/utils";
import { PopupService } from "./popup";
import Logger from "@App/app/logger/logger";
import LoggerCore from "@App/app/logger/core";
import PermissionVerify from "./permission_verify";
import { SystemConfig } from "@App/pkg/config/config";
import { ResourceService } from "./resource";
import { LocalStorageDAO } from "@App/app/repo/localStorage";
import i18n from "@App/locales/locales";
// 为了优化性能存储到缓存时删除了code、value与resource
export interface ScriptMatchInfo extends ScriptRunResouce {

View File

@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
import { dealPatternMatches, parsePatternMatchesURL, UrlMatch } from "./match";
import path from "path";
// https://developer.chrome.com/docs/extensions/mv3/match_patterns/
describe("UrlMatch-google", () => {
@ -39,16 +40,10 @@ describe("UrlMatch-google", () => {
describe("UrlMatch-google-error", () => {
const url = new UrlMatch<string>();
it("error-1", () => {
expect(() => {
url.add("https://*foo/bar", "ok1");
}).toThrow(Error);
});
// 从v0.17.0开始允许这种
it("error-2", () => {
url.add("https://foo.*.bar/baz", "ok1");
expect(url.match("https://foo.api.bar/baz")).toEqual(["ok1"]);
});
it("error-3", () => {
it("error-2", () => {
expect(() => {
url.add("http:/bar", "ok1");
}).toThrow(Error);
@ -77,6 +72,13 @@ describe("UrlMatch-search", () => {
expect(url.match("http://api.bar.example.com/")).toEqual(["ok1"]);
expect(url.match("http://api.example.com/")).toEqual([]);
});
it("*://example*/*/example.path*", () => {
const url = new UrlMatch<string>();
url.add("*://example*/*/example.path*", "ok1");
expect(url.match("https://example.com/foo/example.path")).toEqual(["ok1"]);
expect(url.match("https://example.com/foo/bar/example.path")).toEqual(["ok1"]);
expect(url.match("https://example.com/foo/bar/example.path2")).toEqual(["ok1"]);
});
});
describe("UrlMatch-port1", () => {
@ -191,7 +193,7 @@ describe("parsePatternMatchesURL", () => {
const matches = parsePatternMatchesURL("*://www.example.com*");
expect(matches).toEqual({
scheme: "*",
host: "www.example.com",
host: "*",
path: "*",
});
});
@ -203,4 +205,24 @@ describe("parsePatternMatchesURL", () => {
path: "*",
});
});
it("一些怪异的情况", () => {
let matches = parsePatternMatchesURL("*://*./*");
expect(matches).toEqual({
scheme: "*",
host: "*",
path: "*",
});
matches = parsePatternMatchesURL("*://example*/*");
expect(matches).toEqual({
scheme: "*",
host: "*",
path: "*",
});
matches = parsePatternMatchesURL("http*://*.example.com/*");
expect(matches).toEqual({
scheme: "*",
host: "*.example.com",
path: "*",
});
});
});

View File

@ -64,20 +64,11 @@ export default class Match<T> {
let pos = u.host.indexOf("*");
if (u.host === "*" || u.host === "**") {
pos = -1;
} else if (u.host.endsWith("*")) {
// 处理*结尾
if (!u.host.endsWith(":*")) {
u.host = u.host.substring(0, u.host.length - 1);
}
}
u.host = u.host.replace(/\*/g, "[^/]*?");
// 处理 *.开头
if (u.host.startsWith("[^/]*?.")) {
u.host = `([^/]*?\\.?)${u.host.substring(7)}`;
} else if (pos !== -1) {
if (u.host.indexOf(".") === -1) {
return "";
}
}
// 处理顶域
if (u.host.endsWith("tld")) {
@ -223,6 +214,7 @@ export interface PatternMatchesUrl {
}
// 解析URL, 根据https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns?hl=zh-cn进行处理
// 将一些异常情况直接转为通配用最大的范围去注册userScript在执行的时候再用UrlMatch去匹配过滤
export function parsePatternMatchesURL(
url: string,
options?: {
@ -251,6 +243,9 @@ export function parsePatternMatchesURL(
}
}
if (result) {
if (result.scheme === "http*") {
result.scheme = "*";
}
if (result.host !== "*") {
// *开头但是不是*.的情况
if (result.host.startsWith("*")) {
@ -261,6 +256,10 @@ export function parsePatternMatchesURL(
}
// 结尾是*的情况
if (result.host.endsWith("*")) {
result.host = "*";
}
// 结尾是.的情况
if (result.host.endsWith(".")) {
result.host = result.host.slice(0, -1);
}
// 处理 www.*.example.com 的情况为 *.example.com