权限操作

This commit is contained in:
王一之 2025-04-16 10:31:16 +08:00
parent 44b6f11b19
commit 071e728f06
6 changed files with 121 additions and 16 deletions

View File

@ -4,6 +4,7 @@ import { InstallSource } from ".";
import { Resource } from "@App/app/repo/resource"; import { Resource } from "@App/app/repo/resource";
import { MessageSend } from "@Packages/message/server"; import { MessageSend } from "@Packages/message/server";
import { ScriptMenu, ScriptMenuItem } from "./popup"; import { ScriptMenu, ScriptMenuItem } from "./popup";
import PermissionVerify, { ConfirmParam, UserConfirm } from "./permission_verify";
export class ServiceWorkerClient extends Client { export class ServiceWorkerClient extends Client {
constructor(msg: MessageSend) { 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<void> {
return this.do("confirm", { uuid, userConfirm });
}
getPermissionInfo(uuid: string): ReturnType<PermissionVerify["getInfo"]> {
return this.do("getInfo", uuid);
}
}

View File

@ -70,9 +70,8 @@ export default class GMApi {
scriptDAO: ScriptDAO = new ScriptDAO(); scriptDAO: ScriptDAO = new ScriptDAO();
permissionVerify: PermissionVerify = new PermissionVerify();
constructor( constructor(
private permissionVerify: PermissionVerify,
private group: Group, private group: Group,
private send: MessageSend, private send: MessageSend,
private mq: MessageQueue, private mq: MessageQueue,
@ -109,7 +108,49 @@ export default class GMApi {
return req; return req;
} }
@PermissionVerify.API() @PermissionVerify.API({
confirm(request: Request) {
if (request.params[0] === "store") {
return Promise.resolve(true);
}
const detail = <GMTypes.CookieDetails>request.params[1];
if (!detail.url && !detail.domain) {
return Promise.reject(new Error("there must be one of url or domain"));
}
let url: 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) { async GM_cookie(request: Request, sender: GetSender) {
const param = request.params; const param = request.params;
if (param.length !== 2) { if (param.length !== 2) {

View File

@ -6,6 +6,7 @@ import { Api, Request } from "./gm_api";
import Queue from "@App/pkg/utils/queue"; import Queue from "@App/pkg/utils/queue";
import CacheKey from "@App/app/cache_key"; import CacheKey from "@App/app/cache_key";
import { Permission, PermissionDAO } from "@App/app/repo/permission"; import { Permission, PermissionDAO } from "@App/app/repo/permission";
import { Group } from "@Packages/message/server";
export interface ConfirmParam { export interface ConfirmParam {
// 权限名 // 权限名
@ -95,21 +96,18 @@ export default class PermissionVerify {
reject: (reason: any) => void; reject: (reason: any) => void;
}> = new Queue(); }> = new Queue();
async removePermissionCache(scriptId: number) { async removePermissionCache(uuid: string) {
// 先删除缓存 // 先删除缓存
(await Cache.getInstance().list()).forEach((key) => { (await Cache.getInstance().list()).forEach((key) => {
if (key.startsWith(`permission:${scriptId.toString()}:`)) { if (key.startsWith(`permission:${uuid}:`)) {
Cache.getInstance().del(key); Cache.getInstance().del(key);
} }
}); });
} }
private permissionDAO: PermissionDAO; private permissionDAO: PermissionDAO = new PermissionDAO();
constructor() { constructor(private group: Group) {}
this.permissionDAO = new PermissionDAO();
this.dealConfirmQueue();
}
// 验证是否有权限 // 验证是否有权限
verify(request: Request, api: ApiValue): Promise<boolean> { verify(request: Request, api: ApiValue): Promise<boolean> {
@ -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));
}
} }

View File

@ -24,6 +24,7 @@ import { compileInjectScript } from "../content/utils";
import { PopupService } from "./popup"; import { PopupService } from "./popup";
import Logger from "@App/app/logger/logger"; import Logger from "@App/app/logger/logger";
import LoggerCore from "@App/app/logger/core"; import LoggerCore from "@App/app/logger/core";
import PermissionVerify from "./permission_verify";
// 为了优化性能存储到缓存时删除了code与value // 为了优化性能存储到缓存时删除了code与value
export interface ScriptMatchInfo extends ScriptRunResouce { export interface ScriptMatchInfo extends ScriptRunResouce {
@ -56,7 +57,9 @@ export class RuntimeService {
async init() { async init() {
// 启动gm api // 启动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(); gmApi.start();
this.group.on("stopScript", this.stopScript.bind(this)); this.group.on("stopScript", this.stopScript.bind(this));

View File

@ -2,6 +2,7 @@ import { ConfirmParam } from "@App/app/service/service_worker/permission_verify"
import { Button, Message, Space } from "@arco-design/web-react"; import { Button, Message, Space } from "@arco-design/web-react";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { permissionClient } from "../store/features/script";
function App() { function App() {
const uuid = window.location.search.split("=")[1]; const uuid = window.location.search.split("=")[1];
@ -21,15 +22,16 @@ function App() {
useEffect(() => { useEffect(() => {
window.addEventListener("beforeunload", () => { window.addEventListener("beforeunload", () => {
permissionCtrl.sendConfirm(uuid, { permissionClient.confirm(uuid, {
allow: false, allow: false,
type: 0, type: 0,
}); });
}); });
permissionCtrl permissionClient
.getConfirm(uuid) .getPermissionInfo(uuid)
.then((data) => { .then((data) => {
console.log(data);
setConfirm(data.confirm); setConfirm(data.confirm);
setLikeNum(data.likeNum); setLikeNum(data.likeNum);
}) })
@ -41,7 +43,7 @@ function App() {
const handleConfirm = (allow: boolean, type: number) => { const handleConfirm = (allow: boolean, type: number) => {
return async () => { return async () => {
try { try {
await permissionCtrl.sendConfirm(uuid, { await permissionClient.confirm(uuid, {
allow, allow,
type, type,
}); });

View File

@ -8,12 +8,13 @@ import {
ScriptDAO, ScriptDAO,
} from "@App/app/repo/scripts"; } from "@App/app/repo/scripts";
import { arrayMove } from "@dnd-kit/sortable"; 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"; import { message } from "../global";
export const scriptClient = new ScriptClient(message); export const scriptClient = new ScriptClient(message);
export const runtimeClient = new RuntimeClient(message); export const runtimeClient = new RuntimeClient(message);
export const popupClient = new PopupClient(message); export const popupClient = new PopupClient(message);
export const permissionClient = new PermissionClient(message);
export const fetchAndSortScriptList = createAsyncThunk("script/fetchScriptList", async () => { export const fetchAndSortScriptList = createAsyncThunk("script/fetchScriptList", async () => {
// 排序 // 排序