diff --git a/src/app/service/service_worker/gm_api/gm_api.test.ts b/src/app/service/service_worker/gm_api/gm_api.test.ts index efc9bdb76..3a7e823ad 100644 --- a/src/app/service/service_worker/gm_api/gm_api.test.ts +++ b/src/app/service/service_worker/gm_api/gm_api.test.ts @@ -41,7 +41,11 @@ describe.concurrent("isConnectMatched", () => { it.concurrent('metadata 包含 "self" 且 sender.url 与 reqURL 主机相同时回传 true', () => { const req = new URL("https://app.example.com/dashboard"); const sender = makeSender("https://app.example.com/some-page"); - expect(getConnectMatched(["self"], req, sender)).toBe(ConnectMatch.SELF); + expect(getConnectMatched(["self"], req, sender)).toBe(ConnectMatch.EXACT); + + const req2 = new URL("https://app.example.com/dashboard"); + const sender2 = makeSender("https://example.com/some-page"); + expect(getConnectMatched(["self"], req2, sender2)).toBe(ConnectMatch.DOMAIN); }); it.concurrent('metadata 包含 "self" 但 sender.url 与 reqURL 主机不同时回传 false(若无其他规则命中)', () => { diff --git a/src/app/service/service_worker/gm_api/gm_api.ts b/src/app/service/service_worker/gm_api/gm_api.ts index 4e279a862..7118e1621 100644 --- a/src/app/service/service_worker/gm_api/gm_api.ts +++ b/src/app/service/service_worker/gm_api/gm_api.ts @@ -45,7 +45,7 @@ import { headerModifierMap, headersReceivedMap } from "./gm_xhr"; import { BgGMXhr } from "@App/pkg/utils/xhr/bg_gm_xhr"; const askUnlistedConnect = false; -const askConnectStar = true; +const askConnectStar = true; // 如果只有 "*", 而脚本要求连接自己以外的网域,则需要询问 let generatedUniqueMarkerIDs = ""; let generatedUniqueMarkerIDWhen = ""; @@ -138,10 +138,16 @@ export const checkHasUnsafeHeaders = (key: string) => { }; export enum ConnectMatch { + NONE = 0, // 没有匹配 + ALL = 1, // 遇到 "*" 通配符 + DOMAIN = 2, // 匹配子域 + EXACT = 3, // 完全匹配 +} + +export enum SelfMatch { NONE = 0, - ALL = 1, - DOMAIN = 2, - SELF = 3, + EXACT = 1, + SUB = 2, } export const getConnectMatched = ( @@ -150,27 +156,41 @@ export const getConnectMatched = ( sender: IGetSender ): ConnectMatch => { if (metadataConnect?.length) { + const checkSelfDomainMatching = () => { + const senderURL = sender.getSender()?.url; + if (senderURL) { + let senderURLObject; + try { + senderURLObject = new URL(senderURL); + } catch { + // ignore + } + if (senderURLObject) { + if (reqURL.hostname === senderURLObject.hostname) return SelfMatch.EXACT; // 自身 + if (`.${reqURL.hostname}`.endsWith(`.${senderURLObject.hostname}`)) return SelfMatch.SUB; // 子域 + } + } + return SelfMatch.NONE; + }; + let withWildCard = false; for (let i = 0, l = metadataConnect.length; i < l; i += 1) { const lowerMetaConnect = metadataConnect[i].toLowerCase(); if (lowerMetaConnect === "self") { - const senderURL = sender.getSender()?.url; - if (senderURL) { - let senderURLObject; - try { - senderURLObject = new URL(senderURL); - } catch { - // ignore - } - if (senderURLObject) { - if (reqURL.hostname === senderURLObject.hostname) return ConnectMatch.SELF; - } + switch (checkSelfDomainMatching()) { + case SelfMatch.EXACT: + return ConnectMatch.EXACT; // 完全匹配 + case SelfMatch.SUB: + return ConnectMatch.DOMAIN; // 完全匹配或其子域 } } else if (lowerMetaConnect === "*") { - return ConnectMatch.ALL; + if (checkSelfDomainMatching() === SelfMatch.EXACT) return ConnectMatch.EXACT; // 完全匹配 + withWildCard = true; // 检查其他 @connect } else if (`.${reqURL.hostname}`.endsWith(`.${lowerMetaConnect}`)) { - return ConnectMatch.DOMAIN; + return ConnectMatch.DOMAIN; // 完全匹配或其子域 } } + // 有 * 但不是自身网域 又不是列明网域 则询问 + if (withWildCard) return ConnectMatch.ALL; } return ConnectMatch.NONE; }; @@ -280,7 +300,7 @@ export default class GMApi { url.host = detail.domain || ""; url.hostname = detail.domain || ""; } - if (getConnectMatched(request.script.metadata.connect, url, sender) === 0) { + if (getConnectMatched(request.script.metadata.connect, url, sender) === ConnectMatch.NONE) { throw new Error("hostname must be in the definition of connect"); } const metadata: { [key: string]: string } = {}; @@ -682,7 +702,7 @@ export default class GMApi { return false; } const connectMatched = getConnectMatched(request.script.metadata.connect, url, sender); - if (connectMatched === 1) { + if (connectMatched === ConnectMatch.ALL) { if (!askConnectStar) { return true; }