From 6247f163d3ca89d5570450ac7ac8fd18f73bb74b Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 2 Sep 2021 18:35:49 +0200 Subject: enable toggling of global script blocking policy\n\nThis commit also introduces `light_storage' module which is later going to replace the storage code we use right now.\nAlso included is a hack to properly display scrollbars under Mozilla (needs testing on newer Mozilla browsers). --- common/storage_light.js | 129 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 common/storage_light.js (limited to 'common/storage_light.js') diff --git a/common/storage_light.js b/common/storage_light.js new file mode 100644 index 0000000..067bf0c --- /dev/null +++ b/common/storage_light.js @@ -0,0 +1,129 @@ +/** + * part of Hachette + * Storage manager, lighter than the previous one. + * + * Copyright (C) 2021 Wojtek Kosior + * Redistribution terms are gathered in the `copyright' file. + */ + +/* + * IMPORTS_START + * IMPORT TYPE_PREFIX + * IMPORT raw_storage + * IMPORT is_mozilla + * IMPORT observables + */ + +const reg_spec = new Set(["\\", "[", "]", "(", ")", "{", "}", ".", "*", "+"]); +const escape_reg_special = c => reg_spec.has(c) ? "\\" + c : c; + +function make_regex(name) +{ + return new RegExp(`^${name.split("").map(escape_reg_special).join("")}\$`); +} + +const listeners_by_callback = new Map(); + +function listen(callback, prefix, name) +{ + let by_prefix = listeners_by_callback.get(callback); + if (!by_prefix) { + by_prefix = new Map(); + listeners_by_callback.set(callback, by_prefix); + } + + let by_name = by_prefix.get(prefix); + if (!by_name) { + by_name = new Map(); + by_prefix.set(prefix, by_name); + } + + let name_reg = by_name.get(name); + if (!name_reg) { + name_reg = name.test ? name : make_regex(name); + by_name.set(name, name_reg); + } +} + +function no_listen(callback, prefix, name) +{ + const by_prefix = listeners_by_callback.get(callback); + if (!by_prefix) + return; + + const by_name = by_prefix.get(prefix); + if (!by_name) + return; + + const name_reg = by_name.get(name); + if (!name_reg) + return; + + by_name.delete(name); + + if (by_name.size === 0) + by_prefix.delete(prefix); + + if (by_prefix.size === 0) + listeners_by_callback.delete(callback); +} + +function storage_change_callback(changes, area) +{ + if (is_mozilla && area !== "local") + {console.log("area", area);return;} + + for (const item of Object.keys(changes)) { + for (const [callback, by_prefix] of listeners_by_callback.entries()) { + const by_name = by_prefix.get(item[0]); + if (!by_name) + continue; + + for (const reg of by_name.values()) { + if (!reg.test(item.substring(1))) + continue; + + try { + callback(item, changes[item]); + } catch(e) { + console.error(e); + } + } + } + } +} + +raw_storage.listen(storage_change_callback); + + +const created_observables = new Map(); + +async function observe(prefix, name) +{ + const observable = observables.make(); + const callback = (it, ch) => observables.set(observable, ch.newValue); + listen(callback, prefix, name); + created_observables.set(observable, [callback, prefix, name]); + observables.silent_set(observable, await raw_storage.get(prefix + name)); + + return observable; +} + +const observe_var = name => observe(TYPE_PREFIX.VAR, name); + +function no_observe(observable) +{ + no_listen(...created_observables.get(observable) || []); + created_observables.delete(observable); +} + +const light_storage = {}; +Object.assign(light_storage, raw_storage); +Object.assign(light_storage, + {listen, no_listen, observe, observe_var, no_observe}); + +/* + * EXPORTS_START + * EXPORT light_storage + * EXPORTS_END + */ -- cgit v1.2.3 From 2bd35bc4b0d32b70320b06d932db90e75e89373e Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 13 Sep 2021 16:56:44 +0200 Subject: rename the extension to "Haketilo" --- README.txt | 6 +- background/cookie_filter.js | 17 ++--- background/main.js | 4 +- background/page_actions_server.js | 4 +- background/policy_injector.js | 26 ++++---- background/storage.js | 4 +- background/storage_server.js | 4 +- background/stream_filter.js | 6 +- common/ajax.js | 5 +- common/connection_types.js | 4 +- common/lock.js | 4 +- common/message_server.js | 4 +- common/misc.js | 4 +- common/observable.js | 5 +- common/once.js | 5 +- common/patterns.js | 4 +- common/sanitize_JSON.js | 5 +- common/settings_query.js | 4 +- common/signing.js | 7 ++- common/storage_client.js | 4 +- common/storage_light.js | 5 +- common/storage_raw.js | 5 +- common/stored_types.js | 4 +- content/activity_info_server.js | 7 ++- content/main.js | 22 ++++--- content/page_actions.js | 6 +- content/repo_query.js | 5 +- copyright | 2 +- html/DOM_helpers.js | 4 +- html/MOZILLA_scrollbar_fix.css | 6 +- html/back_button.css | 5 +- html/base.css | 4 +- html/default_blocking_policy.js | 5 +- html/display-panel.html | 8 ++- html/display-panel.js | 4 +- html/import_frame.js | 4 +- html/options.html | 6 +- html/options_main.js | 4 +- icons/hachette.svg | 127 -------------------------------------- icons/hachette128.png | Bin 6031 -> 0 bytes icons/hachette16.png | Bin 752 -> 0 bytes icons/hachette32.png | Bin 1358 -> 0 bytes icons/hachette48.png | Bin 2154 -> 0 bytes icons/hachette64.png | Bin 2908 -> 0 bytes icons/haketilo.svg | 127 ++++++++++++++++++++++++++++++++++++++ icons/haketilo128.png | Bin 0 -> 6031 bytes icons/haketilo16.png | Bin 0 -> 752 bytes icons/haketilo32.png | Bin 0 -> 1358 bytes icons/haketilo48.png | Bin 0 -> 2154 bytes icons/haketilo64.png | Bin 0 -> 2908 bytes manifest.json | 28 +++++---- re-generate_icons.sh | 2 +- 52 files changed, 292 insertions(+), 224 deletions(-) delete mode 100644 icons/hachette.svg delete mode 100644 icons/hachette128.png delete mode 100644 icons/hachette16.png delete mode 100644 icons/hachette32.png delete mode 100644 icons/hachette48.png delete mode 100644 icons/hachette64.png create mode 100644 icons/haketilo.svg create mode 100644 icons/haketilo128.png create mode 100644 icons/haketilo16.png create mode 100644 icons/haketilo32.png create mode 100644 icons/haketilo48.png create mode 100644 icons/haketilo64.png (limited to 'common/storage_light.js') diff --git a/README.txt b/README.txt index ad640b0..1aec0ba 100644 --- a/README.txt +++ b/README.txt @@ -1,4 +1,4 @@ -# Hachette - Make The Web Great Again! # +# Haketilo - Make The Web Great Again! # This extension's goal is to allow replacing javascript served by websites with scripts specified by user. Something like NoScript and Greasemonkey @@ -9,7 +9,7 @@ Currently, the target browsers for this extension are Ungoogled Chromium and various forks of Firefox (version 60+). This extension is still in an early stage. Also see -`https://hachettebugs.koszko.org/projects/hachette/wiki/' for documentation in +`https://hydrillabugs.koszko.org/projects/haketilo/wiki/' for documentation in development. ## Installation ## @@ -28,6 +28,6 @@ various additional licenses and permissions for particular files. ## Contributing ## Get the code from: https://git.koszko.org/browser-extension/ -Come to: https://hachettebugs.koszko.org/projects/hachette +Come to: https://hydrillabugs.koszko.org/projects/haketilo Optionally, write to $(echo a29zemtvQGtvc3prby5vcmcK | base64 -d) diff --git a/background/cookie_filter.js b/background/cookie_filter.js index fea2d23..64d18b2 100644 --- a/background/cookie_filter.js +++ b/background/cookie_filter.js @@ -1,7 +1,8 @@ /** - * part of Hachette - * Filtering request headers to remove hachette cookies that might have slipped - * through. + * This file is part of Haketilo. + * + * Function: Filtering request headers to remove haketilo cookies that might + * have slipped through. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. @@ -13,29 +14,29 @@ * IMPORTS_END */ -function is_valid_hachette_cookie(cookie) +function is_valid_haketilo_cookie(cookie) { - const match = /^hachette-(\w*)=(.*)$/.exec(cookie); + const match = /^haketilo-(\w*)=(.*)$/.exec(cookie); if (!match) return false; return !extract_signed(match.slice(1, 3)).fail; } -function remove_hachette_cookies(header) +function remove_haketilo_cookies(header) { if (header.name !== "Cookie") return header; const cookies = header.value.split("; "); - const value = cookies.filter(c => !is_valid_hachette_cookie(c)).join("; "); + const value = cookies.filter(c => !is_valid_haketilo_cookie(c)).join("; "); return value ? {name: "Cookie", value} : null; } function filter_cookie_headers(headers) { - return headers.map(remove_hachette_cookies).filter(h => h); + return headers.map(remove_haketilo_cookies).filter(h => h); } /* diff --git a/background/main.js b/background/main.js index 03cd5d7..40b3a9e 100644 --- a/background/main.js +++ b/background/main.js @@ -1,5 +1,7 @@ /** - * Hachette main background script + * This file is part of Haketilo. + * + * Function: Main background script. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/background/page_actions_server.js b/background/page_actions_server.js index e21ca6e..156a79f 100644 --- a/background/page_actions_server.js +++ b/background/page_actions_server.js @@ -1,5 +1,7 @@ /** - * Hachette serving of page actions to content scripts + * This file is part of Haketilo. + * + * Function: Serving page actions to content scripts. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/background/policy_injector.js b/background/policy_injector.js index e5af055..881595b 100644 --- a/background/policy_injector.js +++ b/background/policy_injector.js @@ -1,5 +1,7 @@ /** - * Hachette injecting policy to page using webRequest + * This file is part of Haketilo. + * + * Function: Injecting policy to page by modifying HTTP headers. * * Copyright (C) 2021 Wojtek Kosior * Copyright (C) 2021 jahoti @@ -19,10 +21,10 @@ function inject_csp_headers(headers, policy) { let csp_headers; let old_signature; - let hachette_header; + let haketilo_header; - for (const header of headers.filter(h => h.name === "x-hachette")) { - /* x-hachette header has format: _0_ */ + for (const header of headers.filter(h => h.name === "x-haketilo")) { + /* x-haketilo header has format: _0_ */ const match = /^([^_]+)_(0_.*)$/.exec(header.value); if (!match) continue; @@ -38,7 +40,7 @@ function inject_csp_headers(headers, policy) csp_headers = old_data.csp_headers; old_signature = old_data.policy_sig; - hachette_header = header; + haketilo_header = header; break; } @@ -53,9 +55,9 @@ function inject_csp_headers(headers, policy) headers.push(...csp_headers || []); } - if (!hachette_header) { - hachette_header = {name: "x-hachette"}; - headers.push(hachette_header); + if (!haketilo_header) { + haketilo_header = {name: "x-haketilo"}; + headers.push(haketilo_header); } if (old_signature) @@ -66,7 +68,7 @@ function inject_csp_headers(headers, policy) const later_30sec = new Date(new Date().getTime() + 30000).toGMTString(); headers.push({ name: "Set-Cookie", - value: `hachette-${signed_policy.join("=")}; Expires=${later_30sec};` + value: `haketilo-${signed_policy.join("=")}; Expires=${later_30sec};` }); /* @@ -74,9 +76,9 @@ function inject_csp_headers(headers, policy) * These are signed with a time of 0, as it's not clear there is a limit on * how long Firefox might retain headers in the cache. */ - let hachette_data = {csp_headers, policy_sig: signed_policy[0]}; - hachette_data = encodeURIComponent(JSON.stringify(hachette_data)); - hachette_header.value = sign_data(hachette_data, 0).join("_"); + let haketilo_data = {csp_headers, policy_sig: signed_policy[0]}; + haketilo_data = encodeURIComponent(JSON.stringify(haketilo_data)); + haketilo_header.value = sign_data(haketilo_data, 0).join("_"); if (!policy.allow) { headers.push({ diff --git a/background/storage.js b/background/storage.js index 12c0c61..a4e626a 100644 --- a/background/storage.js +++ b/background/storage.js @@ -1,5 +1,7 @@ /** - * Hachette storage manager + * This file is part of Haketilo. + * + * Function: Storage manager. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/background/storage_server.js b/background/storage_server.js index 2252eb5..73126d4 100644 --- a/background/storage_server.js +++ b/background/storage_server.js @@ -1,5 +1,7 @@ /** - * Hachette storage through connection (server side) + * This file is part of Haketilo. + * + * Function: Storage through messages (server side). * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/background/stream_filter.js b/background/stream_filter.js index 3e30a4b..e5e0827 100644 --- a/background/stream_filter.js +++ b/background/stream_filter.js @@ -1,5 +1,7 @@ /** - * Hachette modifying a web page using the StreamFilter API + * This file is part of Haketilo. + * + * Function: Modifying a web page using the StreamFilter API. * * Copyright (C) 2018 Giorgio Maone * Copyright (C) 2021 Wojtek Kosior @@ -173,7 +175,7 @@ function filter_data(properties, event) */ const dummy_script = - ``; + ``; const doctype_decl = /^(\s*"']*>)?/i.exec(decoded)[0]; decoded = doctype_decl + dummy_script + decoded.substring(doctype_decl.length); diff --git a/common/ajax.js b/common/ajax.js index 8082bbe..7269a8a 100644 --- a/common/ajax.js +++ b/common/ajax.js @@ -1,6 +1,7 @@ /** - * part of Hachette - * Wrapping XMLHttpRequest into a Promise. + * This file is part of Haketilo. + * + * Function: Wrapping XMLHttpRequest into a Promise. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/connection_types.js b/common/connection_types.js index 88c6964..3e9df56 100644 --- a/common/connection_types.js +++ b/common/connection_types.js @@ -1,5 +1,7 @@ /** - * Hachette background scripts message connection types "enum" + * This file is part of Haketilo. + * + * Function: Define an "enum" of message connection types. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/lock.js b/common/lock.js index 822ad1b..6cf0835 100644 --- a/common/lock.js +++ b/common/lock.js @@ -1,5 +1,7 @@ /** - * Hachette lock (aka binary semaphore aka mutex) + * This file is part of Haketilo. + * + * Function: Implement a lock (aka binary semaphore aka mutex). * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/message_server.js b/common/message_server.js index ea40487..c8c6696 100644 --- a/common/message_server.js +++ b/common/message_server.js @@ -1,5 +1,7 @@ /** - * Hachette message server + * This file is part of Haketilo. + * + * Function: Message server. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/misc.js b/common/misc.js index 6cded84..9ffb7ff 100644 --- a/common/misc.js +++ b/common/misc.js @@ -1,5 +1,7 @@ /** - * Hachette miscellaneous operations refactored to a separate file + * This file is part of Haketilo. + * + * Function: Miscellaneous operations refactored to a separate file. * * Copyright (C) 2021 Wojtek Kosior * Copyright (C) 2021 jahoti diff --git a/common/observable.js b/common/observable.js index 02f1c1b..ab3b444 100644 --- a/common/observable.js +++ b/common/observable.js @@ -1,6 +1,7 @@ /** - * part of Hachette - * Facilitate listening to events + * This file is part of Haketilo. + * + * Function: Facilitate listening to (internal, self-generated) events. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/once.js b/common/once.js index 098b43f..93e842f 100644 --- a/common/once.js +++ b/common/once.js @@ -1,5 +1,8 @@ /** - * Hachette feature initialization promise + * This file is part of Haketilo. + * + * Function: Wrap APIs that depend on some asynchronous initialization into + * promises. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/patterns.js b/common/patterns.js index ae29fcd..625be05 100644 --- a/common/patterns.js +++ b/common/patterns.js @@ -1,5 +1,7 @@ /** - * Hachette operations on page url patterns + * This file is part of Haketilo. + * + * Function: Operations on page URL patterns. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/sanitize_JSON.js b/common/sanitize_JSON.js index 8b86d2d..4cf1ef4 100644 --- a/common/sanitize_JSON.js +++ b/common/sanitize_JSON.js @@ -1,6 +1,7 @@ /** - * part of Hachette - * Powerful, full-blown format enforcer for externally-obtained JSON + * This file is part of Haketilo. + * + * Function: Powerful, full-blown format enforcer for externally-obtained JSON. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/settings_query.js b/common/settings_query.js index b54e580..7e1315e 100644 --- a/common/settings_query.js +++ b/common/settings_query.js @@ -1,5 +1,7 @@ /** - * Hachette querying page settings with regard to wildcard records + * This file is part of Haketilo. + * + * Function: Querying page settings. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/signing.js b/common/signing.js index 1904bcd..11cd442 100644 --- a/common/signing.js +++ b/common/signing.js @@ -1,6 +1,7 @@ /** - * part of Hachette - * Functions related to "signing" of data, refactored to a separate file. + * This file is part of Haketilo. + * + * Functions: Operations related to "signing" of data. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. @@ -16,7 +17,7 @@ /* * In order to make certain data synchronously accessible in certain contexts, - * hachette smuggles it in string form in places like cookies, URLs and headers. + * Haketilo smuggles it in string form in places like cookies, URLs and headers. * When using the smuggled data, we first need to make sure it isn't spoofed. * For that, we use this pseudo-signing mechanism. * diff --git a/common/storage_client.js b/common/storage_client.js index 2b2f495..ef4a0b8 100644 --- a/common/storage_client.js +++ b/common/storage_client.js @@ -1,5 +1,7 @@ /** - * Hachette storage through connection (client side) + * This file is part of Haketilo. + * + * Function: Storage through messages (client side). * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/storage_light.js b/common/storage_light.js index 067bf0c..32e3b1f 100644 --- a/common/storage_light.js +++ b/common/storage_light.js @@ -1,6 +1,7 @@ /** - * part of Hachette - * Storage manager, lighter than the previous one. + * This file is part of Haketilo. + * + * Function: Storage manager, lighter than the previous one. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/storage_raw.js b/common/storage_raw.js index 4c02ee4..e354b6b 100644 --- a/common/storage_raw.js +++ b/common/storage_raw.js @@ -1,6 +1,7 @@ /** - * part of Hachette - * Basic wrappers for storage API functions. + * This file is part of Haketilo. + * + * Function: Basic wrappers for storage API functions. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/common/stored_types.js b/common/stored_types.js index bfceba6..a693b1c 100644 --- a/common/stored_types.js +++ b/common/stored_types.js @@ -1,5 +1,7 @@ /** - * Hachette stored item types "enum" + * This file is part of Haketilo. + * + * Function: Define an "enum" of stored item types. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/content/activity_info_server.js b/content/activity_info_server.js index 1b69703..d1dfe36 100644 --- a/content/activity_info_server.js +++ b/content/activity_info_server.js @@ -1,7 +1,8 @@ /** - * part of Hachette - * Informing about activities performed by content script (script injection, - * script blocking). + * This file is part of Haketilo. + * + * Function: Informing the popup about what happens in the content script + * (script injection, script blocking, etc.). * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/content/main.js b/content/main.js index 6478ea0..cec9943 100644 --- a/content/main.js +++ b/content/main.js @@ -1,5 +1,7 @@ /** - * Hachette main content script run in all frames + * This file is part of Haketilo. + * + * Function: Main content script that runs in all frames. * * Copyright (C) 2021 Wojtek Kosior * Copyright (C) 2021 jahoti @@ -33,7 +35,7 @@ function extract_cookie_policy(cookie, min_time) let policy = null; const extracted_signatures = []; - for (const match of cookie.matchAll(/hachette-(\w*)=([^;]*)/g)) { + for (const match of cookie.matchAll(/haketilo-(\w*)=([^;]*)/g)) { const new_result = extract_signed(...match.slice(1, 3)); if (new_result.fail) continue; @@ -60,7 +62,7 @@ function extract_url_policy(url, min_time) const [base_url, payload, anchor] = /^([^#]*)#?([^#]*)(#?.*)$/.exec(url).splice(1, 4); - const match = /^hachette_([^_]+)_(.*)$/.exec(payload); + const match = /^haketilo_([^_]+)_(.*)$/.exec(payload); if (!match) return [null, url]; @@ -83,7 +85,7 @@ function employ_nonhttp_policy(policy) policy.nonce = gen_nonce(); const [base_url, target] = /^([^#]*)(#?.*)$/.exec(policy.url).slice(1, 3); const encoded_policy = encodeURIComponent(JSON.stringify(policy)); - const payload = "hachette_" + + const payload = "haketilo_" + sign_data(encoded_policy, new Date().getTime()).join("_"); const resulting_url = `${base_url}#${payload}${target}`; location.href = resulting_url; @@ -187,7 +189,7 @@ function sanitize_meta(meta) function sanitize_script(script) { - script.hachette_blocked_type = script.getAttribute("type"); + script.haketilo_blocked_type = script.getAttribute("type"); script.type = "text/plain"; } @@ -197,12 +199,12 @@ function sanitize_script(script) */ function desanitize_script(script) { - script.setAttribute("type", script.hachette_blocked_type); + script.setAttribute("type", script.haketilo_blocked_type); - if ([null, undefined].includes(script.hachette_blocked_type)) + if ([null, undefined].includes(script.haketilo_blocked_type)) script.removeAttribute("type"); - delete script.hachette_blocked_type; + delete script.haketilo_blocked_type; } const bad_url_reg = /^data:([^,;]*ml|unknown-content-type)/i; @@ -235,7 +237,7 @@ function start_data_urls_sanitizing(doc) */ function prevent_script_execution(event) { - if (!event.target._hachette_payload) + if (!event.target.haketilo_payload) event.preventDefault(); } @@ -336,7 +338,7 @@ if (!is_privileged_url(document.URL)) { let signatures; [policy, signatures] = extract_cookie_policy(document.cookie, min_time); for (const signature of signatures) - document.cookie = `hachette-${signature}=; Max-Age=-1;`; + document.cookie = `haketilo-${signature}=; Max-Age=-1;`; } else { const scheme = /^([^:]*)/.exec(document.URL)[1]; const known_scheme = ["file", "ftp"].includes(scheme); diff --git a/content/page_actions.js b/content/page_actions.js index 040b4ab..db7c352 100644 --- a/content/page_actions.js +++ b/content/page_actions.js @@ -1,5 +1,7 @@ /** - * Hachette handling of page actions in content scripts + * This file is part of Haketilo. + * + * Function: Handle page actions in a content script. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. @@ -60,7 +62,7 @@ function add_script(script_text) let script = document.createElement("script"); script.textContent = script_text; script.setAttribute("nonce", nonce); - script._hachette_payload = true; + script.haketilo_payload = true; document.body.appendChild(script); report_script(script_text); diff --git a/content/repo_query.js b/content/repo_query.js index 3708108..637282c 100644 --- a/content/repo_query.js +++ b/content/repo_query.js @@ -1,6 +1,7 @@ /** - * part of Hachette - * Getting available content for site from remote repositories. + * This file is part of Haketilo. + * + * Function: Getting available content for site from remote repositories. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/copyright b/copyright index 4c37eb3..fe2aed7 100644 --- a/copyright +++ b/copyright @@ -1,5 +1,5 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: Hachette +Upstream-Name: Haketilo Source: https://git.koszko.org/browser-extension/ Files: * diff --git a/html/DOM_helpers.js b/html/DOM_helpers.js index 01e2be9..4fe118d 100644 --- a/html/DOM_helpers.js +++ b/html/DOM_helpers.js @@ -1,5 +1,7 @@ /** - * Hachette operations on DOM elements + * This file is part of Haketilo. + * + * Function: Operations on DOM elements. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/html/MOZILLA_scrollbar_fix.css b/html/MOZILLA_scrollbar_fix.css index 5feb7c3..cdbd5c6 100644 --- a/html/MOZILLA_scrollbar_fix.css +++ b/html/MOZILLA_scrollbar_fix.css @@ -1,6 +1,8 @@ /** - * Hachette - * Hacky fix for vertical scrollbar width being included in child's width. + * This file is part of Haketilo. + * + * Function: Hacky fix for vertical scrollbar width being included in child's + * width. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/html/back_button.css b/html/back_button.css index 1ddc5da..b83e834 100644 --- a/html/back_button.css +++ b/html/back_button.css @@ -1,6 +1,7 @@ /** - * part of Hachette - * Style for a "back" button with a CSS arrow image. + * This file is part of Haketilo. + * + * Function: Style for a "back" button with a CSS arrow image. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/html/base.css b/html/base.css index df52f7c..517a5c1 100644 --- a/html/base.css +++ b/html/base.css @@ -1,5 +1,7 @@ /** - * Hachette base styles + * This file is part of Haketilo. + * + * Function: Base styles. * * Copyright (C) 2021 Wojtek Kosior * Copyright (C) 2021 Nicholas Johnson diff --git a/html/default_blocking_policy.js b/html/default_blocking_policy.js index 2f49bac..b6458f3 100644 --- a/html/default_blocking_policy.js +++ b/html/default_blocking_policy.js @@ -1,6 +1,7 @@ /** - * part of Hachette - * Default policy dialog logic. + * This file is part of Haketilo. + * + * Function: Logic for the dialog of default policy selection. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/html/display-panel.html b/html/display-panel.html index 3ed1b7a..ee9e767 100644 --- a/html/display-panel.html +++ b/html/display-panel.html @@ -1,12 +1,16 @@ - Hachette - page settings + Haketilo - page settings @@ -331,7 +335,7 @@ diff --git a/html/display-panel.js b/html/display-panel.js index 84c922f..c078850 100644 --- a/html/display-panel.js +++ b/html/display-panel.js @@ -1,5 +1,7 @@ /** - * Hachette display panel logic + * This file is part of Haketilo. + * + * Function: Popup logic. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/html/import_frame.js b/html/import_frame.js index c0eb2f0..ae6fab4 100644 --- a/html/import_frame.js +++ b/html/import_frame.js @@ -1,5 +1,7 @@ /** - * Hachette HTML import frame script + * This file is part of Haketilo. + * + * Function: Logic for the settings import frame. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/html/options.html b/html/options.html index 54ab9e8..2e8317c 100644 --- a/html/options.html +++ b/html/options.html @@ -1,12 +1,16 @@ - Hachette options + Haketilo options diff --git a/html/options_main.js b/html/options_main.js index 27ab0ec..f8faf9b 100644 --- a/html/options_main.js +++ b/html/options_main.js @@ -1,5 +1,7 @@ /** - * Hachette HTML options page main script + * This file is part of Haketilo. + * + * Function: Settings page logic. * * Copyright (C) 2021 Wojtek Kosior * Redistribution terms are gathered in the `copyright' file. diff --git a/icons/hachette.svg b/icons/hachette.svg deleted file mode 100644 index 6e8948d..0000000 --- a/icons/hachette.svg +++ /dev/null @@ -1,127 +0,0 @@ - - - Hatchet - - - - - - - - - - - - image/svg+xml - - Hatchet - - - David Lyons - - - - - dlyons - - - - 2017-05 - - - hatchet - ax - wood - - - Hatchet - - - - - - - - - - - - - - - - - - - - - - diff --git a/icons/hachette128.png b/icons/hachette128.png deleted file mode 100644 index 18816e9..0000000 Binary files a/icons/hachette128.png and /dev/null differ diff --git a/icons/hachette16.png b/icons/hachette16.png deleted file mode 100644 index 182ede5..0000000 Binary files a/icons/hachette16.png and /dev/null differ diff --git a/icons/hachette32.png b/icons/hachette32.png deleted file mode 100644 index ffaa84b..0000000 Binary files a/icons/hachette32.png and /dev/null differ diff --git a/icons/hachette48.png b/icons/hachette48.png deleted file mode 100644 index 1ffcd38..0000000 Binary files a/icons/hachette48.png and /dev/null differ diff --git a/icons/hachette64.png b/icons/hachette64.png deleted file mode 100644 index a02abb0..0000000 Binary files a/icons/hachette64.png and /dev/null differ diff --git a/icons/haketilo.svg b/icons/haketilo.svg new file mode 100644 index 0000000..6e8948d --- /dev/null +++ b/icons/haketilo.svg @@ -0,0 +1,127 @@ + + + Hatchet + + + + + + + + + + + + image/svg+xml + + Hatchet + + + David Lyons + + + + + dlyons + + + + 2017-05 + + + hatchet + ax + wood + + + Hatchet + + + + + + + + + + + + + + + + + + + + + + diff --git a/icons/haketilo128.png b/icons/haketilo128.png new file mode 100644 index 0000000..18816e9 Binary files /dev/null and b/icons/haketilo128.png differ diff --git a/icons/haketilo16.png b/icons/haketilo16.png new file mode 100644 index 0000000..182ede5 Binary files /dev/null and b/icons/haketilo16.png differ diff --git a/icons/haketilo32.png b/icons/haketilo32.png new file mode 100644 index 0000000..ffaa84b Binary files /dev/null and b/icons/haketilo32.png differ diff --git a/icons/haketilo48.png b/icons/haketilo48.png new file mode 100644 index 0000000..1ffcd38 Binary files /dev/null and b/icons/haketilo48.png differ diff --git a/icons/haketilo64.png b/icons/haketilo64.png new file mode 100644 index 0000000..a02abb0 Binary files /dev/null and b/icons/haketilo64.png differ diff --git a/manifest.json b/manifest.json index ce2577e..9d34732 100644 --- a/manifest.json +++ b/manifest.json @@ -1,18 +1,20 @@ +// This is the manifest file of Haketilo. +// // Copyright (C) 2021 Wojtek Kosior // Redistribution terms are gathered in the `copyright' file. { "manifest_version": 2, - "name": "Hachette", - "short_name": "Hachette", + "name": "Haketilo", + "short_name": "Haketilo", "version": "0.0.1", "author": "various", "description": "Control your \"Web\" browsing.",_GECKO_APPLICATIONS_ "icons":{ - "128": "icons/hachette128.png", - "64": "icons/hachette64.png", - "48": "icons/hachette48.png", - "32": "icons/hachette32.png", - "16": "icons/hachette16.png" + "128": "icons/haketilo128.png", + "64": "icons/haketilo64.png", + "48": "icons/haketilo48.png", + "32": "icons/haketilo32.png", + "16": "icons/haketilo16.png" }, "permissions": [ "contextMenus", @@ -29,13 +31,13 @@ "browser_action": { "browser_style": true, "default_icon": { - "128": "icons/hachette128.png", - "64": "icons/hachette64.png", - "48": "icons/hachette48.png", - "32": "icons/hachette32.png", - "16": "icons/hachette16.png" + "128": "icons/haketilo128.png", + "64": "icons/haketilo64.png", + "48": "icons/haketilo48.png", + "32": "icons/haketilo32.png", + "16": "icons/haketilo16.png" }, - "default_title": "Hachette", + "default_title": "Haketilo", "default_popup": "html/display-panel.html" }, "options_ui": { diff --git a/re-generate_icons.sh b/re-generate_icons.sh index ba0c28a..e557ad0 100755 --- a/re-generate_icons.sh +++ b/re-generate_icons.sh @@ -4,5 +4,5 @@ # Redistribution terms are gathered in the `copyright' file. for SIZE in 128 64 48 32 16; do - inkscape -z -e icons/hachette$SIZE.png -w $SIZE -h $SIZE icons/hachette.svg + inkscape -z -e icons/haketilo$SIZE.png -w $SIZE -h $SIZE icons/haketilo.svg done -- cgit v1.2.3 From 6106c789ee818fd18240fd3f99eead598406852f Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 30 Nov 2021 19:31:49 +0100 Subject: rewrite parts of build script in awk --- CHROMIUM_exports_init.js | 3 + MOZILLA_exports_init.js | 57 +++++++++++ build.sh | 257 +++++++++++------------------------------------ common/storage_light.js | 1 + compute_scripts.awk | 196 ++++++++++++++++++++++++++++++++++++ copyright | 3 +- process_html_file.sh | 2 +- shell_utils.sh | 25 ++--- upload_amo.sh | 25 +++-- write_makefile.sh | 4 +- 10 files changed, 343 insertions(+), 230 deletions(-) create mode 100644 CHROMIUM_exports_init.js create mode 100644 MOZILLA_exports_init.js create mode 100644 compute_scripts.awk (limited to 'common/storage_light.js') diff --git a/CHROMIUM_exports_init.js b/CHROMIUM_exports_init.js new file mode 100644 index 0000000..d2ca065 --- /dev/null +++ b/CHROMIUM_exports_init.js @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: CC0-1.0 + +window.killtheweb={is_chrome: true, browser: window.chrome}; diff --git a/MOZILLA_exports_init.js b/MOZILLA_exports_init.js new file mode 100644 index 0000000..0015f0c --- /dev/null +++ b/MOZILLA_exports_init.js @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +/** + * This file is part of Haketilo. + * + * Function: Data structure to query items by URL patterns. + * + * Copyright (C) 2021 Wojtek Kosior + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * As additional permission under GNU GPL version 3 section 7, you + * may distribute forms of that code without the copy of the GNU + * GPL normally required by section 4, provided you include this + * license notice and, in case of non-source distribution, a URL + * through which recipients can access the Corresponding Source. + * If you modify file(s) with this exception, you may extend this + * exception to your version of the file(s), but you are not + * obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + * + * As a special exception to the GPL, any HTML file which merely + * makes function calls to this code, and for that purpose + * includes it by reference shall be deemed a separate work for + * copyright law purposes. If you modify this code, you may extend + * this exception to your version of the code, but you are not + * obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * I, Wojtek Kosior, thereby promise not to sue for violation of this file's + * license. Although I request that you do not make use this code in a + * proprietary program, I am not going to enforce this in court. + */ + +/* Polyfill for IceCat 60. */ +String.prototype.matchAll = String.prototype.matchAll || function(regex) { + if (regex.flags.search("g") === -1) + throw new TypeError("String.prototype.matchAll called with a non-global RegExp argument"); + + for (const matches = [];;) { + if (matches[matches.push(regex.exec(this)) - 1] === null) + return matches.splice(0, matches.length - 1); + } +} + +window.killtheweb={is_mozilla: true, browser: this.browser}; diff --git a/build.sh b/build.sh index ed6a141..3d3d4be 100755 --- a/build.sh +++ b/build.sh @@ -3,180 +3,70 @@ # Copyright (C) 2021 Wojtek Kosior # Redistribution terms are gathered in the `copyright' file. -handle_export_line() { - if [ "x$1" = "xEXPORTS_START" ]; then - if [ "$STATE" = "before_block" ]; then - STATE="in_block" - fi - elif [ "x$1" = "xEXPORT" ]; then - if [ "$STATE" != "in_block" ]; then - return - fi - - EXPORTCODE="${EXPORTCODE}window.killtheweb.$2 = $2;$ENDL" - - PREVIOUS_FILE="$(map_get EXPORTS $2)" - if [ "x$PREVIOUS_FILE" != "x" ]; then - errcho "export $2 present in both $PREVIOUS_FILE and $FILE" - return 1 - fi - - map_set_instr EXPORTS $2 "$FILE" - - elif [ "x$1" = "xEXPORTS_END" ]; then - if [ "$STATE" = "in_block" ]; then - STATE="after_block" - fi - fi -} - -translate_exports() { - STATE="before_block" - EXPORTCODE='' - - while read EXPORT_LINE; do - handle_export_line $EXPORT_LINE || return 1 - done - - map_set_instr EXPORTCODES $FILEKEY "$EXPORTCODE" -} - -add_exports() { - FILE="$1" - FILEKEY="$(sanitize "$FILE")" - - eval "$(grep -o 'EXPORT.\+' "$1" | translate_exports || exit 1)" -} - -handle_import_line() { - if [ "x$1" = "xIMPORTS_START" ]; then - if [ "$STATE" = "before_block" ]; then - STATE="in_block" - fi - elif [ "x$1" = "xIMPORT" ]; then - if [ "$STATE" != "in_block" ]; then - return - fi - - IMPORTCODE="${IMPORTCODE}const $2 = window.killtheweb.$2;$ENDL" - - IMPORTS="$IMPORTS $2" - - elif [ "x$1" = "xIMPORTS_END" ]; then - if [ "$STATE" = "in_block" ]; then - STATE="after_block" - fi - fi -} - -translate_imports() { - STATE="before_block" - IMPORTCODE='' - IMPORTS='' - - while read IMPORT_LINE; do - handle_import_line $IMPORT_LINE || return 1 - done - - map_set_instr IMPORTCODES $FILEKEY "$IMPORTCODE" - map_set_instr IMPORTS $FILEKEY "$IMPORTS" -} - -add_imports() { - FILE="$1" - FILEKEY="$(sanitize "$FILE")" - - eval "$(grep -o 'IMPORT.\+' "$1" | translate_imports || exit 1)" -} +set -e -compute_scripts_list_rec() { - local FILE="$1" - local FILEKEY=$(sanitize "$1") - - local FILESTATE="$(map_get FILESTATES $FILEKEY)" - if [ "xprocessed" = "x$FILESTATE" ]; then - return - fi - if [ "xprocessing" = "x$FILESTATE" ]; then - errcho "import loop on $FILE" - return 1 - fi - - USED="$USED $FILEKEY" - - map_set FILESTATES $FILEKEY "processing" - - local IMPORT - for IMPORT in $(map_get IMPORTS $FILEKEY); do - NEXT_FILE="$(map_get EXPORTS $IMPORT)" - if [ "x" = "x$NEXT_FILE" ]; then - errcho "nothing exports $IMPORT, required by $FILE" - return 1 - fi - if ! compute_scripts_list_rec "$NEXT_FILE"; then - errcho "when satisfying $IMPORT for $FILE" - return 1 - fi - done - - [ "x$FILE" = "xexports_init.js" ] || echo $FILE # exports_init.js is hardcoded to load first; the entire export system depends on it - map_set FILESTATES $FILEKEY "processed" -} - -compute_scripts_list() { - USED='' - echo COMPUTED_SCRIPTS=\"exports_init.js - compute_scripts_list_rec "$1" - echo \" - - for FILEKEY in $USED; do - map_set_instr USED $FILEKEY yes - done -} +. ./shell_utils.sh as_json_list() { while true; do if [ "x" = "x$2" ]; then - echo -n '\\n'"\t\t\"$1\""'\\n\t' + printf '\\n\t\t"%s"\\n\t' "$1" return fi - echo -n '\\n'"\t\t\"$1\"," + printf '\\n\t\t"%s",' "$1" shift done } as_html_list() { while [ "x" != "x$1" ]; do - echo -n '\\n'" " + printf '\\n ' "$1" shift done } -build_main() { - # placate importers of these, as they are exported by the yet-to-be-created exports_init.js - EXPORTS__browser=exports_init.js - EXPORTS__is_chrome=exports_init.js - EXPORTS__is_mozilla=exports_init.js +compute_scripts() { + local DIRS="$1" + local ROOT_SCRIPT="$2" + + local AVAILABLE="$(find $DIRS -name '[^.#]*.js')" + + awk -f compute_scripts.awk script_dependencies "$ROOT_SCRIPT" $AVAILABLE +} - SCRIPTDIRS='background html common content' +build_main() { + local ALL_SCRIPTDIRS='background html common content' - SCRIPTS=$(find $SCRIPTDIRS -name '[^.#]*.js') + local ALL_SCRIPTS_AVAILABLE="$(find $ALL_SCRIPTDIRS -name '[^.#]*.js')" - for SCRIPT in $SCRIPTS; do - add_exports $SCRIPT - add_imports $SCRIPT + local SCRIPT + for SCRIPT in $ALL_SCRIPTS_AVAILABLE; do + map_set SCRIPTS_UNUSED $(sanitize $SCRIPT) yes done - eval "$(compute_scripts_list background/main.js || exit 1)" - BGSCRIPTS="$(as_json_list $COMPUTED_SCRIPTS)" - eval "$(compute_scripts_list content/main.js || exit 1)" - CONTENTSCRIPTS="$(as_json_list $COMPUTED_SCRIPTS)" - eval "$(compute_scripts_list html/display-panel.js || exit 1)" - POPUPSCRIPTS="$(as_html_list $COMPUTED_SCRIPTS)" - eval "$(compute_scripts_list html/options_main.js || exit 1)" - OPTIONSSCRIPTS="$(as_html_list $COMPUTED_SCRIPTS)" + local ROOT=background/main.js + local SCRIPTS_BG="$( compute_scripts 'common/ background/' $ROOT)" + + local ROOT=content/main.js + local SCRIPTS_CONTENT="$( compute_scripts 'common/ content/' $ROOT)" + + local ROOT=html/display-panel.js + local SCRIPTS_POPUP="$( compute_scripts 'common/ html/' $ROOT)" + + local ROOT=html/options_main.js + local SCRIPTS_OPTIONS="$( compute_scripts 'common/ html/' $ROOT)" - for DIR in $(find $SCRIPTDIRS -type d); do + local BGSCRIPTS="$( as_json_list $SCRIPTS_BG )" + local CONTENTSCRIPTS="$( as_json_list $SCRIPTS_CONTENT )" + local POPUPSCRIPTS="$( as_html_list $SCRIPTS_POPUP )" + local OPTIONSSCRIPTS="$( as_html_list $SCRIPTS_OPTIONS )" + + for SCRIPT in $SCRIPTS_BG $SCRIPTS_CONTENT $SCRIPTS_POPUP $SCRIPTS_OPTIONS + do + map_del SCRIPTS_UNUSED $(sanitize $SCRIPT) + done + + for DIR in $(find $ALL_SCRIPTDIRS -type d); do mkdir -p "$BUILDDIR"/$DIR done @@ -214,53 +104,24 @@ s^_CONTENTSCRIPTS_^$CONTENTSCRIPTS^" \ sed "s^_OPTIONSSCRIPTS_^$OPTIONSSCRIPTS^" \ > "$BUILDDIR"/html/options.html - for FILE in $SCRIPTS; do + for FILE in $ALL_SCRIPTS_AVAILABLE; do FILEKEY=$(sanitize "$FILE") - if [ "xyes" != "x$(map_get USED $FILEKEY)" ]; then - errcho "WARNING! $FILE not used" + if [ "x$(map_get SCRIPTS_UNUSED $FILEKEY)" = "xyes" ]; then + printf 'WARNING! %s not used\n' "$FILE" >&2 else - (echo "\ -\"use strict\"; - -({fun: (function() { -$(map_get IMPORTCODES $FILEKEY) - -"; - -# A hack to insert the contents of default_settings.json at the appropriate location in background/main.js -if [ "$FILE" = "background/main.js" ]; then - # Uses an internal sed expression to escape and indent the JSON file for use in the external sed expression - sed 's/^ `DEFAULT SETTINGS`$/'"$(sed -E 's/([\\\&\/])/\\\1/g; s/^/ /; s/$/\\/' < default_settings.json) "/g < "$FILE" -else - cat $FILE -fi - -echo " - -$(map_get EXPORTCODES $FILEKEY) -})}).fun();") > "$BUILDDIR"/$FILE + awk -f compute_scripts.awk wrapped_code "$FILE" > "$BUILDDIR"/$FILE fi done + # A hack to insert the contents of default_settings.json at the appropriate + # location in background/main.js. Uses an internal sed expression to escape + # and indent the JSON file for use in the external sed expression. + sed -i 's/^ `DEFAULT SETTINGS`$/'"$(sed -E 's/([\\\&\/])/\\\1/g; s/^/ /; s/$/\\/' < default_settings.json) "/g "$BUILDDIR"/background/main.js + if [ "$BROWSER" = "chromium" ]; then - cat > "$BUILDDIR"/exports_init.js < "$BUILDDIR"/exports_init.js < "$MOZILLA_FILE" + printf '\n' > "$MOZILLA_FILE" done fi if [ "$BROWSER" = "mozilla" ]; then for CHROMIUM_FILE in $(find "$BUILDDIR" -name "CHROMIUM_*"); do - echo > "$CHROMIUM_FILE" + printf '\n' > "$CHROMIUM_FILE" done fi } +print_usage() { + printf 'usage: %s mozilla|chromium [source directory] [update url]\n' \ + "$0" >&2 +} + main() { if [ "x$1" = "xmozilla" -o "x$1" = "xchromium" ]; then BROWSER=$1 else - errcho "usage: $0 mozilla|chromium [source directory] [update url]" + print_usage exit 1 fi @@ -296,13 +162,12 @@ main() { mkdir "$BUILDDIR" cd "$SRCDIR" else - errcho "usage: $0 mozilla|chromium [source directory] [update url]" + print_usage exit 2 fi UPDATE_URL="$3" - . ./shell_utils.sh build_main } diff --git a/common/storage_light.js b/common/storage_light.js index 32e3b1f..246e5eb 100644 --- a/common/storage_light.js +++ b/common/storage_light.js @@ -13,6 +13,7 @@ * IMPORT raw_storage * IMPORT is_mozilla * IMPORT observables + * IMPORTS_END */ const reg_spec = new Set(["\\", "[", "]", "(", ")", "{", "}", ".", "*", "+"]); diff --git a/compute_scripts.awk b/compute_scripts.awk new file mode 100644 index 0000000..123106c --- /dev/null +++ b/compute_scripts.awk @@ -0,0 +1,196 @@ +# SPDX-License-Identifier: CC0-1.0 +# +# Process javascript files and resolve dependencies between them +# +# This file is part of Haketilo +# +# Copyright (C) 2021, Wojtek Kosior +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the CC0 1.0 Universal License as published by +# the Creative Commons Corporation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# CC0 1.0 Universal License for more details. + +function read_file(filename, + imports_state, exports_state, line, record, result) { + imports_state = "not_started" + exports_state = "not_started" + + do { + result = (getline line < filename) + if (result < 0) { + printf "error reading %s", filename + exit 1 + } + + if (imports_state == "started" && + line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORT[[:space:]]+[_a-zA-Z][_a-zA-Z0-9]*[[:space:]]*$/) { + record = line + + sub(/^([[:space:]]*\*[[:space:]]+)?IMPORT[[:space:]]+/, "", record) + sub(/([[:space:]]+$)/, "", record) + + imports[filename,++import_counts[filename]] = record + } + if (imports_state == "started" && + line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORTS_END[[:space:]]*$/) + imports_state = "finished" + if (imports_state == "not_started" && + line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORTS_START[[:space:]]*$/) + imports_state = "started" + + if (exports_state == "started" && + line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORT[[:space:]]+[_a-zA-Z][_a-zA-Z0-9]*[[:space:]]*$/) { + record = line + + sub(/^([[:space:]]*\*[[:space:]]+)?EXPORT[[:space:]]+/, "", record) + sub(/([[:space:]]+$)/, "", record) + + if (record in exports) { + printf "ERROR: '%s' exported by both %s and %s\n", + exports[record], filename > "/dev/stderr" + } + + provides[record] = filename + exports[filename,++export_counts[filename]] = record + } + if (exports_state == "started" && + line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORTS_END[[:space:]]*$/) + exports_state = "finished" + if (exports_state == "not_started" && + line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORTS_START[[:space:]]*$/) + exports_state = "started" + } while (result > 0) + + if (imports_state == "started") { + printf "ERROR: Unclosed IMPORTS list in '%s'\n", filename \ + > "/dev/stderr" + exit 1 + } + + if (exports_state == "started") { + printf "ERROR: Unclosed EXPORTS list in '%s'\n", filename \ + > "/dev/stderr" + exit 1 + } + + close(filename) +} + +function print_file(filename, line) { + while ((getline line < filename) > 0) + print(line) + + close(filename) +} + +function print_imports_code(filename, i, count, import_name) { + count = import_counts[filename] + for (i = 1; i <= count; i++) { + import_name = imports[filename,i] + printf "const %s = window.killtheweb.%s;\n", import_name, import_name + } +} + +function print_exports_code(filename, i, count, export_name) { + count = export_counts[filename] + for (i = 1; i <= count; i++) { + export_name = exports[filename,i] + printf "window.killtheweb.%s = %s;\n", export_name, export_name + } +} + +function wrap_file(filename) { + print "\"use strict\";\n\n({fun: (function() {\n" + print_imports_code(filename) + printf "\n\n" + + print_file(filename) + + printf "\n\n" + print_exports_code(filename) + print "\n})}).fun();" +} + +function compute_dependencies(filename, i, count, import_name, next_file) { + if (processed[filename] == "used") + return 0 + + if (processed[filename] == "on_stack") { + printf "import loop on %s\n", filename > "/dev/stderr" + return 1 + } + + processed[filename] = "on_stack" + + count = import_counts[filename] + for (i = 1; i <= count; i++) { + import_name = imports[filename,i] + if (!(import_name in provides)) { + printf "nothing exports %s, required by %s\n", + import_name, filename > "/dev/stderr" + return 1 + } + + if (compute_dependencies(provides[import_name]) > 0) { + printf "when satisfying %s for %s\n", + import_name, filename > "/dev/stderr" + return 1 + } + } + + processed[filename] = "used" + print filename + + return 0 +} + +function print_usage() { + printf "usage: %2 compute_scripts.awk script_dependencies|wrapped_code FILENAME[...]\n", + ARGV[0] > "/dev/stderr" + exit 1 +} + +function mock_exports_init() { + provides["browser"] = "exports_init.js" + provides["is_chrome"] = "exports_init.js" + provides["is_mozilla"] = "exports_init.js" + + processed["exports_init.js"] = "used" +} + +BEGIN { + operation = ARGV[1] + + if (ARGC < 3) + print_usage() + + root_filename = ARGV[2] + + for (i = 2; i < ARGC; i++) + filenames[ARGV[i]] + + mock_exports_init() + + for (filename in filenames) { + # A filename is allowed to appear multiple times in the list. + # Let's only process it once. + if (!(filename in processed)) + read_file(filename) + processed[filename] = "not_used" + } + + if (operation == "script_dependencies") { + print("exports_init.js") + if (compute_dependencies(root_filename) > 0) + exit 1 + } else if (operation == "wrapped_code") { + wrap_file(root_filename) + } else { + print_usage() + } +} diff --git a/copyright b/copyright index 81f9966..a238d33 100644 --- a/copyright +++ b/copyright @@ -6,7 +6,8 @@ Files: * Copyright: 2021 Wojtek Kosior License: GPL-3+-javascript or Alicense-1.0 -Files: *.sh default_settings.json Makefile.in +Files: *.sh default_settings.json Makefile.in compute_scripts.awk + CHROMIUM_exports_init.js Copyright: 2021 Wojtek Kosior 2021 jahoti License: CC0 diff --git a/process_html_file.sh b/process_html_file.sh index 1ed0295..2f58cbf 100755 --- a/process_html_file.sh +++ b/process_html_file.sh @@ -12,7 +12,7 @@ FILE="$1" FILEKEY=$(sanitize "$FILE") if [ "x$(map_get HTML_FILENAMES $FILEKEY)" = "xyes" ]; then - errcho "import loop on $FILE" + printf 'import loop on %s\n' "$FILE" >&2 exit 1 fi diff --git a/shell_utils.sh b/shell_utils.sh index 5fd24ff..6d4cc76 100644 --- a/shell_utils.sh +++ b/shell_utils.sh @@ -3,21 +3,8 @@ # This file is meant to be sourced in sh. -ENDL=" -" - -# A "raw" echo, interprets neither backclash escapes nor command-line options. -# Does not emit trailing newline. -ech() { - printf %s "$*" -} - -errcho() { - echo "$@" >&2 -} - map_set_instr() { - echo "$1__$2='$3'" + printf "%s__%s='%s'" "$1" "$2" "$3" } map_set() { @@ -29,11 +16,11 @@ map_set_export() { } map_get() { - eval "echo \"\$$1__$2\"" + eval "printf %s \"\$$1__$2\"" } map_del_instr() { - echo "unset $1__$2" + printf 'unset %s__%s' "$1" "$2" } map_del() { @@ -41,18 +28,18 @@ map_del() { } sanitize() { - echo "$1" | tr /.- _ + printf %s "$1" | tr /.- _ } escape_regex_special() { - ech "$1" | sed 's/\([]\.*?{},()[-]\)/\\\1/g' + printf %s "$1" | sed 's/\([]\.*?{},()[-]\)/\\\1/g' } # Note: We don't actually parse JSON. We extract needed keys with sed regexes # which does not work in the general case but is sufficient for now. get_json_key() { local KEY_REG="$(escape_regex_special "$1")" - ech "$2" | + printf %s "$2" | sed 's/\(.*"'"$KEY_REG"'"[[:space:]]*:[[:space:]]*"\([^"]*\)"\)\?.*/\2/' | grep . | head -1 } diff --git a/upload_amo.sh b/upload_amo.sh index 115f39a..71e12ca 100755 --- a/upload_amo.sh +++ b/upload_amo.sh @@ -24,11 +24,11 @@ SECRET="$3" XPI_PATH="$4" base64url() { - ech "$1" | base64 -w 0 | tr '/+' '_-' | tr -d '=' + printf %s "$1" | base64 -w 0 | tr '/+' '_-' | tr -d '=' } sha256hmac() { - base64url "$(ech "$2" | openssl dgst -sha256 -hmac "$1" -binary -)" + base64url "$(printf %s "$2" | openssl dgst -sha256 -hmac "$1" -binary -)" } get_manifest_key() { @@ -52,8 +52,8 @@ EOF local JWT_MESSAGE=$(base64url "$JWT_HEAD").$(base64url "$JWT_PAYLOAD") local JWT_SIGNATURE=$(sha256hmac "$SECRET" "$JWT_MESSAGE") local JWT=$JWT_MESSAGE.$JWT_SIGNATURE - errcho "Using JWT: $JWT" - ech $JWT + printf "Using JWT: $JWT\n" >&2 + printf $JWT } get_extension_url() { @@ -61,19 +61,22 @@ get_extension_url() { EXTENSION_VER="$(get_manifest_key version "$XPI_PATH")" if [ -z "$EXTENSION_ID" -o -z "$EXTENSION_VER" ]; then - errcho "Couldn't extract extension id and version. Please check if $XPI_PATH contains proper manifest.json file." + printf "Couldn't extract extension id and version. Please check if %s contains proper manifest.json file.\n" \ + "$XPI_PATH" >&2 exit 1 fi - ech "https://addons.mozilla.org/api/v4/addons/$EXTENSION_ID/versions/$EXTENSION_VER/" + printf 'https://addons.mozilla.org/api/v4/addons/%s/versions/%s/' \ + "$EXTENSION_ID" "$EXTENSION_VER" } -usage() { - errcho "Usage: $_PROG_NAME upload|check|test API_KEY SECRET XPI_PATH" +print_usage() { + printf 'Usage: %s upload|check|test API_KEY SECRET XPI_PATH\n' \ + "$_PROG_NAME" >&2 } if [ $# != 4 ]; then - usage + print_usage exit 1 fi @@ -83,7 +86,7 @@ case "$OPERATION" in test) curl "https://addons.mozilla.org/api/v4/accounts/profile/" \ -g -H "Authorization: JWT $(generate_jwt)" - echo + printf '\n' ;; check) RETURNED_DATA="$(curl $(get_extension_url) \ @@ -95,7 +98,7 @@ case "$OPERATION" in -H "Authorization: JWT $(generate_jwt)")" ;; *) - usage + print_usage exit 1 ;; esac diff --git a/write_makefile.sh b/write_makefile.sh index d5c0fa9..4011fe8 100755 --- a/write_makefile.sh +++ b/write_makefile.sh @@ -14,10 +14,10 @@ # CC0 1.0 Universal License for more details. if [ ! -e record.conf ]; then - echo "Record of configuration 'record.conf' does not exist." >&2 + printf "Record of configuration 'record.conf' does not exist.\n" >&2 exit 1 elif [ "$(head -n 1 record.conf | cut -c -9)x" != "srcdir = x" ]; then - echo "Record of configuration 'record.conf' is invalid." >&2 + printf "Record of configuration 'record.conf' is invalid.\n" >&2 exit 2 fi -- cgit v1.2.3