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 d10a7f903..94be9d100 100644 --- a/src/app/service/service_worker/gm_api/gm_api.ts +++ b/src/app/service/service_worker/gm_api/gm_api.ts @@ -807,14 +807,43 @@ export default class GMApi { const msg = `Refused to connect to "${details.url}": URL is blacklisted`; throw throwErrorFn(msg); } + let hasOriginPermission = false; + let originPattern = ""; + if (!url.origin || url.origin === "null" || !url.protocol || !url.protocol.startsWith("http")) { + hasOriginPermission = true; // TBC + } else { + originPattern = `${url.origin}/*`; + try { + hasOriginPermission = await chrome.permissions.contains({ origins: [originPattern] }); + } catch (e) { + console.warn(e); + } + } + const extensionSiteAccessOrigins = hasOriginPermission ? undefined : [originPattern]; + const confirmExtensionSiteAccess = (): ConfirmParam => { + const metadata: { [key: string]: string } = {}; + metadata[i18next.t("script_name")] = i18nName(request.script); + metadata[i18next.t("request_domain")] = url.hostname; + metadata[i18next.t("request_url")] = details.url; + throwErrorFn = null; // 确保 GC 可以释放 conn + return { + permission: "extension-site-access", + permissionValue: originPattern, + title: i18next.t("extension_site_access_title"), + metadata, + describe: i18next.t("extension_site_access_description"), + permissionContent: i18next.t("extension_site_access_content"), + extensionSiteAccessOrigins, + } as ConfirmParam; + }; const connectMatched = getConnectMatched(request.script.metadata.connect, url, sender); if (connectMatched === ConnectMatch.ALL) { // SC: 有 @connect * 就不询问 - return true; + return hasOriginPermission ? true : confirmExtensionSiteAccess(); } else { // 如果 @connect 有匹配到就放行 if (connectMatched > 0) { - return true; + return hasOriginPermission ? true : confirmExtensionSiteAccess(); } // @connect 没有匹配,但有列明 @connect 的话,则自动拒绝 if (request.script.metadata.connect?.find((e) => !!e)) { @@ -825,7 +854,7 @@ export default class GMApi { wildcard: true, }); if (ret && ret.allow) { - return true; + return hasOriginPermission ? true : confirmExtensionSiteAccess(); } const msg = `Refused to connect to "${details.url}": This domain is not a part of the @connect list`; throw throwErrorFn(msg); @@ -839,6 +868,14 @@ export default class GMApi { throwErrorFn = null; // 确保 GC 可以释放 conn + const ret = await GMApiInstance.permissionVerify.queryPermission(request, { + permission: "cors", + permissionValue: url.hostname, + wildcard: true, + }); + if (ret?.allow && !hasOriginPermission) { + return confirmExtensionSiteAccess(); + } return { permission: "cors", permissionValue: url.hostname, @@ -847,6 +884,7 @@ export default class GMApi { describe: i18next.t("confirm_operation_description"), wildcard: true, permissionContent: i18next.t("domain"), + extensionSiteAccessOrigins, } as ConfirmParam; }, alias: ["GM.xmlHttpRequest"], diff --git a/src/app/service/service_worker/permission_verify.ts b/src/app/service/service_worker/permission_verify.ts index 0225441f7..34681d1d1 100644 --- a/src/app/service/service_worker/permission_verify.ts +++ b/src/app/service/service_worker/permission_verify.ts @@ -29,6 +29,8 @@ export interface ConfirmParam { wildcard?: boolean; // 权限内容 permissionContent?: string; + // 需要在确认页面通过用户手势请求的扩展站点访问权限 + extensionSiteAccessOrigins?: string[]; } export interface UserConfirm { diff --git a/src/locales/de-DE/translation.json b/src/locales/de-DE/translation.json index 07c1e776e..336b4da33 100644 --- a/src/locales/de-DE/translation.json +++ b/src/locales/de-DE/translation.json @@ -373,6 +373,9 @@ "enabled_background_scripts": "Aktivierte und laufende Hintergrundskripte", "script_accessing_cross_origin_resource": "Skript versucht auf Cross-Origin-Ressourcen zuzugreifen", "confirm_operation_description": "Bitte bestätigen Sie, ob Sie dem Skript erlauben, diese Operation durchzuführen. Das Skript kann auch ein @connect-Tag hinzufügen, um diese Option zu überspringen", + "extension_site_access_title": "ScriptCat benötigt Website-Zugriff", + "extension_site_access_description": "Gewähren Sie dem Browser Website-Zugriff auf diesen Ursprung, damit ScriptCat die Anfrage ausführen kann. Dadurch wird die Website-Zugriffseinstellung der Erweiterung geändert.", + "extension_site_access_content": "Website", "domain": "Domain", "script_name": "Skriptname", "request_domain": "Anfrage-Domain", diff --git a/src/locales/en-US/translation.json b/src/locales/en-US/translation.json index d0d9b7291..d9217cb13 100644 --- a/src/locales/en-US/translation.json +++ b/src/locales/en-US/translation.json @@ -373,6 +373,9 @@ "enabled_background_scripts": "Enabled and Running Background Scripts", "script_accessing_cross_origin_resource": "Script is attempting to access a cross-origin resource", "confirm_operation_description": "Please confirm if you allow the script to perform this operation. The script can also add the @connect tag to bypass this option.", + "extension_site_access_title": "ScriptCat needs site access", + "extension_site_access_description": "Grant browser site access to this origin so ScriptCat can perform the request. This changes the extension's site access setting.", + "extension_site_access_content": "Site", "domain": "Domain", "script_name": "Script Name", "request_domain": "Request Domain", diff --git a/src/locales/ja-JP/translation.json b/src/locales/ja-JP/translation.json index a3ac3677a..fbd5b6fca 100644 --- a/src/locales/ja-JP/translation.json +++ b/src/locales/ja-JP/translation.json @@ -373,6 +373,9 @@ "enabled_background_scripts": "有効および実行中のバックグラウンドスクリプト", "script_accessing_cross_origin_resource": "スクリプトがクロスドメインリソースにアクセスしようとしています", "confirm_operation_description": "スクリプトがこの操作を実行することを許可するかどうか確認してください。スクリプトは@connectタグを追加してこのオプションをスキップすることもできます", + "extension_site_access_title": "ScriptCat にサイトアクセス権限が必要です", + "extension_site_access_description": "ScriptCat がこのリクエストを実行できるように、このオリジンへのブラウザーのサイトアクセス権限を許可してください。これは拡張機能のサイトアクセス設定を変更します。", + "extension_site_access_content": "サイト", "domain": "ドメイン", "script_name": "スクリプト名", "request_domain": "リクエストドメイン", diff --git a/src/locales/ru-RU/translation.json b/src/locales/ru-RU/translation.json index 22990b40f..bb5a03e33 100644 --- a/src/locales/ru-RU/translation.json +++ b/src/locales/ru-RU/translation.json @@ -373,6 +373,9 @@ "enabled_background_scripts": "Включенные и работающие фоновые скрипты", "script_accessing_cross_origin_resource": "Скрипт пытается получить доступ к кросс-доменному ресурсу", "confirm_operation_description": "Пожалуйста, подтвердите, разрешаете ли вы скрипту выполнить эту операцию. Скрипт также может добавить тег @connect, чтобы пропустить эту опцию", + "extension_site_access_title": "ScriptCat требуется доступ к сайту", + "extension_site_access_description": "Разрешите браузеру доступ к сайту для этого источника, чтобы ScriptCat мог выполнить запрос. Это изменит настройку доступа к сайтам для расширения.", + "extension_site_access_content": "Сайт", "domain": "Домен", "script_name": "Название скрипта", "request_domain": "Запрашиваемый домен", diff --git a/src/locales/vi-VN/translation.json b/src/locales/vi-VN/translation.json index f6eaa231a..58125318f 100644 --- a/src/locales/vi-VN/translation.json +++ b/src/locales/vi-VN/translation.json @@ -373,6 +373,9 @@ "enabled_background_scripts": "Script nền đã bật và đang chạy", "script_accessing_cross_origin_resource": "Script đang cố gắng truy cập tài nguyên cross-origin", "confirm_operation_description": "Vui lòng xác nhận xem bạn có cho phép script thực hiện thao tác này không. Script cũng có thể thêm thẻ @connect để bỏ qua tùy chọn này.", + "extension_site_access_title": "ScriptCat cần quyền truy cập trang web", + "extension_site_access_description": "Cấp quyền truy cập trang web của trình duyệt cho nguồn này để ScriptCat có thể thực hiện yêu cầu. Thao tác này thay đổi cài đặt truy cập trang web của tiện ích.", + "extension_site_access_content": "Trang web", "domain": "Miền", "script_name": "Tên script", "request_domain": "Miền yêu cầu", diff --git a/src/locales/zh-CN/translation.json b/src/locales/zh-CN/translation.json index 4d6a1a100..63b734e04 100644 --- a/src/locales/zh-CN/translation.json +++ b/src/locales/zh-CN/translation.json @@ -373,6 +373,9 @@ "enabled_background_scripts": "开启和运行的后台脚本", "script_accessing_cross_origin_resource": "脚本正在试图访问跨域资源", "confirm_operation_description": "请您确认是否允许脚本进行此操作,脚本也可增加@connect标签跳过此选项", + "extension_site_access_title": "ScriptCat 需要站点访问权限", + "extension_site_access_description": "请授予浏览器对此来源的站点访问权限,让 ScriptCat 可以完成本次请求。这会修改扩展的站点访问设置。", + "extension_site_access_content": "站点", "domain": "域名", "script_name": "脚本名称", "request_domain": "请求域名", diff --git a/src/locales/zh-TW/translation.json b/src/locales/zh-TW/translation.json index ce2248677..d4afa7a88 100644 --- a/src/locales/zh-TW/translation.json +++ b/src/locales/zh-TW/translation.json @@ -373,6 +373,9 @@ "enabled_background_scripts": "開啟和執行的背景腳本", "script_accessing_cross_origin_resource": "腳本正在嘗試存取跨網域資源", "confirm_operation_description": "請您確認是否允許腳本進行此操作,腳本也可增加@connect標籤跳過此選項", + "extension_site_access_title": "ScriptCat 需要網站存取權限", + "extension_site_access_description": "請授予瀏覽器對此來源的網站存取權限,讓 ScriptCat 可以完成本次請求。這會修改擴充功能的網站存取設定。", + "extension_site_access_content": "網站", "domain": "網域", "script_name": "腳本名稱", "request_domain": "請求網域", diff --git a/src/pages/confirm/App.tsx b/src/pages/confirm/App.tsx index b440a33ad..b09a97863 100644 --- a/src/pages/confirm/App.tsx +++ b/src/pages/confirm/App.tsx @@ -45,6 +45,21 @@ function App() { return async () => { if (!uuid) return; try { + if (allow && confirm?.extensionSiteAccessOrigins?.length) { + const granted = await chrome.permissions.request({ + origins: confirm.extensionSiteAccessOrigins, + }); + if (!granted) { + await permissionClient + .confirm(uuid, { + allow: false, + type, + }) + .catch(() => {}); + window.close(); + return; + } + } await permissionClient.confirm(uuid, { allow, type, @@ -60,6 +75,7 @@ function App() { }; const metadata = useMemo(() => (confirm && confirm.metadata && Object.keys(confirm.metadata)) || [], [confirm]); + const isExtensionSiteAccessConfirm = confirm?.permission === "extension-site-access"; return (