diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/misc.js | 97 |
1 files changed, 54 insertions, 43 deletions
diff --git a/common/misc.js b/common/misc.js index 472620e..8cb26ab 100644 --- a/common/misc.js +++ b/common/misc.js @@ -27,6 +27,23 @@ function gen_nonce() * generating unique, per-site value that can be computed synchronously * and is impossible to guess for a malicious website */ + +/* Uint8toHex is a separate function not exported as (a) it's useful and (b) it will be used in crypto.subtle-based digests */ +function Uint8toHex(data) +{ + let returnValue = ''; + for (let byte of data) + returnValue += ('00' + byte.toString(16)).slice(-2); + return returnValue; +} + +function gen_nonce(length) // Default 16 +{ + let randomData = new Uint8Array(length || 16); + crypto.getRandomValues(randomData); + return Uint8toHex(randomData); +} + function gen_unique(url) { return sha256(get_secure_salt() + url); @@ -52,24 +69,51 @@ function url_item(url) } /* - * Assume a url like: https://example.com/green?illuminati=confirmed#tinky#winky + * Assume a url like: + * https://example.com/green?illuminati=confirmed#<injected-policy>#winky * This function will make it into an object like: * { - * "base_url" : "https://example.com/green?illuminati=confirmed", - * "target" : "#tinky", - * "target2" : "#winky" + * "base_url": "https://example.com/green?illuminati=confirmed", + * "target": "#<injected-policy>", + * "target2": "#winky", + * "policy": <injected-policy-as-js-object>, + * "current": <boolean-indicating-whether-policy-url-matches> * } * In case url doesn't have 2 #'s, target2 and target can be set to undefined. */ function url_extract_target(url) { - let url_re = /^([^#]*)((#[^#]*)(#.*)?)?$/; - let match = url_re.exec(url); - return { - base_url : match[1], - target : match[3], - target2 : match[4] + const url_re = /^([^#]*)((#[^#]*)(#.*)?)?$/; + const match = url_re.exec(url); + const targets = { + base_url: match[1], + target: match[3] || "", + target2: match[4] || "" }; + if (!targets.target) + return targets; + + /* %7B -> { */ + const index = targets.target.indexOf('%7B'); + if (index === -1) + return targets; + + const now = new Date(); + const sig = targets.target.substring(1, index); + const policy = targets.target.substring(index); + if (sig !== sign_policy(policy, now) && + sig !== sign_policy(policy, now, -1)) + return targets; + + try { + targets.policy = JSON.parse(decodeURIComponent(policy)); + targets.current = targets.policy.base_url === targets.base_url; + } catch (e) { + /* This should not be reached - it's our self-produced valid JSON. */ + console.log("Unexpected internal error - invalid JSON smuggled!", e); + } + + return targets; } /* csp rule that blocks all scripts except for those injected by us */ @@ -110,45 +154,12 @@ function sign_policy(policy, now, hours_offset) { return gen_unique(time + policy); } -/* Extract any policy present in the URL */ -function url_extract_policy(url) -{ - const targets = url_extract_target(url); - if (!targets.target) - return targets; - - /* %7B -> { */ - const index = targets.target.indexOf('%7B'); - if (index === -1) - return targets; - - const now = new Date(); - const sig = targets.target.substring(1, index); - const policy = targets.target.substring(index); - if ( - sig !== sign_policy(policy, now) && - sig !== sign_policy(policy, now, -1) && - sig !== sign_policy(policy, now, 1) - ) - return targets; - - try { - targets.policy = JSON.parse(decodeURIComponent(policy)); - targets.current = targets.policy.base_url === targets.base_url; - } catch (e) { - /* TODO what should happen here? */ - } - - return targets; -} - /* * EXPORTS_START * EXPORT gen_nonce * EXPORT gen_unique * EXPORT url_item * EXPORT url_extract_target - * EXPORT url_extract_policy * EXPORT sign_policy * EXPORT csp_rule * EXPORT nice_name |