Revision 44e89d8e
Added by koszko almost 2 years ago
| content/main.js | ||
|---|---|---|
| 16 | 16 |
* IMPORT is_chrome |
| 17 | 17 |
* IMPORT is_mozilla |
| 18 | 18 |
* IMPORT start_activity_info_server |
| 19 |
* IMPORT csp_rule |
|
| 20 |
* IMPORT is_csp_header_name |
|
| 21 |
* IMPORT sanitize_csp_header |
|
| 19 |
* IMPORT make_csp_rule |
|
| 20 |
* IMPORT csp_header_regex |
|
| 22 | 21 |
* IMPORTS_END |
| 23 | 22 |
*/ |
| 24 | 23 |
|
| ... | ... | |
| 172 | 171 |
const name = construct_name.join("");
|
| 173 | 172 |
seta(node, `${blocked_str}-${name}`, geta(node, name));
|
| 174 | 173 |
} |
| 175 |
} |
|
| 176 |
|
|
| 177 |
function sanitize_meta(meta, policy) |
|
| 178 |
{
|
|
| 179 |
const value = meta.content || ""; |
|
| 180 | 174 |
|
| 181 |
if (!value || !is_csp_header_name(meta.httpEquiv || "", true)) |
|
| 182 |
return; |
|
| 183 |
|
|
| 184 |
block_attribute(meta, "content"); |
|
| 175 |
rema(node, attr); |
|
| 185 | 176 |
} |
| 186 | 177 |
|
| 187 | 178 |
/* |
| 188 |
* Used to disable <script> that has not yet been added to live DOM (doesn't
|
|
| 189 |
* work for those already added). |
|
| 179 |
* Used to disable `<script>'s and `<meta>'s that have not yet been added to
|
|
| 180 |
* live DOM (doesn't work for those already added).
|
|
| 190 | 181 |
*/ |
| 182 |
function sanitize_meta(meta) |
|
| 183 |
{
|
|
| 184 |
if (csp_header_regex.test(meta.httpEquiv) && meta.content) |
|
| 185 |
block_attribute(meta, "content"); |
|
| 186 |
} |
|
| 187 |
|
|
| 191 | 188 |
function sanitize_script(script) |
| 192 | 189 |
{
|
| 193 | 190 |
script.hachette_blocked_type = script.getAttribute("type");
|
| ... | ... | |
| 195 | 192 |
} |
| 196 | 193 |
|
| 197 | 194 |
/* |
| 198 |
* Executed after script has been connected to the DOM, when it is no longer
|
|
| 199 |
* eligible for being executed by the browser |
|
| 195 |
* Executed after `<script>' has been connected to the DOM, when it is no longer
|
|
| 196 |
* eligible for being executed by the browser.
|
|
| 200 | 197 |
*/ |
| 201 |
function desanitize_script(script, policy)
|
|
| 198 |
function desanitize_script(script) |
|
| 202 | 199 |
{
|
| 203 | 200 |
script.setAttribute("type", script.hachette_blocked_type);
|
| 204 | 201 |
|
| 205 |
if (script.hachette_blocked_type === null)
|
|
| 202 |
if ([null, undefined].includes(script.hachette_blocked_type))
|
|
| 206 | 203 |
script.removeAttribute("type");
|
| 207 | 204 |
|
| 208 | 205 |
delete script.hachette_blocked_type; |
| ... | ... | |
| 233 | 230 |
* cause part of the DOM to be loaded when our content scripts get to run. Thus, |
| 234 | 231 |
* before the CSP rules we inject (for non-HTTP pages) become effective, we need |
| 235 | 232 |
* to somehow block the execution of `<script>'s and intrinsics that were |
| 236 |
* already there. |
|
| 233 |
* already there. Additionally, some browsers (IceCat 60) seem to have problems |
|
| 234 |
* applying this CSP to non-inline `<scripts>' in certain scenarios. |
|
| 237 | 235 |
*/ |
| 236 |
function prevent_script_execution(event) |
|
| 237 |
{
|
|
| 238 |
if (!event.target._hachette_payload) |
|
| 239 |
event.preventDefault(); |
|
| 240 |
} |
|
| 241 |
|
|
| 238 | 242 |
function mozilla_initial_block(doc) |
| 239 | 243 |
{
|
| 240 |
const blocker = e => e.preventDefault(); |
|
| 241 |
doc.addEventListener("beforescriptexecute", blocker);
|
|
| 242 |
setTimeout(() => doc.removeEventListener("beforescriptexecute", blocker));
|
|
| 244 |
doc.addEventListener("beforescriptexecute", prevent_script_execution);
|
|
| 243 | 245 |
|
| 244 | 246 |
[...doc.all].flatMap(ele => [...ele.attributes].map(attr => [ele, attr])) |
| 245 | 247 |
.map(([ele, attr]) => [ele, attr.localName]) |
| ... | ... | |
| 273 | 275 |
* non-HTML documents. |
| 274 | 276 |
*/ |
| 275 | 277 |
const html = new DOMParser().parseFromString(`<html><head><meta \ |
| 276 |
http-equiv="Content-Security-Policy" content="${csp_rule(policy.nonce)}"\
|
|
| 278 |
http-equiv="Content-Security-Policy" content="${make_csp_rule(policy)}"\
|
|
| 277 | 279 |
/></head><body>Loading...</body></html>`, "text/html").documentElement; |
| 278 | 280 |
|
| 279 | 281 |
/* |
| ... | ... | |
| 284 | 286 |
root.replaceWith(html); |
| 285 | 287 |
|
| 286 | 288 |
/* |
| 287 |
* For XML documents, we don't intend to inject payload, so we neither block
|
|
| 288 |
* document's CSP `<meta>' tags nor wait for `<head>' to be parsed.
|
|
| 289 |
* When we don't inject payload, we neither block document's CSP `<meta>'
|
|
| 290 |
* tags nor wait for `<head>' to be parsed. |
|
| 289 | 291 |
*/ |
| 290 |
if (document instanceof HTMLDocument) {
|
|
| 292 |
if (policy.has_payload) {
|
|
| 291 | 293 |
await wait_for_head(doc, root); |
| 292 | 294 |
|
| 293 | 295 |
root.querySelectorAll("head meta")
|
| ... | ... | |
| 333 | 335 |
policy = {allow: false, nonce: gen_nonce()};
|
| 334 | 336 |
} |
| 335 | 337 |
|
| 338 |
if (!(document instanceof HTMLDocument)) |
|
| 339 |
policy.has_payload = false; |
|
| 340 |
|
|
| 336 | 341 |
console.debug("current policy", policy);
|
| 337 | 342 |
|
| 338 | 343 |
const doc_ready = Promise.all([ |
Also available in: Unified diff
simplify CSP handling
All page's CSP rules are now removed when a payload is to be injected. When there is no payload, CSP rules are not modified but only supplemented with Hachette's own.