From d0b9962164ecf9211e2bab25e653c7023f41aff5 Mon Sep 17 00:00:00 2001 From: Namit Nathwani Date: Mon, 24 Feb 2025 12:57:31 +0530 Subject: [PATCH] update: handle url normalize without lower --- supertokens_python/normalised_url_path.py | 27 ++-- tests/test_config.py | 164 +++++++++------------- 2 files changed, 79 insertions(+), 112 deletions(-) diff --git a/supertokens_python/normalised_url_path.py b/supertokens_python/normalised_url_path.py index 6d5812e18..3a817cc7f 100644 --- a/supertokens_python/normalised_url_path.py +++ b/supertokens_python/normalised_url_path.py @@ -45,23 +45,26 @@ def is_a_recipe_path(self) -> bool: def normalise_url_path_or_throw_error(input_str: str) -> str: - input_str = input_str.strip().lower() + input_str = input_str.strip() + input_str_lower = input_str.lower() + try: - if not input_str.startswith("http://") and not input_str.startswith("https://"): + if not input_str_lower.startswith(("http://", "https://")): raise Exception("converting to proper URL") + url_obj = urlparse(input_str) - input_str = url_obj.path - if input_str.endswith("/"): - return input_str[:-1] - return input_str + url_path = url_obj.path + + if url_path.endswith("/"): + return url_path[:-1] + + return url_path except Exception: pass if ( - (domain_given(input_str) or input_str.startswith("localhost")) - and not input_str.startswith("http://") - and not input_str.startswith("https://") - ): + domain_given(input_str_lower) or input_str_lower.startswith("localhost") + ) and not input_str_lower.startswith(("http://", "https://")): input_str = "http://" + input_str return normalise_url_path_or_throw_error(input_str) @@ -69,8 +72,8 @@ def normalise_url_path_or_throw_error(input_str: str) -> str: input_str = "/" + input_str try: - urlparse("http://example.com" + input_str) - return normalise_url_path_or_throw_error("http://example.com" + input_str) + urlparse(f"http://example.com{input_str}") + return normalise_url_path_or_throw_error(f"http://example.com{input_str}") except Exception: raise_general_exception("Please provide a valid URL path") diff --git a/tests/test_config.py b/tests/test_config.py index 9132390b7..7e087e4ec 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -11,7 +11,6 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -from typing import Any, Dict, Optional from unittest.mock import MagicMock import pytest @@ -24,8 +23,9 @@ from supertokens_python.recipe.session import SessionRecipe from supertokens_python.recipe.session.asyncio import create_new_session from supertokens_python.types import RecipeUserId +from typing_extensions import Any, Dict, Optional -from tests.utils import get_new_core_app_url, reset +from tests.utils import get_new_core_app_url, outputs, reset # Tests do not rely on the core. @@ -35,109 +35,73 @@ def st_config() -> SupertokensConfig: return SupertokensConfig(get_new_core_app_url()) -def testing_URL_path_normalisation(): +@mark.parametrize( + ("input", "expectation"), + [ + ("exists?email=john.doe%40gmail.com", outputs("/exists")), + ( + "/auth/email/exists?email=john.doe%40gmail.com", + outputs("/auth/email/exists"), + ), + ("http://api.example.com", outputs("")), + ("https://api.example.com", outputs("")), + ("http://api.example.com?hello=1", outputs("")), + ("http://api.example.com/hello", outputs("/hello")), + ("http://api.example.com/HellO", outputs("/HellO")), + ("http://api.example.com/", outputs("")), + ("http://api.example.com:8080", outputs("")), + ("api.example.com/", outputs("")), + ("api.example.com#random", outputs("")), + (".example.com", outputs("")), + ("api.example.com/?hello=1&bye=2", outputs("")), + ("exists", outputs("/exists")), + ("eXiStS", outputs("/eXiStS")), + ("/exists", outputs("/exists")), + ("/eXiStS", outputs("/eXiStS")), + ("/exists?email=john.doe%40gmail.com", outputs("/exists")), + ("http://api.example.com/one/two", outputs("/one/two")), + ("http://1.2.3.4/one/two", outputs("/one/two")), + ("1.2.3.4/one/two", outputs("/one/two")), + ("https://api.example.com/one/two/", outputs("/one/two")), + ("http://api.example.com/one/two?hello=1", outputs("/one/two")), + ("http://api.example.com/hello/", outputs("/hello")), + ("http://api.example.com/one/two/", outputs("/one/two")), + ("http://api.example.com/one/two#random2", outputs("/one/two")), + ("api.example.com/one/two", outputs("/one/two")), + (".example.com/one/two", outputs("/one/two")), + ("api.example.com/one/two?hello=1&bye=2", outputs("/one/two")), + ("/one/two", outputs("/one/two")), + ("one/two", outputs("/one/two")), + ("one/two/", outputs("/one/two")), + ("/one", outputs("/one")), + ("one", outputs("/one")), + ("one/", outputs("/one")), + ("/one/two/", outputs("/one/two")), + ("/one/two?hello=1", outputs("/one/two")), + ("one/two?hello=1", outputs("/one/two")), + ("/one/two/#randm,", outputs("/one/two")), + ("one/two#random", outputs("/one/two")), + ("localhost:4000/one/two", outputs("/one/two")), + ("127.0.0.1:4000/one/two", outputs("/one/two")), + ("127.0.0.1/one/two", outputs("/one/two")), + ("https://127.0.0.1:80/one/two", outputs("/one/two")), + ("/", outputs("")), + ("", outputs("")), + ("/.netlify/functions/api", outputs("/.netlify/functions/api")), + ("/netlify/.functions/api", outputs("/netlify/.functions/api")), + ("app.example.com/.netlify/functions/api", outputs("/.netlify/functions/api")), + ("app.example.com/netlify/.functions/api", outputs("/netlify/.functions/api")), + ("/app.example.com", outputs("/app.example.com")), + ], +) +def testing_URL_path_normalisation(input: str, expectation: Any) -> None: def normalise_url_path_or_throw_error( input: str, ): # pylint: disable=redefined-builtin return NormalisedURLPath(input).get_as_string_dangerous() - assert ( - normalise_url_path_or_throw_error("exists?email=john.doe%40gmail.com") - == "/exists" - ) - assert ( - normalise_url_path_or_throw_error( - "/auth/email/exists?email=john.doe%40gmail.com" - ) - == "/auth/email/exists" - ) - assert normalise_url_path_or_throw_error("exists") == "/exists" - assert normalise_url_path_or_throw_error("/exists") == "/exists" - assert ( - normalise_url_path_or_throw_error("/exists?email=john.doe%40gmail.com") - == "/exists" - ) - assert normalise_url_path_or_throw_error("http://api.example.com") == "" - assert normalise_url_path_or_throw_error("https://api.example.com") == "" - assert normalise_url_path_or_throw_error("http://api.example.com?hello=1") == "" - assert normalise_url_path_or_throw_error("http://api.example.com/hello") == "/hello" - assert normalise_url_path_or_throw_error("http://api.example.com/") == "" - assert normalise_url_path_or_throw_error("http://api.example.com:8080") == "" - assert normalise_url_path_or_throw_error("api.example.com/") == "" - assert normalise_url_path_or_throw_error("api.example.com#random") == "" - assert normalise_url_path_or_throw_error(".example.com") == "" - assert normalise_url_path_or_throw_error("api.example.com/?hello=1&bye=2") == "" - - assert ( - normalise_url_path_or_throw_error("http://api.example.com/one/two") - == "/one/two" - ) - assert normalise_url_path_or_throw_error("http://1.2.3.4/one/two") == "/one/two" - assert normalise_url_path_or_throw_error("1.2.3.4/one/two") == "/one/two" - assert ( - normalise_url_path_or_throw_error("https://api.example.com/one/two/") - == "/one/two" - ) - assert ( - normalise_url_path_or_throw_error("http://api.example.com/one/two?hello=1") - == "/one/two" - ) - assert ( - normalise_url_path_or_throw_error("http://api.example.com/hello/") == "/hello" - ) - assert ( - normalise_url_path_or_throw_error("http://api.example.com/one/two/") - == "/one/two" - ) - assert ( - normalise_url_path_or_throw_error("http://api.example.com/one/two#random2") - == "/one/two" - ) - assert normalise_url_path_or_throw_error("api.example.com/one/two") == "/one/two" - assert normalise_url_path_or_throw_error(".example.com/one/two") == "/one/two" - assert ( - normalise_url_path_or_throw_error("api.example.com/one/two?hello=1&bye=2") - == "/one/two" - ) - - assert normalise_url_path_or_throw_error("/one/two") == "/one/two" - assert normalise_url_path_or_throw_error("one/two") == "/one/two" - assert normalise_url_path_or_throw_error("one/two/") == "/one/two" - assert normalise_url_path_or_throw_error("/one") == "/one" - assert normalise_url_path_or_throw_error("one") == "/one" - assert normalise_url_path_or_throw_error("one/") == "/one" - assert normalise_url_path_or_throw_error("/one/two/") == "/one/two" - assert normalise_url_path_or_throw_error("/one/two?hello=1") == "/one/two" - assert normalise_url_path_or_throw_error("one/two?hello=1") == "/one/two" - assert normalise_url_path_or_throw_error("/one/two/#randm,") == "/one/two" - assert normalise_url_path_or_throw_error("one/two#random") == "/one/two" - - assert normalise_url_path_or_throw_error("localhost:4000/one/two") == "/one/two" - assert normalise_url_path_or_throw_error("127.0.0.1:4000/one/two") == "/one/two" - assert normalise_url_path_or_throw_error("127.0.0.1/one/two") == "/one/two" - assert ( - normalise_url_path_or_throw_error("https://127.0.0.1:80/one/two") == "/one/two" - ) - assert normalise_url_path_or_throw_error("/") == "" - assert normalise_url_path_or_throw_error("") == "" - - assert ( - normalise_url_path_or_throw_error("/.netlify/functions/api") - == "/.netlify/functions/api" - ) - assert ( - normalise_url_path_or_throw_error("/netlify/.functions/api") - == "/netlify/.functions/api" - ) - assert ( - normalise_url_path_or_throw_error("app.example.com/.netlify/functions/api") - == "/.netlify/functions/api" - ) - assert ( - normalise_url_path_or_throw_error("app.example.com/netlify/.functions/api") - == "/netlify/.functions/api" - ) - assert normalise_url_path_or_throw_error("/app.example.com") == "/app.example.com" + with expectation as output: + assert normalise_url_path_or_throw_error(input) == output def testing_URL_domain_normalisation():