From 786aa2279c5c829ee0cbf8954ae57f7dc5e01637 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 29 Apr 2024 04:49:13 -0500 Subject: [PATCH] chore: Replace python-jose with PyJWT (#3521) Co-authored-by: boc-the-git <3479092+boc-the-git@users.noreply.github.com> --- mealie/core/dependencies/dependencies.py | 17 ++--- .../core/security/providers/auth_provider.py | 2 +- mealie/core/security/security.py | 2 +- poetry.lock | 72 +++++-------------- pyproject.toml | 2 +- 5 files changed, 30 insertions(+), 65 deletions(-) diff --git a/mealie/core/dependencies/dependencies.py b/mealie/core/dependencies/dependencies.py index ba30327f52b5..84ea86681489 100644 --- a/mealie/core/dependencies/dependencies.py +++ b/mealie/core/dependencies/dependencies.py @@ -5,9 +5,10 @@ from pathlib import Path from uuid import uuid4 import fastapi +import jwt from fastapi import BackgroundTasks, Depends, HTTPException, Request, status from fastapi.security import OAuth2PasswordBearer -from jose import JWTError, jwt +from jwt.exceptions import PyJWTError from sqlalchemy.orm.session import Session from mealie.core import root_logger @@ -96,8 +97,8 @@ async def get_current_user( try: payload = jwt.decode(token, settings.SECRET, algorithms=[ALGORITHM]) - user_id: str = payload.get("sub") - long_token: str = payload.get("long_token") + user_id: str | None = payload.get("sub") + long_token: str | None = payload.get("long_token") if long_token is not None: return validate_long_live_token(session, token, payload.get("id")) @@ -106,7 +107,7 @@ async def get_current_user( raise credentials_exception token_data = TokenData(user_id=user_id) - except JWTError as e: + except PyJWTError as e: raise credentials_exception from e repos = get_repositories(session) @@ -126,7 +127,7 @@ async def get_integration_id(token: str = Depends(oauth2_scheme)) -> str: decoded_token = jwt.decode(token, settings.SECRET, algorithms=[ALGORITHM]) return decoded_token.get("integration_id", DEFAULT_INTEGRATION_ID) - except JWTError as e: + except PyJWTError as e: raise credentials_exception from e @@ -162,7 +163,7 @@ def validate_file_token(token: str | None = None) -> Path: try: payload = jwt.decode(token, settings.SECRET, algorithms=[ALGORITHM]) file_path = Path(payload.get("file")) - except JWTError as e: + except PyJWTError as e: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="could not validate file token", @@ -181,7 +182,7 @@ def validate_recipe_token(token: str | None = None) -> str: Raises: HTTPException: 400 Bad Request when no token or the recipe doesn't exist - HTTPException: 401 JWTError when token is invalid + HTTPException: 401 PyJWTError when token is invalid Returns: str: token data @@ -192,7 +193,7 @@ def validate_recipe_token(token: str | None = None) -> str: try: payload = jwt.decode(token, settings.SECRET, algorithms=[ALGORITHM]) slug: str | None = payload.get("slug") - except JWTError as e: + except PyJWTError as e: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="could not validate file token", diff --git a/mealie/core/security/providers/auth_provider.py b/mealie/core/security/providers/auth_provider.py index 46b7d583cfd3..ee5f15c90bfd 100644 --- a/mealie/core/security/providers/auth_provider.py +++ b/mealie/core/security/providers/auth_provider.py @@ -2,7 +2,7 @@ import abc from datetime import datetime, timedelta, timezone from typing import Generic, TypeVar -from jose import jwt +import jwt from sqlalchemy.orm.session import Session from mealie.core.config import get_app_settings diff --git a/mealie/core/security/security.py b/mealie/core/security/security.py index 0b937b592a54..3a0fad52f983 100644 --- a/mealie/core/security/security.py +++ b/mealie/core/security/security.py @@ -2,8 +2,8 @@ import secrets from datetime import datetime, timedelta, timezone from pathlib import Path +import jwt from fastapi import Request -from jose import jwt from sqlalchemy.orm.session import Session from mealie.core import root_logger diff --git a/poetry.lock b/poetry.lock index 69e8c7c029ae..ea505c99b8e2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -566,24 +566,6 @@ files = [ {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, ] -[[package]] -name = "ecdsa" -version = "0.18.0" -description = "ECDSA cryptographic signature library (pure python)" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "ecdsa-0.18.0-py2.py3-none-any.whl", hash = "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd"}, - {file = "ecdsa-0.18.0.tar.gz", hash = "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49"}, -] - -[package.dependencies] -six = ">=1.9.0" - -[package.extras] -gmpy = ["gmpy"] -gmpy2 = ["gmpy2"] - [[package]] name = "exceptiongroup" version = "1.1.0" @@ -2031,6 +2013,23 @@ files = [ {file = "pyhumps-3.8.0.tar.gz", hash = "sha256:498026258f7ee1a8e447c2e28526c0bea9407f9a59c03260aee4bd6c04d681a3"}, ] +[[package]] +name = "pyjwt" +version = "2.8.0" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, + {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, +] + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + [[package]] name = "pylint" version = "3.1.0" @@ -2175,27 +2174,6 @@ files = [ [package.extras] cli = ["click (>=5.0)"] -[[package]] -name = "python-jose" -version = "3.3.0" -description = "JOSE implementation in Python" -optional = false -python-versions = "*" -files = [ - {file = "python-jose-3.3.0.tar.gz", hash = "sha256:55779b5e6ad599c6336191246e95eb2293a9ddebd555f796a65f838f07e5d78a"}, - {file = "python_jose-3.3.0-py2.py3-none-any.whl", hash = "sha256:9b1376b023f8b298536eedd47ae1089bcdb848f1535ab30555cd92002d78923a"}, -] - -[package.dependencies] -ecdsa = "!=0.15" -pyasn1 = "*" -rsa = "*" - -[package.extras] -cryptography = ["cryptography (>=3.4.0)"] -pycrypto = ["pyasn1", "pycrypto (>=2.6.0,<2.7.0)"] -pycryptodome = ["pyasn1", "pycryptodome (>=3.3.1,<4.0.0)"] - [[package]] name = "python-ldap" version = "3.4.4" @@ -2612,20 +2590,6 @@ pygments = ">=2.13.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] -[[package]] -name = "rsa" -version = "4.9" -description = "Pure-Python RSA implementation" -optional = false -python-versions = ">=3.6,<4" -files = [ - {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, - {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, -] - -[package.dependencies] -pyasn1 = ">=0.1.3" - [[package]] name = "ruff" version = "0.4.1" @@ -3200,4 +3164,4 @@ pgsql = ["psycopg2-binary"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "44f2eaba7090df4e28644795f40a751dd86c25a3ee2882d75871ffb19f626823" +content-hash = "19ce4d2b50eda32826cbb2fb6aa7bd6cf72ab05e234402f7b5222244115d32ea" diff --git a/pyproject.toml b/pyproject.toml index 56c5df69c1e0..03102aec4a14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,6 @@ pyhumps = "^3.5.3" python = "^3.10" python-dateutil = "^2.8.2" python-dotenv = "^1.0.0" -python-jose = "^3.3.0" python-ldap = "^3.3.1" python-multipart = "^0.0.9" python-slugify = "^8.0.0" @@ -48,6 +47,7 @@ html2text = "^2024.0.0" paho-mqtt = "^1.6.1" pydantic-settings = "^2.1.0" pillow-heif = "^0.16.0" +pyjwt = "^2.8.0" [tool.poetry.group.postgres.dependencies] psycopg2-binary = { version = "^2.9.1" }