Project

General

Profile

« Previous | Next » 

Revision 44e89d8e

Added by koszko almost 2 years ago

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.

View differences:

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