Skip to content

Commit ad9a388

Browse files
committed
fix: firfox csp nonce
1 parent 16a79f7 commit ad9a388

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

packages/force-copy/src/content/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { implantScript } from "./runtime/script";
1212
logger.setLevel(LOG_LEVEL.INFO);
1313
}
1414
logger.info("Content Script Loaded");
15-
implantScript();
15+
// implantScript();
1616
!isInIframe && initializeWorker();
1717
PCBridge.onPopupMessage(onPopupMessage);
1818
})();

packages/force-copy/src/manifest/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,13 @@ if (process.env.PLATFORM === "gecko") {
5656
__MANIFEST__.background = {
5757
scripts: [__MANIFEST__.background.service_worker],
5858
};
59-
__MANIFEST__.permissions = ["activeTab", "tabs", ...__URL_MATCH__];
59+
__MANIFEST__.permissions = [
60+
"activeTab",
61+
"tabs",
62+
"webRequest",
63+
"webRequestBlocking",
64+
...__URL_MATCH__,
65+
];
6066
__MANIFEST__.browser_specific_settings = {
6167
gecko: { strict_min_version: "91.1.0" },
6268
gecko_android: { strict_min_version: "91.1.0" },

packages/force-copy/src/worker/runtime/script.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,63 @@ export const implantScript = () => {
4747
// #ENDIF
4848
// #IFDEF GECKO
4949
logger.info("Register Inject Scripts By Content Script Inline Code");
50+
// 使用 cross.tabs.executeScript 得到的 window 是 content window
51+
// 此时就必须要使用 Inject Script 的方式才能正常注入脚本
52+
// 然而这种方式就会受到 CSP 的限制, 因此在这里处理 CSP 问题
53+
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/onHeadersReceived
54+
let nonceId = "";
55+
chrome.webRequest.onHeadersReceived.addListener(
56+
res => {
57+
if (!res.responseHeaders) return void 0;
58+
if (res.type !== "main_frame" && res.type !== "sub_frame") {
59+
return void 0;
60+
}
61+
for (let i = 0; i < res.responseHeaders.length; i++) {
62+
const responseHeaderName = res.responseHeaders[i].name.toLowerCase();
63+
if (responseHeaderName === "content-security-policy") {
64+
const value = res.responseHeaders[i].value || "";
65+
const nonce = /'nonce-([-+/=\w]+)'/.exec(value);
66+
if (nonce && nonce[1]) {
67+
nonceId = nonce[1];
68+
}
69+
}
70+
}
71+
return {
72+
responseHeaders: res.responseHeaders,
73+
};
74+
},
75+
{ urls: URL_MATCH },
76+
["responseHeaders"]
77+
);
78+
// https://developer.mozilla.org/zh-CN/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript
79+
cross.tabs.onUpdated.addListener((_, changeInfo, tab) => {
80+
if (changeInfo.status == "loading") {
81+
const tabId = tab && tab.id;
82+
const tabURL = tab && tab.url;
83+
if (!tabId || !tabURL) return void 0;
84+
if (!URL_MATCH.some(match => new RegExp(match).test(tabURL))) {
85+
return void 0;
86+
}
87+
const code = `
88+
if (window["${process.env.INJECT_FILE}"] && document instanceof XMLDocument === false) {
89+
const script = document.createElementNS("http://www.w3.org/1999/xhtml", "script");
90+
script.setAttribute("type", "text/javascript");
91+
script.innerText = \`;(\${window["${process.env.INJECT_FILE}"].toString()})();\`;
92+
script.nonce = "${nonceId}";
93+
document.documentElement.appendChild(script);
94+
// script.onload = () => script.remove();
95+
// delete window["${process.env.INJECT_FILE}"];
96+
};`;
97+
cross.tabs
98+
.executeScript(tabId, {
99+
allFrames: true,
100+
code: code,
101+
runAt: "document_start",
102+
})
103+
.catch(err => {
104+
if (__DEV__) logger.warning("Inject Script", err);
105+
});
106+
}
107+
});
50108
// #ENDIF
51109
};

0 commit comments

Comments
 (0)