diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/entities.js | 18 | ||||
-rw-r--r-- | common/indexeddb.js | 27 | ||||
-rw-r--r-- | common/misc.js | 31 |
3 files changed, 49 insertions, 27 deletions
diff --git a/common/entities.js b/common/entities.js index 60a7e2d..b70661f 100644 --- a/common/entities.js +++ b/common/entities.js @@ -54,6 +54,24 @@ const parse_version = ver_str => ver_str.split(".").map(n => parseInt(n)); * No version normalization is performed. */ const version_string = (ver, rev=0) => ver.join(".") + (rev ? `-${rev}` : ""); +#EXPORT version_string + +/* + * This function overloads on the number of arguments. If one argument is + * passed, it is an item definition (it need not be complete, only identifier, + * version and, if applicable, revision properties are relevant). If two or + * three arguments are given, they are in order: item identifier, item version + * and item revision. + * Returned is a string identifying this version of item. + */ +function item_id_string(...args) { + let def = args[0] + if (args.length > 1) + def = {identifier: args[0], version: args[1], revision: args[2]}; + return !Array.isArray(def.version) ? def.identifier : + `${def.identifier}-${version_string(def.version, def.revision)}`; +} +#EXPORT item_id_string /* vers should be an array of comparable values. Return the greatest one. */ const max = vals => Array.reduce(vals, (v1, v2) => v1 > v2 ? v1 : v2); diff --git a/common/indexeddb.js b/common/indexeddb.js index a18c9be..1b8e574 100644 --- a/common/indexeddb.js +++ b/common/indexeddb.js @@ -61,8 +61,8 @@ const version_nr = ver => Array.reduce(ver.slice(0, 3), nr_reductor, [2, 0])[1]; const stores = [ ["files", {keyPath: "hash_key"}], ["file_uses", {keyPath: "hash_key"}], - ["resources", {keyPath: "identifier"}], - ["mappings", {keyPath: "identifier"}], + ["resource", {keyPath: "identifier"}], + ["mapping", {keyPath: "identifier"}], ["settings", {keyPath: "name"}], ["blocking", {keyPath: "pattern"}], ["repos", {keyPath: "url"}] @@ -175,8 +175,8 @@ function make_context(transaction, files) } /* - * item_store_names should be an array with either string "mappings", string - * "resources" or both. files should be a dict with values being contents of + * item_store_names should be an array with either string "mapping", string + * "resource" or both. files should be an object with values being contents of * files that are to be possibly saved in this transaction and keys of the form * `sha256-<file's-sha256-sum>`. * @@ -292,7 +292,7 @@ async function finalize_transaction(context) */ async function save_items(data) { - const item_store_names = ["resources", "mappings"]; + const item_store_names = ["resource", "mapping"]; const context = await start_items_transaction(item_store_names, data.files); return _save_items(data.resources, data.mappings, context); @@ -323,15 +323,13 @@ async function _save_items(resources, mappings, context) */ async function save_item(item, context) { - const store_name = {resource: "resources", mapping: "mappings"}[item.type]; - for (const file_ref of entities.get_files(item)) await incr_file_uses(context, file_ref); - broadcast.prepare(context.sender, `idb_changes_${store_name}`, + broadcast.prepare(context.sender, `idb_changes_${item.type}`, item.identifier); - await _remove_item(store_name, item.identifier, context, false); - await idb_put(context.transaction, store_name, item); + await _remove_item(item.type, item.identifier, context, false); + await idb_put(context.transaction, item.type, item); } #EXPORT save_item @@ -360,10 +358,10 @@ async function remove_item(store_name, identifier, context) await idb_del(context.transaction, store_name, identifier); } -const remove_resource = (id, ctx) => remove_item("resources", id, ctx); +const remove_resource = (id, ctx) => remove_item("resource", id, ctx); #EXPORT remove_resource -const remove_mapping = (id, ctx) => remove_item("mappings", id, ctx); +const remove_mapping = (id, ctx) => remove_item("mapping", id, ctx); #EXPORT remove_mapping /* Function to retrieve all items from a given store. */ @@ -460,7 +458,8 @@ async function track_change(tracking, key) /* * Monitor changes to `store_name` IndexedDB object store. * - * `store_name` should be either "resources", "mappings" or "settings". + * `store_name` should be either "resource", "mapping", "settings", "blocking" + * or "repos". * * `onchange` should be a callback that will be called when an item is added, * modified or removed from the store. The callback will be passed an object @@ -491,7 +490,7 @@ async function start_tracking(store_name, onchange) } const track = {}; -const trackable = ["resources", "mappings", "settings", "blocking", "repos"]; +const trackable = ["resource", "mapping", "settings", "blocking", "repos"]; for (const store_name of trackable) track[store_name] = onchange => start_tracking(store_name, onchange); #EXPORT track diff --git a/common/misc.js b/common/misc.js index ba14a33..ed8f400 100644 --- a/common/misc.js +++ b/common/misc.js @@ -45,25 +45,30 @@ #FROM common/browser.js IMPORT browser #FROM common/stored_types.js IMPORT TYPE_NAME, TYPE_PREFIX +/* uint8_to_hex is a separate function used in cryptographic functions. */ +const uint8_to_hex = + array => [...array].map(b => ("0" + b.toString(16)).slice(-2)).join(""); + /* - * generating unique, per-site value that can be computed synchronously - * and is impossible to guess for a malicious website + * Asynchronously compute hex string representation of a sha256 digest of a + * UTF-8 string. */ - -/* 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; +async function sha256_async(string) { + const input_ab = new TextEncoder("utf-8").encode(string); + const digest_ab = await crypto.subtle.digest("SHA-256", input_ab); + return uint8_to_hex(new Uint8Array(digest_ab)); } +#EXPORT sha256_async +/* + * Generate a unique value that can be computed synchronously and is impossible + * to guess for a malicious website. + */ function gen_nonce(length=16) { - let randomData = new Uint8Array(length); - crypto.getRandomValues(randomData); - return Uint8toHex(randomData); + const random_data = new Uint8Array(length); + crypto.getRandomValues(random_data); + return uint8_to_hex(random_data); } #EXPORT gen_nonce |