aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/entities.js22
-rw-r--r--common/jsonschema.js28
-rw-r--r--common/misc.js27
-rw-r--r--common/policy.js43
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