diff options
Diffstat (limited to 'background')
-rw-r--r-- | background/main.js | 262 | ||||
-rw-r--r-- | background/message_server.js | 41 | ||||
-rw-r--r-- | background/page_actions_server.js | 264 | ||||
-rw-r--r-- | background/policy_injector.js | 114 | ||||
-rw-r--r-- | background/settings_query.js | 204 | ||||
-rw-r--r-- | background/storage.js | 654 | ||||
-rw-r--r-- | background/storage_server.js | 95 |
7 files changed, 834 insertions, 800 deletions
diff --git a/background/main.js b/background/main.js index ca56e37..aec25b6 100644 --- a/background/main.js +++ b/background/main.js @@ -5,127 +5,128 @@ * Redistribution terms are gathered in the `copyright' file. */ -"use strict"; - -(() => { - const TYPE_PREFIX = window.TYPE_PREFIX; - const get_storage = window.get_storage; - const start_storage_server = window.start_storage_server; - const start_page_actions_server = window.start_page_actions_server; - const start_policy_injector = window.start_policy_injector; - const browser = window.browser; - - start_storage_server(); - start_page_actions_server(); - start_policy_injector(); - - async function init_myext(install_details) - { - console.log("details:", install_details); - if (install_details.reason != "install") - return; - - let storage = await get_storage(); - - await storage.clear(); - - /* - * Below we add sample settings to the extension. - * Those should be considered example values for viewing in the options - * page. They won't make my.fsf.org work. The only scripts that does - * something useful right now is the opencores one. - */ - - let components = []; - for (let script_data of [ - {url: "http://127.0.0.1:8000/myfsf_define_CRM.js", - hash:"bf0cc81c7e8d5f800877b4bc3f14639f946f5ac6d4dc120255ffac5eba5e48fe"}, - {url: "https://my.fsf.org/misc/jquery.js?v=1.4.4", - hash:"261ae472fa0cbf27c80c9200a1599a60fde581a0e652eee4bf41def8cb61f2d0"}, - {url: "https://my.fsf.org/misc/jquery-extend-3.4.0.js?v=1.4.4", - hash:"c54103ba57ee210ca55c052e70415402707548a4e6a68dd6efb3895019bee392"}, - {url: "https://my.fsf.org/misc/jquery-html-prefilter-3.5.0-backport.js?v=1.4.4", - hash:"fad84efa145fb507e5df9b582fa01b1c4e6313de7f72ebdd55726d92fa4dbf06"}, - {url: "https://my.fsf.org/misc/jquery.once.js?v=1.2", - hash:"1430f42c0d760ba8e05bb3762480502e541f654fec5739ee40625ab22dc38c4f"}, - {url: "https://my.fsf.org/misc/drupal.js?qmaukd", - hash:"2e08dccbd4d8b728a6871562995a4636b89bfe0ed3b8fb0138191c922228b116"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/jquery/dist/jquery.min.js?qmaukd", - hash:"a6d01520d28d15dbe476de84eea90eb3ee2d058722efc062ec73cb5fad78a17b"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/jquery-ui/jquery-ui.min.js?qmaukd", - hash:"28ce75d953678c4942df47a11707a15e3c756021cf89090e3e6aa7ad6b6971c3"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/lodash-compat/lodash.min.js?qmaukd", - hash:"f2871cc80c52fe8c04c582c4a49797c9c8fd80391cf1452e47f7fe97835ed5cc"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/packages/jquery/plugins/jquery.mousewheel.min.js?qmaukd", - hash:"f50233e84c2ac7ada37a094d3f7d3b3f7c97716d6b7b47bf69619d93ee4ac1ce"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/select2/select2.min.js?qmaukd", - hash:"ce61298fb9aa4ec49ccd4172d097e36a9e5db3af06a7b82796659368f15b7c1b"}, - {url: "https://my.fsf.org/sites/all/modules/civi crm/packages/jquery/plugins/jquery.form.min.js?qmaukd", - hash:"c90f0e501d2948fbc2b61bffd654fa4ab64741fd48923782419eeb14d3816fb8"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/packages/jquery/plugins/jquery.timeentry.min.js?qmaukd", - hash:"8e85df981e8ad7049d06dfb075277d038734d36a7097c7f021021b2bdccfe9bb"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/packages/jquery/plugins/jquery.blockUI.min.js?qmaukd", - hash:"806aedff52ac822f2adc5797073e1e5c5cec32eb9f15f2319cb32a347dcd232b"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/datatables/media/js/jquery.dataTables.min.js?qmaukd", - hash:"b796504d9b1b422f0dc6ccc2d740ac78a8c9e5078cc3934836d39742b1121925"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/jquery-validation/dist/jquery.validate.min.js?qmaukd", - hash:"f0f5373ad203101ea91bf826c5a7ef8f7cd74887f06bad2cb9277a504503b9e2"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/packages/jquery/plugins/jquery.ui.datepicker.validation.min.js?qmaukd", - hash:"c6e6f6bf7f8fff25cca338045774e267e8eaa2d48ac9100540f3d59a6d2b3c61"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/js/Common.js?qmaukd", - hash:"17aa222a3af2e8958be16accb5e77ef39f67009cb3b500718d8fffd45b399148"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/js/crm.datepicker.js?qmaukd", - hash:"9bd8d10208aa99c156325f7819da6f0dd62ba221ac4119c3ccd4834e2cf36535"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/js/crm.ajax.js?qmaukd", - hash:"6401a4e257b7499ae4a00be2c200e4504a2c9b3d6b278a830c31a7b63374f0fe"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/js/wysiwyg/crm.wysiwyg.js?qmaukd", - hash:"fa962356072a36672c3b4b25bdeb657f020995a067e20a29cd5bb84b05157762"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/js/noconflict.js?qmaukd", - hash:"58d6d9f496a235d23cf891926d71f2104e4f2afe1d14bb4e2b5233f646c35e62"}, - {url: "https://my.fsf.org/sites/all/modules/matomo/matomo.js?qmaukd", - hash:"7f39ccd085f348189cd2fb62ea4d4a658d96f6bba266265880b98605e777e2de"}, - {url: "https://my.fsf.org/sites/all/themes/fsf_venture/js/global.js?qmaukd", - hash:"aa7983f6b902f9f4415cfc8346e0c3f194cc95b78f52f2ad09ec7effa1326b9c"}, - {url: "https://my.fsf.org/sites/all/themes/fsf_venture/js/jquery.superfish.min.js?qmaukd", - hash:"5ef1f93bf3901227056bf9ed0ed93a148eec4dda30f419756b12bedd1098815e"}, - {url: "https://my.fsf.org/sites/all/themes/fsf_venture/js/jquery.sidr.min.js?qmaukd", - hash:"c4914d415826676c6af2e61f16edb72c5388f8600ba6de9049892aee49d980a0"}, - {url: "https://my.fsf.org/sites/all/themes/fsf_venture/js/jquery.flexslider.min.js?qmaukd", - hash:"cefaf715761b4494913851249b9d40dacb4a8cb61242b0efc859dc586d56e0d4"}, - {url: "http://127.0.0.1:8000/myfsf_crap.js", - hash:"d91ccf21592d0f861ea0ba946bc257fc5d88269327cad0a91387da6cb8ff633e"}, - {url: "https://my.fsf.org/sites/all/modules/civicrm/templates/CRM/Core/BillingBlock.js?r=lp7Di", - hash:"2f25d35e7a0c0060ab0a444a577f09dd3c9934ae898a7ee0eb20b6c986ab5a1c"}, - {url: "https://my.fsf.org/extensions/com.aghstrategies.giftmemberships/js/giftpricefield.js?r=lp7Di", - hash:"f86080e6bd306fe46474039aeca2808235005bce5a2a29416d08210022039a45"}, - {url: "https://my.fsf.org/extensions/com.ginkgostreet.negativenegator/js/negativenegator.js?r=lp7Di", - hash:"d0e87bac832856db70947d82a7ab4e0b7c8b1070d5f1a32335345e033ece3a14"} - ]) { - let name_regex = /\/([^/]+)\.js/; - let name = name_regex.exec(script_data.url)[1]; - await storage.set(TYPE_PREFIX.SCRIPT, name, script_data); - components.push([TYPE_PREFIX.SCRIPT, name]); - } - - await storage.set(TYPE_PREFIX.BAG, "myfsf_join", components); - - await storage.set(TYPE_PREFIX.PAGE, "https://my.fsf.org/join", { - components: [TYPE_PREFIX.BAG, "myfsf_join"] - }); - - let hello_script = { - text: "console.log(\"hello, every1!\");\n" - }; - await storage.set(TYPE_PREFIX.SCRIPT, "hello", hello_script); - await storage.set(TYPE_PREFIX.BAG, "hello", - [[TYPE_PREFIX.SCRIPT, "hello"]]); - await storage.set(TYPE_PREFIX.PAGE, "https://my.fsf.org/", { - components: [TYPE_PREFIX.BAG, "hello"], - allow: true - }); - - let opencores_script = { - text: `\ +/* + * IMPORTS_START + * IMPORT TYPE_PREFIX + * IMPORT get_storage + * IMPORT start_storage_server + * IMPORT start_page_actions_server + * IMPORT start_policy_injector + * IMPORT browser + * IMPORTS_END + */ + +start_storage_server(); +start_page_actions_server(); +start_policy_injector(); + +async function init_myext(install_details) +{ + console.log("details:", install_details); + if (install_details.reason != "install") + return; + + let storage = await get_storage(); + + await storage.clear(); + + /* + * Below we add sample settings to the extension. + * Those should be considered example values for viewing in the options + * page. They won't make my.fsf.org work. The only scripts that does + * something useful right now is the opencores one. + */ + + let components = []; + for (let script_data of [ + {url: "http://127.0.0.1:8000/myfsf_define_CRM.js", + hash:"bf0cc81c7e8d5f800877b4bc3f14639f946f5ac6d4dc120255ffac5eba5e48fe"}, + {url: "https://my.fsf.org/misc/jquery.js?v=1.4.4", + hash:"261ae472fa0cbf27c80c9200a1599a60fde581a0e652eee4bf41def8cb61f2d0"}, + {url: "https://my.fsf.org/misc/jquery-extend-3.4.0.js?v=1.4.4", + hash:"c54103ba57ee210ca55c052e70415402707548a4e6a68dd6efb3895019bee392"}, + {url: "https://my.fsf.org/misc/jquery-html-prefilter-3.5.0-backport.js?v=1.4.4", + hash:"fad84efa145fb507e5df9b582fa01b1c4e6313de7f72ebdd55726d92fa4dbf06"}, + {url: "https://my.fsf.org/misc/jquery.once.js?v=1.2", + hash:"1430f42c0d760ba8e05bb3762480502e541f654fec5739ee40625ab22dc38c4f"}, + {url: "https://my.fsf.org/misc/drupal.js?qmaukd", + hash:"2e08dccbd4d8b728a6871562995a4636b89bfe0ed3b8fb0138191c922228b116"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/jquery/dist/jquery.min.js?qmaukd", + hash:"a6d01520d28d15dbe476de84eea90eb3ee2d058722efc062ec73cb5fad78a17b"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/jquery-ui/jquery-ui.min.js?qmaukd", + hash:"28ce75d953678c4942df47a11707a15e3c756021cf89090e3e6aa7ad6b6971c3"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/lodash-compat/lodash.min.js?qmaukd", + hash:"f2871cc80c52fe8c04c582c4a49797c9c8fd80391cf1452e47f7fe97835ed5cc"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/packages/jquery/plugins/jquery.mousewheel.min.js?qmaukd", + hash:"f50233e84c2ac7ada37a094d3f7d3b3f7c97716d6b7b47bf69619d93ee4ac1ce"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/select2/select2.min.js?qmaukd", + hash:"ce61298fb9aa4ec49ccd4172d097e36a9e5db3af06a7b82796659368f15b7c1b"}, + {url: "https://my.fsf.org/sites/all/modules/civi crm/packages/jquery/plugins/jquery.form.min.js?qmaukd", + hash:"c90f0e501d2948fbc2b61bffd654fa4ab64741fd48923782419eeb14d3816fb8"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/packages/jquery/plugins/jquery.timeentry.min.js?qmaukd", + hash:"8e85df981e8ad7049d06dfb075277d038734d36a7097c7f021021b2bdccfe9bb"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/packages/jquery/plugins/jquery.blockUI.min.js?qmaukd", + hash:"806aedff52ac822f2adc5797073e1e5c5cec32eb9f15f2319cb32a347dcd232b"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/datatables/media/js/jquery.dataTables.min.js?qmaukd", + hash:"b796504d9b1b422f0dc6ccc2d740ac78a8c9e5078cc3934836d39742b1121925"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/bower_components/jquery-validation/dist/jquery.validate.min.js?qmaukd", + hash:"f0f5373ad203101ea91bf826c5a7ef8f7cd74887f06bad2cb9277a504503b9e2"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/packages/jquery/plugins/jquery.ui.datepicker.validation.min.js?qmaukd", + hash:"c6e6f6bf7f8fff25cca338045774e267e8eaa2d48ac9100540f3d59a6d2b3c61"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/js/Common.js?qmaukd", + hash:"17aa222a3af2e8958be16accb5e77ef39f67009cb3b500718d8fffd45b399148"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/js/crm.datepicker.js?qmaukd", + hash:"9bd8d10208aa99c156325f7819da6f0dd62ba221ac4119c3ccd4834e2cf36535"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/js/crm.ajax.js?qmaukd", + hash:"6401a4e257b7499ae4a00be2c200e4504a2c9b3d6b278a830c31a7b63374f0fe"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/js/wysiwyg/crm.wysiwyg.js?qmaukd", + hash:"fa962356072a36672c3b4b25bdeb657f020995a067e20a29cd5bb84b05157762"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/js/noconflict.js?qmaukd", + hash:"58d6d9f496a235d23cf891926d71f2104e4f2afe1d14bb4e2b5233f646c35e62"}, + {url: "https://my.fsf.org/sites/all/modules/matomo/matomo.js?qmaukd", + hash:"7f39ccd085f348189cd2fb62ea4d4a658d96f6bba266265880b98605e777e2de"}, + {url: "https://my.fsf.org/sites/all/themes/fsf_venture/js/global.js?qmaukd", + hash:"aa7983f6b902f9f4415cfc8346e0c3f194cc95b78f52f2ad09ec7effa1326b9c"}, + {url: "https://my.fsf.org/sites/all/themes/fsf_venture/js/jquery.superfish.min.js?qmaukd", + hash:"5ef1f93bf3901227056bf9ed0ed93a148eec4dda30f419756b12bedd1098815e"}, + {url: "https://my.fsf.org/sites/all/themes/fsf_venture/js/jquery.sidr.min.js?qmaukd", + hash:"c4914d415826676c6af2e61f16edb72c5388f8600ba6de9049892aee49d980a0"}, + {url: "https://my.fsf.org/sites/all/themes/fsf_venture/js/jquery.flexslider.min.js?qmaukd", + hash:"cefaf715761b4494913851249b9d40dacb4a8cb61242b0efc859dc586d56e0d4"}, + {url: "http://127.0.0.1:8000/myfsf_crap.js", + hash:"d91ccf21592d0f861ea0ba946bc257fc5d88269327cad0a91387da6cb8ff633e"}, + {url: "https://my.fsf.org/sites/all/modules/civicrm/templates/CRM/Core/BillingBlock.js?r=lp7Di", + hash:"2f25d35e7a0c0060ab0a444a577f09dd3c9934ae898a7ee0eb20b6c986ab5a1c"}, + {url: "https://my.fsf.org/extensions/com.aghstrategies.giftmemberships/js/giftpricefield.js?r=lp7Di", + hash:"f86080e6bd306fe46474039aeca2808235005bce5a2a29416d08210022039a45"}, + {url: "https://my.fsf.org/extensions/com.ginkgostreet.negativenegator/js/negativenegator.js?r=lp7Di", + hash:"d0e87bac832856db70947d82a7ab4e0b7c8b1070d5f1a32335345e033ece3a14"} + ]) { + let name_regex = /\/([^/]+)\.js/; + let name = name_regex.exec(script_data.url)[1]; + await storage.set(TYPE_PREFIX.SCRIPT, name, script_data); + components.push([TYPE_PREFIX.SCRIPT, name]); + } + + await storage.set(TYPE_PREFIX.BAG, "myfsf_join", components); + + await storage.set(TYPE_PREFIX.PAGE, "https://my.fsf.org/join", { + components: [TYPE_PREFIX.BAG, "myfsf_join"] + }); + + let hello_script = { + text: "console.log(\"hello, every1!\");\n" + }; + await storage.set(TYPE_PREFIX.SCRIPT, "hello", hello_script); + await storage.set(TYPE_PREFIX.BAG, "hello", + [[TYPE_PREFIX.SCRIPT, "hello"]]); + await storage.set(TYPE_PREFIX.PAGE, "https://my.fsf.org/", { + components: [TYPE_PREFIX.BAG, "hello"], + allow: true + }); + + let opencores_script = { + text: `\ let data = JSON.parse(document.getElementById("__NEXT_DATA__").textContent); let sections = {}; for (let h1 of document.getElementsByClassName("cMJCrc")) { @@ -154,16 +155,15 @@ for (let prop of data.props.pageProps.list) { ul.appendChild(li); } ` - }; + }; - await storage.set(TYPE_PREFIX.SCRIPT, "opencores", opencores_script); - await storage.set(TYPE_PREFIX.PAGE, "https://opencores.org/projects", { - components: [TYPE_PREFIX.SCRIPT, "opencores"], - allow: false - }); - } + await storage.set(TYPE_PREFIX.SCRIPT, "opencores", opencores_script); + await storage.set(TYPE_PREFIX.PAGE, "https://opencores.org/projects", { + components: [TYPE_PREFIX.SCRIPT, "opencores"], + allow: false + }); +} - browser.runtime.onInstalled.addListener(init_myext); +browser.runtime.onInstalled.addListener(init_myext); - console.log("hello, myext"); -})(); +console.log("hello, myext"); diff --git a/background/message_server.js b/background/message_server.js index 358e9d5..a541a04 100644 --- a/background/message_server.js +++ b/background/message_server.js @@ -5,28 +5,33 @@ * Redistribution terms are gathered in the `copyright' file. */ -"use strict"; - -(() => { - const browser = window.browser; +/* + * IMPORTS_START + * IMPORT browser + * IMPORTS_END + */ - var listeners = {}; +var listeners = {}; - /* magic should be one of the constants from /common/connection_types.js */ +/* magic should be one of the constants from /common/connection_types.js */ - function listen_for_connection(magic, cb) - { - listeners[magic] = cb; - } +function listen_for_connection(magic, cb) +{ + listeners[magic] = cb; +} - function raw_listen(port) { - if (listeners[port.name] === undefined) - return; +function raw_listen(port) +{ + if (listeners[port.name] === undefined) + return; - listeners[port.name](port); - } + listeners[port.name](port); +} - browser.runtime.onConnect.addListener(raw_listen); +browser.runtime.onConnect.addListener(raw_listen); - window.listen_for_connection = listen_for_connection; -})(); +/* + * EXPORTS_START + * EXPORT listen_for_connection + * EXPORTS_END + */ diff --git a/background/page_actions_server.js b/background/page_actions_server.js index dbf4db3..f9773f6 100644 --- a/background/page_actions_server.js +++ b/background/page_actions_server.js @@ -5,145 +5,149 @@ * Redistribution terms are gathered in the `copyright' file. */ -"use strict"; - -(() => { - const get_storage = window.get_storage; - const TYPE_PREFIX = window.TYPE_PREFIX; - const CONNECTION_TYPE = window.CONNECTION_TYPE; - const browser = window.browser; - const listen_for_connection = window.listen_for_connection; - const sha256 = window.sha256; - const get_query_best = window.get_query_best; - - var storage; - var query_best; - var handler; - - function send_scripts(url, port) - { - let [pattern, settings] = query_best(url); - if (settings === undefined) - return; - - let components = settings.components; - let processed_bags = new Set(); - - if (components !== undefined) - send_scripts_rec([components], port, processed_bags); - } +/* + * IMPORTS_START + * IMPORT get_storage + * IMPORT TYPE_PREFIX + * IMPORT CONNECTION_TYPE + * IMPORT browser + * IMPORT listen_for_connection + * IMPORT sha256 + * IMPORT get_query_best + * IMPORTS_END + */ - // TODO: parallelize script fetching - async function send_scripts_rec(components, port, processed_bags) - { - for (let [prefix, name] of components) { - if (prefix === TYPE_PREFIX.BAG) { - if (processed_bags.has(name)) { - console.log(`preventing recursive inclusion of bag ${name}`); - continue; - } - - var bag = storage.get(TYPE_PREFIX.BAG, name); - - if (bag === undefined) { - console.log(`no bag in storage for key ${name}`); - continue; - } - - processed_bags.add(name); - await send_scripts_rec(bag, port, processed_bags); - processed_bags.delete(name); - } else { - let script_text = await get_script_text(name); - if (script_text === undefined) - continue; - - port.postMessage({inject : [script_text]}); +var storage; +var query_best; +var handler; + +function send_scripts(url, port) +{ + let [pattern, settings] = query_best(url); + if (settings === undefined) + return; + + let components = settings.components; + let processed_bags = new Set(); + + if (components !== undefined) + send_scripts_rec([components], port, processed_bags); +} + +// TODO: parallelize script fetching +async function send_scripts_rec(components, port, processed_bags) +{ + for (let [prefix, name] of components) { + if (prefix === TYPE_PREFIX.BAG) { + if (processed_bags.has(name)) { + console.log(`preventing recursive inclusion of bag ${name}`); + continue; } - } - } - async function get_script_text(script_name) - { - try { - let script_data = storage.get(TYPE_PREFIX.SCRIPT, script_name); - if (script_data === undefined) { - console.log(`missing data for ${script_name}`); - return; + var bag = storage.get(TYPE_PREFIX.BAG, name); + + if (bag === undefined) { + console.log(`no bag in storage for key ${name}`); + continue; } - let script_text = script_data.text; - if (!script_text) - script_text = await fetch_remote_script(script_data); - return script_text; - } catch (e) { - console.log(e); - } - } - function ajax_callback() - { - if (this.readyState == 4) - this.resolve_callback(this); - } + processed_bags.add(name); + await send_scripts_rec(bag, port, processed_bags); + processed_bags.delete(name); + } else { + let script_text = await get_script_text(name); + if (script_text === undefined) + continue; - function initiate_ajax_request(resolve, method, url) - { - var xhttp = new XMLHttpRequest(); - xhttp.resolve_callback = resolve; - xhttp.onreadystatechange = ajax_callback; - xhttp.open(method, url, true); - xhttp.send(); + port.postMessage({inject : [script_text]}); + } } - - function make_ajax_request(method, url) - { - return new Promise((resolve, reject) => - initiate_ajax_request(resolve, method, url)); +} + +async function get_script_text(script_name) +{ + try { + let script_data = storage.get(TYPE_PREFIX.SCRIPT, script_name); + if (script_data === undefined) { + console.log(`missing data for ${script_name}`); + return; + } + let script_text = script_data.text; + if (!script_text) + script_text = await fetch_remote_script(script_data); + return script_text; + } catch (e) { + console.log(e); } - - async function fetch_remote_script(script_data) - { - try { - let xhttp = await make_ajax_request("GET", script_data.url); - if (xhttp.status === 200) { - let computed_hash = sha256(xhttp.responseText); - if (computed_hash !== script_data.hash) { - console.log(`Bad hash for ${script_data.url}\n got ${computed_hash} instead of ${script_data.hash}`); - return; - } - return xhttp.responseText; - } else { - console.log("script not fetched: " + script_data.url); +} + +function ajax_callback() +{ + if (this.readyState == 4) + this.resolve_callback(this); +} + +function initiate_ajax_request(resolve, method, url) +{ + var xhttp = new XMLHttpRequest(); + xhttp.resolve_callback = resolve; + xhttp.onreadystatechange = ajax_callback; + xhttp.open(method, url, true); + xhttp.send(); +} + +function make_ajax_request(method, url) +{ + return new Promise((resolve, reject) => + initiate_ajax_request(resolve, method, url)); +} + +async function fetch_remote_script(script_data) +{ + try { + let xhttp = await make_ajax_request("GET", script_data.url); + if (xhttp.status === 200) { + let computed_hash = sha256(xhttp.responseText); + if (computed_hash !== script_data.hash) { + console.log(`Bad hash for ${script_data.url}\n got ${computed_hash} instead of ${script_data.hash}`); return; } - } catch (e) { - console.log(e); + return xhttp.responseText; + } else { + console.log("script not fetched: " + script_data.url); + return; } + } catch (e) { + console.log(e); } - - function handle_message(port, message, handler) - { - port.onMessage.removeListener(handler[0]); - let url = message.url; - console.log({url}); - send_scripts(url, port); - } - - function new_connection(port) - { - console.log("new page actions connection!"); - let handler = []; - handler.push(m => handle_message(port, m, handler)); - port.onMessage.addListener(handler[0]); - } - - async function start() - { - storage = await get_storage(); - query_best = await get_query_best(); - - listen_for_connection(CONNECTION_TYPE.PAGE_ACTIONS, new_connection); - } - - window.start_page_actions_server = start; -})(); +} + +function handle_message(port, message, handler) +{ + port.onMessage.removeListener(handler[0]); + let url = message.url; + console.log({url}); + send_scripts(url, port); +} + +function new_connection(port) +{ + console.log("new page actions connection!"); + let handler = []; + handler.push(m => handle_message(port, m, handler)); + port.onMessage.addListener(handler[0]); +} + +async function start_page_actions_server() +{ + storage = await get_storage(); + query_best = await get_query_best(); + + listen_for_connection(CONNECTION_TYPE.PAGE_ACTIONS, new_connection); +} + +/* + * EXPORTS_START + * EXPORT start_page_actions_server + * EXPORTS_END + */ diff --git a/background/policy_injector.js b/background/policy_injector.js index d4d22b6..f05a422 100644 --- a/background/policy_injector.js +++ b/background/policy_injector.js @@ -5,71 +5,77 @@ * Redistribution terms are gathered in the `copyright' file. */ -"use strict"; +/* + * IMPORTS_START + * IMPORT TYPE_PREFIX + * IMPORT get_storage + * IMPORT browser + * IMPORT is_chrome + * IMPORT gen_unique + * IMPORT url_item + * IMPORT get_query_best + * IMPORTS_END + */ -(() => { - const TYPE_PREFIX = window.TYPE_PREFIX; - const get_storage = window.get_storage; - const browser = window.browser; - const is_chrome = window.is_chrome; - const gen_unique = window.gen_unique; - const url_item = window.url_item; - const get_query_best = window.get_query_best; +var storage; +var query_best; - var storage; - var query_best; +let csp_header_names = { + "content-security-policy" : true, + "x-webkit-csp" : true, + "x-content-security-policy" : true +}; - let csp_header_names = { - "content-security-policy" : true, - "x-webkit-csp" : true, - "x-content-security-policy" : true - }; +function is_noncsp_header(header) +{ + return !csp_header_names[header.name.toLowerCase()]; +} - function is_noncsp_header(header) - { - return !csp_header_names[header.name.toLowerCase()]; - } +function inject(details) +{ + let url = url_item(details.url); - function inject(details) - { - let url = url_item(details.url); + let [pattern, settings] = query_best(url); - let [pattern, settings] = query_best(url); + if (settings !== undefined && settings.allow) + return {cancel : false}; - if (settings !== undefined && settings.allow) { - console.log("allowing", url); - return {cancel : false}; - } + let nonce = gen_unique(url).substring(1); + let headers = details.responseHeaders.filter(is_noncsp_header); - let nonce = gen_unique(url).substring(1); - let headers = details.responseHeaders.filter(is_noncsp_header); - headers.push({ - name : "content-security-policy", - value : `script-src 'nonce-${nonce}'; script-src-elem 'nonce-${nonce}';` - }); + let rule = `script-src 'nonce-${nonce}';`; + if (is_chrome) + rule += `script-src-elem 'nonce-${nonce}';`; - console.log("modified headers", url, headers); + headers.push({ + name : "content-security-policy", + value : rule + }); - return {responseHeaders: headers}; - } + return {responseHeaders: headers}; +} - async function start() { - storage = await get_storage(); - query_best = await get_query_best(); +async function start_policy_injector() +{ + storage = await get_storage(); + query_best = await get_query_best(); - let extra_opts = ["blocking", "responseHeaders"]; - if (is_chrome) - extra_opts.push("extraHeaders"); + let extra_opts = ["blocking", "responseHeaders"]; + if (is_chrome) + extra_opts.push("extraHeaders"); - browser.webRequest.onHeadersReceived.addListener( - inject, - { - urls: ["<all_urls>"], - types: ["main_frame", "sub_frame"] - }, - extra_opts - ); - } + browser.webRequest.onHeadersReceived.addListener( + inject, + { + urls: ["<all_urls>"], + types: ["main_frame", "sub_frame"] + }, + extra_opts + ); +} - window.start_policy_injector = start; -})(); +/* + * EXPORTS_START + * EXPORT start_policy_injector + * EXPORTS_END + */ diff --git a/background/settings_query.js b/background/settings_query.js index 43538d5..ce01b80 100644 --- a/background/settings_query.js +++ b/background/settings_query.js @@ -5,32 +5,34 @@ * Redistribution terms are gathered in the `copyright' file. */ -"use strict"; - -(() => { - const make_once = window.make_once; - const get_storage = window.get_storage; +/* + * IMPORTS_START + * IMPORT make_once + * IMPORT get_storage + * IMPORT TYPE_PREFIX + * IMPORTS_END + */ - var storage; +var storage; - var exports = {}; +var exports = {}; - async function init(fun) - { - storage = await get_storage(); +async function init(fun) +{ + storage = await get_storage(); - return fun; - } + return fun; +} - // TODO: also support urls with specified ports as well as `data:' urls - function query(url, multiple) - { - let proto_re = "[a-zA-Z]*:\/\/"; - let domain_re = "[^/?#]+"; - let segments_re = "/[^?#]*"; - let query_re = "\\?[^#]*"; +// TODO: also support urls with specified ports +function query(url, multiple) +{ + let proto_re = "[a-zA-Z]*:\/\/"; + let domain_re = "[^/?#]+"; + let segments_re = "/[^?#]*"; + let query_re = "\\?[^#]*"; - let url_regex = new RegExp(`\ + let url_regex = new RegExp(`\ ^\ (${proto_re})\ (${domain_re})\ @@ -39,89 +41,95 @@ #?.*\$\ `); - let regex_match = url_regex.exec(url); - if (regex_match === null) { - console.log("bad url format", url); - return multiple ? [] : [undefined, undefined]; - } + let regex_match = url_regex.exec(url); + if (regex_match === null) { + console.log("bad url format", url); + return multiple ? [] : [undefined, undefined]; + } + + let [_, proto, domain, segments, query] = regex_match; + + domain = domain.split("."); + let segments_trailing_dash = + segments && segments[segments.length - 1] === "/"; + segments = (segments || "").split("/").filter(s => s !== ""); + segments.unshift(""); + + let matched = []; + + for (let d_slice = 0; d_slice < domain.length; d_slice++) { + let domain_part = domain.slice(d_slice).join("."); + let domain_wildcards = []; + if (d_slice === 0) + domain_wildcards.push(""); + if (d_slice === 1) + domain_wildcards.push("*."); + if (d_slice > 0) + domain_wildcards.push("**."); + domain_wildcards.push("***."); + + for (let domain_wildcard of domain_wildcards) { + let domain_pattern = domain_wildcard + domain_part; + + for (let s_slice = segments.length; s_slice > 0; s_slice--) { + let segments_part = segments.slice(0, s_slice).join("/"); + let segments_wildcards = []; + if (s_slice === segments.length) { + if (segments_trailing_dash) + segments_wildcards.push("/"); + segments_wildcards.push(""); + } + if (s_slice === segments.length - 1) { + if (segments[s_slice] !== "*") + segments_wildcards.push("/*"); + } + if (s_slice < segments.length && + (segments[s_slice] !== "**" || + s_slice < segments.length - 1)) + segments_wildcards.push("/**"); + if (segments[s_slice] !== "***" || + s_slice < segments.length) + segments_wildcards.push("/***"); + + for (let segments_wildcard of segments_wildcards) { + let segments_pattern = + segments_part + segments_wildcard; - let [_, proto, domain, segments, query] = regex_match; - - domain = domain.split("."); - let segments_trailing_dash = - segments && segments[segments.length - 1] === "/"; - segments = (segments || "").split("/").filter(s => s !== ""); - segments.unshift(""); - - let matched = []; - - for (let d_slice = 0; d_slice < domain.length; d_slice++) { - let domain_part = domain.slice(d_slice).join("."); - let domain_wildcards = []; - if (d_slice === 0) - domain_wildcards.push(""); - if (d_slice === 1) - domain_wildcards.push("*."); - if (d_slice > 0) - domain_wildcards.push("**."); - domain_wildcards.push("***."); - - for (let domain_wildcard of domain_wildcards) { - let domain_pattern = domain_wildcard + domain_part; - - for (let s_slice = segments.length; s_slice > 0; s_slice--) { - let segments_part = segments.slice(0, s_slice).join("/"); - let segments_wildcards = []; - if (s_slice === segments.length) { - if (segments_trailing_dash) - segments_wildcards.push("/"); - segments_wildcards.push(""); - } - if (s_slice === segments.length - 1) { - if (segments[s_slice] !== "*") - segments_wildcards.push("/*"); - } - if (s_slice < segments.length && - (segments[s_slice] !== "**" || - s_slice < segments.length - 1)) - segments_wildcards.push("/**"); - if (segments[s_slice] !== "***" || - s_slice < segments.length) - segments_wildcards.push("/***"); - - for (let segments_wildcard of segments_wildcards) { - let segments_pattern = - segments_part + segments_wildcard; - - let pattern = proto + domain_pattern + segments_pattern; - console.log("trying", pattern); - let settings = storage.get(TYPE_PREFIX.PAGE, pattern); - - if (settings === undefined) - continue; - - if (!multiple) - return [pattern, settings]; - - matched.push([pattern, settings]); - } + let pattern = proto + domain_pattern + segments_pattern; + console.log("trying", pattern); + let settings = storage.get(TYPE_PREFIX.PAGE, pattern); + + if (settings === undefined) + continue; + + if (!multiple) + return [pattern, settings]; + + matched.push([pattern, settings]); } } } - - return multiple ? matched : [undefined, undefined]; } - function query_best(url) - { - return query(url, false); - } + return multiple ? matched : [undefined, undefined]; +} - function query_all(url) - { - return query(url, true); - } +function query_best(url) +{ + return query(url, false); +} + +function query_all(url) +{ + return query(url, true); +} - window.get_query_best = make_once(() => init(query_best)); - window.get_query_all = make_once(() => init(query_all)); -})(); +const get_query_best = make_once(() => init(query_best)); +const get_query_all = make_once(() => init(query_all)); + +/* + * EXPORTS_START + * EXPORT get_query_best + * EXPORT get_query_all + * EXPORTS_END + */ diff --git a/background/storage.js b/background/storage.js index f3f08c9..48e4e52 100644 --- a/background/storage.js +++ b/background/storage.js @@ -5,390 +5,396 @@ * Redistribution terms are gathered in the `copyright' file. */ -"use strict"; - -(() => { - const TYPE_PREFIX = window.TYPE_PREFIX; - const TYPE_NAME = window.TYPE_NAME; - const list_prefixes = window.list_prefixes; - const make_lock = window.make_lock; - const lock = window.lock; - const unlock = window.unlock; - const make_once = window.make_once; - const browser = window.browser; - const is_chrome = window.is_chrome; - - var exports = {}; - - /* We're yet to decide how to handle errors... */ - - /* Here are some basic wrappers for storage API functions */ - - async function get(key) - { - try { - /* Fix for fact that Chrome does not use promises here */ - let promise = is_chrome ? - new Promise((resolve, reject) => - chrome.storage.local.get(key, - val => resolve(val))) : - browser.storage.local.get(key); - - return (await promise)[key]; - } catch (e) { - console.log(e); - } - } +/* + * IMPORTS_START + * IMPORT TYPE_PREFIX + * IMPORT TYPE_NAME + * IMPORT list_prefixes + * IMPORT make_lock + * IMPORT lock + * IMPORT unlock + * IMPORT make_once + * IMPORT browser + * IMPORT is_chrome + * IMPORTS_END + */ - async function set(key, value) - { - try { - return browser.storage.local.set({[key]: value}); - } catch (e) { - console.log(e); - } - } +var exports = {}; - async function setn(keys_and_values) - { - let obj = Object(); - while (keys_and_values.length > 1) { - let value = keys_and_values.pop(); - let key = keys_and_values.pop(); - obj[key] = value; - } +/* We're yet to decide how to handle errors... */ - try { - return browser.storage.local.set(obj); - } catch (e) { - console.log(e); - } - } +/* Here are some basic wrappers for storage API functions */ - async function set_var(name, value) - { - return set(TYPE_PREFIX.VAR + name, value); - } +async function get(key) +{ + try { + /* Fix for fact that Chrome does not use promises here */ + let promise = is_chrome ? + new Promise((resolve, reject) => + chrome.storage.local.get(key, + val => resolve(val))) : + browser.storage.local.get(key); - async function get_var(name) - { - return get(TYPE_PREFIX.VAR + name); + return (await promise)[key]; + } catch (e) { + console.log(e); + } +} + +async function set(key, value) +{ + try { + return browser.storage.local.set({[key]: value}); + } catch (e) { + console.log(e); + } +} + +async function setn(keys_and_values) +{ + let obj = Object(); + while (keys_and_values.length > 1) { + let value = keys_and_values.pop(); + let key = keys_and_values.pop(); + obj[key] = value; } - /* - * A special case of persisted variable is one that contains list - * of items. - */ - - async function get_list_var(name) - { - let list = await get_var(name); - - return list === undefined ? [] : list; + try { + return browser.storage.local.set(obj); + } catch (e) { + console.log(e); } +} - /* We maintain in-memory copies of some stored lists. */ +async function set_var(name, value) +{ + return set(TYPE_PREFIX.VAR + name, value); +} - async function list(prefix) - { - let name = TYPE_NAME[prefix] + "s"; /* Make plural. */ - let map = new Map(); +async function get_var(name) +{ + return get(TYPE_PREFIX.VAR + name); +} - for (let item of await get_list_var(name)) - map.set(item, await get(prefix + item)); +/* + * A special case of persisted variable is one that contains list + * of items. + */ - return {map, prefix, name, listeners : new Set(), lock : make_lock()}; - } +async function get_list_var(name) +{ + let list = await get_var(name); - var pages; - var bags; - var scripts; + return list === undefined ? [] : list; +} - var list_by_prefix = {}; +/* We maintain in-memory copies of some stored lists. */ - async function init() - { - for (let prefix of list_prefixes) - list_by_prefix[prefix] = await list(prefix); +async function list(prefix) +{ + let name = TYPE_NAME[prefix] + "s"; /* Make plural. */ + let map = new Map(); - return exports; - } + for (let item of await get_list_var(name)) + map.set(item, await get(prefix + item)); - /* - * Facilitate listening to changes - */ + return {map, prefix, name, listeners : new Set(), lock : make_lock()}; +} - exports.add_change_listener = function (cb, prefixes=list_prefixes) - { - if (typeof(prefixes) === "string") - prefixes = [prefixes]; +var pages; +var bags; +var scripts; - for (let prefix of prefixes) - list_by_prefix[prefix].listeners.add(cb); - } +var list_by_prefix = {}; - exports.remove_change_listener = function (cb, prefixes=list_prefixes) - { - if (typeof(prefixes) === "string") - prefixes = [prefixes]; +async function init() +{ + for (let prefix of list_prefixes) + list_by_prefix[prefix] = await list(prefix); - for (let prefix of prefixes) - list_by_prefix[prefix].listeners.delete(cb); - } + return exports; +} - function broadcast_change(change, list) - { - for (let listener_callback of list.listeners) - listener_callback(change); - } +/* + * Facilitate listening to changes + */ - /* Prepare some hepler functions to get elements of a list */ +exports.add_change_listener = function (cb, prefixes=list_prefixes) +{ + if (typeof(prefixes) === "string") + prefixes = [prefixes]; - function list_items_it(list, with_values=false) - { - return with_values ? list.map.entries() : list.map.keys(); - } + for (let prefix of prefixes) + list_by_prefix[prefix].listeners.add(cb); +} - function list_entries_it(list) - { - return list_items_it(list, true); - } +exports.remove_change_listener = function (cb, prefixes=list_prefixes) +{ + if (typeof(prefixes) === "string") + prefixes = [prefixes]; - function list_items(list, with_values=false) - { - let array = []; + for (let prefix of prefixes) + list_by_prefix[prefix].listeners.delete(cb); +} - for (let item of list_items_it(list, with_values)) - array.push(item); +function broadcast_change(change, list) +{ + for (let listener_callback of list.listeners) + listener_callback(change); +} - return array; - } +/* Prepare some hepler functions to get elements of a list */ - function list_entries(list) - { - return list_items(list, true); - } +function list_items_it(list, with_values=false) +{ + return with_values ? list.map.entries() : list.map.keys(); +} - /* - * Below we make additional effort to update map of given kind of items - * every time an item is added/removed to keep everything coherent. - */ - async function set_item(item, value, list) - { - await lock(list.lock); - let result = await _set_item(...arguments); - unlock(list.lock) - return result; - } - async function _set_item(item, value, list) - { - let key = list.prefix + item; - let old_val = list.map.get(item); - if (old_val === undefined) { - let items = list_items(list); - items.push(item); - await setn([key, value, "_" + list.name, items]); - } else { - await set(key, value); - } +function list_entries_it(list) +{ + return list_items_it(list, true); +} - list.map.set(item, value) +function list_items(list, with_values=false) +{ + let array = []; - let change = { - prefix : list.prefix, - item, - old_val, - new_val : value - }; + for (let item of list_items_it(list, with_values)) + array.push(item); - broadcast_change(change, list); + return array; +} - return old_val; - } +function list_entries(list) +{ + return list_items(list, true); +} - // TODO: The actual idea to set value to undefined is good - this way we can - // also set a new list of items in the same API call. But such key - // is still stored in the storage. We need to somehow remove it later. - // For that, we're going to have to store 1 more list of each kind. - async function remove_item(item, list) - { - await lock(list.lock); - let result = await _remove_item(...arguments); - unlock(list.lock) - return result; +/* + * Below we make additional effort to update map of given kind of items + * every time an item is added/removed to keep everything coherent. + */ +async function set_item(item, value, list) +{ + await lock(list.lock); + let result = await _set_item(...arguments); + unlock(list.lock) + return result; +} +async function _set_item(item, value, list) +{ + let key = list.prefix + item; + let old_val = list.map.get(item); + if (old_val === undefined) { + let items = list_items(list); + items.push(item); + await setn([key, value, "_" + list.name, items]); + } else { + await set(key, value); } - async function _remove_item(item, list) - { - let old_val = list.map.get(item); + + list.map.set(item, value) + + let change = { + prefix : list.prefix, + item, + old_val, + new_val : value + }; + + broadcast_change(change, list); + + return old_val; +} + +// TODO: The actual idea to set value to undefined is good - this way we can +// also set a new list of items in the same API call. But such key +// is still stored in the storage. We need to somehow remove it later. +// For that, we're going to have to store 1 more list of each kind. +async function remove_item(item, list) +{ + await lock(list.lock); + let result = await _remove_item(...arguments); + unlock(list.lock) + return result; +} +async function _remove_item(item, list) +{ + let old_val = list.map.get(item); + if (old_val === undefined) + return; + + let key = list.prefix + item; + let items = list_items(list); + let index = items.indexOf(item); + items.splice(index, 1); + + await setn([key, undefined, "_" + list.name, items]); + + list.map.delete(item); + + let change = { + prefix : list.prefix, + item, + old_val, + new_val : undefined + }; + + broadcast_change(change, list); + + return old_val; +} + +// TODO: same as above applies here +async function replace_item(old_item, new_item, list, new_val=undefined) +{ + await lock(list.lock); + let result = await _replace_item(...arguments); + unlock(list.lock) + return result; +} +async function _replace_item(old_item, new_item, list, new_val=undefined) +{ + let old_val = list.map.get(old_item); + if (new_val === undefined) { if (old_val === undefined) return; - - let key = list.prefix + item; - let items = list_items(list); - let index = items.indexOf(item); - items.splice(index, 1); - - await setn([key, undefined, "_" + list.name, items]); - - list.map.delete(item); - - let change = { - prefix : list.prefix, - item, - old_val, - new_val : undefined - }; - - broadcast_change(change, list); - + new_val = old_val + } else if (new_val === old_val && new_item === old_item) { return old_val; } - // TODO: same as above applies here - async function replace_item(old_item, new_item, list, new_val=undefined) - { - await lock(list.lock); - let result = await _replace_item(...arguments); - unlock(list.lock) - return result; + if (old_item === new_item || old_val === undefined) { + await _set_item(new_item, new_val, list); + return old_val; } - async function _replace_item(old_item, new_item, list, new_val=undefined) - { - let old_val = list.map.get(old_item); - if (new_val === undefined) { - if (old_val === undefined) - return; - new_val = old_val - } else if (new_val === old_val && new_item === old_item) { - return old_val; - } - if (old_item === new_item || old_val === undefined) { - await _set_item(new_item, new_val, list); - return old_val; - } + let new_key = list.prefix + new_item; + let old_key = list.prefix + old_item; + let items = list_items(list); + let index = items.indexOf(old_item); + items[index] = new_item; + await setn([old_key, undefined, new_key, new_val, + "_" + list.name, items]); - let new_key = list.prefix + new_item; - let old_key = list.prefix + old_item; - let items = list_items(list); - let index = items.indexOf(old_item); - items[index] = new_item; - await setn([old_key, undefined, new_key, new_val, - "_" + list.name, items]); + list.map.delete(old_item); - list.map.delete(old_item); + let change = { + prefix : list.prefix, + item : old_item, + old_val, + new_val : undefined + }; - let change = { - prefix : list.prefix, - item : old_item, - old_val, - new_val : undefined - }; + broadcast_change(change, list); - broadcast_change(change, list); + list.map.set(new_item, new_val); - list.map.set(new_item, new_val); + change.item = new_item; + change.old_val = undefined; + change.new_val = new_val; - change.item = new_item; - change.old_val = undefined; - change.new_val = new_val; + broadcast_change(change, list); - broadcast_change(change, list); - - return old_val; - } + return old_val; +} - /* - * For scripts, item name is chosen by user, data should be - * an object containing: - * - script's url and hash or - * - script's text or - * - all three - */ - - /* - * For bags, item name is chosen by user, data is an array of 2-element - * arrays with type prefix and script/bag names. - */ - - /* - * For pages data argument is an object with properties `allow' - * and `components'. Item name is url. - */ - - exports.set = async function (prefix, item, data) - { - return set_item(item, data, list_by_prefix[prefix]); - } +/* + * For scripts, item name is chosen by user, data should be + * an object containing: + * - script's url and hash or + * - script's text or + * - all three + */ - exports.get = function (prefix, item) - { - return list_by_prefix[prefix].map.get(item); - } +/* + * For bags, item name is chosen by user, data is an array of 2-element + * arrays with type prefix and script/bag names. + */ - exports.remove = async function (prefix, item) - { - return remove_item(item, list_by_prefix[prefix]); - } +/* + * For pages data argument is an object with properties `allow' + * and `components'. Item name is url. + */ - exports.replace = async function (prefix, old_item, new_item, - new_data=undefined) - { - return replace_item(old_item, new_item, list_by_prefix[prefix], - new_data); - } +exports.set = async function (prefix, item, data) +{ + return set_item(item, data, list_by_prefix[prefix]); +} + +exports.get = function (prefix, item) +{ + return list_by_prefix[prefix].map.get(item); +} + +exports.remove = async function (prefix, item) +{ + return remove_item(item, list_by_prefix[prefix]); +} + +exports.replace = async function (prefix, old_item, new_item, + new_data=undefined) +{ + return replace_item(old_item, new_item, list_by_prefix[prefix], + new_data); +} + +exports.get_all_names = function (prefix) +{ + return list_items(list_by_prefix[prefix]); +} + +exports.get_all_names_it = function (prefix) +{ + return list_items_it(list_by_prefix[prefix]); +} + +exports.get_all = function (prefix) +{ + return list_entries(list_by_prefix[prefix]); +} + +exports.get_all_it = function (prefix) +{ + return list_entries_it(list_by_prefix[prefix]); +} + +/* Finally, a quick way to wipe all the data. */ +// TODO: maybe delete items in such order that none of them ever references +// an already-deleted one? +exports.clear = async function () +{ + let lists = list_prefixes.map((p) => list_by_prefix[p]); + + for (let list of lists) + await lock(list.lock); - exports.get_all_names = function (prefix) - { - return list_items(list_by_prefix[prefix]); - } + for (let list of lists) { - exports.get_all_names_it = function (prefix) - { - return list_items_it(list_by_prefix[prefix]); - } + let change = { + prefix : list.prefix, + new_val : undefined + }; - exports.get_all = function (prefix) - { - return list_entries(list_by_prefix[prefix]); - } + for (let [item, val] of list_entries_it(list)) { + change.item = item; + change.old_val = val; + broadcast_change(change, list); + } - exports.get_all_it = function (prefix) - { - return list_entries_it(list_by_prefix[prefix]); + list.map = new Map(); } - /* Finally, a quick way to wipe all the data. */ - // TODO: maybe delete items in such order that none of them ever references - // an already-deleted one? - exports.clear = async function () - { - let lists = list_prefixes.map((p) => list_by_prefix[p]); - - for (let list of lists) - await lock(list.lock); - - for (let list of lists) { - - let change = { - prefix : list.prefix, - new_val : undefined - }; + await browser.storage.local.clear(); - for (let [item, val] of list_entries_it(list)) { - change.item = item; - change.old_val = val; - broadcast_change(change, list); - } + for (let list of lists) + unlock(list.lock); +} - list.map = new Map(); - } - - await browser.storage.local.clear(); +const get_storage = make_once(init); - for (let list of lists) - unlock(list.lock); - } - - window.get_storage = make_once(init); -})(); +/* + * EXPORTS_START + * EXPORT get_storage + * EXPORTS_END + */ diff --git a/background/storage_server.js b/background/storage_server.js index acdca27..d39898d 100644 --- a/background/storage_server.js +++ b/background/storage_server.js @@ -5,58 +5,63 @@ * Redistribution terms are gathered in the `copyright' file. */ -"use strict"; - -(() => { - const listen_for_connection = window.listen_for_connection; - const get_storage = window.get_storage; - const TYPE_PREFIX = window.TYPE_PREFIX; - const CONNECTION_TYPE = window.CONNECTION_TYPE; - - var storage; - - async function handle_remote_call(port, message) - { - let [call_id, func, args] = message; - - try { - let result = await Promise.resolve(storage[func](...args)); - port.postMessage({call_id, result}); - } catch (error) { - error = error + ''; - port.postMessage({call_id, error}); - } - } +/* + * IMPORTS_START + * IMPORT listen_for_connection + * IMPORT get_storage + * IMPORT TYPE_PREFIX + * IMPORT CONNECTION_TYPE + * IMPORTS_END + */ + +var storage; + +async function handle_remote_call(port, message) +{ + let [call_id, func, args] = message; - function remove_storage_listener(cb) { - storage.remove_change_listener(cb); + try { + let result = await Promise.resolve(storage[func](...args)); + port.postMessage({call_id, result}); + } catch (error) { + error = error + ''; + port.postMessage({call_id, error}); } +} - function new_connection(port) - { - console.log("new remote storage connection!"); +function remove_storage_listener(cb) +{ + storage.remove_change_listener(cb); +} - port.postMessage({ - [TYPE_PREFIX.SCRIPT] : storage.get_all(TYPE_PREFIX.SCRIPT), - [TYPE_PREFIX.BAG] : storage.get_all(TYPE_PREFIX.BAG), - [TYPE_PREFIX.PAGE] : storage.get_all(TYPE_PREFIX.PAGE) - }); +function new_connection(port) +{ + console.log("new remote storage connection!"); - let handle_change = change => port.postMessage(change); + port.postMessage({ + [TYPE_PREFIX.SCRIPT] : storage.get_all(TYPE_PREFIX.SCRIPT), + [TYPE_PREFIX.BAG] : storage.get_all(TYPE_PREFIX.BAG), + [TYPE_PREFIX.PAGE] : storage.get_all(TYPE_PREFIX.PAGE) + }); - storage.add_change_listener(handle_change); + let handle_change = change => port.postMessage(change); - port.onMessage.addListener(m => handle_remote_call(port, m)); - port.onDisconnect.addListener(() => - remove_storage_listener(handle_change)); - } + storage.add_change_listener(handle_change); - async function start() - { - storage = await get_storage(); + port.onMessage.addListener(m => handle_remote_call(port, m)); + port.onDisconnect.addListener(() => + remove_storage_listener(handle_change)); +} - listen_for_connection(CONNECTION_TYPE.REMOTE_STORAGE, new_connection); - } +async function start_storage_server() +{ + storage = await get_storage(); - window.start_storage_server = start; -})(); + listen_for_connection(CONNECTION_TYPE.REMOTE_STORAGE, new_connection); +} + +/* + * EXPORTS_START + * EXPORT start_storage_server + * EXPORTS_END + */ |