From 47cb58c9b14eb90f837147b3e1b25e9810c7ed16 Mon Sep 17 00:00:00 2001 From: Tiara Rodney Date: Sat, 16 Apr 2022 22:48:00 +0200 Subject: [PATCH 1/5] fix(Dockerfile): add missing dependencies for PILLOW --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index d64fa0e..ae4aa6c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ WORKDIR /usr/local/src/httpaste COPY . . RUN apt-get update && \ - apt-get install -y libffi-dev gcc && \ + apt-get install -y libffi-dev gcc fontconfig && \ python3 -m pip install pipenv && \ python3 -m pipenv install --deploy --system --verbose && \ python3 setup.py install && \ @@ -27,4 +27,4 @@ FROM base as uwsgi ENTRYPOINT ["uwsgi", "--master", "--enable-threads", "--manage-script-name", "-w", "httpaste.wsgi:application"] -CMD ["-s", "/tmp/yourapplication.sock"] \ No newline at end of file +CMD ["-s", "/tmp/yourapplication.sock"] From 68d9240c0c79eafa25465a7c9973b0cdc1e5d585 Mon Sep 17 00:00:00 2001 From: Tiara Rodney Date: Sun, 17 Apr 2022 03:51:42 +0200 Subject: [PATCH 2/5] 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 %}

From 56f46172ce8938cf8ccf9af72f90cf3feab83f4d Mon Sep 17 00:00:00 2001 From: Tiara Rodney Date: Sun, 17 Apr 2022 03:53:51 +0200 Subject: [PATCH 3/5] feat(samples/httpaste.it/httpd) enable SSL --- samples/httpaste.it/docker-compose.yml | 2 ++ .../httpd/usr/local/apache2/conf/httpd.conf | 19 ++++++++++++++++++- .../httpd/usr/local/apache2/ssl/.gitignore | 2 ++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 samples/httpaste.it/httpd/usr/local/apache2/ssl/.gitignore diff --git a/samples/httpaste.it/docker-compose.yml b/samples/httpaste.it/docker-compose.yml index 2150c79..3c7cf0f 100644 --- a/samples/httpaste.it/docker-compose.yml +++ b/samples/httpaste.it/docker-compose.yml @@ -22,6 +22,7 @@ services: dockerfile: Dockerfile ports: - "80:80" + - "443:443" volumes: - type: volume @@ -30,6 +31,7 @@ services: volume: nocopy: true - ./httpd/usr/local/apache2/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf + - ./httpd/usr/local/apache2/ssl:/usr/local/apache2/ssl tor: build: context: ./tor diff --git a/samples/httpaste.it/httpd/usr/local/apache2/conf/httpd.conf b/samples/httpaste.it/httpd/usr/local/apache2/conf/httpd.conf index 07c9156..feccc6b 100644 --- a/samples/httpaste.it/httpd/usr/local/apache2/conf/httpd.conf +++ b/samples/httpaste.it/httpd/usr/local/apache2/conf/httpd.conf @@ -18,7 +18,7 @@ LoadModule unixd_module modules/mod_unixd.so LoadModule access_compat_module modules/mod_access_compat.so LoadModule security2_module /usr/lib/apache2/modules/mod_security2.so LoadModule evasive20_module /usr/lib/apache2/modules/mod_evasive20.so - +LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so User www-data @@ -88,3 +88,20 @@ ServerName 127.0.0.1 SetEnv proxy-sendchunks ProxyPass "/" "unix:/shared/uwsgi.sock|uwsgi://localhost/" + + + Listen 0.0.0.0:443 + + + + #ProxyPreserveHost On + ServerName httpaste.it + ServerAlias localhost + SSLEngine on + SSLCertificateFile "ssl/certificate.crt" + SSLCertificateChainFile "ssl/ca_bundle.crt" + SSLCertificateKeyFile "ssl/private.key" + SetEnv proxy-sendchunks + ProxyPass "/" "unix:/shared/uwsgi.sock|uwsgi://localhost/" + + diff --git a/samples/httpaste.it/httpd/usr/local/apache2/ssl/.gitignore b/samples/httpaste.it/httpd/usr/local/apache2/ssl/.gitignore new file mode 100644 index 0000000..0d313d1 --- /dev/null +++ b/samples/httpaste.it/httpd/usr/local/apache2/ssl/.gitignore @@ -0,0 +1,2 @@ +*.key +*.crt \ No newline at end of file From 98586f4fd2accdcc839e51520ff55f49a9f79b54 Mon Sep 17 00:00:00 2001 From: Tiara Rodney Date: Sun, 17 Apr 2022 03:58:22 +0200 Subject: [PATCH 4/5] feat(samples/httpaste.it/tor): make hidden_service transferable --- samples/httpaste.it/docker-compose.yml | 1 + samples/httpaste.it/tor/var/lib/tor/hidden_service/.gitkeep | 1 + 2 files changed, 2 insertions(+) create mode 100644 samples/httpaste.it/tor/var/lib/tor/hidden_service/.gitkeep diff --git a/samples/httpaste.it/docker-compose.yml b/samples/httpaste.it/docker-compose.yml index 3c7cf0f..2dc9ace 100644 --- a/samples/httpaste.it/docker-compose.yml +++ b/samples/httpaste.it/docker-compose.yml @@ -38,5 +38,6 @@ services: dockerfile: Dockerfile volumes: - ./tor/etc/tor/torrc:/etc/tor/torrc + - ./tor/var/lib/tor/hidden_service:./tor/var/lib/tor/hidden_service volumes: system-shared: diff --git a/samples/httpaste.it/tor/var/lib/tor/hidden_service/.gitkeep b/samples/httpaste.it/tor/var/lib/tor/hidden_service/.gitkeep new file mode 100644 index 0000000..f59ec20 --- /dev/null +++ b/samples/httpaste.it/tor/var/lib/tor/hidden_service/.gitkeep @@ -0,0 +1 @@ +* \ No newline at end of file From 90fa8cd7b8d9af8e8dd40429dcccd7b7ed1fb3ea Mon Sep 17 00:00:00 2001 From: Tiara Rodney Date: Sun, 17 Apr 2022 04:00:20 +0200 Subject: [PATCH 5/5] style: remove debug print statements --- src/httpaste/__init__.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/httpaste/__init__.py b/src/httpaste/__init__.py index 8e93560..24716b9 100755 --- a/src/httpaste/__init__.py +++ b/src/httpaste/__init__.py @@ -202,8 +202,6 @@ def get_flask_app(config: Config) -> FlaskApp: """get a flask app object """ - print(config.server.swagger_ui) - options = {"swagger_ui": config.server.swagger_ui} #context manager returns a pathlib.Path object @@ -251,8 +249,6 @@ def get_flask_app(config: Config) -> FlaskApp: if https_url != request.url: - print('Hallo') - request._view['before_request__ssl_url'] = https_url return application