Revision d09b7ee1
Added by koszko about 2 years ago
content/main.js | ||
---|---|---|
11 | 11 |
* IMPORT handle_page_actions |
12 | 12 |
* IMPORT extract_signed |
13 | 13 |
* IMPORT gen_nonce |
14 |
* IMPORT csp_rule |
|
15 | 14 |
* IMPORT is_privileged_url |
16 |
* IMPORT sanitize_attributes |
|
17 | 15 |
* IMPORT mozilla_suppress_scripts |
18 | 16 |
* IMPORT is_chrome |
19 | 17 |
* IMPORT is_mozilla |
20 | 18 |
* IMPORT start_activity_info_server |
19 |
* IMPORT modify_on_the_fly |
|
21 | 20 |
* IMPORTS_END |
22 | 21 |
*/ |
23 | 22 |
|
24 |
/* |
|
25 |
* Due to some technical limitations the chosen method of whitelisting sites |
|
26 |
* is to smuggle whitelist indicator in page's url as a "magical" string |
|
27 |
* after '#'. Right now this is only supplemental in HTTP(s) pages where |
|
28 |
* blocking of native scripts also happens through CSP header injection but is |
|
29 |
* necessary for protocols like ftp:// and file://. |
|
30 |
* |
|
31 |
* The code that actually injects the magical string into ftp:// and file:// |
|
32 |
* urls has not yet been added to the extension. |
|
33 |
*/ |
|
34 |
|
|
35 |
var nonce = undefined; |
|
36 |
|
|
37 |
function handle_mutation(mutations, observer) |
|
38 |
{ |
|
39 |
if (document.readyState === 'complete') { |
|
40 |
console.log("mutation handling complete"); |
|
41 |
observer.disconnect(); |
|
42 |
return; |
|
43 |
} |
|
44 |
for (const mutation of mutations) { |
|
45 |
for (const node of mutation.addedNodes) |
|
46 |
block_node(node); |
|
47 |
} |
|
48 |
} |
|
49 |
|
|
50 |
function block_nodes_recursively(node) |
|
51 |
{ |
|
52 |
block_node(node); |
|
53 |
for (const child of node.children) |
|
54 |
block_nodes_recursively(child); |
|
55 |
} |
|
56 |
|
|
57 |
function block_node(node) |
|
23 |
function accept_node(node, parent) |
|
58 | 24 |
{ |
25 |
const clone = document.importNode(node, false); |
|
26 |
node.hachette_corresponding = clone; |
|
59 | 27 |
/* |
60 |
* Modifying <script> element doesn't always prevent its execution in some
|
|
61 |
* Mozilla browsers. This is Chromium-specific code.
|
|
28 |
* TODO: Stop page's own issues like "Error parsing a meta element's
|
|
29 |
* content:" from appearing as extension's errors.
|
|
62 | 30 |
*/ |
63 |
if (node.tagName === "SCRIPT") { |
|
64 |
block_script(node); |
|
65 |
return; |
|
66 |
} |
|
67 |
|
|
68 |
sanitize_attributes(node); |
|
69 |
|
|
70 |
if (node.tagName === "HEAD") |
|
71 |
inject_csp(node); |
|
72 |
} |
|
73 |
|
|
74 |
function block_script(node) |
|
75 |
{ |
|
76 |
/* |
|
77 |
* Disabling scripts this way allows them to still be relatively |
|
78 |
* easily accessed in case they contain some useful data. |
|
79 |
*/ |
|
80 |
if (node.hasAttribute("type")) |
|
81 |
node.setAttribute("blocked-type", node.getAttribute("type")); |
|
82 |
node.setAttribute("type", "application/json"); |
|
83 |
} |
|
84 |
|
|
85 |
function inject_csp(head) |
|
86 |
{ |
|
87 |
let meta = document.createElement("meta"); |
|
88 |
meta.setAttribute("http-equiv", "Content-Security-Policy"); |
|
89 |
meta.setAttribute("content", csp_rule(nonce)); |
|
90 |
|
|
91 |
if (head.firstElementChild === null) |
|
92 |
head.appendChild(meta); |
|
93 |
else |
|
94 |
head.insertBefore(meta, head.firstElementChild); |
|
31 |
parent.hachette_corresponding.appendChild(clone); |
|
95 | 32 |
} |
96 | 33 |
|
97 | 34 |
if (!is_privileged_url(document.URL)) { |
... | ... | |
110 | 47 |
|
111 | 48 |
handle_page_actions(policy.nonce); |
112 | 49 |
|
113 |
if (!policy.allow) {
|
|
114 |
block_nodes_recursively(document.documentElement);
|
|
50 |
if (!policy.allow && is_mozilla)
|
|
51 |
addEventListener('beforescriptexecute', mozilla_suppress_scripts, true);
|
|
115 | 52 |
|
116 |
if (is_chrome) { |
|
117 |
var observer = new MutationObserver(handle_mutation); |
|
118 |
observer.observe(document.documentElement, { |
|
119 |
attributes: true, |
|
120 |
childList: true, |
|
121 |
subtree: true |
|
122 |
}); |
|
123 |
} |
|
53 |
if (!policy.allow && is_chrome) { |
|
54 |
const old_html = document.documentElement; |
|
55 |
const new_html = document.createElement("html"); |
|
56 |
old_html.replaceWith(new_html); |
|
57 |
old_html.hachette_corresponding = new_html; |
|
124 | 58 |
|
125 |
if (is_mozilla) |
|
126 |
addEventListener('beforescriptexecute', mozilla_suppress_scripts, true); |
|
59 |
const modify_end = |
|
60 |
modify_on_the_fly(old_html, policy, {node_eater: accept_node}); |
|
61 |
document.addEventListener("DOMContentLoaded", modify_end); |
|
127 | 62 |
} |
128 | 63 |
|
129 | 64 |
start_activity_info_server(); |
Also available in: Unified diff
sanitize `' tags containing CSP rules under Chromium
This commit adds a mechanism of hijacking document when it loads and injecting sanitized nodes to the DOM from the level of content script.