inject的GM API调用
Some checks failed
build / Build (push) Failing after 7s
test / Run tests (push) Failing after 8s
Some checks failed
build / Build (push) Failing after 7s
test / Run tests (push) Failing after 8s
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { Group, MessageConnect } from "@Packages/message/server";
|
import { GetSender, Group, MessageConnect } from "@Packages/message/server";
|
||||||
|
|
||||||
export default class GMApi {
|
export default class GMApi {
|
||||||
constructor(private group: Group) {}
|
constructor(private group: Group) {}
|
||||||
@@ -24,8 +24,9 @@ export default class GMApi {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlHttpRequest(details: GMSend.XHRDetails, con: MessageConnect | null) {
|
xmlHttpRequest(details: GMSend.XHRDetails, sender: GetSender) {
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
|
const con = sender.getConnect();
|
||||||
xhr.open(details.method || "GET", details.url);
|
xhr.open(details.method || "GET", details.url);
|
||||||
// 添加header
|
// 添加header
|
||||||
if (details.headers) {
|
if (details.headers) {
|
||||||
@@ -34,7 +35,7 @@ export default class GMApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
xhr.onload = () => {
|
xhr.onload = () => {
|
||||||
this.dealXhrResponse(con!, details, "onload", xhr);
|
this.dealXhrResponse(con, details, "onload", xhr);
|
||||||
};
|
};
|
||||||
xhr.onloadstart = () => {
|
xhr.onloadstart = () => {
|
||||||
this.dealXhrResponse(con!, details, "onloadstart", xhr);
|
this.dealXhrResponse(con!, details, "onloadstart", xhr);
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import LoggerCore from "@App/app/logger/core";
|
import LoggerCore from "@App/app/logger/core";
|
||||||
import Logger from "@App/app/logger/logger";
|
import Logger from "@App/app/logger/logger";
|
||||||
import { Script, ScriptDAO } from "@App/app/repo/scripts";
|
import { Script, ScriptDAO } from "@App/app/repo/scripts";
|
||||||
import { GetSender, Group, MessageConnect, MessageSend, MessageSender } from "@Packages/message/server";
|
import { GetSender, Group, MessageSend, MessageSender } from "@Packages/message/server";
|
||||||
import { ValueService } from "@App/app/service/service_worker/value";
|
import { ValueService } from "@App/app/service/service_worker/value";
|
||||||
import PermissionVerify from "./permission_verify";
|
import PermissionVerify from "./permission_verify";
|
||||||
import { connect } from "@Packages/message/client";
|
import { connect } from "@Packages/message/client";
|
||||||
@@ -23,7 +23,7 @@ export type Request = MessageRequest & {
|
|||||||
sender: MessageSender;
|
sender: MessageSender;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Api = (request: Request, con: MessageConnect | null) => Promise<any>;
|
export type Api = (request: Request, con: GetSender) => Promise<any>;
|
||||||
|
|
||||||
export default class GMApi {
|
export default class GMApi {
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
@@ -34,7 +34,7 @@ export default class GMApi {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private group: Group,
|
private group: Group,
|
||||||
private sender: MessageSend,
|
private send: MessageSend,
|
||||||
private value: ValueService
|
private value: ValueService
|
||||||
) {
|
) {
|
||||||
this.logger = LoggerCore.logger().with({ service: "runtime/gm_api" });
|
this.logger = LoggerCore.logger().with({ service: "runtime/gm_api" });
|
||||||
@@ -53,7 +53,7 @@ export default class GMApi {
|
|||||||
this.logger.error("verify error", { api: data.api }, Logger.E(e));
|
this.logger.error("verify error", { api: data.api }, Logger.E(e));
|
||||||
return Promise.reject(e);
|
return Promise.reject(e);
|
||||||
}
|
}
|
||||||
return api.api.call(this, req, con.getConnect());
|
return api.api.call(this, req, con);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析请求
|
// 解析请求
|
||||||
@@ -80,11 +80,12 @@ export default class GMApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 根据header生成dnr规则
|
// 根据header生成dnr规则
|
||||||
async buildDNRRule(reqeustId: number, params: GMSend.XHRDetails) {
|
async buildDNRRule(reqeustId: number, params: GMSend.XHRDetails): Promise<{ [key: string]: string }> {
|
||||||
// 检查是否有unsafe header,有则生成dnr规则
|
// 检查是否有unsafe header,有则生成dnr规则
|
||||||
const headers = params.headers;
|
const headers = params.headers;
|
||||||
|
console.log(headers, !headers);
|
||||||
if (!headers) {
|
if (!headers) {
|
||||||
return;
|
return Promise.resolve({});
|
||||||
}
|
}
|
||||||
const requestHeaders = [
|
const requestHeaders = [
|
||||||
{
|
{
|
||||||
@@ -100,6 +101,7 @@ export default class GMApi {
|
|||||||
operation: chrome.declarativeNetRequest.HeaderOperation.SET,
|
operation: chrome.declarativeNetRequest.HeaderOperation.SET,
|
||||||
value: headers[key],
|
value: headers[key],
|
||||||
});
|
});
|
||||||
|
delete headers[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const ruleId = reqeustId;
|
const ruleId = reqeustId;
|
||||||
@@ -119,20 +121,23 @@ export default class GMApi {
|
|||||||
});
|
});
|
||||||
rule.condition = {
|
rule.condition = {
|
||||||
resourceTypes: [chrome.declarativeNetRequest.ResourceType.XMLHTTPREQUEST],
|
resourceTypes: [chrome.declarativeNetRequest.ResourceType.XMLHTTPREQUEST],
|
||||||
urlFilter: "^" + params.url + "$",
|
urlFilter: params.url,
|
||||||
|
requestMethods: [(params.method || "GET").toLowerCase() as chrome.declarativeNetRequest.RequestMethod],
|
||||||
excludedTabIds: excludedTabIds,
|
excludedTabIds: excludedTabIds,
|
||||||
};
|
};
|
||||||
|
console.log(rule);
|
||||||
await chrome.declarativeNetRequest.updateSessionRules({
|
await chrome.declarativeNetRequest.updateSessionRules({
|
||||||
removeRuleIds: [ruleId],
|
removeRuleIds: [ruleId],
|
||||||
addRules: [rule],
|
addRules: [rule],
|
||||||
});
|
});
|
||||||
return ruleId;
|
return Promise.resolve(headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
gmXhrHeadersReceived: EventEmitter = new EventEmitter();
|
gmXhrHeadersReceived: EventEmitter = new EventEmitter();
|
||||||
|
|
||||||
@PermissionVerify.API()
|
@PermissionVerify.API()
|
||||||
async GM_xmlhttpRequest(request: Request, con: MessageConnect) {
|
async GM_xmlhttpRequest(request: Request, con: GetSender) {
|
||||||
|
console.log("GM XHR", request);
|
||||||
if (request.params.length === 0) {
|
if (request.params.length === 0) {
|
||||||
return Promise.reject(new Error("param is failed"));
|
return Promise.reject(new Error("param is failed"));
|
||||||
}
|
}
|
||||||
@@ -145,7 +150,8 @@ export default class GMApi {
|
|||||||
params.headers = {};
|
params.headers = {};
|
||||||
}
|
}
|
||||||
params.headers["X-Scriptcat-GM-XHR-Request-Id"] = requestId.toString();
|
params.headers["X-Scriptcat-GM-XHR-Request-Id"] = requestId.toString();
|
||||||
await this.buildDNRRule(requestId, request.params[0]);
|
params.headers = await this.buildDNRRule(requestId, request.params[0]);
|
||||||
|
console.log(" params.headers", params.headers);
|
||||||
let responseHeader = "";
|
let responseHeader = "";
|
||||||
// 等待response
|
// 等待response
|
||||||
this.gmXhrHeadersReceived.addListener(
|
this.gmXhrHeadersReceived.addListener(
|
||||||
@@ -157,12 +163,12 @@ export default class GMApi {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
// 再发送到offscreen, 处理请求
|
// 再发送到offscreen, 处理请求
|
||||||
const offscreenCon = await connect(this.sender, "gmApi/xmlHttpRequest", request.params[0]);
|
const offscreenCon = await connect(this.send, "offscreen/gmApi/xmlHttpRequest", request.params[0]);
|
||||||
offscreenCon.onMessage((msg: { action: string; data: any }) => {
|
offscreenCon.onMessage((msg: { action: string; data: any }) => {
|
||||||
// 发送到content
|
// 发送到content
|
||||||
// 替换msg.data.responseHeaders
|
// 替换msg.data.responseHeaders
|
||||||
msg.data.responseHeaders = responseHeader;
|
msg.data.responseHeaders = responseHeader;
|
||||||
con.sendMessage(msg);
|
con.getConnect().sendMessage(msg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +177,7 @@ export default class GMApi {
|
|||||||
chrome.webRequest.onBeforeSendHeaders.addListener(
|
chrome.webRequest.onBeforeSendHeaders.addListener(
|
||||||
(details) => {
|
(details) => {
|
||||||
if (details.tabId === -1) {
|
if (details.tabId === -1) {
|
||||||
|
console.log(details);
|
||||||
// 判断是否存在X-Scriptcat-GM-XHR-Request-Id
|
// 判断是否存在X-Scriptcat-GM-XHR-Request-Id
|
||||||
// 讲请求id与chrome.webRequest的请求id关联
|
// 讲请求id与chrome.webRequest的请求id关联
|
||||||
if (details.requestHeaders) {
|
if (details.requestHeaders) {
|
||||||
|
@@ -8,7 +8,7 @@ import { ScriptService } from "./script";
|
|||||||
import { runScript, stopScript } from "../offscreen/client";
|
import { runScript, stopScript } from "../offscreen/client";
|
||||||
import { getRunAt } from "./utils";
|
import { getRunAt } from "./utils";
|
||||||
import { randomString } from "@App/pkg/utils/utils";
|
import { randomString } from "@App/pkg/utils/utils";
|
||||||
import { compileInjectScript, compileScriptCode } from "@App/runtime/content/utils";
|
import { compileInjectScript } from "@App/runtime/content/utils";
|
||||||
import Cache from "@App/app/cache";
|
import Cache from "@App/app/cache";
|
||||||
import { dealPatternMatches, UrlMatch } from "@App/pkg/utils/match";
|
import { dealPatternMatches, UrlMatch } from "@App/pkg/utils/match";
|
||||||
|
|
||||||
@@ -113,7 +113,6 @@ export class RuntimeService {
|
|||||||
|
|
||||||
// 匹配当前页面的脚本
|
// 匹配当前页面的脚本
|
||||||
const matchScriptUuid = match.match(chromeSender.url!);
|
const matchScriptUuid = match.match(chromeSender.url!);
|
||||||
console.log("pageLoad", match.match(chromeSender.url!));
|
|
||||||
const scripts = await Promise.all(
|
const scripts = await Promise.all(
|
||||||
matchScriptUuid.map(
|
matchScriptUuid.map(
|
||||||
(uuid) =>
|
(uuid) =>
|
||||||
@@ -249,7 +248,6 @@ export class RuntimeService {
|
|||||||
}
|
}
|
||||||
const scriptRes = await this.script.buildScriptRunResource(script);
|
const scriptRes = await this.script.buildScriptRunResource(script);
|
||||||
|
|
||||||
scriptRes.code = compileScriptCode(scriptRes);
|
|
||||||
scriptRes.code = compileInjectScript(scriptRes);
|
scriptRes.code = compileInjectScript(scriptRes);
|
||||||
|
|
||||||
matches.push(...(script.metadata["include"] || []));
|
matches.push(...(script.metadata["include"] || []));
|
||||||
|
@@ -4,6 +4,7 @@ import { ExtensionMessageSend } from "@Packages/message/extension_message";
|
|||||||
import { CustomEventMessage } from "@Packages/message/custom_event_message";
|
import { CustomEventMessage } from "@Packages/message/custom_event_message";
|
||||||
import { RuntimeClient } from "./app/service/service_worker/client";
|
import { RuntimeClient } from "./app/service/service_worker/client";
|
||||||
import ContentRuntime from "./runtime/content/content";
|
import ContentRuntime from "./runtime/content/content";
|
||||||
|
import { Server } from "@Packages/message/server";
|
||||||
|
|
||||||
// 建立与service_worker页面的连接
|
// 建立与service_worker页面的连接
|
||||||
const send = new ExtensionMessageSend();
|
const send = new ExtensionMessageSend();
|
||||||
@@ -17,9 +18,9 @@ const loggerCore = new LoggerCore({
|
|||||||
const client = new RuntimeClient(send);
|
const client = new RuntimeClient(send);
|
||||||
client.pageLoad().then((data) => {
|
client.pageLoad().then((data) => {
|
||||||
loggerCore.logger().debug("content start");
|
loggerCore.logger().debug("content start");
|
||||||
console.log("content", data);
|
|
||||||
const msg = new CustomEventMessage(data.flag, true);
|
const msg = new CustomEventMessage(data.flag, true);
|
||||||
|
const server = new Server("content", msg);
|
||||||
// 初始化运行环境
|
// 初始化运行环境
|
||||||
const runtime = new ContentRuntime(send, msg);
|
const runtime = new ContentRuntime(server, send, msg);
|
||||||
runtime.start(data.scripts);
|
runtime.start(data.scripts);
|
||||||
});
|
});
|
||||||
|
@@ -17,7 +17,6 @@ const server = new Server("inject", msg);
|
|||||||
|
|
||||||
server.on("pageLoad", (data: { scripts: ScriptRunResouce[] }) => {
|
server.on("pageLoad", (data: { scripts: ScriptRunResouce[] }) => {
|
||||||
logger.logger().debug("inject start");
|
logger.logger().debug("inject start");
|
||||||
console.log("inject", data);
|
|
||||||
const runtime = new InjectRuntime(msg, data.scripts);
|
const runtime = new InjectRuntime(msg, data.scripts);
|
||||||
runtime.start();
|
runtime.start();
|
||||||
});
|
});
|
||||||
|
@@ -149,6 +149,9 @@ export default class Match<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static getId(val: any): string {
|
protected static getId(val: any): string {
|
||||||
|
if (typeof val === "string") {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
return (<{ uuid: string }>(<unknown>val)).uuid;
|
return (<{ uuid: string }>(<unknown>val)).uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,19 +1,23 @@
|
|||||||
import { ScriptRunResouce } from "@App/app/repo/scripts";
|
import { ScriptRunResouce } from "@App/app/repo/scripts";
|
||||||
import { Client } from "@Packages/message/client";
|
import { Client } from "@Packages/message/client";
|
||||||
import { Message, MessageSend } from "@Packages/message/server";
|
import { forwardMessage, Message, MessageSend, Server } from "@Packages/message/server";
|
||||||
|
|
||||||
// content页的处理
|
// content页的处理
|
||||||
export default class ContentRuntime {
|
export default class ContentRuntime {
|
||||||
constructor(
|
constructor(
|
||||||
|
private server: Server,
|
||||||
private send: MessageSend,
|
private send: MessageSend,
|
||||||
private msg: Message
|
private msg: Message
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
start(scripts: ScriptRunResouce[]) {
|
start(scripts: ScriptRunResouce[]) {
|
||||||
console.log("onMessage");
|
|
||||||
this.msg.onMessage((msg, sendResponse) => {
|
this.msg.onMessage((msg, sendResponse) => {
|
||||||
console.log("content onMessage", msg);
|
console.log("content onMessage", msg);
|
||||||
});
|
});
|
||||||
|
this.msg.onConnect((msg, connect) => {
|
||||||
|
console.log(msg, connect);
|
||||||
|
});
|
||||||
|
forwardMessage("serviceWorker", "runtime/gmApi", this.server, this.send);
|
||||||
// 由content到background
|
// 由content到background
|
||||||
// 转发gmApi消息
|
// 转发gmApi消息
|
||||||
// this.contentMessage.setHandler("gmApi", (action, data) => {
|
// this.contentMessage.setHandler("gmApi", (action, data) => {
|
||||||
|
@@ -2,7 +2,8 @@ import { ScriptRunResouce } from "@App/app/repo/scripts";
|
|||||||
import ExecScript from "./exec_script";
|
import ExecScript from "./exec_script";
|
||||||
import { compileScript, compileScriptCode } from "./utils";
|
import { compileScript, compileScriptCode } from "./utils";
|
||||||
import { ExtVersion } from "@App/app/const";
|
import { ExtVersion } from "@App/app/const";
|
||||||
import initTestEnv from "@Tests/utils";
|
import { initTestEnv } from "@Tests/utils";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
initTestEnv();
|
initTestEnv();
|
||||||
|
|
||||||
|
@@ -35,6 +35,7 @@ export default class ExecScript {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
scriptRes: ScriptRunResouce,
|
scriptRes: ScriptRunResouce,
|
||||||
|
envPrefix: "content" | "offscreen",
|
||||||
message: Message,
|
message: Message,
|
||||||
code: string | ScriptFunc,
|
code: string | ScriptFunc,
|
||||||
thisContext?: { [key: string]: any }
|
thisContext?: { [key: string]: any }
|
||||||
@@ -61,7 +62,7 @@ export default class ExecScript {
|
|||||||
this.proxyContent = global;
|
this.proxyContent = global;
|
||||||
} else {
|
} else {
|
||||||
// 构建脚本GM上下文
|
// 构建脚本GM上下文
|
||||||
this.sandboxContent = createContext(scriptRes, this.GM_info, message);
|
this.sandboxContent = createContext(scriptRes, this.GM_info, envPrefix, message);
|
||||||
this.proxyContent = proxyContext(global, this.sandboxContent, thisContext);
|
this.proxyContent = proxyContext(global, this.sandboxContent, thisContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +77,6 @@ export default class ExecScript {
|
|||||||
return this.scriptFunc.apply(this.proxyContent, [this.proxyContent, this.GM_info]);
|
return this.scriptFunc.apply(this.proxyContent, [this.proxyContent, this.GM_info]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 实现脚本的停止,资源释放
|
|
||||||
stop() {
|
stop() {
|
||||||
this.logger.debug("script stop");
|
this.logger.debug("script stop");
|
||||||
return true;
|
return true;
|
||||||
|
@@ -63,7 +63,7 @@ export class BgExecScriptWarp extends ExecScript {
|
|||||||
};
|
};
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
thisContext.CATRetryError = CATRetryError;
|
thisContext.CATRetryError = CATRetryError;
|
||||||
super(scriptRes, message, thisContext);
|
super(scriptRes, "offscreen", message, scriptRes.code, thisContext);
|
||||||
this.setTimeout = setTimeout;
|
this.setTimeout = setTimeout;
|
||||||
this.setInterval = setInterval;
|
this.setInterval = setInterval;
|
||||||
}
|
}
|
||||||
|
@@ -58,12 +58,15 @@ export default class GMApi {
|
|||||||
|
|
||||||
valueChangeListener = new Map<number, { name: string; listener: GMTypes.ValueChangeListener }>();
|
valueChangeListener = new Map<number, { name: string; listener: GMTypes.ValueChangeListener }>();
|
||||||
|
|
||||||
constructor(private message: Message) {}
|
constructor(
|
||||||
|
private prefix: string,
|
||||||
|
private message: Message
|
||||||
|
) {}
|
||||||
|
|
||||||
// 单次回调使用
|
// 单次回调使用
|
||||||
public sendMessage(api: string, params: any[]) {
|
public sendMessage(api: string, params: any[]) {
|
||||||
return this.message.sendMessage({
|
return this.message.sendMessage({
|
||||||
action: "runtime/gmApi",
|
action: this.prefix + "/runtime/gmApi",
|
||||||
data: {
|
data: {
|
||||||
uuid: this.scriptRes.uuid,
|
uuid: this.scriptRes.uuid,
|
||||||
api,
|
api,
|
||||||
@@ -75,7 +78,7 @@ export default class GMApi {
|
|||||||
// 长连接使用,connect只用于接受消息,不发送消息
|
// 长连接使用,connect只用于接受消息,不发送消息
|
||||||
public connect(api: string, params: any[]) {
|
public connect(api: string, params: any[]) {
|
||||||
return this.message.connect({
|
return this.message.connect({
|
||||||
action: "runtime/gmApi",
|
action: this.prefix + "/runtime/gmApi",
|
||||||
data: {
|
data: {
|
||||||
uuid: this.scriptRes.uuid,
|
uuid: this.scriptRes.uuid,
|
||||||
api,
|
api,
|
||||||
|
@@ -32,7 +32,7 @@ export class InjectRuntime {
|
|||||||
execScript(script: ScriptRunResouce, scriptFunc: ScriptFunc) {
|
execScript(script: ScriptRunResouce, scriptFunc: ScriptFunc) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
delete window[script.flag];
|
delete window[script.flag];
|
||||||
const exec = new ExecScript(script, this.msg, scriptFunc);
|
const exec = new ExecScript(script, "content", this.msg, scriptFunc);
|
||||||
this.execList.push(exec);
|
this.execList.push(exec);
|
||||||
// 注入css
|
// 注入css
|
||||||
if (script.metadata["require-css"]) {
|
if (script.metadata["require-css"]) {
|
||||||
|
@@ -53,9 +53,10 @@ function setDepend(context: { [key: string]: any }, apiVal: ApiValue) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 构建沙盒上下文
|
// 构建沙盒上下文
|
||||||
export function createContext(scriptRes: ScriptRunResouce, GMInfo: any, message: Message): GMApi {
|
export function createContext(scriptRes: ScriptRunResouce, GMInfo: any, envPrefix: string, message: Message): GMApi {
|
||||||
// 按照GMApi构建
|
// 按照GMApi构建
|
||||||
const context: { [key: string]: any } = {
|
const context: { [key: string]: any } = {
|
||||||
|
prefix: envPrefix,
|
||||||
message: message,
|
message: message,
|
||||||
scriptRes,
|
scriptRes,
|
||||||
valueChangeListener: new Map<number, { name: string; listener: GMTypes.ValueChangeListener }>(),
|
valueChangeListener: new Map<number, { name: string; listener: GMTypes.ValueChangeListener }>(),
|
||||||
|
Reference in New Issue
Block a user