From e22e38b3043de5fcbfbf86aea4742e93e4b41324 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Mon, 22 Aug 2022 17:18:03 +0200 Subject: [PATCH] Implement custom UA parsing, allowing to update Flask and Werkzeug Signed-off-by: Ferdinand Thiessen --- flaschengeist/controller/pluginController.py | 1 + flaschengeist/controller/sessionController.py | 43 +++++++++++++++++-- flaschengeist/models/session.py | 4 +- flaschengeist/utils/decorators.py | 2 +- setup.cfg | 8 ++-- 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/flaschengeist/controller/pluginController.py b/flaschengeist/controller/pluginController.py index ba0e91b..86ea301 100644 --- a/flaschengeist/controller/pluginController.py +++ b/flaschengeist/controller/pluginController.py @@ -25,6 +25,7 @@ def get_enabled_plugins(): class PluginStub: def __init__(self, name) -> None: self.name = name + self.version = "?" logger.error("Could not connect to database or database not initialized! No plugins enabled!") logger.debug("Can not query enabled plugins", exc_info=True) diff --git a/flaschengeist/controller/sessionController.py b/flaschengeist/controller/sessionController.py index 5d5ceae..da5c81c 100644 --- a/flaschengeist/controller/sessionController.py +++ b/flaschengeist/controller/sessionController.py @@ -11,7 +11,36 @@ from ..database import db lifetime = 1800 -def validate_token(token, user_agent, permission): +def __get_user_agent_platform(ua: str): + if "Win" in ua: + return "Windows" + if "Mac" in ua: + return "Macintosh" + if "Linux" in ua: + return "Linux" + if "Android" in ua: + return "Android" + if "like Mac" in ua: + return "iOS" + return "unknown" + + +def __get_user_agent_browser(ua: str): + ua_str = ua.lower() + if "firefox" in ua_str or "fxios" in ua_str: + return "firefox" + if "safari" in ua_str: + return "safari" + if "opr/" in ua_str: + return "opera" + if "edg" in ua_str: + return "edge" + if "chrom" in ua_str or "crios" in ua_str: + return "chrome" + return "unknown" + + +def validate_token(token, request_headers, permission): """Verify session Verify a Session and Roles so if the User has permission or not. @@ -19,7 +48,7 @@ def validate_token(token, user_agent, permission): Args: token: Token to verify. - user_agent: User agent of browser to check + request_headers: Headers to validate user agent of browser permission: Permission needed to access restricted routes Returns: A Session for this given Token @@ -31,8 +60,16 @@ def validate_token(token, user_agent, permission): session = Session.query.filter_by(token=token).one_or_none() if session: logger.debug("token found, check if expired or invalid user agent differs") + + platform = request_headers.get("Sec-CH-UA-Platform", None) or __get_user_agent_platform( + request_headers.get("User-Agent", "") + ) + browser = request_headers.get("Sec-CH-UA", None) or __get_user_agent_browser( + request_headers.get("User-Agent", "") + ) + if session.expires >= datetime.now(timezone.utc) and ( - session.browser == user_agent.browser and session.platform == user_agent.platform + session.browser == browser and session.platform == platform ): if not permission or session.user_.has_permission(permission): session.refresh() diff --git a/flaschengeist/models/session.py b/flaschengeist/models/session.py index dea7c62..bf584fe 100644 --- a/flaschengeist/models/session.py +++ b/flaschengeist/models/session.py @@ -20,8 +20,8 @@ class Session(db.Model, ModelSerializeMixin): expires: datetime = db.Column(UtcDateTime) token: str = db.Column(db.String(32), unique=True) lifetime: int = db.Column(db.Integer) - browser: str = db.Column(db.String(30)) - platform: str = db.Column(db.String(30)) + browser: str = db.Column(db.String(127)) + platform: str = db.Column(db.String(64)) userid: str = "" _id = db.Column("id", Serial, primary_key=True) diff --git a/flaschengeist/utils/decorators.py b/flaschengeist/utils/decorators.py index b26f66a..34814dc 100644 --- a/flaschengeist/utils/decorators.py +++ b/flaschengeist/utils/decorators.py @@ -14,7 +14,7 @@ def extract_session(permission=None): logger.debug("Missing Authorization header or ill-formed") raise Unauthorized - session = sessionController.validate_token(token, request.user_agent, permission) + session = sessionController.validate_token(token, request.headers, permission) return session diff --git a/setup.cfg b/setup.cfg index 46433c8..4c1c786 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,14 +22,14 @@ include_package_data = True python_requires = >=3.10 packages = find: install_requires = - Flask==2.0.3 - Pillow>=9.0 + Flask>=2.2.2 + Pillow>=9.2 flask_cors flask_migrate>=3.1.0 flask_sqlalchemy>=2.5.1 - sqlalchemy>=1.4.39 + sqlalchemy>=1.4.40 toml - werkzeug==2.0.3 + werkzeug>=2.2.2 [options.extras_require] argon = argon2-cffi