diff options
author | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-05-13 09:27:56 +0200 |
---|---|---|
committer | Wojtek Kosior <wk@koszkonutek-tmp.pl.eu.org> | 2021-05-13 11:13:11 +0200 |
commit | 57f32a269a06ec5102b08824d251afa5456d4195 (patch) | |
tree | 8ef9e47c91cf74ac47dea2e29998c4aaa7068638 | |
parent | f6a7f24e61a78f197250875ac9833f497a455d20 (diff) | |
download | browser-extension-57f32a269a06ec5102b08824d251afa5456d4195.tar.gz browser-extension-57f32a269a06ec5102b08824d251afa5456d4195.zip |
only allow a single injection payload for page, rely on script bags for complex payloads
-rw-r--r-- | TODOS.org | 5 | ||||
-rw-r--r-- | background/main.js | 10 | ||||
-rw-r--r-- | background/page_actions_server.js | 3 | ||||
-rw-r--r-- | background/reverse_use_info.js | 6 | ||||
-rw-r--r-- | html/options.html | 68 | ||||
-rw-r--r-- | html/options_main.js | 288 |
6 files changed, 266 insertions, 114 deletions
@@ -1,5 +1,7 @@ TODO: - parallelize fetching of remote scripts +- allow specifying whether a script occurring mutiple times directly + or indirectly in a bag should be included multiple times or once - make it possible to provide backup urls for remote scripts - make it possible to cache remote scripts - make it possible to use wildcards or something similar to be able to assign a script set to -- CRUCIAL @@ -17,6 +19,7 @@ TODO: settings and settings for pages that currently happen to live in iframes - add some nice styling to settings page +- make script bag components re-orderable (via drag&drop in options page) -- CRUCIAL - find some way not to require each chrome user to modify manifest.json - rename the extension to something good - port to gecko-based browsers -- CRUCIAL @@ -37,8 +40,10 @@ TODO: - rearrange files in extension, add some mechanism to build the extension - all solutions to modularize js code SUCK; come up with own simple DSL to manage imports/exports +- perform never-ending refactoring of already-written code DONE: +- only allow a single injection payload for page -- DONE 2021-05-13 - rename "bundles" to "bags" to avoid confusion with Web Bundles -- DONE 2021-05-12 - use non-predictable value in place of "myext-allow", utilizing hashes -- DONE 2021-05-12 - stop using modules (not available on all browsers) -- DONE 2021-05-12 diff --git a/background/main.js b/background/main.js index 6b636c4..6656284 100644 --- a/background/main.js +++ b/background/main.js @@ -110,7 +110,11 @@ components.push([TYPE_PREFIX.SCRIPT, name]); } - await storage.set(TYPE_PREFIX.PAGE, "https://my.fsf.org/join", {components}); + 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" @@ -119,7 +123,7 @@ 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"]], + components: [TYPE_PREFIX.BAG, "hello"], allow: true }); @@ -157,7 +161,7 @@ for (let prop of data.props.pageProps.list) { await storage.set(TYPE_PREFIX.SCRIPT, "opencores", opencores_script); await storage.set(TYPE_PREFIX.PAGE, "https://opencores.org/projects", { - components: [[TYPE_PREFIX.SCRIPT, "opencores"]], + components: [TYPE_PREFIX.SCRIPT, "opencores"], allow: false }); } diff --git a/background/page_actions_server.js b/background/page_actions_server.js index 2a0b858..2dfcf9a 100644 --- a/background/page_actions_server.js +++ b/background/page_actions_server.js @@ -31,7 +31,8 @@ let components = settings.components; let processed_bags = new Set(); - send_scripts_rec(components, port, processed_bags); + if (components !== undefined) + send_scripts_rec([components], port, processed_bags); } // TODO: parallelize script fetching diff --git a/background/reverse_use_info.js b/background/reverse_use_info.js index 688cd64..c51d06b 100644 --- a/background/reverse_use_info.js +++ b/background/reverse_use_info.js @@ -11,6 +11,12 @@ "use strict"; /* + * Warning! + * This script file has not been used for some time and underlying storage + * model has changed since then! Fix required! + */ + +/* * We want to count referenes to scripts and bags in order to know, * for example, whether one can be safely deleted. */ diff --git a/html/options.html b/html/options.html index cb39090..ac6c736 100644 --- a/html/options.html +++ b/html/options.html @@ -4,8 +4,7 @@ <meta charset="utf-8"/> <title>Myext options</title> <style> - input[type="checkbox"], input[type="radio"], - .hide { + input[type="checkbox"], input[type="radio"], .hide, .popup.hide { display: none; } @@ -50,8 +49,8 @@ display: inline-block; } - /* popup window with list of selectable components for adding */ - #select_components_window { + /* popup window with list of selectable components */ + .popup { position: fixed; width: 100vw; height: 100vh; @@ -64,7 +63,7 @@ horizontal-align: center; } - #select_components_frame { + .popup_frame { background-color: white; width: 50vw; } @@ -78,14 +77,18 @@ <button> Edit </button> <button> Remove </button> </li> - <li id="component_li_template"> + <li id="bag_component_li_template"> <span></span> <button> Remove </button> </li> - <li id="selectable_component_li_template"> + <li id="chbx_component_li_template"> <input type="checkbox" style="display: inline;"></input> <span></span> </li> + <li id="radio_component_li_template"> + <input type="radio" style="display: inline;" name="page_components"></input> + <span></span> + </li> </div> <input type="radio" name="tabs" id="show_pages" checked></input> @@ -103,17 +106,18 @@ <li id="work_page_li" class="hide"> <label for="page_url_field">URL: </label> <input id="page_url_field"></input> - <ul id="page_components_ul"> - <li id="empty_page_component_li" class="hide"></li> - </ul> + <br/> + <label>Payload: </label> + <span id="page_payload"></span> + <button id="select_page_components_but"> + Choose payload + </button> + <br/> <input id="page_allow_chbx" type="checkbox" style="display: inline;"></input> <label for="page_allow_chbx">Allow native scripts</label> - <button id="page_select_components_but"> - Add scripts - </button> <br/> - <button id="page_save_but" type="button"> Save </button> - <button id="page_discard_but" type="button"> Cancel </button> + <button id="save_page_but" type="button"> Save </button> + <button id="discard_page_but" type="button"> Cancel </button> </li> </ul> <button id="add_page_but" type="button"> Add page </button> @@ -127,12 +131,12 @@ <ul id="bag_components_ul"> <li id="empty_bag_component_li" class="hide"></li> </ul> - <button id="bag_select_components_but"> + <button id="select_bag_components_but"> Add scripts </button> <br/> - <button id="bag_save_but"> Save </button> - <button id="bag_discard_but"> Cancel </button> + <button id="save_bag_but"> Save </button> + <button id="discard_bag_but"> Cancel </button> </li> </ul> <button id="add_bag_but" type="button"> Add bag </button> @@ -153,20 +157,34 @@ <label for="script_contents_field"> contents: </label> <textarea id="script_contents_field" rows="20" cols="80"></textarea> <br/> - <button id="script_save_but"> Save </button> - <button id="script_discard_but"> Cancel </button> + <button id="save_script_but"> Save </button> + <button id="discard_script_but"> Cancel </button> </li> </ul> <button id="add_script_but" type="button"> Add script </button> </div> - <div id="select_components_window" class="hide" position="absolute"> - <div id="select_components_frame"> - <ul id="selectable_components_ul"> + <div id="chbx_components_window" class="hide popup" position="absolute"> + <div class="popup_frame"> + <ul id="chbx_components_ul"> + + </ul> + <button id="commit_bag_components_but"> Add </button> + <button id="cancel_bag_components_but"> Cancel </button> + </div> + </div> + + <div id="radio_components_window" class="hide popup" position="absolute"> + <div class="popup_frame"> + <ul id="radio_components_ul"> + <li id="radio_component_none_li"> + <input id="radio_component_none_input" type="radio" style="display: inline;" name="page_components"></input> + <span>(None)</span> + </li> </ul> - <button id="commit_components_but"> Add </button> - <button id="cancel_components_but"> Cancel </button> + <button id="commit_page_components_but"> Choose </button> + <button id="cancel_page_components_but"> Cancel </button> </div> </div> diff --git a/html/options_main.js b/html/options_main.js index 104f771..c643f25 100644 --- a/html/options_main.js +++ b/html/options_main.js @@ -23,19 +23,21 @@ } const item_li_template = by_id("item_li_template"); - const component_li_template = by_id("component_li_template"); - const selectable_component_li_template = - by_id("selectable_component_li_template"); + const bag_component_li_template = by_id("bag_component_li_template"); + const chbx_component_li_template = by_id("chbx_component_li_template"); + const radio_component_li_template = by_id("radio_component_li_template"); /* Make sure they are later cloned without id. */ item_li_template.removeAttribute("id"); - component_li_template.removeAttribute("id"); - selectable_component_li_template.removeAttribute("id"); + bag_component_li_template.removeAttribute("id"); + chbx_component_li_template.removeAttribute("id"); + radio_component_li_template.removeAttribute("id"); function item_li_id(prefix, item) { return `li_${prefix}_${item}`; } + /* Insert into list of bags/pages/scripts */ function add_li(prefix, item, at_the_end=false) { let ul = ul_by_prefix[prefix]; @@ -65,20 +67,28 @@ ul.ul.appendChild(li); } - const selectable_components_ul = by_id("selectable_components_ul"); + const chbx_components_ul = by_id("chbx_components_ul"); + const radio_components_ul = by_id("radio_components_ul"); - function selectable_li_id(prefix, item) + function chbx_li_id(prefix, item) { - return `sli_${prefix}_${item}`; + return `cli_${prefix}_${item}`; } - function add_selectable(prefix, name) + function radio_li_id(prefix, item) + { + return `rli_${prefix}_${item}`; + } + + //TODO: refactor the 2 functions below + + function add_chbx_li(prefix, name) { if (prefix === TYPE_PREFIX.PAGE) return; - let li = selectable_component_li_template.cloneNode(true); - li.id = selectable_li_id(prefix, name); + let li = chbx_component_li_template.cloneNode(true); + li.id = chbx_li_id(prefix, name); li.setAttribute("data-prefix", prefix); li.setAttribute("data-name", name); @@ -87,35 +97,102 @@ span.textContent = `${name} (${TYPE_NAME[prefix]})`; - selectable_components_ul.appendChild(li); + chbx_components_ul.appendChild(li); } - /* - * Used to construct and update components list of edited - * bag as well as edited page. - */ - function add_components(ul, components) + var radio_component_none_li = by_id("radio_component_none_li"); + + function add_radio_li(prefix, name) { - let components_ul = ul.work_name_input.nextElementSibling; + if (prefix === TYPE_PREFIX.PAGE) + return; + + let li = radio_component_li_template.cloneNode(true); + li.id = radio_li_id(prefix, name); + li.setAttribute("data-prefix", prefix); + li.setAttribute("data-name", name); + + let radio = li.firstElementChild; + let span = radio.nextElementSibling; + + span.textContent = `${name} (${TYPE_NAME[prefix]})`; + + radio_components_ul.insertBefore(li, radio_component_none_li); + } + + const page_payload_span = by_id("page_payload"); + + function set_page_components(components) + { + if (components === undefined) { + page_payload_span.setAttribute("data-payload", "no"); + page_payload_span.textContent = "(None)"; + } else { + page_payload_span.setAttribute("data-payload", "yes"); + let [prefix, name] = components; + page_payload_span.setAttribute("data-prefix", prefix); + page_payload_span.setAttribute("data-name", name); + page_payload_span.textContent = `${name} (${TYPE_NAME[prefix]})`; + } + } + const page_allow_chbx = by_id("page_allow_chbx"); + + /* Used to reset edited page. */ + function reset_work_page_li(ul, item, settings) + { + ul.work_name_input.value = item; + page_allow_chbx.checked = !!settings?.allow; + + set_page_components(settings?.components); + } + + function work_page_li_components() + { + if (page_payload_span.getAttribute("data-payload") === "no") + return undefined; + + let prefix = page_payload_span.getAttribute("data-prefix"); + let name = page_payload_span.getAttribute("data-name"); + return [prefix, name]; + } + + /* Used to get edited page data for saving. */ + function work_page_li_data(ul) + { + let url = ul.work_name_input.value; + let settings = { + components : work_page_li_components(), + allow : !!page_allow_chbx.checked + }; + + return [url, settings]; + } + + const empty_bag_component_li = by_id("empty_bag_component_li"); + var bag_components_ul = by_id("bag_components_ul"); + + /* Used to construct and update components list of edited bag. */ + function add_bag_components(components) + { for (let component of components) { let [prefix, name] = component; - let li = component_li_template.cloneNode(true); + let li = bag_component_li_template.cloneNode(true); li.setAttribute("data-prefix", prefix); li.setAttribute("data-name", name); let span = li.firstElementChild; span.textContent = `${name} (${TYPE_NAME[prefix]})`; let remove_but = span.nextElementSibling; remove_but.addEventListener("click", () => - components_ul.removeChild(li)); - components_ul.appendChild(li); + bag_components_ul.removeChild(li)); + bag_components_ul.appendChild(li); } - components_ul.appendChild(ul.work_empty_component_li); + bag_components_ul.appendChild(empty_bag_component_li); } - /* Used to reset edited bag as well as edited page. */ - function generic_reset_work_li(ul, item, components) + /* Used to reset edited bag. */ + function reset_work_bag_li(ul, item, components) { if (item === undefined) { item = ""; @@ -123,23 +200,17 @@ }; ul.work_name_input.value = item; - let old_components_ul = ul.work_name_input.nextElementSibling; - let components_ul = old_components_ul.cloneNode(false); + let old_components_ul = bag_components_ul; + bag_components_ul = old_components_ul.cloneNode(false); - ul.work_li.insertBefore(components_ul, old_components_ul); + ul.work_li.insertBefore(bag_components_ul, old_components_ul); ul.work_li.removeChild(old_components_ul); - add_components(ul, components); - } - - function reset_work_page_li(ul, item, settings) - { - ul.work_page_allow_chbx.checked = !!settings?.allow; - generic_reset_work_li(ul, item, settings?.components); + add_bag_components(components); } - /* Used to get edited bag as well as edited page data for saving. */ - function generic_work_li_data(ul) + /* Used to get edited bag data for saving. */ + function work_bag_li_data(ul) { let components_ul = ul.work_name_input.nextElementSibling; let component_li = components_ul.firstElementChild; @@ -156,14 +227,6 @@ return [ul.work_name_input.value, components]; } - function work_page_li_data(ul) - { - let [url, components] = generic_work_li_data(ul); - let settings = {components, allow : !!ul.work_page_allow_chbx.checked}; - - return [url, settings]; - } - const script_url_input = by_id("script_url_field"); const script_sha256_input = by_id("script_sha256_field"); const script_contents_field = by_id("script_contents_field"); @@ -173,6 +236,7 @@ return maybe_defined === undefined ? "" : maybe_defined + ""; } + /* Used to reset edited script. */ function reset_work_script_li(ul, name, data) { ul.work_name_input.value = maybe_string(name); @@ -181,6 +245,7 @@ script_contents_field.value = maybe_string(data?.text); } + /* Used to get edited script data for saving. */ function work_script_li_data(ul) { return [ul.work_name_input.value, { @@ -251,25 +316,24 @@ ul.state = UL_STATE.ADDING_ENTRY; } - const select_components_window = by_id("select_components_window"); - var select_prefix; + const chbx_components_window = by_id("chbx_components_window"); - function select_components(prefix) + function bag_components() { - select_prefix = prefix; - select_components_window.classList.remove("hide"); + chbx_components_window.classList.remove("hide"); + radio_components_window.classList.add("hide"); - for (let li of selectable_components_ul.children) { + for (let li of chbx_components_ul.children) { let chbx = li.firstElementChild; chbx.checked = false; } } - function commit_components() + function commit_bag_components() { let selected = []; - for (let li of selectable_components_ul.children) { + for (let li of chbx_components_ul.children) { let chbx = li.firstElementChild; if (!chbx.checked) continue; @@ -278,13 +342,59 @@ li.getAttribute("data-name")]); } - add_components(ul_by_prefix[select_prefix], selected); + add_bag_components(selected); + cancel_components(); + } + + const radio_components_window = by_id("radio_components_window"); + var radio_component_none_input = by_id("radio_component_none_input"); + + function page_components() + { + radio_components_window.classList.remove("hide"); + chbx_components_window.classList.add("hide"); + + radio_component_none_input.checked = true; + + let components = work_page_li_components(); + if (components === undefined) + return; + + let [prefix, item] = components; + let li = by_id(radio_li_id(prefix, item)); + if (li === null) + radio_component_none_input.checked = false; + else + li.firstElementChild.checked = true; + } + + function commit_page_components() + { + let components = null; + + for (let li of radio_components_ul.children) { + let radio = li.firstElementChild; + if (!radio.checked) + continue; + + components = [li.getAttribute("data-prefix"), + li.getAttribute("data-name")]; + + if (radio.id === "radio_component_none_input") + components = undefined; + + break; + } + + if (components !== null) + set_page_components(components); cancel_components(); } function cancel_components() { - select_components_window.classList.add("hide"); + chbx_components_window.classList.add("hide"); + radio_components_window.classList.add("hide"); } const UL_STATE = { @@ -298,10 +408,10 @@ ul : by_id("pages_ul"), work_li : by_id("work_page_li"), work_name_input : by_id("page_url_field"), - work_empty_component_li : by_id("empty_page_component_li"), - work_page_allow_chbx : by_id("page_allow_chbx"), reset_work_li : reset_work_page_li, get_work_li_data : work_page_li_data, + select_components : page_components, + commit_components : commit_page_components, state : UL_STATE.IDLE, edited_item : undefined, }, @@ -309,9 +419,10 @@ ul : by_id("bags_ul"), work_li : by_id("work_bag_li"), work_name_input : by_id("bag_name_field"), - work_empty_component_li : by_id("empty_bag_component_li"), - reset_work_li : generic_reset_work_li, - get_work_li_data : generic_work_li_data, + reset_work_li : reset_work_bag_li, + get_work_li_data : work_bag_li_data, + select_components : bag_components, + commit_components : commit_bag_components, state : UL_STATE.IDLE, edited_item : undefined, }, @@ -333,42 +444,46 @@ for (let prefix of list_prefixes) { for (let item of storage.get_all_names(prefix).sort()) { add_li(prefix, item, true); - add_selectable(prefix, item); + add_chbx_li(prefix, item); + add_radio_li(prefix, item); } - } - storage.add_change_listener(handle_change); + let name = TYPE_NAME[prefix]; - let commit_components_but = by_id("commit_components_but"); - let cancel_components_but = by_id("cancel_components_but"); - commit_components_but.addEventListener("click", commit_components); - cancel_components_but.addEventListener("click", cancel_components); - - for (let prefix of list_prefixes) { - let add_but = by_id(`add_${TYPE_NAME[prefix]}_but`); - let discard_but = by_id(`${TYPE_NAME[prefix]}_discard_but`); - let save_but = by_id(`${TYPE_NAME[prefix]}_save_but`); - let select_components_but = - by_id(`${TYPE_NAME[prefix]}_select_components_but`); + let add_but = by_id(`add_${name}_but`); + let discard_but = by_id(`discard_${name}_but`); + let save_but = by_id(`save_${name}_but`); add_but.addEventListener("click", () => add_new_item(prefix)); discard_but.addEventListener("click", () => cancel_work(prefix)); save_but.addEventListener("click", () => save_work(prefix)); - if (select_components_but === null) + + if (prefix === TYPE_PREFIX.SCRIPT) continue; - select_components_but.addEventListener( - "click", - () => select_components(prefix) - ); + let ul = ul_by_prefix[prefix]; + + let commit_components_but = by_id(`commit_${name}_components_but`); + let cancel_components_but = by_id(`cancel_${name}_components_but`); + let select_components_but = by_id(`select_${name}_components_but`); + + commit_components_but + .addEventListener("click", ul.commit_components); + select_components_but + .addEventListener("click", ul.select_components); + cancel_components_but.addEventListener("click", cancel_components); } + + storage.add_change_listener(handle_change); } function handle_change(change) { if (change.old_val === undefined) { add_li(change.prefix, change.item); - add_selectable(change.prefix, change.item); + add_chbx_li(change.prefix, change.item); + add_radio_li(change.prefix, change.item); + return; } @@ -382,14 +497,17 @@ return; } - let li = by_id(item_li_id(change.prefix, change.item)); - ul.ul.removeChild(li); + let uls_creators = [[ul.ul, item_li_id]]; - if (change.prefix === TYPE_PREFIX.PAGE) - return; + if (change.prefix !== TYPE_PREFIX.PAGE) { + uls_creators.push([chbx_components_ul, chbx_li_id]); + uls_creators.push([radio_components_ul, radio_li_id]); + } - let sli = by_id(selectable_li_id(change.prefix, change.item)); - selectable_components_ul.removeChild(sli); + for (let [components_ul, id_creator] of uls_creators) { + let li = by_id(id_creator(change.prefix, change.item)); + components_ul.remove_child(li); + } } main(); |