From 68d9240c0c79eafa25465a7c9973b0cdc1e5d585 Mon Sep 17 00:00:00 2001 From: Tiara Rodney Date: Sun, 17 Apr 2022 03:51:42 +0200 Subject: [PATCH] feat(router): establish shared router/view/controller global variables - add ssl warning --- src/httpaste/__init__.py | 17 +++++++++++++++ src/httpaste/controller/ui/__init__.py | 9 ++++++-- src/httpaste/controller/ui/paste/__init__.py | 13 +++++++++--- src/httpaste/controller/ui/paste/private.py | 10 ++++++--- src/httpaste/controller/ui/paste/public.py | 9 ++++++-- src/httpaste/controller/ui/user/__init__.py | 10 ++++++--- .../controller/ui/user/session/__init__.py | 9 ++++---- src/httpaste/helper/template.py | 21 ++++++++++++++++++- src/httpaste/helper/url.py | 20 ++++++++++++++++++ src/httpaste/server.py | 2 ++ src/httpaste/view/frame/decorated.html | 19 +++++++++++++++++ 11 files changed, 121 insertions(+), 18 deletions(-) diff --git a/src/httpaste/__init__.py b/src/httpaste/__init__.py index 9a062cf..8e93560 100755 --- a/src/httpaste/__init__.py +++ b/src/httpaste/__init__.py @@ -152,6 +152,7 @@ from httpaste.model import Config as ModelConfig from httpaste.backend import get_backend_config from httpaste.backend import Config as BackendConfig from httpaste.helper.config import get_configparser, CONFIGPATH_ENVIRON +from httpaste.helper.url import url_upgrade_to_https from httpaste.helper.http import ( BadRequestError, ForbiddenError, @@ -238,6 +239,22 @@ def get_flask_app(config: Config) -> FlaskApp: response.headers['WWW-Authenticate'] = 'Basic realm="private"' return response + @application.app.before_request + def before_request_func(): + from flask import request + + request._view = {} + + if config.server.request_ssl: + + https_url = url_upgrade_to_https(request.url, config.server.ssl_port) + + if https_url != request.url: + + print('Hallo') + + request._view['before_request__ssl_url'] = https_url + return application diff --git a/src/httpaste/controller/ui/__init__.py b/src/httpaste/controller/ui/__init__.py index 23890e6..6e740a6 100644 --- a/src/httpaste/controller/ui/__init__.py +++ b/src/httpaste/controller/ui/__init__.py @@ -1,6 +1,8 @@ -from httpaste.helper.template import views +from httpaste.helper.template import views, render_template_with_context from httpaste import __doc__ as man_page +from flask import current_app + def search(**kwargs): template = views.get_template("viewport/ui/search.html") @@ -13,4 +15,7 @@ def search(**kwargs): 'delete_session_url': '/ui/user/session/delete' } - return template.render(**variables), 200 \ No newline at end of file + with current_app.app_context(): + view_render = render_template_with_context(template, **variables) + + return view_render, 200 \ No newline at end of file diff --git a/src/httpaste/controller/ui/paste/__init__.py b/src/httpaste/controller/ui/paste/__init__.py index e743a4c..7d05d47 100644 --- a/src/httpaste/controller/ui/paste/__init__.py +++ b/src/httpaste/controller/ui/paste/__init__.py @@ -2,8 +2,9 @@ from io import BytesIO from base64 import b64encode from connexion import request +from flask import current_app -from httpaste.helper.template import views +from httpaste.helper.template import views, render_template_with_context from httpaste.helper.url import url_query_string, url_append_query_param from httpaste.helper.syntax import syntax_shortnames, format_shortnames from httpaste.helper.http import mime_types @@ -23,7 +24,10 @@ def search(**kwargs): 'delete_session_url': '/ui/user/session/delete' } - return template.render(**variables), 200 + with current_app.app_context(): + view_render = render_template_with_context(template, **variables) + + return view_render, 200 def post(**kwargs): @@ -93,4 +97,7 @@ def get(**kwargs): 'mime_types': mime_types() } - return template.render(**variables) \ No newline at end of file + with current_app.app_context(): + view_render = render_template_with_context(template, **variables) + + return view_render, 200 \ No newline at end of file diff --git a/src/httpaste/controller/ui/paste/private.py b/src/httpaste/controller/ui/paste/private.py index 4236f67..3f2fe65 100644 --- a/src/httpaste/controller/ui/paste/private.py +++ b/src/httpaste/controller/ui/paste/private.py @@ -1,4 +1,6 @@ -from httpaste.helper.template import views +from flask import current_app + +from httpaste.helper.template import views, render_template_with_context from httpaste.controller.ui.paste import post as post_proxy from httpaste.controller.ui.paste import get as get_proxy @@ -8,10 +10,12 @@ def search(**kwargs): variables = { 'paste_form_url': '/ui/paste/private', - 'user': kwargs.get('user') } - return template.render(**variables), 200 + with current_app.app_context(): + view_render = render_template_with_context(template, **variables) + + return view_render, 200 def post(**kwargs): diff --git a/src/httpaste/controller/ui/paste/public.py b/src/httpaste/controller/ui/paste/public.py index 0659d5c..3110c53 100644 --- a/src/httpaste/controller/ui/paste/public.py +++ b/src/httpaste/controller/ui/paste/public.py @@ -1,4 +1,6 @@ -from httpaste.helper.template import views +from flask import current_app + +from httpaste.helper.template import views, render_template_with_context from httpaste.controller.ui.paste import post as post_proxy from httpaste.controller.ui.paste import get as get_proxy @@ -10,7 +12,10 @@ def search(**kwargs): 'paste_form_url': '/ui/paste/public' } - return template.render(**variables), 200 + with current_app.app_context(): + view_render = render_template_with_context(template, **variables) + + return view_render, 200 def post(**kwargs): diff --git a/src/httpaste/controller/ui/user/__init__.py b/src/httpaste/controller/ui/user/__init__.py index 6c6d86a..0fd5766 100644 --- a/src/httpaste/controller/ui/user/__init__.py +++ b/src/httpaste/controller/ui/user/__init__.py @@ -1,5 +1,6 @@ -from httpaste.helper.template import views -from httpaste import __doc__ as man_page +from flask import current_app + +from httpaste.helper.template import views, render_template_with_context def search(**kwargs): @@ -9,4 +10,7 @@ def search(**kwargs): 'delete_session_url': '/ui/user/session/delete' } - return template.render(**variables), 200 \ No newline at end of file + with current_app.app_context(): + view_render = render_template_with_context(template, **variables) + + return view_render, 200 \ No newline at end of file diff --git a/src/httpaste/controller/ui/user/session/__init__.py b/src/httpaste/controller/ui/user/session/__init__.py index 54376bc..6f1eeee 100644 --- a/src/httpaste/controller/ui/user/session/__init__.py +++ b/src/httpaste/controller/ui/user/session/__init__.py @@ -1,4 +1,4 @@ -from httpaste.helper.template import views +from httpaste.helper.template import views, render_template_with_context from httpaste.controller.user.session import delete as raw_delete from connexion import request @@ -7,11 +7,12 @@ def search(**kwargs): template = views.get_template("viewport/ui/user/session/search.html") - print(request.path) - variables = {'session_delete_url': request.path + '/delete'} - return template.render(**variables), 200 + with current_app.app_context(): + view_render = render_template_with_context(template, **variables) + + return view_render, 200 def delete(**kwargs): diff --git a/src/httpaste/helper/template.py b/src/httpaste/helper/template.py index 1ae6d0e..3543ea9 100644 --- a/src/httpaste/helper/template.py +++ b/src/httpaste/helper/template.py @@ -1,6 +1,25 @@ from jinja2 import Environment, PackageLoader, select_autoescape +from collections import namedtuple views = Environment( loader=PackageLoader("httpaste", "view"), autoescape=select_autoescape() -) \ No newline at end of file +) + + +def render_template_with_context(template: object, **kwargs): + """render a template with global context variables + + the definition of a global context is abstract, it does neither apply + to Flask, nor to Jinja2 and only acts as a bridge for passing + variables from flask to jinja2, without having to define them within + each controller. + + :param template: jinja2 template object + """ + + from flask import request + + return template.render(**{**kwargs, **{ + 'flask': namedtuple('Flask', request._view.keys())(**request._view) + }}) \ No newline at end of file diff --git a/src/httpaste/helper/url.py b/src/httpaste/helper/url.py index 38528a1..cd0c800 100644 --- a/src/httpaste/helper/url.py +++ b/src/httpaste/helper/url.py @@ -1,3 +1,4 @@ +from typing import Optional from urllib.parse import urlparse, parse_qs @@ -18,3 +19,22 @@ def url_append_query_param(url:str, name: str, value:str): return urlcomps._replace(query=qs).geturl() + +def url_upgrade_to_https(url: str, port: Optional[int] = 443): + + urlcomps = urlparse(url) + + urlcomps = urlcomps._replace(scheme='https') + + if url != urlcomps.geturl(): + + hostname = urlcomps.netloc.rsplit(':', 1)[0] + + if port != 443: + netloc = ':'.join((hostname, str(port))) + else: + netloc = hostname + + urlcomps = urlcomps._replace(netloc=netloc) + + return urlcomps.geturl() \ No newline at end of file diff --git a/src/httpaste/server.py b/src/httpaste/server.py index 55c0542..14103e3 100755 --- a/src/httpaste/server.py +++ b/src/httpaste/server.py @@ -10,6 +10,8 @@ class Config(NamedTuple): """ swagger_ui: bool = True bind_address: str = None + request_ssl: bool = True + ssl_port: int = 443 def get_server_config(configIni: ConfigParser) -> Config: diff --git a/src/httpaste/view/frame/decorated.html b/src/httpaste/view/frame/decorated.html index d7c6cf7..e3983dc 100644 --- a/src/httpaste/view/frame/decorated.html +++ b/src/httpaste/view/frame/decorated.html @@ -15,10 +15,29 @@ margin-bottom: 1em; } + .blinking{ + animation:blinkingText 1.0s infinite; + animation-timing-function: step-start; + } + + .warning { + color: red; + } + + @keyframes blinkingText { + 0%{ color: red; } + 50%{ color: transparent; } + 100%{ color: red; } + }
+ {% if flask.before_request__ssl_url is defined %} +

+ WARNING: Communication not encrypted - SSL/TLS will not be enforced. Visit {{ flask.before_request__ssl_url }}, for SSL/TLS encryption. +

+ {% endif %} {% block header %}{% endblock %}