aboutsummaryrefslogtreecommitdiff
path: root/src/hydrilla/proxy
diff options
context:
space:
mode:
Diffstat (limited to 'src/hydrilla/proxy')
-rw-r--r--src/hydrilla/proxy/policies/base.py25
-rw-r--r--src/hydrilla/proxy/policies/misc.py10
-rw-r--r--src/hydrilla/proxy/policies/payload.py2
-rw-r--r--src/hydrilla/proxy/policies/rule.py6
-rw-r--r--src/hydrilla/proxy/state.py2
-rw-r--r--src/hydrilla/proxy/state_impl/concrete_state.py26
-rw-r--r--src/hydrilla/proxy/web_ui/root.py40
-rw-r--r--src/hydrilla/proxy/web_ui/templates/index.html.jinja19
8 files changed, 108 insertions, 22 deletions
diff --git a/src/hydrilla/proxy/policies/base.py b/src/hydrilla/proxy/policies/base.py
index 95021cd..967e2c4 100644
--- a/src/hydrilla/proxy/policies/base.py
+++ b/src/hydrilla/proxy/policies/base.py
@@ -43,7 +43,7 @@ import jinja2
from immutables import Map
-from ...translations import translation as make_translation
+from ... import translations
from ... import url_patterns
from ... import common_jinja_templates
from .. import state
@@ -62,14 +62,9 @@ _jinja_info_env = jinja2.Environment(
lstrip_blocks = True,
extensions = ['jinja2.ext.i18n', 'jinja2.ext.do']
)
-_jinja_info_env.install_gettext_translations(make_translation()) # type: ignore
_jinja_info_env.globals['url_patterns'] = url_patterns
_jinja_info_lock = threading.Lock()
-def get_info_template(template_file_name: str) -> jinja2.Template:
- with _jinja_info_lock:
- return _jinja_info_env.get_template(template_file_name)
-
_jinja_script_loader = jinja2.PackageLoader(
__package__,
@@ -164,6 +159,20 @@ class Policy(ABC):
return (self.current_popup_settings.popup_enabled and
http_messages.is_likely_a_page(request_info, response_info))
+ def _get_info_template(self, template_file_name: str) -> jinja2.Template:
+ with _jinja_info_lock:
+ chosen_locale = self.haketilo_settings.locale
+ if chosen_locale not in translations.supported_locales:
+ chosen_locale = None
+
+ if chosen_locale is None:
+ chosen_locale = translations.default_locale
+
+ trans = translations.translation(chosen_locale)
+ _jinja_info_env.install_gettext_translations(trans) # type: ignore
+ return _jinja_info_env.get_template(template_file_name)
+
+
def _csp_to_clear(self, http_info: http_messages.FullHTTPInfo) \
-> t.Union[t.Sequence[str], t.Literal['all']]:
return ()
@@ -215,7 +224,9 @@ class Policy(ABC):
popup_page = self.make_info_page(http_info)
if popup_page is None:
- template = get_info_template('special_page_info.html.jinja')
+ template = self._get_info_template(
+ 'special_page_info.html.jinja'
+ )
popup_page = template.render(
url = http_info.request_info.url.orig_url
)
diff --git a/src/hydrilla/proxy/policies/misc.py b/src/hydrilla/proxy/policies/misc.py
index 0ff4596..e789b29 100644
--- a/src/hydrilla/proxy/policies/misc.py
+++ b/src/hydrilla/proxy/policies/misc.py
@@ -47,7 +47,9 @@ class FallbackAllowPolicy(AllowPolicy):
def make_info_page(self, http_info: http_messages.FullHTTPInfo) \
-> t.Optional[str]:
- template = base.get_info_template('js_fallback_allowed_info.html.jinja')
+ template = self._get_info_template(
+ 'js_fallback_allowed_info.html.jinja'
+ )
return template.render(url=http_info.request_info.url.orig_url)
@@ -56,7 +58,9 @@ class FallbackBlockPolicy(BlockPolicy):
def make_info_page(self, http_info: http_messages.FullHTTPInfo) \
-> t.Optional[str]:
- template = base.get_info_template('js_fallback_blocked_info.html.jinja')
+ template = self._get_info_template(
+ 'js_fallback_blocked_info.html.jinja'
+ )
return template.render(url=http_info.request_info.url.orig_url)
@@ -71,7 +75,7 @@ class ErrorBlockPolicy(BlockPolicy):
def make_info_page(self, http_info: http_messages.FullHTTPInfo) \
-> t.Optional[str]:
- template = base.get_info_template('js_error_blocked_info.html.jinja')
+ template = self._get_info_template('js_error_blocked_info.html.jinja')
return template.render(
url = http_info.request_info.url.orig_url,
settings = self.haketilo_settings,
diff --git a/src/hydrilla/proxy/policies/payload.py b/src/hydrilla/proxy/policies/payload.py
index 55851cc..3660eac 100644
--- a/src/hydrilla/proxy/policies/payload.py
+++ b/src/hydrilla/proxy/policies/payload.py
@@ -175,7 +175,7 @@ class PayloadInjectPolicy(PayloadAwarePolicy):
def make_info_page(self, http_info: http_messages.FullHTTPInfo) \
-> t.Optional[str]:
- return base.get_info_template('payload_info.html.jinja').render(
+ return self._get_info_template('payload_info.html.jinja').render(
url = http_info.request_info.url.orig_url,
payload_data = self.payload_data
)
diff --git a/src/hydrilla/proxy/policies/rule.py b/src/hydrilla/proxy/policies/rule.py
index 1f39295..e318a7f 100644
--- a/src/hydrilla/proxy/policies/rule.py
+++ b/src/hydrilla/proxy/policies/rule.py
@@ -69,7 +69,8 @@ class RuleAllowPolicy(AllowPolicy):
def make_info_page(self, http_info: http_messages.FullHTTPInfo) \
-> t.Optional[str]:
- return base.get_info_template('js_rule_allowed_info.html.jinja').render(
+ template = self._get_info_template('js_rule_allowed_info.html.jinja')
+ return template.render(
url = http_info.request_info.url.orig_url,
pattern = self.pattern.orig_url
)
@@ -81,7 +82,8 @@ class RuleBlockPolicy(BlockPolicy):
def make_info_page(self, http_info: http_messages.FullHTTPInfo) \
-> t.Optional[str]:
- return base.get_info_template('js_rule_blocked_info.html.jinja').render(
+ template = self._get_info_template('js_rule_blocked_info.html.jinja')
+ return template.render(
url = http_info.request_info.url.orig_url,
pattern = self.pattern.orig_url
)
diff --git a/src/hydrilla/proxy/state.py b/src/hydrilla/proxy/state.py
index 72eaaa0..1a2d344 100644
--- a/src/hydrilla/proxy/state.py
+++ b/src/hydrilla/proxy/state.py
@@ -544,6 +544,7 @@ class HaketiloGlobalSettings:
default_allow_scripts: bool
advanced_user: bool
repo_refresh_seconds: int
+ locale: t.Optional[str]
default_popup_jsallowed: PopupSettings
default_popup_jsblocked: PopupSettings
@@ -627,6 +628,7 @@ class HaketiloState(ABC):
default_allow_scripts: t.Optional[bool] = None,
advanced_user: t.Optional[bool] = None,
repo_refresh_seconds: t.Optional[int] = None,
+ locale: t.Optional[str] = None,
default_popup_settings: t.Mapping[str, PopupSettings] = {}
) -> None:
...
diff --git a/src/hydrilla/proxy/state_impl/concrete_state.py b/src/hydrilla/proxy/state_impl/concrete_state.py
index a5c547f..e97514a 100644
--- a/src/hydrilla/proxy/state_impl/concrete_state.py
+++ b/src/hydrilla/proxy/state_impl/concrete_state.py
@@ -71,6 +71,14 @@ def _add_popup_settings_columns(cursor: sqlite3.Cursor) -> None:
'''
)
+def _add_locale_column(cursor: sqlite3.Cursor) -> None:
+ cursor.execute(
+ '''
+ ALTER TABLE general ADD COLUMN
+ locale VARCHAR NOT NULL DEFAULT 'unknown';
+ '''
+ )
+
def _prepare_database(connection: sqlite3.Connection) -> None:
cursor = connection.cursor()
@@ -111,6 +119,7 @@ def _prepare_database(connection: sqlite3.Connection) -> None:
raise HaketiloException(_('err.proxy.unknown_db_schema'))
popup_settings_columns_present = False
+ locale_column_present = False
cursor.execute("PRAGMA TABLE_INFO('general')")
for __cid, name, __type, __notnull, __dflt_value, __pk \
@@ -118,16 +127,20 @@ def _prepare_database(connection: sqlite3.Connection) -> None:
if name == 'default_popup_jsallowed_onkeyboard':
popup_settings_columns_present = True
+ if name == 'locale':
+ locale_column_present = True
+
if not popup_settings_columns_present:
_add_popup_settings_columns(cursor)
+ if not locale_column_present:
+ _add_locale_column(cursor)
+
cursor.execute('COMMIT TRANSACTION;')
except:
cursor.execute('ROLLBACK TRANSACTION;')
raise
-
-
cursor.execute('PRAGMA FOREIGN_KEYS;')
if cursor.fetchall() == []:
raise HaketiloException(_('err.proxy.no_sqlite_foreign_keys'))
@@ -144,14 +157,15 @@ def load_settings(cursor: sqlite3.Cursor) -> st.HaketiloGlobalSettings:
default_allow_scripts,
advanced_user,
repo_refresh_seconds,
- mapping_use_mode
+ mapping_use_mode,
+ locale
FROM
general;
'''
)
(default_allow_scripts, advanced_user, repo_refresh_seconds,
- mapping_use_mode), = cursor.fetchall()
+ mapping_use_mode, locale), = cursor.fetchall()
popup_settings_dict = {}
@@ -181,6 +195,7 @@ def load_settings(cursor: sqlite3.Cursor) -> st.HaketiloGlobalSettings:
advanced_user = advanced_user,
repo_refresh_seconds = repo_refresh_seconds,
mapping_use_mode = st.MappingUseMode(mapping_use_mode),
+ locale = locale,
**popup_settings_dict
)
@@ -422,6 +437,7 @@ class ConcreteHaketiloState(base.HaketiloStateWithFields):
default_allow_scripts: t.Optional[bool] = None,
advanced_user: t.Optional[bool] = None,
repo_refresh_seconds: t.Optional[int] = None,
+ locale: t.Optional[str] = None,
default_popup_settings: t.Mapping[str, st.PopupSettings] = {}
) -> None:
with self.cursor(transaction=True) as cursor:
@@ -436,6 +452,8 @@ class ConcreteHaketiloState(base.HaketiloStateWithFields):
set_opt('advanced_user', advanced_user)
if repo_refresh_seconds is not None:
set_opt('repo_refresh_seconds', repo_refresh_seconds)
+ if locale is not None:
+ set_opt('locale', locale)
for page_type in ('jsallowed', 'jsblocked', 'payloadon'):
popup_settings = default_popup_settings.get(page_type)
diff --git a/src/hydrilla/proxy/web_ui/root.py b/src/hydrilla/proxy/web_ui/root.py
index 4915e51..6f9e349 100644
--- a/src/hydrilla/proxy/web_ui/root.py
+++ b/src/hydrilla/proxy/web_ui/root.py
@@ -60,6 +60,30 @@ from . import prompts
from . import _app
+def choose_locale() -> None:
+ app = t.cast(WebUIAppImpl, flask.current_app)
+
+ user_chosen_locale = get_settings().locale
+ if user_chosen_locale not in translations.supported_locales:
+ user_chosen_locale = None
+
+ if user_chosen_locale is None:
+ best_locale_match = flask.request.accept_languages.best_match(
+ translations.supported_locales,
+ default = translations.default_locale
+ )
+ if best_locale_match is None:
+ app._haketilo_request_locale = translations.default_locale
+ else:
+ app._haketilo_request_locale = best_locale_match
+ else:
+ app._haketilo_request_locale = user_chosen_locale
+
+ trans = translations.translation(app._haketilo_request_locale)
+
+ app.jinja_env.install_gettext_translations(trans)
+
+
def authenticate_by_referrer() -> t.Optional[werkzeug.Response]:
if flask.request.method == 'GET':
return None
@@ -90,6 +114,8 @@ class WebUIAppImpl(_app.WebUIApp):
_haketilo_blueprints: t.ClassVar[t.Sequence[flask.Blueprint]]
_haketilo_ui_domain: t.ClassVar[_app.UIDomain]
+ _haketilo_request_locale: str
+
def __init__(self):
super().__init__(__name__)
@@ -122,6 +148,7 @@ class WebUIAppImpl(_app.WebUIApp):
self.jinja_env.globals['doc_base_filename'] = 'doc_base.html.jinja'
self.before_request(authenticate_by_referrer)
+ self.before_request(choose_locale)
for bp in self._haketilo_blueprints:
self.register_blueprint(bp)
@@ -150,7 +177,11 @@ def home_post() -> werkzeug.Response:
state = _app.get_haketilo_state()
- if action == 'use_enabled':
+ if action == 'set_lang':
+ new_locale = flask.request.form['locale']
+ assert new_locale in translations.supported_locales
+ state.update_settings(locale=new_locale)
+ elif action == 'use_enabled':
state.update_settings(mapping_use_mode=st.MappingUseMode.WHEN_ENABLED)
elif action == 'use_auto':
state.update_settings(mapping_use_mode=st.MappingUseMode.AUTO)
@@ -188,7 +219,9 @@ def home_doc(page: str) -> str:
if page not in self_doc.page_names:
flask.abort(404)
- locale = translations.select_best_locale(self_doc.available_locales)
+ locale = t.cast(WebUIAppImpl, flask.current_app)._haketilo_request_locale
+ if locale not in self_doc.available_locales:
+ locale = translations.default_locale
return flask.render_template(
f'{locale}/{page}.html.jinja',
@@ -241,9 +274,6 @@ def process_request(
with app._haketilo_app_lock:
app._haketilo_state = state
- best_translations = translations.translation()
- app.jinja_env.install_gettext_translations(best_translations)
-
flask_response = app.test_client().open(
path = path,
base_url = request_info.url.url_without_path,
diff --git a/src/hydrilla/proxy/web_ui/templates/index.html.jinja b/src/hydrilla/proxy/web_ui/templates/index.html.jinja
index 1e498a3..fe9c5d5 100644
--- a/src/hydrilla/proxy/web_ui/templates/index.html.jinja
+++ b/src/hydrilla/proxy/web_ui/templates/index.html.jinja
@@ -73,6 +73,25 @@ code in a proprietary work, I am not going to enforce this in court.
{{ _('web_ui.home.heading.options') }}
</h4>
+ {{ label(_('web_ui.home.choose_language_label')) }}
+
+ {% call unordered_list() %}
+ {%
+ for lang_name, lang_code in [
+ ('english', 'en_US'),
+ ('polski', 'pl_PL')
+ ]
+ %}
+ {% call list_entry() %}
+ <form method="POST" class="inline">
+ <input type="hidden" name="action" value="set_lang">
+ <input type="hidden" name="locale" value="{{ lang_code }}">
+ <button>{{ lang_name }}</button>
+ </form>
+ {% endcall %}
+ {% endfor %}
+ {% endcall %}
+
{% call label(_('web_ui.home.mapping_usage_mode_label')) %}
{{ hkt_doc_link('packages') }}
{% endcall %}