From 2a778ff46ce5e46692f98df2f7c7f05bbd4750b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Fri, 8 Apr 2022 17:39:58 +0200 Subject: [PATCH] login/logout only valid from some origin as host (and host is already checked by hypercorn) --- setup.cfg | 2 +- src/capport/api/app.py | 4 ++-- src/capport/api/views.py | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index 00b80b4..81d1b13 100644 --- a/setup.cfg +++ b/setup.cfg @@ -21,8 +21,8 @@ packages = find: python_requires = >=3.9 install_requires = trio - quart-trio quart + quart-trio hypercorn[trio] PyYAML protobuf diff --git a/src/capport/api/app.py b/src/capport/api/app.py index 70ab89e..b6bc3d4 100644 --- a/src/capport/api/app.py +++ b/src/capport/api/app.py @@ -1,9 +1,9 @@ +from __future__ import annotations + from .app_cls import MyQuartApp - app = MyQuartApp(__name__) - __import__('capport.api.setup') __import__('capport.api.lang') __import__('capport.api.views') diff --git a/src/capport/api/views.py b/src/capport/api/views.py index e7cc3ea..37ffcb9 100644 --- a/src/capport/api/views.py +++ b/src/capport/api/views.py @@ -96,6 +96,23 @@ async def user_lookup() -> cptypes.MacPublicState: # return app.my_hub.database.as_json() +def check_self_origin(): + origin = quart.request.headers.get('Origin', None) + if origin is None: + # not a request by a modern browser - probably curl or something similar. don't care. + return + origin_parts = origin.split('/') + # Origin should look like: protocol://hostname (possibly a /path suffix?) + if len(origin_parts) < 3: + quart.abort(400, 'Broken Origin header') + origin_host = origin_parts[2].lower() + host = quart.request.headers.get('Host', None) + if host is None: + quart.abort(400, 'Missing Host header') + if host.lower() != origin_host: + quart.abort(400, 'Origin mismatch') + + @app.route('/', methods=['GET']) async def index(missing_accept: bool=False): state = await user_lookup() @@ -109,6 +126,7 @@ async def index(missing_accept: bool=False): @app.route('/login', methods=['POST']) async def login(): + check_self_origin() with trio.fail_after(5.0): form = await quart.request.form if form.get('accept') != '1': @@ -126,6 +144,7 @@ async def login(): @app.route('/logout', methods=['POST']) async def logout(): + check_self_origin() with trio.fail_after(5.0): form = await quart.request.form req_mac = form.get('mac')