From b7e2870ff58ef85370781aa04e9e0126988e39fd Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 6 Jul 2021 18:25:34 +0200 Subject: show some settings of the current page in the popup --- html/display-panel.js | 226 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 225 insertions(+), 1 deletion(-) (limited to 'html/display-panel.js') diff --git a/html/display-panel.js b/html/display-panel.js index 4a4cdcd..9ae35fd 100644 --- a/html/display-panel.js +++ b/html/display-panel.js @@ -8,8 +8,232 @@ /* * IMPORTS_START * IMPORT browser + * IMPORT is_chrome + * IMPORT is_mozilla + * IMPORT CONNECTION_TYPE + * IMPORT url_item + * IMPORT is_privileged_url + * IMPORT TYPE_PREFIX + * IMPORT nice_name + * IMPORT open_in_settings + * IMPORT for_each_possible_pattern * IMPORTS_END */ -document.getElementById("settings_but") +function by_id(id) +{ + return document.getElementById(id); +} + +const tab_query = {currentWindow: true, active: true}; + +async function get_current_tab() +{ + /* Fix for fact that Chrome does not use promises here */ + const promise = is_chrome ? + new Promise((resolve, reject) => + browser.tabs.query(tab_query, tab => resolve(tab))) : + browser.tabs.query(tab_query); + + try { + return (await promise)[0]; + } catch(e) { + console.log(e); + } +} + +const page_url_heading = by_id("page_url_heading"); +const show_privileged_notice_chbx = by_id("show_privileged_notice_chbx"); +const show_page_state_chbx = by_id("show_page_state_chbx"); + +async function show_page_activity_info() +{ + const tab = await get_current_tab(); + + if (tab === undefined) { + page_url_heading.textContent = "unknown page"; + return; + } + + const url = url_item(tab.url); + page_url_heading.textContent = url; + if (is_privileged_url(url)) { + show_privileged_notice_chbx.checked = true; + return; + } + + populate_possible_patterns_list(url); + show_page_state_chbx.checked = true; + + try_to_connect(tab.id); +} + +function populate_possible_patterns_list(url) +{ + for_each_possible_pattern(url, add_pattern_to_list); + + const port = browser.runtime.connect({name: CONNECTION_TYPE.PAGE_INFO}); + port.onMessage.addListener(handle_page_info); + port.postMessage(["subscribe", url]); +} + +const possible_patterns_ul = by_id("possible_patterns"); +const pattern_li_template = by_id("pattern_li_template"); +pattern_li_template.removeAttribute("id"); +const known_patterns = new Map(); + +function add_pattern_to_list(pattern) +{ + const li = pattern_li_template.cloneNode(true); + li.id = `pattern_li_${known_patterns.size}`; + known_patterns.set(pattern, li.id); + + const span = li.firstElementChild; + span.textContent = pattern; + + const button = span.nextElementSibling; + const settings_opener = () => open_in_settings(TYPE_PREFIX.PAGE, pattern); + button.addEventListener("click", settings_opener); + + possible_patterns_ul.appendChild(li) + + return li.id; +} + +function ensure_pattern_exists(pattern) +{ + let id = known_patterns.get(pattern); + /* + * As long as pattern computation works well, we should never get into this + * conditional block. This is just a safety measure. To be removed as part + * of a bigger rework when we start taking iframes into account. + */ + if (id === undefined) { + console.log(`unknown pattern: ${pattern}`); + id = add_pattern_to_list(pattern); + } + + return id; +} + +function set_pattern_li_button_text(li_id, text) +{ + by_id(li_id).firstElementChild.nextElementSibling.textContent = text; +} + +function handle_page_info(message) +{ + const [type, data] = message; + + if (type === "change") { + const li_id = ensure_pattern_exists(data.item); + if (data.old_val === undefined) + set_pattern_li_button_text(li_id, "Edit in settings"); + if (data.new_val === undefined) + set_pattern_li_button_text(li_id, "Add setting"); + } + + if (type === "new_url") { + for (const li_id of known_patterns.values()) + set_pattern_li_button_text(li_id, "Add setting"); + for (const [pattern, settings] of data) { + set_pattern_li_button_text(ensure_pattern_exists(pattern), + "Edit in settings") + } + } +} + +const connected_chbx = by_id("connected_chbx"); + +function try_to_connect(tab_id) +{ + /* This won't connect to iframes. We'll add support for them later */ + const connect_info = {name: CONNECTION_TYPE.ACTIVITY_INFO, frameId: 0}; + const port = browser.tabs.connect(tab_id, connect_info); + + port.onDisconnect.addListener(port => handle_disconnect(tab_id)); + port.onMessage.addListener(handle_activity_report); + + if (is_mozilla) + setTimeout(() => monitor_connecting(port, tab_id), 1000); +} + +const loading_chbx = by_id("loading_chbx"); + +function handle_disconnect(tab_id) +{ + if (is_chrome && !browser.runtime.lastError) + return; + + /* return if there was no connection initialization failure */ + if (connected_chbx.checked) + return; + + loading_chbx.checked = !loading_chbx.checked; + setTimeout(() => try_to_connect(tab_id), 1000); +} + +function monitor_connecting(port, tab_id) +{ + if (connected_chbx.checked) + return; + + port.disconnect(); + loading_chbx.checked = !loading_chbx.checked; + try_to_connect(tab_id); +} + +const pattern_span = by_id("pattern"); +const view_pattern_but = by_id("view_pattern"); +const blocked_span = by_id("blocked"); +const payload_span = by_id("payload"); +const view_payload_but = by_id("view_payload"); +const container_for_injected = by_id("container_for_injected"); + +function handle_activity_report(message) +{ + connected_chbx.checked = true; + + const [type, data] = message; + + if (type === "settings") { + let [pattern, settings] = data; + + settings = settings || {}; + blocked_span.textContent = settings.allow ? "no" : "yes"; + + if (pattern) { + pattern_span.textContent = pattern; + const settings_opener = + () => open_in_settings(TYPE_PREFIX.PAGE, pattern); + view_pattern_but.classList.remove("hide"); + view_pattern_but.addEventListener("click", settings_opener); + } else { + pattern_span.textContent = "none"; + } + + const components = settings.components; + if (components) { + payload_span.textContent = nice_name(...components); + const settings_opener = () => open_in_settings(...components); + view_payload_but.classList.remove("hide"); + view_payload_but.addEventListener("click", settings_opener); + } else { + payload_span.textContent = "none"; + } + } + if (type === "script") { + const h4 = document.createElement("h4"); + const pre = document.createElement("pre"); + h4.textContent = "script"; + pre.textContent = data; + + container_for_injected.appendChild(h4); + container_for_injected.appendChild(pre); + } +} + +by_id("settings_but") .addEventListener("click", (e) => browser.runtime.openOptionsPage()); + +show_page_activity_info(); -- cgit v1.2.3