Skip to content

Commit d587351

Browse files
committed
feat: firefox nonce retry
1 parent ab20c09 commit d587351

File tree

4 files changed

+44
-12
lines changed

4 files changed

+44
-12
lines changed

packages/force-copy/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"devDependencies": {
3030
"@rspack/cli": "0.2.5",
3131
"@rspack/plugin-html": "0.2.5",
32-
"@types/chrome": "0.0.241",
32+
"@types/chrome": "0.0.287",
3333
"@types/react": "17.0.2",
3434
"@types/react-dom": "17.0.2",
3535
"less": "3.0.0",

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ export const implantScript = () => {
99
// 这里的内容需要跟 WrapperCodePlugin 的 HASH 计算保持一致
1010
script.innerText = `;(${fn.toString()})();`;
1111
document.documentElement.appendChild(script);
12+
// 在这里仅移除 script 标签, 但不会删除 window 上的属性
13+
// 保证在 CSP 限制下可以重试, 且处于隔离环境不会受到影响
1214
script.onload = () => script.remove();
13-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
14-
// @ts-ignore
15-
delete window[process.env.INJECT_FILE];
1615
}
1716
// #ENDIF
1817
};

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

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,12 @@ export const implantScript = () => {
4545
});
4646
}
4747
// #ENDIF
48+
4849
// #IFDEF GECKO
4950
logger.info("Register Inject Scripts By Content Script Inline Code");
5051
// 使用 cross.tabs.executeScript 得到的 window 是 content window
5152
// 此时就必须要使用 Inject Script 的方式才能正常注入脚本
5253
// 然而这种方式就会受到 CSP 的限制, 因此在这里处理 CSP 问题
53-
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
54-
// https://developer.mozilla.org/zh-CN/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript
5554
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/onHeadersReceived
5655
chrome.webRequest.onHeadersReceived.addListener(
5756
res => {
@@ -66,7 +65,9 @@ export const implantScript = () => {
6665
const value = res.responseHeaders[i].value || "";
6766
const types = value.split(";").map(it => it.trim());
6867
const target: string[] = [];
69-
// 这里的 HASH 在 WrapperCodePlugin 中计算并替换资源
68+
// CSP 不支持多个 nonce, 但可以配置多个 hash
69+
// 这里的 HASH 会在 WrapperCodePlugin 中计算并替换资源
70+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
7071
const hashed = "'sha256-${CSP-HASH}'";
7172
for (const item of types) {
7273
const [type, ...rest] = item.split(" ");
@@ -76,10 +77,42 @@ export const implantScript = () => {
7677
}
7778
target.push(item);
7879
}
79-
// 这里存在一个问题, 扩展的 CSP 总是更倾向于更加严格的模式
80+
// 覆盖原有的响应头, 但扩展的 CSP 总是更倾向于更加严格的模式
8081
// 实际测试中仅有完全抹除标头时, 才可以解决冲突的问题
8182
res.responseHeaders[i].value = target.join(";");
83+
// 如果存在 nonce 的配置, 则尝试注入 Inject Script
84+
const nonce = /'nonce-([-+/=\w]+)'/.exec(value);
85+
if (nonce && nonce[1]) {
86+
const nonceId = nonce[1];
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+
};`;
96+
const onUpdate = (_: number, changeInfo: chrome.tabs.TabChangeInfo) => {
97+
if (changeInfo.status !== "loading") return void 0;
98+
// https://developer.mozilla.org/zh-CN/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript
99+
cross.tabs
100+
.executeScript(res.tabId, {
101+
allFrames: true,
102+
code: code,
103+
runAt: "document_start",
104+
})
105+
.catch(err => {
106+
if (__DEV__) logger.warning("Inject Script", err);
107+
});
108+
cross.tabs.onUpdated.removeListener(onUpdate);
109+
};
110+
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/onUpdated
111+
// @ts-expect-error filter params
112+
cross.tabs.onUpdated.addListener(onUpdate, { tabId: res.tabId });
113+
}
82114
}
115+
// 返回修改后的响应头配置
83116
return {
84117
responseHeaders: res.responseHeaders,
85118
};

pnpm-lock.yaml

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)