From 43ed7392cdfc734a4304284906b9d0d503381841 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 28 Oct 2022 20:15:30 +0200 Subject: [proxy] make it possible to export embedded documentation as standalone .html files and include these in the binary release tarball --- .gitignore | 1 + Makefile | 13 +- setup.py | 57 ++- src/hydrilla/proxy/self_doc.py | 8 +- .../proxy/self_doc/advanced_ui_features.html.jinja | 70 ---- src/hydrilla/proxy/self_doc/doc_index.html.jinja | 59 --- .../self_doc/en_US/advanced_ui_features.html.jinja | 70 ++++ .../proxy/self_doc/en_US/doc_index.html.jinja | 59 +++ .../proxy/self_doc/en_US/packages.html.jinja | 218 +++++++++++ .../self_doc/en_US/policy_selection.html.jinja | 109 ++++++ src/hydrilla/proxy/self_doc/en_US/popup.html.jinja | 157 ++++++++ .../proxy/self_doc/en_US/repositories.html.jinja | 128 +++++++ .../self_doc/en_US/script_blocking.html.jinja | 125 +++++++ .../proxy/self_doc/en_US/url_patterns.html.jinja | 409 +++++++++++++++++++++ src/hydrilla/proxy/self_doc/packages.html.jinja | 218 ----------- .../proxy/self_doc/policy_selection.html.jinja | 109 ------ src/hydrilla/proxy/self_doc/popup.html.jinja | 157 -------- .../proxy/self_doc/repositories.html.jinja | 128 ------- .../proxy/self_doc/script_blocking.html.jinja | 125 ------- .../proxy/self_doc/url_patterns.html.jinja | 409 --------------------- src/hydrilla/proxy/web_ui/root.py | 8 +- src/hydrilla/translations.py | 8 +- 22 files changed, 1354 insertions(+), 1291 deletions(-) delete mode 100644 src/hydrilla/proxy/self_doc/advanced_ui_features.html.jinja delete mode 100644 src/hydrilla/proxy/self_doc/doc_index.html.jinja create mode 100644 src/hydrilla/proxy/self_doc/en_US/advanced_ui_features.html.jinja create mode 100644 src/hydrilla/proxy/self_doc/en_US/doc_index.html.jinja create mode 100644 src/hydrilla/proxy/self_doc/en_US/packages.html.jinja create mode 100644 src/hydrilla/proxy/self_doc/en_US/policy_selection.html.jinja create mode 100644 src/hydrilla/proxy/self_doc/en_US/popup.html.jinja create mode 100644 src/hydrilla/proxy/self_doc/en_US/repositories.html.jinja create mode 100644 src/hydrilla/proxy/self_doc/en_US/script_blocking.html.jinja create mode 100644 src/hydrilla/proxy/self_doc/en_US/url_patterns.html.jinja delete mode 100644 src/hydrilla/proxy/self_doc/packages.html.jinja delete mode 100644 src/hydrilla/proxy/self_doc/policy_selection.html.jinja delete mode 100644 src/hydrilla/proxy/self_doc/popup.html.jinja delete mode 100644 src/hydrilla/proxy/self_doc/repositories.html.jinja delete mode 100644 src/hydrilla/proxy/self_doc/script_blocking.html.jinja delete mode 100644 src/hydrilla/proxy/self_doc/url_patterns.html.jinja diff --git a/.gitignore b/.gitignore index f24719d..d758574 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ messages.mo make-release.log *-tarball-repack haketilo-and-hydrilla-bin-*.tar.gz +htmldoc/ diff --git a/Makefile b/Makefile index 1cfdd82..f98362e 100644 --- a/Makefile +++ b/Makefile @@ -50,10 +50,13 @@ dist src/hydrilla/_version.py: @printf "Generated source tarball in:\n" @printf "./dist/hydrilla-$(GET_VER).tar.gz\n" +doc: + $(GUIX_DEVSHELL) python3 setup.py build_htmldoc + # Make a release tarball and repack its files as writeable - this will make it # easier for non-technical users to remove the unpacked release once they no # longer need it. -release: dist +release: dist doc $(GUIX_TM) pack -L ./hydrilla-guix -RR hydrilla \ -S /hydrilla=bin/hydrilla \ -S /hydrilla-builder=bin/hydrilla-builder \ @@ -67,6 +70,7 @@ release: dist mkdir bin-tarball-repack/"$$RELNAME" && \ tar -C bin-tarball-repack/"$$RELNAME"/ -xf "$$PACKFILE" && \ chmod -R +w bin-tarball-repack/"$$RELNAME" && \ + cp -R htmldoc/ bin-tarball-repack/"$$RELNAME" && \ $(DETERMINISTIC_TAR) -C bin-tarball-repack/ \ -cf "$$RELNAME".tar.gz "$$RELNAME" @printf "Generated binary release tarball for $$(arch) in:\n" @@ -132,7 +136,10 @@ clean-bin-tarball-repack: clean-source-tarball-repack: rm -rf source-tarball-repack/ -clean: clean-bin-tarball-repack clean-source-tarball-repack +clean-doc: + rm -rf htmldoc/ + +clean: clean-bin-tarball-repack clean-source-tarball-repack clean-doc rm -rf build/ dist/ src/hydrilla.egg-info/ src/hydrilla/_version.py \ src/hydrilla/locales/messages.pot make-release.log \ haketilo-and-hydrilla-bin-*.tar.gz .mypy_cache/ .pytest_cache/ @@ -140,7 +147,7 @@ clean: clean-bin-tarball-repack clean-source-tarball-repack rm -rf $$(find -name "__pycache__") .PHONY: shell shell-with-haketilo \ - release dist wheel catalogs \ + wheel dist doc release catalogs \ refresh-catalogs test run-haketilo \ mypy-lint mypy-lint-server mypy-lint-builder mypy-lint-haketilo \ clean-bin-tarball-repack clean-source-tarball-repack clean diff --git a/setup.py b/setup.py index 3aa9f74..a8a5bfa 100755 --- a/setup.py +++ b/setup.py @@ -9,6 +9,7 @@ import setuptools from setuptools.command.build_py import build_py from setuptools.command.sdist import sdist +from setuptools import Command from pathlib import Path @@ -43,7 +44,59 @@ class CustomSdistCommand(sdist): for path, contents in locale_files.items(): path.write_bytes(contents) +class BuildDocCommand(Command): + """ + Command to create an `htmldoc/` catalog with Haketilo documentation inside + as standalone .html files. + """ + user_options = [] + + def run (self, *args, **kwargs): + """Generate the .html files""" + import jinja2 + import shutil + import sys + + htmldoc_dir = here / 'htmldoc' + if htmldoc_dir.exists(): + shutil.rmtree(htmldoc_dir) + + proxy_doc_dir = htmldoc_dir / 'haketilo' + + sys.path.insert(0, str(here / 'src')) + + from hydrilla.proxy import self_doc + from hydrilla import common_jinja_templates + + loader = common_jinja_templates.combine_with_loaders([self_doc.loader]) + jinja_env = jinja2.Environment( + loader = loader, + autoescape = jinja2.select_autoescape(['html.jinja']), + lstrip_blocks = True, + extensions = ['jinja2.ext.do'] + ) + + for locale in self_doc.available_locales: + doc_dir = proxy_doc_dir / locale + doc_dir.mkdir(parents=True) + + for page_name in self_doc.page_names: + file_name = f'{locale}/{page_name}.html.jinja' + template = jinja_env.get_template(file_name) + html_text = template.render(doc_output='html') + + out_name = 'index' if page_name == 'doc_index' else page_name + + (doc_dir / f'{out_name}.html').write_text(html_text) + + def initialize_options(self): + pass + + def finalize_options(self): + pass + setuptools.setup(cmdclass = { - 'build_py': CustomBuildCommand, - 'sdist': CustomSdistCommand + 'build_py': CustomBuildCommand, + 'sdist': CustomSdistCommand, + 'build_htmldoc': BuildDocCommand }) diff --git a/src/hydrilla/proxy/self_doc.py b/src/hydrilla/proxy/self_doc.py index 838df57..eb5e9fd 100644 --- a/src/hydrilla/proxy/self_doc.py +++ b/src/hydrilla/proxy/self_doc.py @@ -16,6 +16,12 @@ loader = jinja2.PackageLoader(__package__, package_path='self_doc') suffix_len = len('.html.jinja') page_names = frozenset( path.name[:-suffix_len] - for path in (here / 'self_doc').glob('*.html.jinja') + for path in (here / 'self_doc/en_US').glob('*.html.jinja') if path.name != 'doc_base.html.jinja' ) + +available_locales = tuple( + path.name + for path in (here / 'self_doc').iterdir() + if path.is_dir() +) diff --git a/src/hydrilla/proxy/self_doc/advanced_ui_features.html.jinja b/src/hydrilla/proxy/self_doc/advanced_ui_features.html.jinja deleted file mode 100644 index 045309b..0000000 --- a/src/hydrilla/proxy/self_doc/advanced_ui_features.html.jinja +++ /dev/null @@ -1,70 +0,0 @@ -{# -SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 - -Documentation page explaining what Haketilo's advanced UI features are. - -This file is part of Hydrilla&Haketilo. - -Copyright (C) 2022 Wojtek Kosior - -Dual licensed under -* GNU General Public License v3.0 or later and -* Creative Commons Attribution Share Alike 4.0 International. - -You can choose to use either of these licenses or both. - - -I, Wojtek Kosior, thereby promise not to sue for violation of this -file's licenses. Although I request that you do not make use of this -code in a proprietary work, I am not going to enforce this in court. -#} -{% extends "doc_base.html.jinja" %} - -{% block title %} Advanced UI features {% endblock %} - -{% block main %} - {{ big_heading('Haketilo user interface features for advanced users') }} - - {% call section() %} - {% call paragraph() %} - Certain options that may cause a lot of unnecessary confusion to casual - Haketilo users have been hidden by default. They can be accessed after - enabling advanced UI features on the - {{ hkt_link('settings page', 'home.home') }}. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Concept of libraries') }} - - {% call paragraph() %} - Haketilo has a concept of 2 types of entities - - packages and - libraries. - As explained on the {{ doc_page_link('packages', 'packages') }} page, it's - ultimately a package that provides concrete functionality and a casual - user does not need to be aware of the existence of libraries. - Consequently, with advanced features off the UI does not contain any - notion of libraries and even the - {{ hkt_link('libraries listing page', 'items.libraries') }} link is - removed from the navigation bar. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Selective installation/uninstallation of packages') }} - - {% call paragraph() %} - A packages is automatically installed together with all its dependencies - when the user enables it. - Additionally, whenever some installed Haketilo packages or libraries are - found not to be needed anymore, they can be pruned from the - {{ hkt_link('settings page', 'home.home') }}. - This functionality was deemed sufficient for most users' needs. - With advanced features enabled the UI also allows any single package or - library not in use to be uninstalled manually and any package or library - available from a {{ doc_page_link('repository', 'repositories') }} to be - installed without prior enabling. - {% endcall %} - {% endcall %} -{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/doc_index.html.jinja b/src/hydrilla/proxy/self_doc/doc_index.html.jinja deleted file mode 100644 index 03f2231..0000000 --- a/src/hydrilla/proxy/self_doc/doc_index.html.jinja +++ /dev/null @@ -1,59 +0,0 @@ -{# -SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 - -Documentation pages index. - -This file is part of Hydrilla&Haketilo. - -Copyright (C) 2022 Wojtek Kosior - -Dual licensed under -* GNU General Public License v3.0 or later and -* Creative Commons Attribution Share Alike 4.0 International. - -You can choose to use either of these licenses or both. - - -I, Wojtek Kosior, thereby promise not to sue for violation of this -file's licenses. Although I request that you do not make use of this -code in a proprietary work, I am not going to enforce this in court. -#} -{% extends "doc_base.html.jinja" %} - -{% block title %} Documentation index {% endblock %} - -{% block main %} - {{ big_heading('Haketilo embedded documentation') }} - - {% call section() %} - {% call paragraph() %} - This is the embedded documentation of Haketilo proxy. - It contains some basic information aimed to help new users understand how - the tool works. - {% endcall %} - - {% call unordered_list() %} - {% call list_entry() %} - {{ doc_page_link('Advanced UI features', 'advanced_ui_features') }} - {% endcall %} - {% call list_entry() %} - {{ doc_page_link('Packages', 'packages') }} - {% endcall %} - {% call list_entry() %} - {{ doc_page_link('Policy selection', 'policy_selection') }} - {% endcall %} - {% call list_entry() %} - {{ doc_page_link('Popup', 'popup') }} - {% endcall %} - {% call list_entry() %} - {{ doc_page_link('Repositories', 'repositories') }} - {% endcall %} - {% call list_entry() %} - {{ doc_page_link('Script blocking', 'script_blocking') }} - {% endcall %} - {% call list_entry() %} - {{ doc_page_link('URL patterns', 'url_patterns') }} - {% endcall %} - {% endcall %} - {% endcall %} -{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/en_US/advanced_ui_features.html.jinja b/src/hydrilla/proxy/self_doc/en_US/advanced_ui_features.html.jinja new file mode 100644 index 0000000..045309b --- /dev/null +++ b/src/hydrilla/proxy/self_doc/en_US/advanced_ui_features.html.jinja @@ -0,0 +1,70 @@ +{# +SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 + +Documentation page explaining what Haketilo's advanced UI features are. + +This file is part of Hydrilla&Haketilo. + +Copyright (C) 2022 Wojtek Kosior + +Dual licensed under +* GNU General Public License v3.0 or later and +* Creative Commons Attribution Share Alike 4.0 International. + +You can choose to use either of these licenses or both. + + +I, Wojtek Kosior, thereby promise not to sue for violation of this +file's licenses. Although I request that you do not make use of this +code in a proprietary work, I am not going to enforce this in court. +#} +{% extends "doc_base.html.jinja" %} + +{% block title %} Advanced UI features {% endblock %} + +{% block main %} + {{ big_heading('Haketilo user interface features for advanced users') }} + + {% call section() %} + {% call paragraph() %} + Certain options that may cause a lot of unnecessary confusion to casual + Haketilo users have been hidden by default. They can be accessed after + enabling advanced UI features on the + {{ hkt_link('settings page', 'home.home') }}. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Concept of libraries') }} + + {% call paragraph() %} + Haketilo has a concept of 2 types of entities - + packages and + libraries. + As explained on the {{ doc_page_link('packages', 'packages') }} page, it's + ultimately a package that provides concrete functionality and a casual + user does not need to be aware of the existence of libraries. + Consequently, with advanced features off the UI does not contain any + notion of libraries and even the + {{ hkt_link('libraries listing page', 'items.libraries') }} link is + removed from the navigation bar. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Selective installation/uninstallation of packages') }} + + {% call paragraph() %} + A packages is automatically installed together with all its dependencies + when the user enables it. + Additionally, whenever some installed Haketilo packages or libraries are + found not to be needed anymore, they can be pruned from the + {{ hkt_link('settings page', 'home.home') }}. + This functionality was deemed sufficient for most users' needs. + With advanced features enabled the UI also allows any single package or + library not in use to be uninstalled manually and any package or library + available from a {{ doc_page_link('repository', 'repositories') }} to be + installed without prior enabling. + {% endcall %} + {% endcall %} +{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/en_US/doc_index.html.jinja b/src/hydrilla/proxy/self_doc/en_US/doc_index.html.jinja new file mode 100644 index 0000000..03f2231 --- /dev/null +++ b/src/hydrilla/proxy/self_doc/en_US/doc_index.html.jinja @@ -0,0 +1,59 @@ +{# +SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 + +Documentation pages index. + +This file is part of Hydrilla&Haketilo. + +Copyright (C) 2022 Wojtek Kosior + +Dual licensed under +* GNU General Public License v3.0 or later and +* Creative Commons Attribution Share Alike 4.0 International. + +You can choose to use either of these licenses or both. + + +I, Wojtek Kosior, thereby promise not to sue for violation of this +file's licenses. Although I request that you do not make use of this +code in a proprietary work, I am not going to enforce this in court. +#} +{% extends "doc_base.html.jinja" %} + +{% block title %} Documentation index {% endblock %} + +{% block main %} + {{ big_heading('Haketilo embedded documentation') }} + + {% call section() %} + {% call paragraph() %} + This is the embedded documentation of Haketilo proxy. + It contains some basic information aimed to help new users understand how + the tool works. + {% endcall %} + + {% call unordered_list() %} + {% call list_entry() %} + {{ doc_page_link('Advanced UI features', 'advanced_ui_features') }} + {% endcall %} + {% call list_entry() %} + {{ doc_page_link('Packages', 'packages') }} + {% endcall %} + {% call list_entry() %} + {{ doc_page_link('Policy selection', 'policy_selection') }} + {% endcall %} + {% call list_entry() %} + {{ doc_page_link('Popup', 'popup') }} + {% endcall %} + {% call list_entry() %} + {{ doc_page_link('Repositories', 'repositories') }} + {% endcall %} + {% call list_entry() %} + {{ doc_page_link('Script blocking', 'script_blocking') }} + {% endcall %} + {% call list_entry() %} + {{ doc_page_link('URL patterns', 'url_patterns') }} + {% endcall %} + {% endcall %} + {% endcall %} +{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/en_US/packages.html.jinja b/src/hydrilla/proxy/self_doc/en_US/packages.html.jinja new file mode 100644 index 0000000..23e6f45 --- /dev/null +++ b/src/hydrilla/proxy/self_doc/en_US/packages.html.jinja @@ -0,0 +1,218 @@ +{# +SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 + +Documentation page describing the concept of packages in Haketilo. + +This file is part of Hydrilla&Haketilo. + +Copyright (C) 2022 Wojtek Kosior + +Dual licensed under +* GNU General Public License v3.0 or later and +* Creative Commons Attribution Share Alike 4.0 International. + +You can choose to use either of these licenses or both. + + +I, Wojtek Kosior, thereby promise not to sue for violation of this +file's licenses. Although I request that you do not make use of this +code in a proprietary work, I am not going to enforce this in court. +#} +{% extends "doc_base.html.jinja" %} + +{% block title %} Packages {% endblock %} + +{% block main %} + {{ big_heading('Packages in Haketilo') }} + + {% call section() %} + {% call paragraph() %} + Users can modify web pages by creating, installing and enabling + packages. + A package associates {{ doc_page_link('URL patterns', 'url_patterns') }} + with payloads (i.e. sets of scripts) that can be injected to pages. + For instance, if an enabled package associates pattern + https://example.com/*** with a script that adds a big + "Hello world!" text to the page, this package shall cause "Hello world!" + to appear on pages under example.com. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Packages and libraries') }} + + {% call paragraph() %} + To make mapping custom JavaScript applications and their dependencies to + web pages more manageable, Haketilo defines its own concept of "packages" + and "libraries". + {% endcall %} + + {% call unordered_list() %} + {% call list_entry() %} + package - Also called mapping. + It associates URL patterns with libraries. + {% endcall %} + {% call list_entry() %} + library - Sometimes also referred to as + resource. + Defines a set of scripts that can be injected together into a page. + It can also name other libraries as its dependencies. + When injecting scripts of a given library into some page, Haketilo will + first inject scripts of all libraries depended on. + {% endcall %} + {% endcall %} + + {% call paragraph() %} + It's ultimately a package that provides concrete functionality to the end + user and that can be enabled or disabled. + For this reason, a casual user does not even need to be aware of the + existence of libraries. + Haketilo UI advanced interface features need to be enabled on the + {{ hkt_link('settings page', 'home.home') }} for installed libraries to be + viewable. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Installing') }} + + {% call paragraph() %} + Useful packages prepared by others can be installed from Hydrilla + repositories. The repositories can be configured + {{ hkt_link('through Haketilo user interface', 'repos.repos') }} as + described on + {{ doc_page_link('the relevant documentation page', 'repositories') }}. + As of Haketilo 3.0-beta1 they need to be manually "refreshed" for new + packages from them to be shown in Haketilo. + Available packages viewable on the + {{ hkt_link('packages listing page', 'items.packages') }} are not + immediately installed. + This only happens after they are explicitly enabled or automatically + enabled (if the user configured Haketilo to do this). + {% endcall %} + + {% call paragraph() %} + For convenience, users can also create simple packages + {{ hkt_link('directly in Haketilo UI', 'import.items_import') }}. + A simple form can be used to quickly define a standalone script payload + for a set of URL patterns. As of Haketilo 3.0 only simple (i.e. + single-library) payloads can be created this way. + {% endcall %} + + {% call paragraph() %} + It is also possible to import packages from files. + For this, a directory of serveable mappings and reasources - as produced + by Hydrilla builder and used by Hydrilla server - has to be put into a ZIP + archive. + It can then be uploaded to Haketilo via its + {{ hkt_link('import page', 'import.items_import') }}. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Uninstalling') }} + + {% call paragraph() %} + Haketilo tracks dependencies between packages and libraries and + automatically determines which of them are no longer needed. + These are called orphans and if present, can be + removed from the {{ hkt_link('settings page', 'home.home') }}. + A version of package or library that is not being used but is still + available from an active repository is not considered an orphan. It + automatically becomes one when the repository either stops advertising it + as available or gets removed by the user from + {{ hkt_link('the repositories list', 'repos.repos') }}. + {% endcall %} + + {% call paragraph() %} + When advanced UI features are enabled, it is additionally possible to + manually uninstall any single package that is not in use at a given + moment. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Package contents') }} + + {% call paragraph() %} + Each package has an identifier (built from a + restricted set of characters), a long name, a + description, a version + and almost always a list of license files and a + set of URL patterns mapped to libraries. + In addition there might also be other pieces of information such as + required permissions. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Enabling/disabling') }} + + {% call paragraph() %} + The user can put package in any of 3 possible states. + It can be either enabled, + disabled or + not configured. + {% endcall %} + + {% call paragraph() %} + An enabled package always has its payloads injected on pages matched by + their patterns (unless some more specific pattern takes precedence on the + given page as described on the + {{ doc_page_link('policy selection page', 'policy_selection') }}). + {% endcall %} + + {% call paragraph() %} + A disabled package is always ignored. + It has to be manually re-enabled for Haketilo to take it into account + again. + {% endcall %} + + {% call paragraph() %} + Finally, a package that is neither explicitly enabled nor disabled can be + treated differently depending on user's choice on the + {{ hkt_link('settings page', 'home.home') }}. + It is possible to have Haketilo + {% endcall %} + + {% call unordered_list() %} + {% call list_entry() %} + automatically inject such packages' payloads on mathing pages, + {% endcall %} + {% call list_entry() %} + prompt the user on matching pages asking whether the package should be + enabled or + {% endcall %} + {% call list_entry() %} + completely ignore non-configured packages. + {% endcall %} + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Handling multiple versions') }} + + {% call paragraph() %} + It is possible to have many versions of the same package or library + installed. + When this is the case, Haketilo by default uses the newest versions it + can. + Additionally, if certain package is enabled, its page also allows the user + to configure its pinning. + A package can be + {% endcall %} + + {% call unordered_list() %} + {% call list_entry() %} + pinned to use a particular version, + {% endcall %} + {% call list_entry() %} + pinned to use the best version from a particular + {{ doc_page_link('repository', 'repositories') }} or + {% endcall %} + {% call list_entry() %} + not pinned at all (best version overall is used). + {% endcall %} + {% endcall %} + {% endcall %} +{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/en_US/policy_selection.html.jinja b/src/hydrilla/proxy/self_doc/en_US/policy_selection.html.jinja new file mode 100644 index 0000000..687d2bd --- /dev/null +++ b/src/hydrilla/proxy/self_doc/en_US/policy_selection.html.jinja @@ -0,0 +1,109 @@ +{# +SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 + +Documentation page describing how Haketilo selects policy to apply to a page. + +This file is part of Hydrilla&Haketilo. + +Copyright (C) 2022 Wojtek Kosior + +Dual licensed under +* GNU General Public License v3.0 or later and +* Creative Commons Attribution Share Alike 4.0 International. + +You can choose to use either of these licenses or both. + + +I, Wojtek Kosior, thereby promise not to sue for violation of this +file's licenses. Although I request that you do not make use of this +code in a proprietary work, I am not going to enforce this in court. +#} +{% extends "doc_base.html.jinja" %} + +{% block title %} Policy selection {% endblock %} + +{% block main %} + {{ big_heading('Page policy selection') }} + + {% call section() %} + {% call paragraph() %} + When a web page is opened, Haketilo is capable of either + {% call unordered_list() %} + {% call list_entry() %} + blocking page's own scripts and + {{ doc_page_link('injecting payload', 'packages') }} + configured by the user, + {% endcall %} + {% call list_entry() %} + blocking page's own scripts and injecting an automatically-chosen + payload that is usable with the page, + {% endcall %} + {% call list_entry() %} + presenting a dialog asking whether to enable an automatically-chosen + payload that is usable with the page, + {% endcall %} + {% call list_entry() %} + {{ doc_page_link('blocking', 'script_blocking') }} page's own scripts + or + {% endcall %} + {% call list_entry() %} + allowing page's own scripts to execute normally (i.e. not modifying + the page in any meaningful way). + {% endcall %} + {% endcall %} + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Policy precedence') }} + + {% call paragraph() %} + User configures Haketilo's behavior by defining script-blocking and + -allowing rules and by adding and enabling packages. Each rule and each + package payload has a {{ doc_page_link('URL pattern', 'url_patterns') }}. + This pattern determines which pages the policy is compatible with. + Patterns also have well-defined specificity. When multiple rules and + packages are combatible with given page's URL, the one with the most + specific pattern "wins". In case of a tie, payload injection is assumed to + take precedence over rule application. + {% endcall %} + + {% call paragraph() %} + In the absence of suitable rules and enabled packages, Haketilo may + consider non-enabled packages that are suitable for use on the + currently-visited site. It will either inject package payload + automatically, ask the user whether to enable the package or ignore it + completely. The user can switch between these 3 behaviors on the Haketilo + {{ hkt_link('settings page', 'home.home') }}. Packages that were + explicitly marked as disabled will always be ignored. Pattern specificity + is also taken into account in case of multiple packages. + {% endcall %} + + {% call paragraph() %} + When absolutely no explicit policy appears suitable for given page, + Haketilo will apply its default script handling behavrior. Whether + JavaScript is blocked or allowed by default is also determined by user's + choice on the {{ hkt_link('settings page', 'home.home') }}. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Special cases') }} + + {% call paragraph() %} + The sites served by Haketilo itself are exempt from all policies. These + are http://hkt.mitm.it, https://hkt.mitm.it + and http://mitm.it. Additionally, if Haketilo experiences an + internal error (e.g. because it could not parse current URL as sent in by + the browser), it will try to block page's JavaScript as a security + measure. + {% endcall %} + + {% call paragraph() %} + Internally, Haketilo also has a special high-priority policy for serving + files used by payloads and for making its APIs accessible to payload + scripts. This is, however, an implementation detail and casual users need + not care about it nor understand these nuances. + {% endcall %} + {% endcall %} +{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/en_US/popup.html.jinja b/src/hydrilla/proxy/self_doc/en_US/popup.html.jinja new file mode 100644 index 0000000..a5ad909 --- /dev/null +++ b/src/hydrilla/proxy/self_doc/en_US/popup.html.jinja @@ -0,0 +1,157 @@ +{# +SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 + +Documentation page describing Haketilo popup. + +This file is part of Hydrilla&Haketilo. + +Copyright (C) 2022 Wojtek Kosior + +Dual licensed under +* GNU General Public License v3.0 or later and +* Creative Commons Attribution Share Alike 4.0 International. + +You can choose to use either of these licenses or both. + + +I, Wojtek Kosior, thereby promise not to sue for violation of this +file's licenses. Although I request that you do not make use of this +code in a proprietary work, I am not going to enforce this in court. +#} +{% extends "doc_base.html.jinja" %} + +{% block title %} Popup {% endblock %} + +{% block main %} + {{ big_heading('Haketilo popup') }} + + {% call section() %} + {% call paragraph() %} + Taking inspiration from user interface features of browser extensions, + Haketilo also offers a popup window for quick interaction with the + user. For technical reasons, the popup is presented as part of the web + page and behaves slightly differently from those some users might have + found in similar tools. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Operating') }} + + {% call paragraph() %} + The popup dialog can be opened by typing big letters "HKT" anywhere on the + page. It then presents some basic information about the handling of + current URL. It also allows the user quickly define new + {{ doc_page_link('rules', 'script_blocking') }} or + {{ doc_page_link('payloads', 'packages') }} for it. As of Haketilo 3.0, + however, the actual configuration is not performed from the popup itself + but rather a relevant Haketilo rule/payload definition page is opened in a + new tab. + {% endcall %} + + {% call paragraph() %} + The dialog can be closed by clicking anywhere on the darker area around + it. It can then be reopened by typing "HKT" again. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Enabling/disabling') }} + + {% call paragraph() %} + Popup is unavailable by default on Haketilo special sites including + https://hkt.mitm.it. It can also be disabled independently on + {% endcall %} + + {% call unordered_list() %} + {% call list_entry() %} + pages with JS allowed, + {% endcall %} + {% call list_entry() %} + pages with JS blocked and + {% endcall %} + {% call list_entry() %} + pages with script payload injected. + {% endcall %} + {% endcall %} + + {% call paragraph() %} + This can be configured on the {{ hkt_link('setings page', 'home.home') }} + and might be useful to users who are careful about fingerprinting. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Fingerprinting considerations') }} + + {% call paragraph() %} + To make the popup available, Haketilo has to inject an additional script + to all pages. That makes it easy for pages to determine with certainty + that given user is running Haketilo. This has implications for privacy and + may also be used by a hostile site to selectively cause annoyance to + Haketilo users. + {% endcall %} + + {% call paragraph() %} + The above problems would be present regardless on pages with + Haketilo-injected payloads. I.e. in many cases a site could theoretically + find out the user is not accessing it in a normal way. However, the popup + also increases fingerprintability when no payload is in use and especially + on pages with JavaScript allowed. For this reason, the presence of popup + on pages has been made configurable. + {% endcall %} + + {% call paragraph() %} + It is also worth noting that as of version 3.0 Haketilo does not make + guarantees about the browser fingerprint. Despite best efforts, there are + still other aspects that might make a Haketilo user distinguishable to a + website even when popup is disabled. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Other caveats') }} + + {% call paragraph() %} + Some other potential issues related to the popup are described below. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ small_heading('Interference with the site') }} + + {% call paragraph() %} + The popup gets injected by Haketilo into the actual web page. Although + care was taken to make accidental breakage unlikely, it might still happen + under some specific conditions. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ small_heading('Interference with other script-blocking tools') }} + + {% call paragraph() %} + The popup is driven by a piece of JavaScript code injected by Haketilo to + pages. Haketilo by itself makes sure neither the policies specified by the + page nor its own script-blocking mechanisms interfere with this particular + piece. In spite of that, a browser extension or web browser's own settings + might prevent the popup script from executing, making the dialog + unavailable. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ small_heading('URL mismatch') }} + + {% call paragraph() %} + Sometimes a page might change parts of its address visible in browser's + URL bar. E.g. after opening https://entraide.chatons.org/ in + the browser we might see https://entraide.chatons.org/en/ as + the current address even though no reload happened. In addition, some + browsers hide URL's traling dash ("/") from the user. Regardless of that, + Haketilo's popup always presents the original URL under which the current + page was served. Although this the intended behavior, it might cause + confusion and therefore has been documented here. + {% endcall %} + {% endcall %} +{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/en_US/repositories.html.jinja b/src/hydrilla/proxy/self_doc/en_US/repositories.html.jinja new file mode 100644 index 0000000..4cf6d2c --- /dev/null +++ b/src/hydrilla/proxy/self_doc/en_US/repositories.html.jinja @@ -0,0 +1,128 @@ +{# +SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 + +Documentation page describing the concept of repositories in Haketilo. + +This file is part of Hydrilla&Haketilo. + +Copyright (C) 2022 Wojtek Kosior + +Dual licensed under +* GNU General Public License v3.0 or later and +* Creative Commons Attribution Share Alike 4.0 International. + +You can choose to use either of these licenses or both. + + +I, Wojtek Kosior, thereby promise not to sue for violation of this +file's licenses. Although I request that you do not make use of this +code in a proprietary work, I am not going to enforce this in court. +#} +{% extends "doc_base.html.jinja" %} + +{% block title %} Repositories {% endblock %} + +{% block main %} + {{ big_heading('Repositories in Haketilo') }} + + {% call section() %} + {% call paragraph() %} + {{ doc_page_link('Packages', 'packages') }} used to alter sites' behavior + can be obtained by users from Hydrilla repositories. The repositories to + use can be configured from the + {{ hkt_link('relevant Haketilo UI page', 'repos.repos') }}. When Haketilo + is first run, it only has one entry on that page - the official Hydrilla + repository with fixes for sites that normally rely on (often proprietary) + JavaScript. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Adding') }} + + {% call paragraph() %} + Before experimenting with third-party repositories please bear in mind + that a hostile Haketilo package can cause real harm. + Scripts injected by Haketilo have access to data on the page, including + cookies and passwords you may enter. + Do make sure the repositories you are using are trustworthy. + {% endcall %} + + {% call paragraph() %} + On the {{ hkt_link('repository addition page', 'repos.add_repo') }} the + user is expected to supply 2 pieces of information. + The URL of the repository and its + name. + The URL is supposed to be provided by repository owner. + Then name is only used locally and can be chosen by the user. + Allowed are most visible ASCII characters, with possible spaces in-betwen. + No 2 repositories can use the same name. + {% endcall %} + + {% call paragraph() %} + As of Haketilo version 3.0 the user does not need to provide any + authentication data (e.g. private keys) because cryptographic signing of + packages is not yet supported. This may change in the future. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Removing') }} + + {% call paragraph() %} + A repository can be deleted at any time. When this happens, + {% endcall %} + + {% call unordered_list() %} + {% call list_entry() %} + its packages that were in use (e.g. were enabled) retain their state, + {% endcall %} + {% call list_entry() %} + its packages that were installed but not in use become + orphans and can be removed from the + {{ hkt_link('settings page', 'home.home') }} and + {% endcall %} + {% call list_entry() %} + its packages that were not installed are forgotten. + {% endcall %} + {% endcall %} + + {% call paragraph() %} + A deleted repository remains viewable from the + {{ hkt_link('repositories management page', 'repos.repos') }} for as long + as some of its packages remain installed. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Operating') }} + + {% call paragraph() %} + Before repository's contents become viewable on the + {{ hkt_link('packages listing page', 'items.packages') }}, it needs to be + refreshed. + As of Haketilo 3.0-beta1, this action needs to be triggered manually by + the user from the configuration page of that repository. + Subsequent refreshals are needed every time the user wants to pull package + updates. + {% endcall %} + + {% call paragraph() %} + Repository's name and URL can also be changed from its configuration page. + The same requirements for their format hold as when adding a new + repository. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Local items') }} + + {% call paragraph() %} + When the users installs some additional packages without using a + repository, these are considered local packages. + A special "Local items" entry then appears on the + {{ hkt_link('repositories management page', 'repos.repos') }}. Local + packages that are not in use are automatically considered orhpans. + {% endcall %} + {% endcall %} +{% endblock %} diff --git a/src/hydrilla/proxy/self_doc/en_US/script_blocking.html.jinja b/src/hydrilla/proxy/self_doc/en_US/script_blocking.html.jinja new file mode 100644 index 0000000..c0a5275 --- /dev/null +++ b/src/hydrilla/proxy/self_doc/en_US/script_blocking.html.jinja @@ -0,0 +1,125 @@ +{# +SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 + +Documentation page describing how Haketilo blocks scripts. + +This file is part of Hydrilla&Haketilo. + +Copyright (C) 2022 Wojtek Kosior + +Dual licensed under +* GNU General Public License v3.0 or later and +* Creative Commons Attribution Share Alike 4.0 International. + +You can choose to use either of these licenses or both. + + +I, Wojtek Kosior, thereby promise not to sue for violation of this +file's licenses. Although I request that you do not make use of this +code in a proprietary work, I am not going to enforce this in court. +#} +{% extends "doc_base.html.jinja" %} + +{% block title %} Script blocking {% endblock %} + +{% block main %} + {{ big_heading('Script blocking in Haketilo') }} + + {% call section() %} + {% call paragraph() %} + Modern web browsers allow sites to execute software on users' + devices. This software is usually written in a language called JavaScript + and abbreviated as JS. It can serve various purposes - from small + enhancements to deployment of heavy applications inside the + browser. Because Haketilo aims to give users control over their web + browsing, one of its supported features is blocking of JavaScript + execution on per-page and per-site basis. + {% endcall %} + + {% call paragraph() %} + Besides the casual script-blocking discussed here, Haketilo also blocks + page's JavaScript when injecting the user-specified + {{ doc_page_link('script payloads', 'packages') }}. That functionality is + described on its own documentation page. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Configuring script blocking') }} + + {% call paragraph() %} + User can + {{ + hkt_link('define script-blocking and -allowing rules', 'rules.rules') + }} + using {{ doc_page_link('URL patterns', 'url_patterns') }}. Each such rule + tells Haketilo to either block or allow scripts on pages matched by its + pattern. Rules with more specific patterns can override those with less + specific ones as described on the + {{ doc_page_link('policy selection page', 'policy_selection') }}. + {% endcall %} + + {% call paragraph() %} + As an example, if we want all scripts on english Wikipedia pages to be + blocked, we can add a blocking rule with + pattern https://en.wikipedia.org/***. If we then wanted to + make an exception just for the "List of emoticons" page, we could create + an additional allowing rule with + https://en.wikipedia.org/wiki/List_of_emoticons as its + pattern. It would take effect on that page while all the other english + Wikipedia pages would still have their scripts blocked. + {% endcall %} + + {% call paragraph() %} + It is also possible to configure whether scripts should be blocked by + dafault on pages where no explicit rule and no payload is used. The + relevant option can be found on Haketilo + {{ hkt_link('settings page', 'home.home') }}. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Use with other script-blocking tools') }} + + {% call paragraph() %} + Various browsers and browser extension can also be configured to block + JavaScript. Haketilo works independently of those tools. If the user + desires to have scripts on certain page to execute normally, both Haketilo + and other tools must be configured to allow that. + {% endcall %} + + {% call paragraph() %} + Unlike most similar tools, Haketilo operates outside the web browser. As a + result, it is relatively unlikely for Haketilo to cause these to + malfunction. At the same time, it is relatively easy to have another + script blocker break some Haketilo functionality (e.g. its + {{ doc_page_link('popup', 'popup') }}). + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Technical details') }} + + {% call paragraph() %} + From technical point of view, Haketilo, as of version 3.0, blocks + JavaScript by altering the Content-Security-Policy (abbreviated CSP) + headers in HTTP responses. The original CSP directives sent by site are + retained, with exception of those which would result in CSP violation + reports being sent. Haketilo's own script-blocking directives are then + added to produce the final CSP which user's web browser eventually sees. + {% endcall %} + + {% call paragraph() %} + The above means that neither the scripts that would be blocked by page's + own rules nor those that are blocked by Haketilo are going to cause CSP + reports to be sent. + {% endcall %} + + {% call paragraph() %} + In addition, even when a page has JavaScript nominally blocked, Haketilo + 3.0 may nevertheless inject into it its own script responsible for making + the popup available. The CSP is then modified appropriately to allow only + that script to run. + {% endcall %} + {% endcall %} +{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/en_US/url_patterns.html.jinja b/src/hydrilla/proxy/self_doc/en_US/url_patterns.html.jinja new file mode 100644 index 0000000..f3415c5 --- /dev/null +++ b/src/hydrilla/proxy/self_doc/en_US/url_patterns.html.jinja @@ -0,0 +1,409 @@ +{# +SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 + +Documentation page describing URL patterns understood by Haketilo. + +This file is part of Hydrilla&Haketilo. + +Copyright (C) 2022 Wojtek Kosior + +Dual licensed under +* GNU General Public License v3.0 or later and +* Creative Commons Attribution Share Alike 4.0 International. + +You can choose to use either of these licenses or both. + + +I, Wojtek Kosior, thereby promise not to sue for violation of this +file's licenses. Although I request that you do not make use of this +code in a proprietary work, I am not going to enforce this in court. +#} +{% extends "doc_base.html.jinja" %} + +{% block title %} URL patterns {% endblock %} + +{% block main %} + {{ big_heading('Haketio URL patterns') }} + + {% call section() %} + {% call paragraph() %} + We want to be able to apply different rules and custom scripts for + different websites. However, merely specifying "do this for all documents + under https://example.com" is not enough. Single site's pages + might differ strongly and require different custom scripts to be + loaded. Always matching against a full URL like + https://example.com/something/somethingelse is also not + a good option. It doesn't allow us to properly handle a site that serves + similar pages for multiple values substituted for + somethingelse. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Employed solution') }} + + {% call paragraph() %} + Wildcards are being used to address the problem. Each payload and rule in + Haketilo has a URL pattern that specifies to which internet pages it + applies. A URL pattern can be as as simple as literal URL in which case it + only matches itself. It can also contain wildcards in the form of one or + more asterisks (*) that correspond to multiple possible + strings occurring in that place. + {% endcall %} + + {% call paragraph() %} + Wildcards can appear in URL's domain and path that follows it. These 2 + types of wildcards are handled separately. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ small_heading('Domain wildcards') }} + + {% call paragraph() %} + A domain wildcard takes the form of one, two or three asterisks occurring + in place of a single domain name segment at the beginning + (left). Depending on the number of asterisks, the meaning is as follows + {% endcall %} + + {% call unordered_list() %} + {% call list_entry() %} + no asterisks (e.g. example.com) - match domain name exactly + (e.g. example.com) + {% endcall %} + {% call list_entry() %} + one asterisk (e.g. *.example.com) - match all domains + resulting from substituting * with a + single segment (e.g. + banana.example.com or pineapple.example.com + but not pineapple.pen.example.com + nor example.com) + {% endcall %} + {% call list_entry() %} + two asterisks (e.g. **.example.com) - match all domains + resulting from substituting ** with + two or more segments (e.g. + monad.breakfast.example.com or + pure.monad.breakfast.example.com but + not cabalhell.example.com nor + example.com) + {% endcall %} + {% call list_entry() %} + three asterisks (e.g. ***.example.com) - match all domains + resulting from substituting *** with + zero or more segments (e.g. + hello.parkmeter.example.com or + iliketrains.example.com or example.com) + {% endcall %} + {% endcall %} + {% endcall %} + + {% call section() %} + {{ small_heading('Path wildcards') }} + + {% call paragraph() %} + A path wildcard takes the form of one, two or three asterisks occurring in + place of a single path segment at the end of path (right). Depending on + the number of asterisks, the meaning is as follows + {% endcall %} + + {% call unordered_list() %} + {% call list_entry() %} + no asterisks (e.g. /joke/clowns) - match path exactly (e.g. + /joke/clowns) + {% endcall %} + {% call list_entry() %} + one asterisk (e.g. /itscalled/*) - match all paths + resulting from substituting * with a + single segment (e.g. + /itscalled/gnulinux or /itscalled/glamp but + not /itscalled/ nor + /itscalled/gnu/linux) + {% endcall %} + {% call list_entry() %} + two asterisks (e.g. /another/**) - match all paths + resulting from substituting ** with + two or more segments (e.g. + /another/nsa/backdoor or + /another/best/programming/language but + not /another/apibreak nor + /another) + {% endcall %} + {% call list_entry() %} + three asterisks (e.g. /mail/dmarc/***) - match all paths + resulting from substituting *** with + zero or more segments (e.g. + /mail/dmarc/spf, /mail/dmarc or + /mail/dmarc/dkim/failure but + not /mail/) + {% endcall %} + {% endcall %} + + {% call paragraph() %} + If pattern ends without a trailing slash, it + mathes paths with any number of trailing slashes, including zero. If + pattern ends with a trailing slash, it only + mathes paths with one or more trailing slashes. For example, + /itscalled/* matches /itscalled/gnulinux, + /itscalled/gnulinux/ and /itscalled/gnulinux// + while /itscalled/*/ only matches + /itscalled/gnulinux/ and /itscalled/gnulinux// + out of those three. + {% endcall %} + + {% call paragraph() %} + If two patterns only differ by the presence of a trailing slash, + pattern with a trailing slash is considered + more specific. + {% endcall %} + + {% call paragraph() %} + Additionally, any path with literal trailing asterisks is matched by + itself, even if such pattern would otherwise be treated as wildcard + (e.g. /gobacktoxul/** matches /gobacktoxul/**). + This is likely to change in the future and would best not be relied upon. + Appending three additional asterisks to path pattern to represent literal + asterisks is being considered. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ small_heading('URL scheme wildcard') }} + + {% call paragraph() %} + http:// and https:// shemes in the URL are + matched exactly. However, starting with Haketilo 3.0, it is also possible + for scheme pseudo-wildcard of http*:// to be used. Use of URL + pattern with this scheme is equivalent to the use of 2 separate patterns + starting with http:// and https://, + respectively. For example, pattern http*://example.com shall + match both https://example.com and + http://example.com. + {% endcall %} + + {% call paragraph() %} + http*:// may be considered not to be a true wildcard but + rather an alias for either of the other 2 values. As of Haketilo 3.0, the + speicificity of a URL pattern starting with http*:// is + considered to be the same as that of the corresponding URL pattern + starting with http:// or https://. In case of a + conflict, the order of precedence of such patterns is unspecified. This + behavior is likely to change in the future versions of Haketilo. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ small_heading('Wildcard pattern priorities and querying') }} + + {% call paragraph() %} + In case multiple patterns match some URL, the more specific one is + preferred. Specificity is considered as follows + {% endcall %} + + {% call unordered_list() %} + {% call list_entry() %} + If patterns only differ in the final path segment, the one with least + wildcard asterisks in that segment if preferred. + {% endcall %} + {% call list_entry() %} + If patterns, besides the above, only differ in path length, one with + longer path is preferred. Neither final wildcard segment nor trailing + dashes account for path length. + {% endcall %} + {% call list_entry() %} + If patterns, besides the above, only differ in the initial domain + segment, one with least wildcard asterisks in that segment is preferred. + {% endcall %} + {% call list_entry() %} + If patterns differ in domain length, one with longer domain is + preferred. Initial wildcard segment does not account for domain length. + {% endcall %} + {% endcall %} + + {% call paragraph() %} + As an example, consider the URL + http://settings.query.example.com/google/tries/destroy/adblockers//. + Patterns matching it are, in the following order + {% endcall %} + + {% call verbatim() %} +http://settings.query.example.com/google/tries/destroy/adblockers/ +http://settings.query.example.com/google/tries/destroy/adblockers +http://settings.query.example.com/google/tries/destroy/adblockers/***/ +http://settings.query.example.com/google/tries/destroy/adblockers/*** +http://settings.query.example.com/google/tries/destroy/*/ +http://settings.query.example.com/google/tries/destroy/* +http://settings.query.example.com/google/tries/destroy/***/ +http://settings.query.example.com/google/tries/destroy/*** +http://settings.query.example.com/google/tries/**/ +http://settings.query.example.com/google/tries/** +http://settings.query.example.com/google/tries/***/ +http://settings.query.example.com/google/tries/*** +http://settings.query.example.com/google/**/ +http://settings.query.example.com/google/** +http://settings.query.example.com/google/***/ +http://settings.query.example.com/google/*** +http://settings.query.example.com/**/ +http://settings.query.example.com/** +http://settings.query.example.com/***/ +http://settings.query.example.com/*** +http://***.settings.query.example.com/google/tries/destroy/adblockers/ +http://***.settings.query.example.com/google/tries/destroy/adblockers +http://***.settings.query.example.com/google/tries/destroy/adblockers/***/ +http://***.settings.query.example.com/google/tries/destroy/adblockers/*** +http://***.settings.query.example.com/google/tries/destroy/*/ +http://***.settings.query.example.com/google/tries/destroy/* +http://***.settings.query.example.com/google/tries/destroy/***/ +http://***.settings.query.example.com/google/tries/destroy/*** +http://***.settings.query.example.com/google/tries/**/ +http://***.settings.query.example.com/google/tries/** +http://***.settings.query.example.com/google/tries/***/ +http://***.settings.query.example.com/google/tries/*** +http://***.settings.query.example.com/google/**/ +http://***.settings.query.example.com/google/** +http://***.settings.query.example.com/google/***/ +http://***.settings.query.example.com/google/*** +http://***.settings.query.example.com/**/ +http://***.settings.query.example.com/** +http://***.settings.query.example.com/***/ +http://***.settings.query.example.com/*** +http://*.query.example.com/google/tries/destroy/adblockers/ +http://*.query.example.com/google/tries/destroy/adblockers +http://*.query.example.com/google/tries/destroy/adblockers/***/ +http://*.query.example.com/google/tries/destroy/adblockers/*** +http://*.query.example.com/google/tries/destroy/*/ +http://*.query.example.com/google/tries/destroy/* +http://*.query.example.com/google/tries/destroy/***/ +http://*.query.example.com/google/tries/destroy/*** +http://*.query.example.com/google/tries/**/ +http://*.query.example.com/google/tries/** +http://*.query.example.com/google/tries/***/ +http://*.query.example.com/google/tries/*** +http://*.query.example.com/google/**/ +http://*.query.example.com/google/** +http://*.query.example.com/google/***/ +http://*.query.example.com/google/*** +http://*.query.example.com/**/ +http://*.query.example.com/** +http://*.query.example.com/***/ +http://*.query.example.com/*** +http://***.query.example.com/google/tries/destroy/adblockers/ +http://***.query.example.com/google/tries/destroy/adblockers +http://***.query.example.com/google/tries/destroy/adblockers/***/ +http://***.query.example.com/google/tries/destroy/adblockers/*** +http://***.query.example.com/google/tries/destroy/*/ +http://***.query.example.com/google/tries/destroy/* +http://***.query.example.com/google/tries/destroy/***/ +http://***.query.example.com/google/tries/destroy/*** +http://***.query.example.com/google/tries/**/ +http://***.query.example.com/google/tries/** +http://***.query.example.com/google/tries/***/ +http://***.query.example.com/google/tries/*** +http://***.query.example.com/google/**/ +http://***.query.example.com/google/** +http://***.query.example.com/google/***/ +http://***.query.example.com/google/*** +http://***.query.example.com/**/ +http://***.query.example.com/** +http://***.query.example.com/***/ +http://***.query.example.com/*** +http://**.example.com/google/tries/destroy/adblockers/ +http://**.example.com/google/tries/destroy/adblockers +http://**.example.com/google/tries/destroy/adblockers/***/ +http://**.example.com/google/tries/destroy/adblockers/*** +http://**.example.com/google/tries/destroy/*/ +http://**.example.com/google/tries/destroy/* +http://**.example.com/google/tries/destroy/***/ +http://**.example.com/google/tries/destroy/*** +http://**.example.com/google/tries/**/ +http://**.example.com/google/tries/** +http://**.example.com/google/tries/***/ +http://**.example.com/google/tries/*** +http://**.example.com/google/**/ +http://**.example.com/google/** +http://**.example.com/google/***/ +http://**.example.com/google/*** +http://**.example.com/**/ +http://**.example.com/** +http://**.example.com/***/ +http://**.example.com/*** +http://***.example.com/google/tries/destroy/adblockers/ +http://***.example.com/google/tries/destroy/adblockers +http://***.example.com/google/tries/destroy/adblockers/***/ +http://***.example.com/google/tries/destroy/adblockers/*** +http://***.example.com/google/tries/destroy/*/ +http://***.example.com/google/tries/destroy/* +http://***.example.com/google/tries/destroy/***/ +http://***.example.com/google/tries/destroy/*** +http://***.example.com/google/tries/**/ +http://***.example.com/google/tries/** +http://***.example.com/google/tries/***/ +http://***.example.com/google/tries/*** +http://***.example.com/google/**/ +http://***.example.com/google/** +http://***.example.com/google/***/ +http://***.example.com/google/*** +http://***.example.com/**/ +http://***.example.com/** +http://***.example.com/***/ +http://***.example.com/*** + {% endcall %} + + {% call paragraph() %} + Variants of those patterns starting with http*:// would of + course match as well. They have been omitted for simplicity. + {% endcall %} + + {% call paragraph() %} + For a simpler URL like https://example.com the patterns would + be + {% endcall %} + + {% call verbatim() %} +https://example.com +https://example.com/*** +https://***.example.com +https://***.example.com/*** + {% endcall %} + + {% call paragraph() %} + Variants of those patterns with a trailing dash added + would not match the URL. Also, the pattern + variants starting with http*:// have been once again omitted. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ small_heading('Limits') }} + + {% call paragraph() %} + In order to prevent some easy-to-conduct DoS attacks, older versions of + Haketilo and Hydrilla limited the lengths of domain and path parts of + processed URLs. This is no longer the case. + {% endcall %} + {% endcall %} + + {% call section() %} + {{ medium_heading('Alternative solution idea: mimicking web server mechanics') }} + + {% call paragraph() %} + While wildcard patterns as presented give a lot of flexibility, they are + not the only viable approach to specifying what URLs to apply + rules/payloads to. In fact, wildcards are different from how the server + side of a typical website decides what to return for a given URL request. + {% endcall %} + + {% call paragraph() %} + In a typical scenario, an HTTP server like Apache reads configuration + files provided by its administrator and uses various (virtual host, + redirect, request rewrite, CGI, etc.) instructions to decide how to handle + given URL. Perhps using a scheme that mimics the configuration options + typically used with web servers would give more efficiency in specifying + what page settings to apply when. + {% endcall %} + + {% call paragraph() %} + This approach may be considered in the future. + {% endcall %} + {% endcall %} +{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/packages.html.jinja b/src/hydrilla/proxy/self_doc/packages.html.jinja deleted file mode 100644 index 23e6f45..0000000 --- a/src/hydrilla/proxy/self_doc/packages.html.jinja +++ /dev/null @@ -1,218 +0,0 @@ -{# -SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 - -Documentation page describing the concept of packages in Haketilo. - -This file is part of Hydrilla&Haketilo. - -Copyright (C) 2022 Wojtek Kosior - -Dual licensed under -* GNU General Public License v3.0 or later and -* Creative Commons Attribution Share Alike 4.0 International. - -You can choose to use either of these licenses or both. - - -I, Wojtek Kosior, thereby promise not to sue for violation of this -file's licenses. Although I request that you do not make use of this -code in a proprietary work, I am not going to enforce this in court. -#} -{% extends "doc_base.html.jinja" %} - -{% block title %} Packages {% endblock %} - -{% block main %} - {{ big_heading('Packages in Haketilo') }} - - {% call section() %} - {% call paragraph() %} - Users can modify web pages by creating, installing and enabling - packages. - A package associates {{ doc_page_link('URL patterns', 'url_patterns') }} - with payloads (i.e. sets of scripts) that can be injected to pages. - For instance, if an enabled package associates pattern - https://example.com/*** with a script that adds a big - "Hello world!" text to the page, this package shall cause "Hello world!" - to appear on pages under example.com. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Packages and libraries') }} - - {% call paragraph() %} - To make mapping custom JavaScript applications and their dependencies to - web pages more manageable, Haketilo defines its own concept of "packages" - and "libraries". - {% endcall %} - - {% call unordered_list() %} - {% call list_entry() %} - package - Also called mapping. - It associates URL patterns with libraries. - {% endcall %} - {% call list_entry() %} - library - Sometimes also referred to as - resource. - Defines a set of scripts that can be injected together into a page. - It can also name other libraries as its dependencies. - When injecting scripts of a given library into some page, Haketilo will - first inject scripts of all libraries depended on. - {% endcall %} - {% endcall %} - - {% call paragraph() %} - It's ultimately a package that provides concrete functionality to the end - user and that can be enabled or disabled. - For this reason, a casual user does not even need to be aware of the - existence of libraries. - Haketilo UI advanced interface features need to be enabled on the - {{ hkt_link('settings page', 'home.home') }} for installed libraries to be - viewable. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Installing') }} - - {% call paragraph() %} - Useful packages prepared by others can be installed from Hydrilla - repositories. The repositories can be configured - {{ hkt_link('through Haketilo user interface', 'repos.repos') }} as - described on - {{ doc_page_link('the relevant documentation page', 'repositories') }}. - As of Haketilo 3.0-beta1 they need to be manually "refreshed" for new - packages from them to be shown in Haketilo. - Available packages viewable on the - {{ hkt_link('packages listing page', 'items.packages') }} are not - immediately installed. - This only happens after they are explicitly enabled or automatically - enabled (if the user configured Haketilo to do this). - {% endcall %} - - {% call paragraph() %} - For convenience, users can also create simple packages - {{ hkt_link('directly in Haketilo UI', 'import.items_import') }}. - A simple form can be used to quickly define a standalone script payload - for a set of URL patterns. As of Haketilo 3.0 only simple (i.e. - single-library) payloads can be created this way. - {% endcall %} - - {% call paragraph() %} - It is also possible to import packages from files. - For this, a directory of serveable mappings and reasources - as produced - by Hydrilla builder and used by Hydrilla server - has to be put into a ZIP - archive. - It can then be uploaded to Haketilo via its - {{ hkt_link('import page', 'import.items_import') }}. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Uninstalling') }} - - {% call paragraph() %} - Haketilo tracks dependencies between packages and libraries and - automatically determines which of them are no longer needed. - These are called orphans and if present, can be - removed from the {{ hkt_link('settings page', 'home.home') }}. - A version of package or library that is not being used but is still - available from an active repository is not considered an orphan. It - automatically becomes one when the repository either stops advertising it - as available or gets removed by the user from - {{ hkt_link('the repositories list', 'repos.repos') }}. - {% endcall %} - - {% call paragraph() %} - When advanced UI features are enabled, it is additionally possible to - manually uninstall any single package that is not in use at a given - moment. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Package contents') }} - - {% call paragraph() %} - Each package has an identifier (built from a - restricted set of characters), a long name, a - description, a version - and almost always a list of license files and a - set of URL patterns mapped to libraries. - In addition there might also be other pieces of information such as - required permissions. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Enabling/disabling') }} - - {% call paragraph() %} - The user can put package in any of 3 possible states. - It can be either enabled, - disabled or - not configured. - {% endcall %} - - {% call paragraph() %} - An enabled package always has its payloads injected on pages matched by - their patterns (unless some more specific pattern takes precedence on the - given page as described on the - {{ doc_page_link('policy selection page', 'policy_selection') }}). - {% endcall %} - - {% call paragraph() %} - A disabled package is always ignored. - It has to be manually re-enabled for Haketilo to take it into account - again. - {% endcall %} - - {% call paragraph() %} - Finally, a package that is neither explicitly enabled nor disabled can be - treated differently depending on user's choice on the - {{ hkt_link('settings page', 'home.home') }}. - It is possible to have Haketilo - {% endcall %} - - {% call unordered_list() %} - {% call list_entry() %} - automatically inject such packages' payloads on mathing pages, - {% endcall %} - {% call list_entry() %} - prompt the user on matching pages asking whether the package should be - enabled or - {% endcall %} - {% call list_entry() %} - completely ignore non-configured packages. - {% endcall %} - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Handling multiple versions') }} - - {% call paragraph() %} - It is possible to have many versions of the same package or library - installed. - When this is the case, Haketilo by default uses the newest versions it - can. - Additionally, if certain package is enabled, its page also allows the user - to configure its pinning. - A package can be - {% endcall %} - - {% call unordered_list() %} - {% call list_entry() %} - pinned to use a particular version, - {% endcall %} - {% call list_entry() %} - pinned to use the best version from a particular - {{ doc_page_link('repository', 'repositories') }} or - {% endcall %} - {% call list_entry() %} - not pinned at all (best version overall is used). - {% endcall %} - {% endcall %} - {% endcall %} -{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/policy_selection.html.jinja b/src/hydrilla/proxy/self_doc/policy_selection.html.jinja deleted file mode 100644 index 687d2bd..0000000 --- a/src/hydrilla/proxy/self_doc/policy_selection.html.jinja +++ /dev/null @@ -1,109 +0,0 @@ -{# -SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 - -Documentation page describing how Haketilo selects policy to apply to a page. - -This file is part of Hydrilla&Haketilo. - -Copyright (C) 2022 Wojtek Kosior - -Dual licensed under -* GNU General Public License v3.0 or later and -* Creative Commons Attribution Share Alike 4.0 International. - -You can choose to use either of these licenses or both. - - -I, Wojtek Kosior, thereby promise not to sue for violation of this -file's licenses. Although I request that you do not make use of this -code in a proprietary work, I am not going to enforce this in court. -#} -{% extends "doc_base.html.jinja" %} - -{% block title %} Policy selection {% endblock %} - -{% block main %} - {{ big_heading('Page policy selection') }} - - {% call section() %} - {% call paragraph() %} - When a web page is opened, Haketilo is capable of either - {% call unordered_list() %} - {% call list_entry() %} - blocking page's own scripts and - {{ doc_page_link('injecting payload', 'packages') }} - configured by the user, - {% endcall %} - {% call list_entry() %} - blocking page's own scripts and injecting an automatically-chosen - payload that is usable with the page, - {% endcall %} - {% call list_entry() %} - presenting a dialog asking whether to enable an automatically-chosen - payload that is usable with the page, - {% endcall %} - {% call list_entry() %} - {{ doc_page_link('blocking', 'script_blocking') }} page's own scripts - or - {% endcall %} - {% call list_entry() %} - allowing page's own scripts to execute normally (i.e. not modifying - the page in any meaningful way). - {% endcall %} - {% endcall %} - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Policy precedence') }} - - {% call paragraph() %} - User configures Haketilo's behavior by defining script-blocking and - -allowing rules and by adding and enabling packages. Each rule and each - package payload has a {{ doc_page_link('URL pattern', 'url_patterns') }}. - This pattern determines which pages the policy is compatible with. - Patterns also have well-defined specificity. When multiple rules and - packages are combatible with given page's URL, the one with the most - specific pattern "wins". In case of a tie, payload injection is assumed to - take precedence over rule application. - {% endcall %} - - {% call paragraph() %} - In the absence of suitable rules and enabled packages, Haketilo may - consider non-enabled packages that are suitable for use on the - currently-visited site. It will either inject package payload - automatically, ask the user whether to enable the package or ignore it - completely. The user can switch between these 3 behaviors on the Haketilo - {{ hkt_link('settings page', 'home.home') }}. Packages that were - explicitly marked as disabled will always be ignored. Pattern specificity - is also taken into account in case of multiple packages. - {% endcall %} - - {% call paragraph() %} - When absolutely no explicit policy appears suitable for given page, - Haketilo will apply its default script handling behavrior. Whether - JavaScript is blocked or allowed by default is also determined by user's - choice on the {{ hkt_link('settings page', 'home.home') }}. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Special cases') }} - - {% call paragraph() %} - The sites served by Haketilo itself are exempt from all policies. These - are http://hkt.mitm.it, https://hkt.mitm.it - and http://mitm.it. Additionally, if Haketilo experiences an - internal error (e.g. because it could not parse current URL as sent in by - the browser), it will try to block page's JavaScript as a security - measure. - {% endcall %} - - {% call paragraph() %} - Internally, Haketilo also has a special high-priority policy for serving - files used by payloads and for making its APIs accessible to payload - scripts. This is, however, an implementation detail and casual users need - not care about it nor understand these nuances. - {% endcall %} - {% endcall %} -{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/popup.html.jinja b/src/hydrilla/proxy/self_doc/popup.html.jinja deleted file mode 100644 index a5ad909..0000000 --- a/src/hydrilla/proxy/self_doc/popup.html.jinja +++ /dev/null @@ -1,157 +0,0 @@ -{# -SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 - -Documentation page describing Haketilo popup. - -This file is part of Hydrilla&Haketilo. - -Copyright (C) 2022 Wojtek Kosior - -Dual licensed under -* GNU General Public License v3.0 or later and -* Creative Commons Attribution Share Alike 4.0 International. - -You can choose to use either of these licenses or both. - - -I, Wojtek Kosior, thereby promise not to sue for violation of this -file's licenses. Although I request that you do not make use of this -code in a proprietary work, I am not going to enforce this in court. -#} -{% extends "doc_base.html.jinja" %} - -{% block title %} Popup {% endblock %} - -{% block main %} - {{ big_heading('Haketilo popup') }} - - {% call section() %} - {% call paragraph() %} - Taking inspiration from user interface features of browser extensions, - Haketilo also offers a popup window for quick interaction with the - user. For technical reasons, the popup is presented as part of the web - page and behaves slightly differently from those some users might have - found in similar tools. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Operating') }} - - {% call paragraph() %} - The popup dialog can be opened by typing big letters "HKT" anywhere on the - page. It then presents some basic information about the handling of - current URL. It also allows the user quickly define new - {{ doc_page_link('rules', 'script_blocking') }} or - {{ doc_page_link('payloads', 'packages') }} for it. As of Haketilo 3.0, - however, the actual configuration is not performed from the popup itself - but rather a relevant Haketilo rule/payload definition page is opened in a - new tab. - {% endcall %} - - {% call paragraph() %} - The dialog can be closed by clicking anywhere on the darker area around - it. It can then be reopened by typing "HKT" again. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Enabling/disabling') }} - - {% call paragraph() %} - Popup is unavailable by default on Haketilo special sites including - https://hkt.mitm.it. It can also be disabled independently on - {% endcall %} - - {% call unordered_list() %} - {% call list_entry() %} - pages with JS allowed, - {% endcall %} - {% call list_entry() %} - pages with JS blocked and - {% endcall %} - {% call list_entry() %} - pages with script payload injected. - {% endcall %} - {% endcall %} - - {% call paragraph() %} - This can be configured on the {{ hkt_link('setings page', 'home.home') }} - and might be useful to users who are careful about fingerprinting. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Fingerprinting considerations') }} - - {% call paragraph() %} - To make the popup available, Haketilo has to inject an additional script - to all pages. That makes it easy for pages to determine with certainty - that given user is running Haketilo. This has implications for privacy and - may also be used by a hostile site to selectively cause annoyance to - Haketilo users. - {% endcall %} - - {% call paragraph() %} - The above problems would be present regardless on pages with - Haketilo-injected payloads. I.e. in many cases a site could theoretically - find out the user is not accessing it in a normal way. However, the popup - also increases fingerprintability when no payload is in use and especially - on pages with JavaScript allowed. For this reason, the presence of popup - on pages has been made configurable. - {% endcall %} - - {% call paragraph() %} - It is also worth noting that as of version 3.0 Haketilo does not make - guarantees about the browser fingerprint. Despite best efforts, there are - still other aspects that might make a Haketilo user distinguishable to a - website even when popup is disabled. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Other caveats') }} - - {% call paragraph() %} - Some other potential issues related to the popup are described below. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ small_heading('Interference with the site') }} - - {% call paragraph() %} - The popup gets injected by Haketilo into the actual web page. Although - care was taken to make accidental breakage unlikely, it might still happen - under some specific conditions. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ small_heading('Interference with other script-blocking tools') }} - - {% call paragraph() %} - The popup is driven by a piece of JavaScript code injected by Haketilo to - pages. Haketilo by itself makes sure neither the policies specified by the - page nor its own script-blocking mechanisms interfere with this particular - piece. In spite of that, a browser extension or web browser's own settings - might prevent the popup script from executing, making the dialog - unavailable. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ small_heading('URL mismatch') }} - - {% call paragraph() %} - Sometimes a page might change parts of its address visible in browser's - URL bar. E.g. after opening https://entraide.chatons.org/ in - the browser we might see https://entraide.chatons.org/en/ as - the current address even though no reload happened. In addition, some - browsers hide URL's traling dash ("/") from the user. Regardless of that, - Haketilo's popup always presents the original URL under which the current - page was served. Although this the intended behavior, it might cause - confusion and therefore has been documented here. - {% endcall %} - {% endcall %} -{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/repositories.html.jinja b/src/hydrilla/proxy/self_doc/repositories.html.jinja deleted file mode 100644 index 4cf6d2c..0000000 --- a/src/hydrilla/proxy/self_doc/repositories.html.jinja +++ /dev/null @@ -1,128 +0,0 @@ -{# -SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 - -Documentation page describing the concept of repositories in Haketilo. - -This file is part of Hydrilla&Haketilo. - -Copyright (C) 2022 Wojtek Kosior - -Dual licensed under -* GNU General Public License v3.0 or later and -* Creative Commons Attribution Share Alike 4.0 International. - -You can choose to use either of these licenses or both. - - -I, Wojtek Kosior, thereby promise not to sue for violation of this -file's licenses. Although I request that you do not make use of this -code in a proprietary work, I am not going to enforce this in court. -#} -{% extends "doc_base.html.jinja" %} - -{% block title %} Repositories {% endblock %} - -{% block main %} - {{ big_heading('Repositories in Haketilo') }} - - {% call section() %} - {% call paragraph() %} - {{ doc_page_link('Packages', 'packages') }} used to alter sites' behavior - can be obtained by users from Hydrilla repositories. The repositories to - use can be configured from the - {{ hkt_link('relevant Haketilo UI page', 'repos.repos') }}. When Haketilo - is first run, it only has one entry on that page - the official Hydrilla - repository with fixes for sites that normally rely on (often proprietary) - JavaScript. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Adding') }} - - {% call paragraph() %} - Before experimenting with third-party repositories please bear in mind - that a hostile Haketilo package can cause real harm. - Scripts injected by Haketilo have access to data on the page, including - cookies and passwords you may enter. - Do make sure the repositories you are using are trustworthy. - {% endcall %} - - {% call paragraph() %} - On the {{ hkt_link('repository addition page', 'repos.add_repo') }} the - user is expected to supply 2 pieces of information. - The URL of the repository and its - name. - The URL is supposed to be provided by repository owner. - Then name is only used locally and can be chosen by the user. - Allowed are most visible ASCII characters, with possible spaces in-betwen. - No 2 repositories can use the same name. - {% endcall %} - - {% call paragraph() %} - As of Haketilo version 3.0 the user does not need to provide any - authentication data (e.g. private keys) because cryptographic signing of - packages is not yet supported. This may change in the future. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Removing') }} - - {% call paragraph() %} - A repository can be deleted at any time. When this happens, - {% endcall %} - - {% call unordered_list() %} - {% call list_entry() %} - its packages that were in use (e.g. were enabled) retain their state, - {% endcall %} - {% call list_entry() %} - its packages that were installed but not in use become - orphans and can be removed from the - {{ hkt_link('settings page', 'home.home') }} and - {% endcall %} - {% call list_entry() %} - its packages that were not installed are forgotten. - {% endcall %} - {% endcall %} - - {% call paragraph() %} - A deleted repository remains viewable from the - {{ hkt_link('repositories management page', 'repos.repos') }} for as long - as some of its packages remain installed. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Operating') }} - - {% call paragraph() %} - Before repository's contents become viewable on the - {{ hkt_link('packages listing page', 'items.packages') }}, it needs to be - refreshed. - As of Haketilo 3.0-beta1, this action needs to be triggered manually by - the user from the configuration page of that repository. - Subsequent refreshals are needed every time the user wants to pull package - updates. - {% endcall %} - - {% call paragraph() %} - Repository's name and URL can also be changed from its configuration page. - The same requirements for their format hold as when adding a new - repository. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Local items') }} - - {% call paragraph() %} - When the users installs some additional packages without using a - repository, these are considered local packages. - A special "Local items" entry then appears on the - {{ hkt_link('repositories management page', 'repos.repos') }}. Local - packages that are not in use are automatically considered orhpans. - {% endcall %} - {% endcall %} -{% endblock %} diff --git a/src/hydrilla/proxy/self_doc/script_blocking.html.jinja b/src/hydrilla/proxy/self_doc/script_blocking.html.jinja deleted file mode 100644 index c0a5275..0000000 --- a/src/hydrilla/proxy/self_doc/script_blocking.html.jinja +++ /dev/null @@ -1,125 +0,0 @@ -{# -SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 - -Documentation page describing how Haketilo blocks scripts. - -This file is part of Hydrilla&Haketilo. - -Copyright (C) 2022 Wojtek Kosior - -Dual licensed under -* GNU General Public License v3.0 or later and -* Creative Commons Attribution Share Alike 4.0 International. - -You can choose to use either of these licenses or both. - - -I, Wojtek Kosior, thereby promise not to sue for violation of this -file's licenses. Although I request that you do not make use of this -code in a proprietary work, I am not going to enforce this in court. -#} -{% extends "doc_base.html.jinja" %} - -{% block title %} Script blocking {% endblock %} - -{% block main %} - {{ big_heading('Script blocking in Haketilo') }} - - {% call section() %} - {% call paragraph() %} - Modern web browsers allow sites to execute software on users' - devices. This software is usually written in a language called JavaScript - and abbreviated as JS. It can serve various purposes - from small - enhancements to deployment of heavy applications inside the - browser. Because Haketilo aims to give users control over their web - browsing, one of its supported features is blocking of JavaScript - execution on per-page and per-site basis. - {% endcall %} - - {% call paragraph() %} - Besides the casual script-blocking discussed here, Haketilo also blocks - page's JavaScript when injecting the user-specified - {{ doc_page_link('script payloads', 'packages') }}. That functionality is - described on its own documentation page. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Configuring script blocking') }} - - {% call paragraph() %} - User can - {{ - hkt_link('define script-blocking and -allowing rules', 'rules.rules') - }} - using {{ doc_page_link('URL patterns', 'url_patterns') }}. Each such rule - tells Haketilo to either block or allow scripts on pages matched by its - pattern. Rules with more specific patterns can override those with less - specific ones as described on the - {{ doc_page_link('policy selection page', 'policy_selection') }}. - {% endcall %} - - {% call paragraph() %} - As an example, if we want all scripts on english Wikipedia pages to be - blocked, we can add a blocking rule with - pattern https://en.wikipedia.org/***. If we then wanted to - make an exception just for the "List of emoticons" page, we could create - an additional allowing rule with - https://en.wikipedia.org/wiki/List_of_emoticons as its - pattern. It would take effect on that page while all the other english - Wikipedia pages would still have their scripts blocked. - {% endcall %} - - {% call paragraph() %} - It is also possible to configure whether scripts should be blocked by - dafault on pages where no explicit rule and no payload is used. The - relevant option can be found on Haketilo - {{ hkt_link('settings page', 'home.home') }}. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Use with other script-blocking tools') }} - - {% call paragraph() %} - Various browsers and browser extension can also be configured to block - JavaScript. Haketilo works independently of those tools. If the user - desires to have scripts on certain page to execute normally, both Haketilo - and other tools must be configured to allow that. - {% endcall %} - - {% call paragraph() %} - Unlike most similar tools, Haketilo operates outside the web browser. As a - result, it is relatively unlikely for Haketilo to cause these to - malfunction. At the same time, it is relatively easy to have another - script blocker break some Haketilo functionality (e.g. its - {{ doc_page_link('popup', 'popup') }}). - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Technical details') }} - - {% call paragraph() %} - From technical point of view, Haketilo, as of version 3.0, blocks - JavaScript by altering the Content-Security-Policy (abbreviated CSP) - headers in HTTP responses. The original CSP directives sent by site are - retained, with exception of those which would result in CSP violation - reports being sent. Haketilo's own script-blocking directives are then - added to produce the final CSP which user's web browser eventually sees. - {% endcall %} - - {% call paragraph() %} - The above means that neither the scripts that would be blocked by page's - own rules nor those that are blocked by Haketilo are going to cause CSP - reports to be sent. - {% endcall %} - - {% call paragraph() %} - In addition, even when a page has JavaScript nominally blocked, Haketilo - 3.0 may nevertheless inject into it its own script responsible for making - the popup available. The CSP is then modified appropriately to allow only - that script to run. - {% endcall %} - {% endcall %} -{% endblock main %} diff --git a/src/hydrilla/proxy/self_doc/url_patterns.html.jinja b/src/hydrilla/proxy/self_doc/url_patterns.html.jinja deleted file mode 100644 index f3415c5..0000000 --- a/src/hydrilla/proxy/self_doc/url_patterns.html.jinja +++ /dev/null @@ -1,409 +0,0 @@ -{# -SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 - -Documentation page describing URL patterns understood by Haketilo. - -This file is part of Hydrilla&Haketilo. - -Copyright (C) 2022 Wojtek Kosior - -Dual licensed under -* GNU General Public License v3.0 or later and -* Creative Commons Attribution Share Alike 4.0 International. - -You can choose to use either of these licenses or both. - - -I, Wojtek Kosior, thereby promise not to sue for violation of this -file's licenses. Although I request that you do not make use of this -code in a proprietary work, I am not going to enforce this in court. -#} -{% extends "doc_base.html.jinja" %} - -{% block title %} URL patterns {% endblock %} - -{% block main %} - {{ big_heading('Haketio URL patterns') }} - - {% call section() %} - {% call paragraph() %} - We want to be able to apply different rules and custom scripts for - different websites. However, merely specifying "do this for all documents - under https://example.com" is not enough. Single site's pages - might differ strongly and require different custom scripts to be - loaded. Always matching against a full URL like - https://example.com/something/somethingelse is also not - a good option. It doesn't allow us to properly handle a site that serves - similar pages for multiple values substituted for - somethingelse. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Employed solution') }} - - {% call paragraph() %} - Wildcards are being used to address the problem. Each payload and rule in - Haketilo has a URL pattern that specifies to which internet pages it - applies. A URL pattern can be as as simple as literal URL in which case it - only matches itself. It can also contain wildcards in the form of one or - more asterisks (*) that correspond to multiple possible - strings occurring in that place. - {% endcall %} - - {% call paragraph() %} - Wildcards can appear in URL's domain and path that follows it. These 2 - types of wildcards are handled separately. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ small_heading('Domain wildcards') }} - - {% call paragraph() %} - A domain wildcard takes the form of one, two or three asterisks occurring - in place of a single domain name segment at the beginning - (left). Depending on the number of asterisks, the meaning is as follows - {% endcall %} - - {% call unordered_list() %} - {% call list_entry() %} - no asterisks (e.g. example.com) - match domain name exactly - (e.g. example.com) - {% endcall %} - {% call list_entry() %} - one asterisk (e.g. *.example.com) - match all domains - resulting from substituting * with a - single segment (e.g. - banana.example.com or pineapple.example.com - but not pineapple.pen.example.com - nor example.com) - {% endcall %} - {% call list_entry() %} - two asterisks (e.g. **.example.com) - match all domains - resulting from substituting ** with - two or more segments (e.g. - monad.breakfast.example.com or - pure.monad.breakfast.example.com but - not cabalhell.example.com nor - example.com) - {% endcall %} - {% call list_entry() %} - three asterisks (e.g. ***.example.com) - match all domains - resulting from substituting *** with - zero or more segments (e.g. - hello.parkmeter.example.com or - iliketrains.example.com or example.com) - {% endcall %} - {% endcall %} - {% endcall %} - - {% call section() %} - {{ small_heading('Path wildcards') }} - - {% call paragraph() %} - A path wildcard takes the form of one, two or three asterisks occurring in - place of a single path segment at the end of path (right). Depending on - the number of asterisks, the meaning is as follows - {% endcall %} - - {% call unordered_list() %} - {% call list_entry() %} - no asterisks (e.g. /joke/clowns) - match path exactly (e.g. - /joke/clowns) - {% endcall %} - {% call list_entry() %} - one asterisk (e.g. /itscalled/*) - match all paths - resulting from substituting * with a - single segment (e.g. - /itscalled/gnulinux or /itscalled/glamp but - not /itscalled/ nor - /itscalled/gnu/linux) - {% endcall %} - {% call list_entry() %} - two asterisks (e.g. /another/**) - match all paths - resulting from substituting ** with - two or more segments (e.g. - /another/nsa/backdoor or - /another/best/programming/language but - not /another/apibreak nor - /another) - {% endcall %} - {% call list_entry() %} - three asterisks (e.g. /mail/dmarc/***) - match all paths - resulting from substituting *** with - zero or more segments (e.g. - /mail/dmarc/spf, /mail/dmarc or - /mail/dmarc/dkim/failure but - not /mail/) - {% endcall %} - {% endcall %} - - {% call paragraph() %} - If pattern ends without a trailing slash, it - mathes paths with any number of trailing slashes, including zero. If - pattern ends with a trailing slash, it only - mathes paths with one or more trailing slashes. For example, - /itscalled/* matches /itscalled/gnulinux, - /itscalled/gnulinux/ and /itscalled/gnulinux// - while /itscalled/*/ only matches - /itscalled/gnulinux/ and /itscalled/gnulinux// - out of those three. - {% endcall %} - - {% call paragraph() %} - If two patterns only differ by the presence of a trailing slash, - pattern with a trailing slash is considered - more specific. - {% endcall %} - - {% call paragraph() %} - Additionally, any path with literal trailing asterisks is matched by - itself, even if such pattern would otherwise be treated as wildcard - (e.g. /gobacktoxul/** matches /gobacktoxul/**). - This is likely to change in the future and would best not be relied upon. - Appending three additional asterisks to path pattern to represent literal - asterisks is being considered. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ small_heading('URL scheme wildcard') }} - - {% call paragraph() %} - http:// and https:// shemes in the URL are - matched exactly. However, starting with Haketilo 3.0, it is also possible - for scheme pseudo-wildcard of http*:// to be used. Use of URL - pattern with this scheme is equivalent to the use of 2 separate patterns - starting with http:// and https://, - respectively. For example, pattern http*://example.com shall - match both https://example.com and - http://example.com. - {% endcall %} - - {% call paragraph() %} - http*:// may be considered not to be a true wildcard but - rather an alias for either of the other 2 values. As of Haketilo 3.0, the - speicificity of a URL pattern starting with http*:// is - considered to be the same as that of the corresponding URL pattern - starting with http:// or https://. In case of a - conflict, the order of precedence of such patterns is unspecified. This - behavior is likely to change in the future versions of Haketilo. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ small_heading('Wildcard pattern priorities and querying') }} - - {% call paragraph() %} - In case multiple patterns match some URL, the more specific one is - preferred. Specificity is considered as follows - {% endcall %} - - {% call unordered_list() %} - {% call list_entry() %} - If patterns only differ in the final path segment, the one with least - wildcard asterisks in that segment if preferred. - {% endcall %} - {% call list_entry() %} - If patterns, besides the above, only differ in path length, one with - longer path is preferred. Neither final wildcard segment nor trailing - dashes account for path length. - {% endcall %} - {% call list_entry() %} - If patterns, besides the above, only differ in the initial domain - segment, one with least wildcard asterisks in that segment is preferred. - {% endcall %} - {% call list_entry() %} - If patterns differ in domain length, one with longer domain is - preferred. Initial wildcard segment does not account for domain length. - {% endcall %} - {% endcall %} - - {% call paragraph() %} - As an example, consider the URL - http://settings.query.example.com/google/tries/destroy/adblockers//. - Patterns matching it are, in the following order - {% endcall %} - - {% call verbatim() %} -http://settings.query.example.com/google/tries/destroy/adblockers/ -http://settings.query.example.com/google/tries/destroy/adblockers -http://settings.query.example.com/google/tries/destroy/adblockers/***/ -http://settings.query.example.com/google/tries/destroy/adblockers/*** -http://settings.query.example.com/google/tries/destroy/*/ -http://settings.query.example.com/google/tries/destroy/* -http://settings.query.example.com/google/tries/destroy/***/ -http://settings.query.example.com/google/tries/destroy/*** -http://settings.query.example.com/google/tries/**/ -http://settings.query.example.com/google/tries/** -http://settings.query.example.com/google/tries/***/ -http://settings.query.example.com/google/tries/*** -http://settings.query.example.com/google/**/ -http://settings.query.example.com/google/** -http://settings.query.example.com/google/***/ -http://settings.query.example.com/google/*** -http://settings.query.example.com/**/ -http://settings.query.example.com/** -http://settings.query.example.com/***/ -http://settings.query.example.com/*** -http://***.settings.query.example.com/google/tries/destroy/adblockers/ -http://***.settings.query.example.com/google/tries/destroy/adblockers -http://***.settings.query.example.com/google/tries/destroy/adblockers/***/ -http://***.settings.query.example.com/google/tries/destroy/adblockers/*** -http://***.settings.query.example.com/google/tries/destroy/*/ -http://***.settings.query.example.com/google/tries/destroy/* -http://***.settings.query.example.com/google/tries/destroy/***/ -http://***.settings.query.example.com/google/tries/destroy/*** -http://***.settings.query.example.com/google/tries/**/ -http://***.settings.query.example.com/google/tries/** -http://***.settings.query.example.com/google/tries/***/ -http://***.settings.query.example.com/google/tries/*** -http://***.settings.query.example.com/google/**/ -http://***.settings.query.example.com/google/** -http://***.settings.query.example.com/google/***/ -http://***.settings.query.example.com/google/*** -http://***.settings.query.example.com/**/ -http://***.settings.query.example.com/** -http://***.settings.query.example.com/***/ -http://***.settings.query.example.com/*** -http://*.query.example.com/google/tries/destroy/adblockers/ -http://*.query.example.com/google/tries/destroy/adblockers -http://*.query.example.com/google/tries/destroy/adblockers/***/ -http://*.query.example.com/google/tries/destroy/adblockers/*** -http://*.query.example.com/google/tries/destroy/*/ -http://*.query.example.com/google/tries/destroy/* -http://*.query.example.com/google/tries/destroy/***/ -http://*.query.example.com/google/tries/destroy/*** -http://*.query.example.com/google/tries/**/ -http://*.query.example.com/google/tries/** -http://*.query.example.com/google/tries/***/ -http://*.query.example.com/google/tries/*** -http://*.query.example.com/google/**/ -http://*.query.example.com/google/** -http://*.query.example.com/google/***/ -http://*.query.example.com/google/*** -http://*.query.example.com/**/ -http://*.query.example.com/** -http://*.query.example.com/***/ -http://*.query.example.com/*** -http://***.query.example.com/google/tries/destroy/adblockers/ -http://***.query.example.com/google/tries/destroy/adblockers -http://***.query.example.com/google/tries/destroy/adblockers/***/ -http://***.query.example.com/google/tries/destroy/adblockers/*** -http://***.query.example.com/google/tries/destroy/*/ -http://***.query.example.com/google/tries/destroy/* -http://***.query.example.com/google/tries/destroy/***/ -http://***.query.example.com/google/tries/destroy/*** -http://***.query.example.com/google/tries/**/ -http://***.query.example.com/google/tries/** -http://***.query.example.com/google/tries/***/ -http://***.query.example.com/google/tries/*** -http://***.query.example.com/google/**/ -http://***.query.example.com/google/** -http://***.query.example.com/google/***/ -http://***.query.example.com/google/*** -http://***.query.example.com/**/ -http://***.query.example.com/** -http://***.query.example.com/***/ -http://***.query.example.com/*** -http://**.example.com/google/tries/destroy/adblockers/ -http://**.example.com/google/tries/destroy/adblockers -http://**.example.com/google/tries/destroy/adblockers/***/ -http://**.example.com/google/tries/destroy/adblockers/*** -http://**.example.com/google/tries/destroy/*/ -http://**.example.com/google/tries/destroy/* -http://**.example.com/google/tries/destroy/***/ -http://**.example.com/google/tries/destroy/*** -http://**.example.com/google/tries/**/ -http://**.example.com/google/tries/** -http://**.example.com/google/tries/***/ -http://**.example.com/google/tries/*** -http://**.example.com/google/**/ -http://**.example.com/google/** -http://**.example.com/google/***/ -http://**.example.com/google/*** -http://**.example.com/**/ -http://**.example.com/** -http://**.example.com/***/ -http://**.example.com/*** -http://***.example.com/google/tries/destroy/adblockers/ -http://***.example.com/google/tries/destroy/adblockers -http://***.example.com/google/tries/destroy/adblockers/***/ -http://***.example.com/google/tries/destroy/adblockers/*** -http://***.example.com/google/tries/destroy/*/ -http://***.example.com/google/tries/destroy/* -http://***.example.com/google/tries/destroy/***/ -http://***.example.com/google/tries/destroy/*** -http://***.example.com/google/tries/**/ -http://***.example.com/google/tries/** -http://***.example.com/google/tries/***/ -http://***.example.com/google/tries/*** -http://***.example.com/google/**/ -http://***.example.com/google/** -http://***.example.com/google/***/ -http://***.example.com/google/*** -http://***.example.com/**/ -http://***.example.com/** -http://***.example.com/***/ -http://***.example.com/*** - {% endcall %} - - {% call paragraph() %} - Variants of those patterns starting with http*:// would of - course match as well. They have been omitted for simplicity. - {% endcall %} - - {% call paragraph() %} - For a simpler URL like https://example.com the patterns would - be - {% endcall %} - - {% call verbatim() %} -https://example.com -https://example.com/*** -https://***.example.com -https://***.example.com/*** - {% endcall %} - - {% call paragraph() %} - Variants of those patterns with a trailing dash added - would not match the URL. Also, the pattern - variants starting with http*:// have been once again omitted. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ small_heading('Limits') }} - - {% call paragraph() %} - In order to prevent some easy-to-conduct DoS attacks, older versions of - Haketilo and Hydrilla limited the lengths of domain and path parts of - processed URLs. This is no longer the case. - {% endcall %} - {% endcall %} - - {% call section() %} - {{ medium_heading('Alternative solution idea: mimicking web server mechanics') }} - - {% call paragraph() %} - While wildcard patterns as presented give a lot of flexibility, they are - not the only viable approach to specifying what URLs to apply - rules/payloads to. In fact, wildcards are different from how the server - side of a typical website decides what to return for a given URL request. - {% endcall %} - - {% call paragraph() %} - In a typical scenario, an HTTP server like Apache reads configuration - files provided by its administrator and uses various (virtual host, - redirect, request rewrite, CGI, etc.) instructions to decide how to handle - given URL. Perhps using a scheme that mimics the configuration options - typically used with web servers would give more efficiency in specifying - what page settings to apply when. - {% endcall %} - - {% call paragraph() %} - This approach may be considered in the future. - {% endcall %} - {% endcall %} -{% endblock main %} diff --git a/src/hydrilla/proxy/web_ui/root.py b/src/hydrilla/proxy/web_ui/root.py index 4eea860..4915e51 100644 --- a/src/hydrilla/proxy/web_ui/root.py +++ b/src/hydrilla/proxy/web_ui/root.py @@ -188,14 +188,10 @@ def home_doc(page: str) -> str: if page not in self_doc.page_names: flask.abort(404) - locale = translations.select_best_locale() - if locale == translations.default_locale: - prefix = '' - else: - prefix = f'{locale}/' + locale = translations.select_best_locale(self_doc.available_locales) return flask.render_template( - f'{prefix}{page}.html.jinja', + f'{locale}/{page}.html.jinja', doc_output = 'html_hkt_mitm_it' ) diff --git a/src/hydrilla/translations.py b/src/hydrilla/translations.py index 62c8c88..1ff8788 100644 --- a/src/hydrilla/translations.py +++ b/src/hydrilla/translations.py @@ -39,7 +39,7 @@ supported_locales = [f.name for f in localedir.iterdir() if f.is_dir()] default_locale = 'en_US' -def select_best_locale() -> str: +def select_best_locale(supported: t.Iterable[str] = supported_locales) -> str: """ .... @@ -56,8 +56,8 @@ def select_best_locale() -> str: if use_flask: best = flask.request.accept_languages.best_match( - supported_locales, - default=default_locale + supported, + default = default_locale ) assert best is not None return best @@ -72,7 +72,7 @@ def select_best_locale() -> str: except: pass - return locale if locale in supported_locales else default_locale + return locale if locale in supported else default_locale translations: t.Dict[str, gettext.NullTranslations] = {} -- cgit v1.2.3