From a022e5912445966dff5b1e7c5a178feae51c4b0b Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 5 Nov 2024 15:46:08 -0300 Subject: [PATCH 1/4] feat: Check if token is a JWT --- supabase_functions/utils.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/supabase_functions/utils.py b/supabase_functions/utils.py index 1f8b969..c73fd8f 100644 --- a/supabase_functions/utils.py +++ b/supabase_functions/utils.py @@ -17,3 +17,27 @@ def is_valid_str_arg(target: str) -> bool: def is_http_url(url: str) -> bool: return urlparse(url).scheme in {"https", "http"} + + +def is_valid_jwt(value: str) -> bool: + """Checks if value looks like a JWT, does not do any extra parsing.""" + if not isinstance(value, str): + return False + + # Remove trailing whitespaces if any. + value = value.strip() + + # Remove "Bearer " prefix if any. + if value.startswith("Bearer "): + value = value[7:] + + # Valid JWT must have 2 dots (Header.Paylod.Signature) + if value.count(".") != 2: + return False + + okcr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-." + for char in value: + if not char in okcr: + return False + + return True From 452b9d2148f80413f09aafb7ed476ca79f3baa98 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 5 Nov 2024 15:46:18 -0300 Subject: [PATCH 2/4] feat: Check if token is a JWT --- supabase_functions/_async/functions_client.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/supabase_functions/_async/functions_client.py b/supabase_functions/_async/functions_client.py index aa66842..8f30cc2 100644 --- a/supabase_functions/_async/functions_client.py +++ b/supabase_functions/_async/functions_client.py @@ -3,7 +3,7 @@ from httpx import HTTPError, Response from ..errors import FunctionsHttpError, FunctionsRelayError -from ..utils import AsyncClient, is_http_url, is_valid_str_arg +from ..utils import AsyncClient, is_http_url, is_valid_jwt, is_valid_str_arg from ..version import __version__ @@ -60,6 +60,9 @@ def set_auth(self, token: str) -> None: the new jwt token sent in the authorization header """ + if not is_valid_jwt(token): + ValueError("token must be a valid JWT authorization token string.") + self.headers["Authorization"] = f"Bearer {token}" async def invoke( From d49076f5afb1d2a5bbe15ecdb10830bfdd4f2650 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 5 Nov 2024 15:47:13 -0300 Subject: [PATCH 3/4] feat: Check if token is a JWT --- supabase_functions/_sync/functions_client.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/supabase_functions/_sync/functions_client.py b/supabase_functions/_sync/functions_client.py index b407a5f..d153248 100644 --- a/supabase_functions/_sync/functions_client.py +++ b/supabase_functions/_sync/functions_client.py @@ -3,7 +3,7 @@ from httpx import HTTPError, Response from ..errors import FunctionsHttpError, FunctionsRelayError -from ..utils import SyncClient, is_http_url, is_valid_str_arg +from ..utils import SyncClient, is_http_url, is_valid_jwt, is_valid_str_arg from ..version import __version__ @@ -60,6 +60,9 @@ def set_auth(self, token: str) -> None: the new jwt token sent in the authorization header """ + if not is_valid_jwt(token): + ValueError("token must be a valid JWT authorization token string.") + self.headers["Authorization"] = f"Bearer {token}" def invoke( From 40079695c0dec5513d97cca627e38c6ff51f1cdd Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 5 Nov 2024 15:56:21 -0300 Subject: [PATCH 4/4] feat: Check if token is a JWT --- supabase_functions/utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/supabase_functions/utils.py b/supabase_functions/utils.py index c73fd8f..fe6b0ca 100644 --- a/supabase_functions/utils.py +++ b/supabase_functions/utils.py @@ -1,9 +1,11 @@ +import re from urllib.parse import urlparse from httpx import AsyncClient as AsyncClient # noqa: F401 from httpx import Client as BaseClient DEFAULT_FUNCTION_CLIENT_TIMEOUT = 5 +BASE64URL_REGEX = r"^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}$|[a-z0-9_-]{2}$)$" class SyncClient(BaseClient): @@ -35,9 +37,8 @@ def is_valid_jwt(value: str) -> bool: if value.count(".") != 2: return False - okcr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-." - for char in value: - if not char in okcr: + for part in value.split("."): + if not re.search(BASE64URL_REGEX, part, re.IGNORECASE): return False return True