Merged in feature/HTTPASTE-46/view (pull request #50)

Feature/HTTPASTE-46/view
This commit is contained in:
Tiara Rodney 2022-04-17 02:01:23 +00:00
commit 389571522f
16 changed files with 145 additions and 23 deletions

View file

@ -14,7 +14,7 @@ WORKDIR /usr/local/src/httpaste
COPY . . COPY . .
RUN apt-get update && \ 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 pip install pipenv && \
python3 -m pipenv install --deploy --system --verbose && \ python3 -m pipenv install --deploy --system --verbose && \
python3 setup.py install && \ python3 setup.py install && \

View file

@ -22,6 +22,7 @@ services:
dockerfile: Dockerfile dockerfile: Dockerfile
ports: ports:
- "80:80" - "80:80"
- "443:443"
volumes: volumes:
- -
type: volume type: volume
@ -30,11 +31,13 @@ services:
volume: volume:
nocopy: true nocopy: true
- ./httpd/usr/local/apache2/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf - ./httpd/usr/local/apache2/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
- ./httpd/usr/local/apache2/ssl:/usr/local/apache2/ssl
tor: tor:
build: build:
context: ./tor context: ./tor
dockerfile: Dockerfile dockerfile: Dockerfile
volumes: volumes:
- ./tor/etc/tor/torrc:/etc/tor/torrc - ./tor/etc/tor/torrc:/etc/tor/torrc
- ./tor/var/lib/tor/hidden_service:./tor/var/lib/tor/hidden_service
volumes: volumes:
system-shared: system-shared:

View file

@ -18,7 +18,7 @@ LoadModule unixd_module modules/mod_unixd.so
LoadModule access_compat_module modules/mod_access_compat.so LoadModule access_compat_module modules/mod_access_compat.so
LoadModule security2_module /usr/lib/apache2/modules/mod_security2.so LoadModule security2_module /usr/lib/apache2/modules/mod_security2.so
LoadModule evasive20_module /usr/lib/apache2/modules/mod_evasive20.so LoadModule evasive20_module /usr/lib/apache2/modules/mod_evasive20.so
LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so
<IfModule unixd_module> <IfModule unixd_module>
User www-data User www-data
@ -88,3 +88,20 @@ ServerName 127.0.0.1
SetEnv proxy-sendchunks SetEnv proxy-sendchunks
ProxyPass "/" "unix:/shared/uwsgi.sock|uwsgi://localhost/" ProxyPass "/" "unix:/shared/uwsgi.sock|uwsgi://localhost/"
</VirtualHost> </VirtualHost>
<IfFile 'ssl/private.key'>
Listen 0.0.0.0:443
<VirtualHost 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/"
</VirtualHost>
</IfFile>

View file

@ -0,0 +1,2 @@
*.key
*.crt

View file

@ -0,0 +1 @@
*

View file

@ -152,6 +152,7 @@ from httpaste.model import Config as ModelConfig
from httpaste.backend import get_backend_config from httpaste.backend import get_backend_config
from httpaste.backend import Config as BackendConfig from httpaste.backend import Config as BackendConfig
from httpaste.helper.config import get_configparser, CONFIGPATH_ENVIRON from httpaste.helper.config import get_configparser, CONFIGPATH_ENVIRON
from httpaste.helper.url import url_upgrade_to_https
from httpaste.helper.http import ( from httpaste.helper.http import (
BadRequestError, BadRequestError,
ForbiddenError, ForbiddenError,
@ -201,8 +202,6 @@ def get_flask_app(config: Config) -> FlaskApp:
"""get a flask app object """get a flask app object
""" """
print(config.server.swagger_ui)
options = {"swagger_ui": config.server.swagger_ui} options = {"swagger_ui": config.server.swagger_ui}
#context manager returns a pathlib.Path object #context manager returns a pathlib.Path object
@ -238,6 +237,20 @@ def get_flask_app(config: Config) -> FlaskApp:
response.headers['WWW-Authenticate'] = 'Basic realm="private"' response.headers['WWW-Authenticate'] = 'Basic realm="private"'
return response 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:
request._view['before_request__ssl_url'] = https_url
return application return application

View file

@ -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 httpaste import __doc__ as man_page
from flask import current_app
def search(**kwargs): def search(**kwargs):
template = views.get_template("viewport/ui/search.html") template = views.get_template("viewport/ui/search.html")
@ -13,4 +15,7 @@ def search(**kwargs):
'delete_session_url': '/ui/user/session/delete' '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

View file

@ -2,8 +2,9 @@ from io import BytesIO
from base64 import b64encode from base64 import b64encode
from connexion import request 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.url import url_query_string, url_append_query_param
from httpaste.helper.syntax import syntax_shortnames, format_shortnames from httpaste.helper.syntax import syntax_shortnames, format_shortnames
from httpaste.helper.http import mime_types from httpaste.helper.http import mime_types
@ -23,7 +24,10 @@ def search(**kwargs):
'delete_session_url': '/ui/user/session/delete' '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): def post(**kwargs):
@ -93,4 +97,7 @@ def get(**kwargs):
'mime_types': mime_types() 'mime_types': mime_types()
} }
return template.render(**variables) with current_app.app_context():
view_render = render_template_with_context(template, **variables)
return view_render, 200

View file

@ -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 post as post_proxy
from httpaste.controller.ui.paste import get as get_proxy from httpaste.controller.ui.paste import get as get_proxy
@ -8,10 +10,12 @@ def search(**kwargs):
variables = { variables = {
'paste_form_url': '/ui/paste/private', '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): def post(**kwargs):

View file

@ -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 post as post_proxy
from httpaste.controller.ui.paste import get as get_proxy from httpaste.controller.ui.paste import get as get_proxy
@ -10,7 +12,10 @@ def search(**kwargs):
'paste_form_url': '/ui/paste/public' '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): def post(**kwargs):

View file

@ -1,5 +1,6 @@
from httpaste.helper.template import views from flask import current_app
from httpaste import __doc__ as man_page
from httpaste.helper.template import views, render_template_with_context
def search(**kwargs): def search(**kwargs):
@ -9,4 +10,7 @@ def search(**kwargs):
'delete_session_url': '/ui/user/session/delete' '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

View file

@ -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 httpaste.controller.user.session import delete as raw_delete
from connexion import request from connexion import request
@ -7,11 +7,12 @@ def search(**kwargs):
template = views.get_template("viewport/ui/user/session/search.html") template = views.get_template("viewport/ui/user/session/search.html")
print(request.path)
variables = {'session_delete_url': request.path + '/delete'} 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): def delete(**kwargs):

View file

@ -1,6 +1,25 @@
from jinja2 import Environment, PackageLoader, select_autoescape from jinja2 import Environment, PackageLoader, select_autoescape
from collections import namedtuple
views = Environment( views = Environment(
loader=PackageLoader("httpaste", "view"), loader=PackageLoader("httpaste", "view"),
autoescape=select_autoescape() autoescape=select_autoescape()
) )
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)
}})

View file

@ -1,3 +1,4 @@
from typing import Optional
from urllib.parse import urlparse, parse_qs 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() 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()

View file

@ -10,6 +10,8 @@ class Config(NamedTuple):
""" """
swagger_ui: bool = True swagger_ui: bool = True
bind_address: str = None bind_address: str = None
request_ssl: bool = True
ssl_port: int = 443
def get_server_config(configIni: ConfigParser) -> Config: def get_server_config(configIni: ConfigParser) -> Config:

View file

@ -15,10 +15,29 @@
margin-bottom: 1em; 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; }
}
</style> </style>
</head> </head>
<body> <body>
<header> <header>
{% if flask.before_request__ssl_url is defined %}
<p>
<strong class="blinking warning">WARNING:</strong> Communication not encrypted - SSL/TLS will not be enforced. Visit <a href="{{ flask.before_request__ssl_url }}">{{ flask.before_request__ssl_url }}</a>, for SSL/TLS encryption.
</p>
{% endif %}
{% block header %}{% endblock %} {% block header %}{% endblock %}
</header> </header>
<hr/> <hr/>