diff --git a/src/app/service/service_worker/client.ts b/src/app/service/service_worker/client.ts index 83c3ef8..286d691 100644 --- a/src/app/service/service_worker/client.ts +++ b/src/app/service/service_worker/client.ts @@ -4,6 +4,7 @@ import { InstallSource } from "."; import { Resource } from "@App/app/repo/resource"; import { MessageSend } from "@Packages/message/server"; import { ScriptMenu, ScriptMenuItem } from "./popup"; +import PermissionVerify, { ConfirmParam, UserConfirm } from "./permission_verify"; export class ServiceWorkerClient extends Client { constructor(msg: MessageSend) { @@ -127,3 +128,17 @@ export class PopupClient extends Client { }); } } + +export class PermissionClient extends Client { + constructor(msg: MessageSend) { + super(msg, "serviceWorker/runtime/permission"); + } + + confirm(uuid: string, userConfirm: UserConfirm): Promise { + return this.do("confirm", { uuid, userConfirm }); + } + + getPermissionInfo(uuid: string): ReturnType { + return this.do("getInfo", uuid); + } +} diff --git a/src/app/service/service_worker/gm_api.ts b/src/app/service/service_worker/gm_api.ts index efb4af1..0bf953e 100644 --- a/src/app/service/service_worker/gm_api.ts +++ b/src/app/service/service_worker/gm_api.ts @@ -70,9 +70,8 @@ export default class GMApi { scriptDAO: ScriptDAO = new ScriptDAO(); - permissionVerify: PermissionVerify = new PermissionVerify(); - constructor( + private permissionVerify: PermissionVerify, private group: Group, private send: MessageSend, private mq: MessageQueue, @@ -109,7 +108,49 @@ export default class GMApi { return req; } - @PermissionVerify.API() + @PermissionVerify.API({ + confirm(request: Request) { + if (request.params[0] === "store") { + return Promise.resolve(true); + } + const detail = request.params[1]; + if (!detail.url && !detail.domain) { + return Promise.reject(new Error("there must be one of url or domain")); + } + let url: URL = {}; + if (detail.url) { + url = new URL(detail.url); + } else { + url.host = detail.domain || ""; + url.hostname = detail.domain || ""; + } + let flag = false; + if (request.script.metadata.connect) { + const { connect } = request.script.metadata; + for (let i = 0; i < connect.length; i += 1) { + if (url.hostname.endsWith(connect[i])) { + flag = true; + break; + } + } + } + if (!flag) { + return Promise.reject(new Error("hostname must be in the definition of connect")); + } + const metadata: { [key: string]: string } = {}; + metadata[i18next.t("script_name")] = i18nName(request.script); + metadata[i18next.t("request_domain")] = url.host; + return Promise.resolve({ + permission: "cookie", + permissionValue: url.host, + title: i18next.t("access_cookie_content")!, + metadata, + describe: i18next.t("confirm_script_operation")!, + permissionContent: i18next.t("cookie_domain")!, + uuid: "", + }); + }, + }) async GM_cookie(request: Request, sender: GetSender) { const param = request.params; if (param.length !== 2) { diff --git a/src/app/service/service_worker/permission_verify.ts b/src/app/service/service_worker/permission_verify.ts index a4064f2..719f105 100644 --- a/src/app/service/service_worker/permission_verify.ts +++ b/src/app/service/service_worker/permission_verify.ts @@ -6,6 +6,7 @@ import { Api, Request } from "./gm_api"; import Queue from "@App/pkg/utils/queue"; import CacheKey from "@App/app/cache_key"; import { Permission, PermissionDAO } from "@App/app/repo/permission"; +import { Group } from "@Packages/message/server"; export interface ConfirmParam { // 权限名 @@ -95,21 +96,18 @@ export default class PermissionVerify { reject: (reason: any) => void; }> = new Queue(); - async removePermissionCache(scriptId: number) { + async removePermissionCache(uuid: string) { // 先删除缓存 (await Cache.getInstance().list()).forEach((key) => { - if (key.startsWith(`permission:${scriptId.toString()}:`)) { + if (key.startsWith(`permission:${uuid}:`)) { Cache.getInstance().del(key); } }); } - private permissionDAO: PermissionDAO; + private permissionDAO: PermissionDAO = new PermissionDAO(); - constructor() { - this.permissionDAO = new PermissionDAO(); - this.dealConfirmQueue(); - } + constructor(private group: Group) {} // 验证是否有权限 verify(request: Request, api: ApiValue): Promise { @@ -273,4 +271,49 @@ export default class PermissionVerify { }); }); } + + // 处理确认 + private userConfirm(data: { uuid: string; userConfirm: UserConfirm }) { + const confirm = this.confirmMap.get(data.uuid); + if (!confirm) { + if (data.userConfirm.type === 0) { + // 忽略 + return Promise.resolve(undefined); + } + return Promise.reject(new Error("confirm not found")); + } + this.confirmMap.delete(data.uuid); + confirm.resolve(data.userConfirm); + return Promise.resolve(true); + } + + // 获取信息 + private getInfo(uuid: string) { + const data = this.confirmMap.get(uuid); + if (!data) { + return Promise.reject(new Error("permission confirm not found")); + } + const { script, confirm } = data; + // 查询允许统配的有多少个相同等待确认权限 + let likeNum = 0; + if (data.confirm.wildcard) { + this.confirmQueue.list.forEach((value) => { + const confirm = value.confirm as ConfirmParam; + if ( + confirm.wildcard && + value.request.uuid === data.script.uuid && + confirm.permission === data.confirm.permission + ) { + likeNum += 1; + } + }); + } + return Promise.resolve({ script, confirm, likeNum }); + } + + init() { + this.dealConfirmQueue(); + this.group.on("confirm", this.userConfirm.bind(this)); + this.group.on("getInfo", this.getInfo.bind(this)); + } } diff --git a/src/app/service/service_worker/runtime.ts b/src/app/service/service_worker/runtime.ts index 43e8e1b..bccd9ff 100644 --- a/src/app/service/service_worker/runtime.ts +++ b/src/app/service/service_worker/runtime.ts @@ -24,6 +24,7 @@ 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"; // 为了优化性能,存储到缓存时删除了code与value export interface ScriptMatchInfo extends ScriptRunResouce { @@ -56,7 +57,9 @@ export class RuntimeService { async init() { // 启动gm api - const gmApi = new GMApi(this.group, this.sender, this.mq, this.value, this); + const permission = new PermissionVerify(this.group.group("permission")); + const gmApi = new GMApi(permission, this.group, this.sender, this.mq, this.value, this); + permission.init(); gmApi.start(); this.group.on("stopScript", this.stopScript.bind(this)); diff --git a/src/pages/confirm/App.tsx b/src/pages/confirm/App.tsx index a10d4a6..7b27162 100644 --- a/src/pages/confirm/App.tsx +++ b/src/pages/confirm/App.tsx @@ -2,6 +2,7 @@ import { ConfirmParam } from "@App/app/service/service_worker/permission_verify" import { Button, Message, Space } from "@arco-design/web-react"; import React, { useEffect } from "react"; import { useTranslation } from "react-i18next"; +import { permissionClient } from "../store/features/script"; function App() { const uuid = window.location.search.split("=")[1]; @@ -21,15 +22,16 @@ function App() { useEffect(() => { window.addEventListener("beforeunload", () => { - permissionCtrl.sendConfirm(uuid, { + permissionClient.confirm(uuid, { allow: false, type: 0, }); }); - permissionCtrl - .getConfirm(uuid) + permissionClient + .getPermissionInfo(uuid) .then((data) => { + console.log(data); setConfirm(data.confirm); setLikeNum(data.likeNum); }) @@ -41,7 +43,7 @@ function App() { const handleConfirm = (allow: boolean, type: number) => { return async () => { try { - await permissionCtrl.sendConfirm(uuid, { + await permissionClient.confirm(uuid, { allow, type, }); diff --git a/src/pages/store/features/script.ts b/src/pages/store/features/script.ts index d70aa23..9c574bd 100644 --- a/src/pages/store/features/script.ts +++ b/src/pages/store/features/script.ts @@ -8,12 +8,13 @@ import { ScriptDAO, } from "@App/app/repo/scripts"; import { arrayMove } from "@dnd-kit/sortable"; -import { PopupClient, RuntimeClient, ScriptClient } from "@App/app/service/service_worker/client"; +import { PermissionClient, PopupClient, RuntimeClient, ScriptClient } from "@App/app/service/service_worker/client"; import { message } from "../global"; export const scriptClient = new ScriptClient(message); export const runtimeClient = new RuntimeClient(message); export const popupClient = new PopupClient(message); +export const permissionClient = new PermissionClient(message); export const fetchAndSortScriptList = createAsyncThunk("script/fetchScriptList", async () => { // 排序