aa
Some checks failed
test / Run tests (push) Failing after 14s
build / Build (push) Failing after 19s
Some checks failed
test / Run tests (push) Failing after 14s
build / Build (push) Failing after 19s
This commit is contained in:
parent
3d869643b4
commit
7697c91d95
30
package.json
30
package.json
@ -20,7 +20,7 @@
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@reduxjs/toolkit": "^2.3.0",
|
||||
"@reduxjs/toolkit": "^2.5.1",
|
||||
"cron": "^3.2.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
@ -41,10 +41,21 @@
|
||||
"yaml": "^2.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.2.0",
|
||||
"@eslint/js": "^9.12.0",
|
||||
"@rspack/cli": "^1.0.14",
|
||||
"@rspack/core": "^1.0.14",
|
||||
"@eslint/compat": "^1.2.6",
|
||||
"@eslint/js": "^9.19.0",
|
||||
"@rspack/cli": "^1.2.3",
|
||||
"@rspack/core": "^1.2.3",
|
||||
"@rspack/plugin-react-refresh": "^1.0.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.19.0",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"eslint-plugin-react-hooks": "^5.1.0",
|
||||
"globals": "^15.14.0",
|
||||
"prettier": "^3.4.2",
|
||||
"react-refresh": "^0.16.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.22.0",
|
||||
"@types/chrome": "^0.0.279",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/node": "^22.10.2",
|
||||
@ -56,18 +67,9 @@
|
||||
"@unocss/postcss": "0.65.0-beta.2",
|
||||
"@vitest/coverage-v8": "2.1.4",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.12.0",
|
||||
"eslint-plugin-react": "^7.37.1",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"globals": "^15.11.0",
|
||||
"jsdom": "^25.0.1",
|
||||
"postcss": "^8.4.49",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"prettier": "^3.3.3",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.6.3",
|
||||
"typescript-eslint": "^8.8.1",
|
||||
"unocss": "0.65.0-beta.2",
|
||||
"vitest": "^2.1.4"
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import LoggerCore from "@App/app/logger/core";
|
||||
import { Message, MessageConnect, MessageSend } from "./server";
|
||||
import { MessageConnect, MessageSend } from "./server";
|
||||
|
||||
export async function sendMessage(msg: MessageSend, action: string, data?: any): Promise<any> {
|
||||
const res = await msg.sendMessage({ action, data });
|
||||
@ -12,17 +12,19 @@ export async function sendMessage(msg: MessageSend, action: string, data?: any):
|
||||
}
|
||||
}
|
||||
|
||||
export function connect(msg: Message, action: string, data?: any): Promise<MessageConnect> {
|
||||
export function connect(msg: MessageSend, action: string, data?: any): Promise<MessageConnect> {
|
||||
return msg.connect({ action, data });
|
||||
}
|
||||
|
||||
export class Client {
|
||||
constructor(
|
||||
private msg: MessageSend,
|
||||
private prefix: string
|
||||
private prefix?: string
|
||||
) {
|
||||
if (!this.prefix.endsWith("/")) {
|
||||
if (this.prefix && !this.prefix.endsWith("/")) {
|
||||
this.prefix += "/";
|
||||
} else {
|
||||
this.prefix = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,12 @@
|
||||
import { Message, MessageConnect, MessageSend } from "./server";
|
||||
|
||||
export class ExtensionMessageSend implements MessageSend {
|
||||
constructor(protected serverEnv: string) {}
|
||||
constructor() {}
|
||||
|
||||
connect(data: any): Promise<MessageConnect> {
|
||||
return new Promise((resolve) => {
|
||||
const con = chrome.runtime.connect();
|
||||
con.postMessage(
|
||||
Object.assign(data, {
|
||||
serverEnv: this.serverEnv,
|
||||
})
|
||||
);
|
||||
con.postMessage(data);
|
||||
resolve(new ExtensionMessageConnect(con));
|
||||
});
|
||||
}
|
||||
@ -18,14 +14,9 @@ export class ExtensionMessageSend implements MessageSend {
|
||||
// 发送消息 注意不进行回调的内存泄漏
|
||||
sendMessage(data: any): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage(
|
||||
Object.assign(data, {
|
||||
serverEnv: this.serverEnv,
|
||||
}),
|
||||
(resp) => {
|
||||
chrome.runtime.sendMessage(data, (resp) => {
|
||||
resolve(resp);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -35,10 +26,6 @@ export class ExtensionMessage extends ExtensionMessageSend implements Message {
|
||||
chrome.runtime.onConnect.addListener((port) => {
|
||||
const handler = (msg: any) => {
|
||||
port.onMessage.removeListener(handler);
|
||||
if (msg.serverEnv !== this.serverEnv) {
|
||||
port.disconnect();
|
||||
return false;
|
||||
}
|
||||
callback(msg, new ExtensionMessageConnect(port));
|
||||
};
|
||||
port.onMessage.addListener(handler);
|
||||
@ -48,9 +35,6 @@ export class ExtensionMessage extends ExtensionMessageSend implements Message {
|
||||
// 注意chrome.runtime.onMessage.addListener的回调函数需要返回true才能处理异步请求
|
||||
onMessage(callback: (data: any, sendResponse: (data: any) => void) => void) {
|
||||
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
if (msg.serverEnv !== this.serverEnv) {
|
||||
return false;
|
||||
}
|
||||
return callback(msg, sendResponse);
|
||||
});
|
||||
}
|
||||
|
1607
pnpm-lock.yaml
generated
1607
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,7 @@ export class ExtCache implements CacheStorage {
|
||||
get(key: string): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
chrome.storage.local.get(key, (value) => {
|
||||
resolve(value);
|
||||
resolve(value[key]);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -89,6 +89,14 @@ export class MapCache {
|
||||
}
|
||||
}
|
||||
|
||||
export async function incr(cache: Cache, key: string, increase: number): Promise<number> {
|
||||
const value = await cache.get(key);
|
||||
let num = value || 0;
|
||||
num += increase;
|
||||
await cache.set(key, num);
|
||||
return num;
|
||||
}
|
||||
|
||||
export default class Cache {
|
||||
static instance: Cache = new Cache(new ExtCache());
|
||||
|
||||
|
@ -20,5 +20,5 @@ export function proxyUpdateRunStatus(
|
||||
msg: WindowMessage,
|
||||
data: { uuid: string; runStatus: SCRIPT_RUN_STATUS; error?: any; nextruntime?: number }
|
||||
) {
|
||||
return sendMessageToServiceWorker(msg, "serviceWorker/script/updateRunStatus", data);
|
||||
return sendMessageToServiceWorker(msg, "script/updateRunStatus", data);
|
||||
}
|
||||
|
@ -3,8 +3,12 @@ import { Group } from "@Packages/message/server";
|
||||
export class GMApi {
|
||||
constructor(private group: Group) {}
|
||||
|
||||
xmlHttpRequest(){
|
||||
|
||||
}
|
||||
|
||||
init() {
|
||||
this.group.on("requestXhr", async (data) => {
|
||||
this.group.on("xmlHttpRequest", async (data) => {
|
||||
console.log(data);
|
||||
});
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import { GMApi } from "./gm_api";
|
||||
|
||||
// offscreen环境的管理器
|
||||
export class OffscreenManager {
|
||||
private extensionMessage: MessageSend = new ExtensionMessageSend("service_worker");
|
||||
private extensionMessage: MessageSend = new ExtensionMessageSend();
|
||||
|
||||
private windowMessage = new WindowMessage(window, sandbox, true);
|
||||
|
||||
@ -35,11 +35,6 @@ export class OffscreenManager {
|
||||
}
|
||||
|
||||
async initManager() {
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
// 通知service worker已经准备好了
|
||||
registration.active?.postMessage("okkkk");
|
||||
});
|
||||
|
||||
// 监听消息
|
||||
this.windowApi.on("logger", this.logger.bind(this));
|
||||
this.windowApi.on("preparationSandbox", this.preparationSandbox.bind(this));
|
||||
@ -47,7 +42,7 @@ export class OffscreenManager {
|
||||
const script = new ScriptService(this.extensionMessage, this.windowMessage, this.broker);
|
||||
script.init();
|
||||
// 转发gm api请求
|
||||
forwardMessage("serviceWorker/runtime/gmApi", this.windowApi, this.extensionMessage);
|
||||
forwardMessage("runtime/gmApi", this.windowApi, this.extensionMessage);
|
||||
const gmApi = new GMApi(this.windowApi.group("gmApi"));
|
||||
gmApi.init();
|
||||
|
||||
|
@ -7,7 +7,7 @@ import { MessageSend } from "@Packages/message/server";
|
||||
|
||||
export class ServiceWorkerClient extends Client {
|
||||
constructor(msg: MessageSend) {
|
||||
super(msg, "serviceWorker");
|
||||
super(msg);
|
||||
}
|
||||
|
||||
preparationOffscreen() {
|
||||
@ -17,7 +17,7 @@ export class ServiceWorkerClient extends Client {
|
||||
|
||||
export class ScriptClient extends Client {
|
||||
constructor(msg: MessageSend) {
|
||||
super(msg, "serviceWorker/script");
|
||||
super(msg, "script");
|
||||
}
|
||||
|
||||
// 获取安装信息
|
||||
@ -52,7 +52,7 @@ export class ScriptClient extends Client {
|
||||
|
||||
export class ResourceClient extends Client {
|
||||
constructor(msg: MessageSend) {
|
||||
super(msg, "serviceWorker/resource");
|
||||
super(msg, "resource");
|
||||
}
|
||||
|
||||
getScriptResources(script: Script): Promise<{ [key: string]: Resource }> {
|
||||
@ -62,7 +62,7 @@ export class ResourceClient extends Client {
|
||||
|
||||
export class ValueClient extends Client {
|
||||
constructor(msg: MessageSend) {
|
||||
super(msg, "serviceWorker/value");
|
||||
super(msg, "value");
|
||||
}
|
||||
|
||||
getScriptValue(script: Script) {
|
||||
|
@ -5,6 +5,9 @@ import { Group, MessageConnect, MessageSender } from "@Packages/message/server";
|
||||
import { ValueService } from "@App/app/service/service_worker/value";
|
||||
import PermissionVerify from "./permission_verify";
|
||||
import { ServiceWorkerMessageSend } from "@Packages/message/window_message";
|
||||
import { connect, sendMessage } from "@Packages/message/client";
|
||||
import Cache, { incr } from "@App/app/cache";
|
||||
import { unsafeHeaders } from "@App/runtime/utils";
|
||||
|
||||
// GMApi,处理脚本的GM API调用请求
|
||||
|
||||
@ -76,25 +79,75 @@ export default class GMApi {
|
||||
return this.value.setValue(request.script.uuid, key, value);
|
||||
}
|
||||
|
||||
// 根据header生成dnr规则
|
||||
async buildDNRRule(params: GMSend.XHRDetails) {
|
||||
// 检查是否有unsafe header,有则生成dnr规则
|
||||
const headers = params.headers;
|
||||
if (!headers) {
|
||||
return;
|
||||
}
|
||||
const requestHeaders = [] as chrome.declarativeNetRequest.ModifyHeaderInfo[];
|
||||
Object.keys(headers).forEach((key) => {
|
||||
const lowKey = key.toLowerCase();
|
||||
if (unsafeHeaders[lowKey] || lowKey.startsWith("sec-") || lowKey.startsWith("proxy-")) {
|
||||
requestHeaders.push({
|
||||
header: key,
|
||||
operation: chrome.declarativeNetRequest.HeaderOperation.SET,
|
||||
value: headers[key],
|
||||
});
|
||||
}
|
||||
});
|
||||
if (requestHeaders.length === 0) {
|
||||
return;
|
||||
}
|
||||
const ruleId = 1000 + (await incr(Cache.getInstance(), "dnrRuleId", 1));
|
||||
const rule = {} as chrome.declarativeNetRequest.Rule;
|
||||
rule.id = ruleId;
|
||||
rule.action = {
|
||||
type: chrome.declarativeNetRequest.RuleActionType.MODIFY_HEADERS,
|
||||
requestHeaders: requestHeaders,
|
||||
};
|
||||
rule.priority = 1;
|
||||
const tabs = await chrome.tabs.query({});
|
||||
const excludedTabIds: number[] = [];
|
||||
tabs.forEach((tab) => {
|
||||
if (tab.id) {
|
||||
excludedTabIds.push(tab.id);
|
||||
}
|
||||
});
|
||||
rule.condition = {
|
||||
resourceTypes: [chrome.declarativeNetRequest.ResourceType.XMLHTTPREQUEST],
|
||||
urlFilter: "^" + params.url + "$",
|
||||
excludedTabIds: excludedTabIds,
|
||||
};
|
||||
return chrome.declarativeNetRequest.updateSessionRules({
|
||||
removeRuleIds: [ruleId],
|
||||
addRules: [rule],
|
||||
});
|
||||
}
|
||||
|
||||
@PermissionVerify.API()
|
||||
GM_xmlhttpRequest(request: Request, con: MessageConnect) {
|
||||
async GM_xmlhttpRequest(request: Request, con: MessageConnect) {
|
||||
console.log("xml request", request, con);
|
||||
// 先处理unsafe hearder
|
||||
await this.buildDNRRule(request.params[0]);
|
||||
// 再发送到offscreen, 处理请求
|
||||
sendMessageToOffscreen(this.sender, "offscreen/gmApi/requestXhr", request.params);
|
||||
connect(this.sender, "gmApi/xmlHttpRequest", request.params);
|
||||
}
|
||||
|
||||
start() {
|
||||
this.group.on("gmApi", this.handlerRequest.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
export async function sendMessageToOffscreen(sender: ServiceWorkerMessageSend, action: string, data?: any) {
|
||||
// service_worker和offscreen同时监听消息,会导致消息被两边同时接收,但是返回结果时会产生问题,导致报错
|
||||
// 不进行监听的话又无法从service_worker主动发送消息
|
||||
// 所以这里通过clients.matchAll()获取到所有的client,然后通过postMessage发送消息
|
||||
sender.sendMessage({
|
||||
type: "sendMessage",
|
||||
data: { action, data },
|
||||
});
|
||||
// 处理收到的header
|
||||
chrome.webRequest.onHeadersReceived.addListener(
|
||||
(details) => {
|
||||
console.log(details);
|
||||
},
|
||||
{
|
||||
urls: ["<all_urls>"],
|
||||
types: ["xmlhttprequest"],
|
||||
},
|
||||
["responseHeaders", "extraHeaders"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -11,27 +11,26 @@ export type InstallSource = "user" | "system" | "sync" | "subscribe" | "vscode";
|
||||
|
||||
// service worker的管理器
|
||||
export default class ServiceWorkerManager {
|
||||
private api: Server = new Server(new ExtensionMessage("service_worker"));
|
||||
private api: Server = new Server(new ExtensionMessage());
|
||||
|
||||
private mq: MessageQueue = new MessageQueue(this.api);
|
||||
|
||||
private sender: ServiceWorkerMessageSend = new ServiceWorkerMessageSend();
|
||||
|
||||
async initManager() {
|
||||
const group = this.api.group("serviceWorker");
|
||||
group.on("preparationOffscreen", async () => {
|
||||
this.api.on("preparationOffscreen", async () => {
|
||||
// 准备好环境
|
||||
await this.sender.init();
|
||||
this.mq.emit("preparationOffscreen", {});
|
||||
});
|
||||
|
||||
const resource = new ResourceService(group.group("resource"), this.mq);
|
||||
const resource = new ResourceService(this.api.group("resource"), this.mq);
|
||||
resource.init();
|
||||
const value = new ValueService(group.group("value"), this.mq);
|
||||
const value = new ValueService(this.api.group("value"), this.mq);
|
||||
value.init();
|
||||
const script = new ScriptService(group.group("script"), this.mq, value, resource);
|
||||
const script = new ScriptService(this.api.group("script"), this.mq, value, resource);
|
||||
script.init();
|
||||
const runtime = new RuntimeService(group.group("runtime"), this.sender, this.mq, value);
|
||||
const runtime = new RuntimeService(this.api.group("runtime"), this.sender, this.mq, value);
|
||||
runtime.init();
|
||||
|
||||
// 测试xhr
|
||||
|
@ -63,7 +63,7 @@ export default class GMApi {
|
||||
// 单次回调使用
|
||||
public sendMessage(api: string, params: any[]) {
|
||||
return this.message.sendMessage({
|
||||
action: "serviceWorker/runtime/gmApi",
|
||||
action: "runtime/gmApi",
|
||||
data: {
|
||||
uuid: this.scriptRes.uuid,
|
||||
api,
|
||||
@ -75,7 +75,7 @@ export default class GMApi {
|
||||
// 长连接使用,connect只用于接受消息,不发送消息
|
||||
public connect(api: string, params: any[]) {
|
||||
return this.message.connect({
|
||||
action: "serviceWorker/runtime/gmApi",
|
||||
action: "runtime/gmApi",
|
||||
data: {
|
||||
uuid: this.scriptRes.uuid,
|
||||
api,
|
||||
|
@ -1,5 +1,34 @@
|
||||
import { Script } from "@App/app/repo/scripts";
|
||||
|
||||
export const unsafeHeaders: { [key: string]: boolean } = {
|
||||
// 部分浏览器中并未允许
|
||||
"user-agent": true,
|
||||
// 这两个是前缀
|
||||
"proxy-": true,
|
||||
"sec-": true,
|
||||
// cookie已经特殊处理
|
||||
cookie: true,
|
||||
"accept-charset": true,
|
||||
"accept-encoding": true,
|
||||
"access-control-request-headers": true,
|
||||
"access-control-request-method": true,
|
||||
connection: true,
|
||||
"content-length": true,
|
||||
date: true,
|
||||
dnt: true,
|
||||
expect: true,
|
||||
"feature-policy": true,
|
||||
host: true,
|
||||
"keep-alive": true,
|
||||
origin: true,
|
||||
referer: true,
|
||||
te: true,
|
||||
trailer: true,
|
||||
"transfer-encoding": true,
|
||||
upgrade: true,
|
||||
via: true,
|
||||
};
|
||||
|
||||
export function storageKey(script: Script): string {
|
||||
if (script.metadata && script.metadata.storagename) {
|
||||
return script.metadata.storagename[0];
|
||||
|
Loading…
x
Reference in New Issue
Block a user