From d54a95e0f9c689f2bbaaea90a3a16a855a408823 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Wed, 17 Aug 2022 13:50:34 +0200 Subject: allow loading packages from zip files through web UI and listing installed mappings --- src/hydrilla/proxy/web_ui/packages.py | 89 ++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) (limited to 'src/hydrilla/proxy/web_ui/packages.py') diff --git a/src/hydrilla/proxy/web_ui/packages.py b/src/hydrilla/proxy/web_ui/packages.py index 7d67b63..a618ca0 100644 --- a/src/hydrilla/proxy/web_ui/packages.py +++ b/src/hydrilla/proxy/web_ui/packages.py @@ -31,14 +31,99 @@ # Enable using with Python 3.7. from __future__ import annotations +import tempfile +import zipfile import typing as t +from urllib.parse import urlparse +from pathlib import Path + import flask +import werkzeug + +from ...exceptions import HaketiloException +from ...translations import smart_gettext as _ +from .. import state as st +from . import _app + + +class InvalidUploadedMalcontent(HaketiloException): + def __init__(self): + super().__init__(_('err.proxy.uploaded_malcontent_invalid')) bp = flask.Blueprint('load_packages', __package__) -@bp.route('/packages/load_from_disk') -def load_from_disk() -> flask.Response: +@bp.route('/packages/load_from_disk', methods=['GET']) +def load_from_disk_get() -> flask.Response: html = flask.render_template('packages__load_from_disk.html.jinja') return flask.make_response(html, 200) + +@bp.route('/packages/load_from_disk', methods=['POST']) +def load_from_disk_post() -> werkzeug.Response: + parsed_url = urlparse(flask.request.referrer) + if parsed_url.netloc != 'hkt.mitm.it': + return load_from_disk_get() + + zip_file_storage = flask.request.files.get('packages_zipfile') + if zip_file_storage is None: + return load_from_disk_get() + + with tempfile.TemporaryDirectory() as tmpdir_str: + tmpdir = Path(tmpdir_str) + tmpdir_child = tmpdir / 'childdir' + tmpdir_child.mkdir() + + try: + with zipfile.ZipFile(zip_file_storage) as zip_file: + zip_file.extractall(tmpdir_child) + except: + raise HaketiloException(_('err.proxy.uploaded_file_not_zip')) + + extracted_top_level_files = tuple(tmpdir_child.iterdir()) + if extracted_top_level_files == (): + raise InvalidUploadedMalcontent() + + if len(extracted_top_level_files) == 1 and \ + extracted_top_level_files[0].is_dir(): + malcontent_dir_path = extracted_top_level_files[0] + else: + malcontent_dir_path = tmpdir_child + + state = t.cast(_app.WebUIApp, flask.current_app)._haketilo_state + + try: + state.import_packages(malcontent_dir_path) + except: + raise InvalidUploadedMalcontent() + + return flask.redirect(flask.url_for('.packages')) + +@bp.route('/packages') +def packages() -> flask.Response: + state = t.cast(_app.WebUIApp, flask.current_app)._haketilo_state + + display_infos = state.mapping_version_store().get_display_infos() + sorted_infos = sorted(display_infos, key=(lambda di: di.info)) + + html = flask.render_template( + 'packages.html.jinja', + display_infos = sorted_infos + ) + return flask.make_response(html, 200) + +@bp.route('/packages/view/') +def show_package(mapping_id: str) -> flask.Response: + state = t.cast(_app.WebUIApp, flask.current_app)._haketilo_state + + try: + store = state.mapping_version_store() + display_info = store.get(mapping_id).get_display_info() + + html = flask.render_template( + 'packages__show_single.html.jinja', + display_info = display_info + ) + return flask.make_response(html, 200) + except st.MissingItemError: + flask.abort(404) -- cgit v1.2.3