From f101c3283c3d0ffd1a76dcd2da19d9055e61b4fe Mon Sep 17 00:00:00 2001 From: PlayerG9 Date: Mon, 19 Feb 2024 00:02:46 +0100 Subject: [PATCH] simpel way to prevent access to config or userpass file --- src/jarklin/_commands/_get_config.py | 14 ++++++++++++-- src/jarklin/_commands/web/__init__.py | 9 +++++++-- src/jarklin/web/__init__.py | 11 +++++++---- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/jarklin/_commands/_get_config.py b/src/jarklin/_commands/_get_config.py index 682548b..024b671 100644 --- a/src/jarklin/_commands/_get_config.py +++ b/src/jarklin/_commands/_get_config.py @@ -2,14 +2,21 @@ r""" """ +import typing as t from functools import cache import configlib.finder from ._logging import configure_logging from ._process_config import configure_process +@t.overload +def get_config() -> 'configlib.ConfigInterface': ... +@t.overload +def get_config(return_fp: bool = True) -> t.Tuple['configlib.ConfigInterface', str]: ... + + @cache -def get_config() -> 'configlib.ConfigInterface': +def get_config(return_fp: bool = False): try: fp = configlib.find( ".jarklin.ext", @@ -24,4 +31,7 @@ def get_config() -> 'configlib.ConfigInterface': config = configlib.load(fp=fp) configure_logging(config=config) configure_process(config=config) - return config + if return_fp: + return config, str(fp.absolute()) + else: + return config diff --git a/src/jarklin/_commands/web/__init__.py b/src/jarklin/_commands/web/__init__.py index 6ebfb6a..8b4426a 100644 --- a/src/jarklin/_commands/web/__init__.py +++ b/src/jarklin/_commands/web/__init__.py @@ -5,6 +5,7 @@ def run() -> None: + import os.path as p import flask import secrets from werkzeug.middleware.dispatcher import DispatcherMiddleware @@ -12,7 +13,9 @@ def run() -> None: from .._get_config import get_config from ...web import app - config = get_config() + config, config_fp = get_config(return_fp=True) + + app.config['EXCLUDE'] = [config_fp] baseurl = config.getstr('web', 'baseurl', fallback="/") if not baseurl.startswith("/"): @@ -31,7 +34,9 @@ def run() -> None: app.config['USERPASS'][simple_username] = simple_password if config.has('web', 'auth', 'userpass'): from ...common.userpass import parse_userpass - userpass = parse_userpass(config.getstr('web', 'auth', 'userpass')) + userpass_fp = p.abspath(config.getstr('web', 'auth', 'userpass')) + app.config['EXCLUDE'].append(userpass_fp) + userpass = parse_userpass(userpass_fp) app.config['USERPASS'].update(userpass) app.secret_key = config.getstr('web', 'session', 'secret_key', fallback=secrets.token_hex(64)) diff --git a/src/jarklin/web/__init__.py b/src/jarklin/web/__init__.py index 22f8448..edea5e6 100644 --- a/src/jarklin/web/__init__.py +++ b/src/jarklin/web/__init__.py @@ -7,7 +7,7 @@ from http import HTTPStatus from hmac import compare_digest import flask -from werkzeug.exceptions import Unauthorized, BadRequest +from werkzeug.exceptions import Unauthorized as HTTPUnauthorized, BadRequest as HTTPBadRequest, NotFound as HTTPNotFound WEB_UI = p.join(p.dirname(__file__), 'web-ui') @@ -20,7 +20,7 @@ def is_authenticated(fn): @wraps(fn) def wrapper(*args, **kwargs): if app.config.get("USERPASS") and 'username' not in flask.session: - raise Unauthorized("currently not logged in") + raise HTTPUnauthorized("currently not logged in") return fn(*args, **kwargs) return wrapper @@ -29,6 +29,9 @@ def wrapper(*args, **kwargs): @app.get("/files/") @is_authenticated def files(resource: str, download: bool = False): + fp = p.join(os.getcwd(), resource) + if fp in app.config['EXCLUDE']: + raise HTTPNotFound() return flask.send_from_directory(os.getcwd(), resource, as_attachment=download) @@ -48,10 +51,10 @@ def login(): username, password = flask.request.form.get("username"), flask.request.form.get("password") if not username or not password: - raise BadRequest("username or password missing in authorization") + raise HTTPBadRequest("username or password missing in authorization") if username not in userpass or not compare_digest(password, userpass[username]): - raise Unauthorized("bad credentials provided") + raise HTTPUnauthorized("bad credentials provided") flask.session['username'] = username return "", HTTPStatus.NO_CONTENT