diff options
Diffstat (limited to 'background/policy_injector.js')
-rw-r--r-- | background/policy_injector.js | 149 |
1 files changed, 54 insertions, 95 deletions
diff --git a/background/policy_injector.js b/background/policy_injector.js index f58fb71..9725e99 100644 --- a/background/policy_injector.js +++ b/background/policy_injector.js @@ -16,36 +16,32 @@ * IMPORT gen_unique * IMPORT gen_nonce * IMPORT is_privileged_url + * IMPORT url_item * IMPORT url_extract_target * IMPORT sign_policy - * IMPORT get_query_best - * IMPORT parse_csp + * IMPORT query_best + * IMPORT sanitize_csp_header * IMPORTS_END */ var storage; -var query_best; - -const csp_header_names = { - "content-security-policy" : true, - "x-webkit-csp" : true, - "x-content-security-policy" : true -}; - -const unwanted_csp_directives = { - "report-to" : true, - "report-uri" : true, - "script-src" : true, - "script-src-elem" : true, - "prefetch-src": true -}; -const report_only = "content-security-policy-report-only"; +const csp_header_names = new Set([ + "content-security-policy", + "x-webkit-csp", + "x-content-security-policy" +]); + +/* TODO: variable no longer in use; remove if not needed */ +const unwanted_csp_directives = new Set([ + "report-to", + "report-uri", + "script-src", + "script-src-elem", + "prefetch-src" +]); -function not_csp_header(header) -{ - return !csp_header_names[header.name.toLowerCase()]; -} +const report_only = "content-security-policy-report-only"; function url_inject(details) { @@ -60,7 +56,7 @@ function url_inject(details) if (targets.policy) targets.target = ""; - let [pattern, settings] = query_best(targets.base_url); + let [pattern, settings] = query_best(storage, targets.base_url); /* Defaults */ if (!pattern) settings = {}; @@ -83,38 +79,6 @@ function url_inject(details) }; } -function process_csp_header(header, rule, block) -{ - const csp = parse_csp(header.value); - - /* No snitching */ - delete csp['report-to']; - delete csp['report-uri']; - - if (block) { - delete csp['script-src']; - delete csp['script-src-elem']; - csp['script-src-attr'] = ["'none'"]; - csp['prefetch-src'] = ["'none'"]; - } - - if ('script-src' in csp) - csp['script-src'].push(rule); - else - csp['script-src'] = [rule]; - - if ('script-src-elem' in csp) - csp['script-src-elem'].push(rule); - else - csp['script-src-elem'] = [rule]; - - const new_policy = Object.entries(csp).map( - i => i[0] + ' ' + i[1].join(' ') + ';' - ); - - return {name: header.name, value: new_policy.join('')} -} - function headers_inject(details) { const targets = url_extract_target(details.url); @@ -128,48 +92,44 @@ function headers_inject(details) const rule = `'nonce-${targets.policy.nonce}'`; const block = !targets.policy.allow; - - for (let header of details.responseHeaders) { - if (not_csp_header(header)) { - /* Retain all non-snitching headers */ - if (header.name.toLowerCase() !== report_only) { - headers.push(header); - - /* If these are the original CSP headers, use them instead */ - /* Test based on url_extract_target() in misc.js */ - if (is_mozilla && header.name === "x-orig-csp") { - let index = header.value.indexOf('%5B'); - if (index === -1) - continue; - - let sig = header.value.substring(0, index); - let data = header.value.substring(index); - if (sig !== sign_policy(data, 0)) - continue; - - /* Confirmed- it's the originals, smuggled in! */ - try { - data = JSON.parse(decodeURIComponent(data)); - } catch (e) { - /* This should not be reached - - it's our self-produced valid JSON. */ - console.log("Unexpected internal error - invalid JSON smuggled!", e); - } - - orig_csp_headers = csp_headers = null; - for (let header of data) - headers.push(process_csp_header(header, rule, block)); + + for (const header of details.responseHeaders) { + if (!csp_header_names.has(header)) { + /* Remove headers that only snitch on us */ + if (header.name.toLowerCase() === report_only && block) + continue; + headers.push(header); + + /* If these are the original CSP headers, use them instead */ + /* Test based on url_extract_target() in misc.js */ + if (is_mozilla && header.name === "x-orig-csp") { + let index = header.value.indexOf('%5B'); + if (index === -1) + continue; + + let sig = header.value.substring(0, index); + let data = header.value.substring(index); + if (sig !== sign_policy(data, 0)) + continue; + + /* Confirmed- it's the originals, smuggled in! */ + try { + data = JSON.parse(decodeURIComponent(data)); + } catch (e) { + /* This should not be reached - + it's our self-produced valid JSON. */ + console.log("Unexpected internal error - invalid JSON smuggled!", e); } - } - continue; + orig_csp_headers = csp_headers = null; + for (const header of data) + headers.push(sanitize_csp_header(header, rule, block)); + } + } else if (is_chrome || !orig_csp_headers) { + csp_headers.push(sanitize_csp_header(header, rule, block)); + if (is_mozilla) + orig_csp_headers.push(header); } - if (is_mozilla && !orig_csp_headers) - continue; - - csp_headers.push(process_csp_header(header, rule, block)); - if (is_mozilla) - orig_csp_headers.push(header); } if (orig_csp_headers) { @@ -202,7 +162,6 @@ function headers_inject(details) async function start_policy_injector() { storage = await get_storage(); - query_best = await get_query_best(); let extra_opts = ["blocking", "responseHeaders"]; if (is_chrome) |