diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/entities.js | 22 | ||||
-rw-r--r-- | common/jsonschema.js | 28 | ||||
-rw-r--r-- | common/misc.js | 27 | ||||
-rw-r--r-- | common/policy.js | 43 |
4 files changed, 99 insertions, 21 deletions
diff --git a/common/entities.js b/common/entities.js index 74cad20..41d6e3b 100644 --- a/common/entities.js +++ b/common/entities.js @@ -116,6 +116,28 @@ function* get_used_files(item) } #EXPORT get_used_files AS get_files +/* + * Regex to parse URIs like: + * https://hydrilla.koszko.org/schemas/api_mapping_description-2.schema.json + */ +const name_base_re = "(?<name_base>[^/]*)"; +const major_number_re = "(?<major>[1-9][0-9]*)"; +const minor_number_re = "(?:[1-9][0-9]*|0)"; +const numbers_rest_re = `(?:\\.${minor_number_re})*`; +const version_re = `(?<ver>${major_number_re}${numbers_rest_re})`; +const schema_name_re = `${name_base_re}-${version_re}\\.schema\\.json`; + +const haketilo_schema_name_regex = new RegExp(schema_name_re); +#EXPORT haketilo_schema_name_regex + +/* Extract the number that indicates entity's compatibility mode. */ +function get_schema_major_version(instance) { + const match = haketilo_schema_name_regex.exec(instance.$schema); + + return parseInt(match.groups.major); +} +#EXPORT get_schema_major_version + #IF NEVER /* diff --git a/common/jsonschema.js b/common/jsonschema.js index cde3fca..9c4a70c 100644 --- a/common/jsonschema.js +++ b/common/jsonschema.js @@ -57,6 +57,8 @@ #FROM common/jsonschema/scan.js IMPORT SchemaScanResult, scan +#FROM common/entities.js IMPORT haketilo_schema_name_regex + #EXPORT scan #EXPORT SchemaScanResult @@ -67,14 +69,32 @@ function validate(instance, schema, options) { #EXPORT validate const haketilo_schemas = [ -#INCLUDE schemas/api_query_result-1.0.1.schema.json + /* 1.x Hydrilla JSON schema series */ +#INCLUDE schemas/1.x/api_query_result-1.0.1.schema.json + , +#INCLUDE schemas/1.x/api_mapping_description-1.0.1.schema.json + , +#INCLUDE schemas/1.x/api_resource_description-1.0.1.schema.json + , +#INCLUDE schemas/1.x/common_definitions-1.0.1.schema.json , -#INCLUDE schemas/api_mapping_description-1.0.1.schema.json + /* 2.x Hydrilla JSON schema series */ +#INCLUDE schemas/2.x/api_query_result-2.schema.json , -#INCLUDE schemas/api_resource_description-1.0.1.schema.json +#INCLUDE schemas/2.x/api_mapping_description-2.schema.json , -#INCLUDE schemas/common_definitions-1.0.1.schema.json +#INCLUDE schemas/2.x/api_resource_description-2.schema.json + , +#INCLUDE schemas/2.x/common_definitions-2.schema.json ].reduce((ac, s) => Object.assign(ac, {[s.$id]: s}), {}); + +for (const [$id, schema] of [...Object.entries(haketilo_schemas)]) { + const match = haketilo_schema_name_regex.exec($id); + const schema_name = + `${match.groups.name_base}-${match.groups.major}.schema.json`; + haketilo_schemas[schema_name] = schema; +} + #EXPORT haketilo_schemas const haketilo_validator = new Validator(); diff --git a/common/misc.js b/common/misc.js index e609fe0..8096f27 100644 --- a/common/misc.js +++ b/common/misc.js @@ -42,9 +42,13 @@ * proprietary program, I am not going to enforce this in court. */ -/* uint8_to_hex is a separate function used in cryptographic functions. */ +/* + * uint8_to_hex is a separate function used in cryptographic functions and when + * dealing with binary data. + */ const uint8_to_hex = array => [...array].map(b => ("0" + b.toString(16)).slice(-2)).join(""); +#EXPORT uint8_to_hex /* * Asynchronously compute hex string representation of a sha256 digest of a @@ -61,8 +65,7 @@ async function sha256_async(string) { * Generate a unique value that can be computed synchronously and is impossible * to guess for a malicious website. */ -function gen_nonce(length=16) -{ +function gen_nonce(length=16) { const random_data = new Uint8Array(length); crypto.getRandomValues(random_data); return uint8_to_hex(random_data); @@ -71,16 +74,10 @@ function gen_nonce(length=16) /* Check if some HTTP header might define CSP rules. */ const csp_header_regex = - /^\s*(content-security-policy|x-webkit-csp|x-content-security-policy)/i; + /^\s*(content-security-policy|x-webkit-csp|x-content-security-policy)\s*$/i; #EXPORT csp_header_regex /* - * Print item together with type, e.g. - * nice_name("s", "hello") → "hello (script)" - */ -#EXPORT (prefix, name) => `${name} (${TYPE_NAME[prefix]})` AS nice_name - -/* * Check if url corresponds to a browser's special page (or a directory index in * case of `file://' protocol). */ @@ -90,3 +87,13 @@ const priv_reg = /^moz-extension:\/\/|^about:|^view-source:|^file:\/\/[^?#]*\/([ const priv_reg = /^chrome(-extension)?:\/\/|^about:|^view-source:|^file:\/\/[^?#]*\/([?#]|$)/; #ENDIF #EXPORT url => priv_reg.test(url) AS is_privileged_url + +/* Make it possible to serialize en Error object. */ +function error_data_jsonifiable(error) { + const jsonifiable = {}; + for (const property of ["name", "message", "fileName", "lineNumber"]) + jsonifiable[property] = error[property]; + + return jsonifiable; +} +#EXPORT error_data_jsonifiable diff --git a/common/policy.js b/common/policy.js index e14d8cd..6bcb54b 100644 --- a/common/policy.js +++ b/common/policy.js @@ -49,16 +49,15 @@ * CSP rule that either blocks all scripts or only allows scripts with specified * nonce attached. */ -function make_csp(nonce) -{ - const rule = nonce ? `nonce-${nonce}` : "none"; +function make_csp(nonce) { + const rule = nonce ? `'nonce-${nonce}'` : "'none'"; const csp_list = [ - ["prefetch-src", "none"], - ["script-src-attr", "none"], - ["script-src", rule], + ["prefetch-src", "'none'"], + ["script-src-attr", "'none'"], + ["script-src", rule, "'unsafe-eval'"], ["script-src-elem", rule] ]; - return csp_list.map(([a, b]) => `${a} '${b}';`).join(" "); + return csp_list.map(words => `${words.join(" ")};`).join(" "); } function decide_policy(patterns_tree, url, default_allow, secret) @@ -113,3 +112,33 @@ function decide_policy(patterns_tree, url, default_allow, secret) #EXPORT decide_policy #EXPORT () => ({allow: false, csp: make_csp()}) AS fallback_policy + +#IF NEVER + +/* + * Note: the functions below were overeagerly written and are not used now but + * might prove useful to once we add more functionalities and are hence kept... + */ + +function relaxed_csp_eval(csp) { + const new_csp_list = []; + + for (const directive of csp.split(";")) { + const directive_words = directive.trim().split(" "); + if (directive_words[0] === "script-src") + directive_words.push("'unsafe-eval'"); + + new_csp_list.push(directive_words); + } + + new_policy.csp = new_csp_list.map(d => `${d.join(" ")}';`).join(" "); +} + +function relax_policy_eval(policy) { + const new_policy = Object.assign({}, policy); + + return Object.assign(new_policy, {csp: relaxed_csp_eval(policy.csp)}); +} +#EXPORT relax_policy_eval + +#ENDIF |