From 5fc62110111f237f2811b41b08ad42fc8734af40 Mon Sep 17 00:00:00 2001 From: Mayank Thakur Date: Wed, 15 Nov 2023 18:46:33 +0530 Subject: [PATCH 1/8] test: adds test for create_reset_password_link --- tests/emailpassword/test_passwordreset.py | 37 ++++++++++++++++++ .../test_email_delivery.py | 39 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/tests/emailpassword/test_passwordreset.py b/tests/emailpassword/test_passwordreset.py index 6a67dc632..118cf3972 100644 --- a/tests/emailpassword/test_passwordreset.py +++ b/tests/emailpassword/test_passwordreset.py @@ -14,6 +14,7 @@ import asyncio import json from typing import Any, Dict, Union +from urllib.parse import urlparse from fastapi import FastAPI from fastapi.requests import Request @@ -22,6 +23,7 @@ from supertokens_python import InputAppInfo, SupertokensConfig, init from supertokens_python.framework.fastapi import get_middleware from supertokens_python.recipe import emailpassword, session +from supertokens_python.recipe.emailpassword.asyncio import create_reset_password_link from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.asyncio import ( create_new_session, @@ -339,3 +341,38 @@ async def send_email( assert dict_response["status"] == "OK" assert dict_response["user"]["id"] == user_info["id"] assert dict_response["user"]["email"] == user_info["email"] + + +@mark.asyncio +async def test_create_reset_password_link( + driver_config_client: TestClient, +): + init( + supertokens_config=SupertokensConfig("http://localhost:3567"), + app_info=InputAppInfo( + app_name="SuperTokens Demo", + api_domain="http://api.supertokens.io", + website_domain="http://supertokens.io", + api_base_path="/auth", + ), + framework="fastapi", + recipe_list=[ + emailpassword.init(), + session.init(get_token_transfer_method=lambda _, __, ___: "cookie"), + ], + ) + start_st() + + response_1 = sign_up_request( + driver_config_client, "random@gmail.com", "validpass123" + ) + assert response_1.status_code == 200 + dict_response = json.loads(response_1.text) + user_info = dict_response["user"] + assert dict_response["status"] == "OK" + link = await create_reset_password_link("public", user_info["id"]) + url = urlparse(link.link) # type: ignore + queries = url.query.strip("&").split("&") + assert url.path == "/auth/reset-password" + assert "tenantId=public" in queries + assert "rid=emailpassword" in queries diff --git a/tests/thirdpartyemailpassword/test_email_delivery.py b/tests/thirdpartyemailpassword/test_email_delivery.py index 0d95d31f2..49b16861d 100644 --- a/tests/thirdpartyemailpassword/test_email_delivery.py +++ b/tests/thirdpartyemailpassword/test_email_delivery.py @@ -21,6 +21,7 @@ from fastapi.requests import Request from fastapi.testclient import TestClient from pytest import fixture, mark +from urllib.parse import urlparse from supertokens_python import InputAppInfo, SupertokensConfig, init from supertokens_python.framework.fastapi import get_middleware @@ -37,6 +38,9 @@ session, thirdpartyemailpassword, ) +from supertokens_python.recipe.thirdpartyemailpassword.asyncio import ( + create_reset_password_link, +) from supertokens_python.recipe.emailverification.emaildelivery.services import ( SMTPService as EVSMTPService, ) @@ -1036,3 +1040,38 @@ async def send_email( assert email == "test@example.com" assert email_verify_url != "" + + +@mark.asyncio +async def test_create_reset_password_link( + driver_config_client: TestClient, +): + init( + supertokens_config=SupertokensConfig("http://localhost:3567"), + app_info=InputAppInfo( + app_name="SuperTokens Demo", + api_domain="http://api.supertokens.io", + website_domain="http://supertokens.io", + api_base_path="/auth", + ), + framework="fastapi", + recipe_list=[ + thirdpartyemailpassword.init(), + session.init(get_token_transfer_method=lambda _, __, ___: "cookie"), + ], + ) + start_st() + + response_1 = sign_up_request( + driver_config_client, "random@gmail.com", "validpass123" + ) + assert response_1.status_code == 200 + dict_response = json.loads(response_1.text) + user_info = dict_response["user"] + assert dict_response["status"] == "OK" + link = await create_reset_password_link("public", user_info["id"]) + url = urlparse(link.link) # type: ignore + queries = url.query.strip("&").split("&") + assert url.path == "/auth/reset-password" + assert "tenantId=public" in queries + assert "rid=thirdpartyemailpassword" in queries From 3895ad8e6455a0061c4d6324bd7404b61dbbba61 Mon Sep 17 00:00:00 2001 From: Mayank Thakur Date: Wed, 15 Nov 2023 19:07:41 +0530 Subject: [PATCH 2/8] bumped version and updated changelog --- CHANGELOG.md | 3 +++ setup.py | 2 +- supertokens_python/constants.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f23e0687..f6ac9828e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.17.1] - 2023-11-15 +- Added test for `create_reset_password_link` in both `emailpassword` and `thirdpartyemailpassword` recipes. + ## [0.17.0] - 2023-11-14 - Fixes `create_reset_password_link` in the emailpassword recipe wherein we passed the `rid` instead of the token in the link diff --git a/setup.py b/setup.py index e129656a7..397cb82ef 100644 --- a/setup.py +++ b/setup.py @@ -70,7 +70,7 @@ setup( name="supertokens_python", - version="0.17.0", + version="0.17.1", author="SuperTokens", license="Apache 2.0", author_email="team@supertokens.com", diff --git a/supertokens_python/constants.py b/supertokens_python/constants.py index 2eb0fe55b..a1d716086 100644 --- a/supertokens_python/constants.py +++ b/supertokens_python/constants.py @@ -14,7 +14,7 @@ from __future__ import annotations SUPPORTED_CDI_VERSIONS = ["3.0"] -VERSION = "0.17.0" +VERSION = "0.17.1" TELEMETRY = "/telemetry" USER_COUNT = "/users/count" USER_DELETE = "/user/remove" From a8c9276069d9396c26d38ee73691cf14168d7631 Mon Sep 17 00:00:00 2001 From: Mayank Thakur Date: Wed, 15 Nov 2023 19:25:44 +0530 Subject: [PATCH 3/8] test: adds test for negative cases --- tests/emailpassword/test_passwordreset.py | 13 ++++++++++++- .../thirdpartyemailpassword/test_email_delivery.py | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/emailpassword/test_passwordreset.py b/tests/emailpassword/test_passwordreset.py index 118cf3972..f9a10dcd1 100644 --- a/tests/emailpassword/test_passwordreset.py +++ b/tests/emailpassword/test_passwordreset.py @@ -19,11 +19,15 @@ from fastapi import FastAPI from fastapi.requests import Request from fastapi.testclient import TestClient -from pytest import fixture, mark +from pytest import fixture, mark, raises from supertokens_python import InputAppInfo, SupertokensConfig, init +from supertokens_python.exceptions import GeneralError from supertokens_python.framework.fastapi import get_middleware from supertokens_python.recipe import emailpassword, session from supertokens_python.recipe.emailpassword.asyncio import create_reset_password_link +from supertokens_python.recipe.emailpassword.interfaces import ( + CreateResetPasswordLinkUnknownUserIdError, +) from supertokens_python.recipe.session import SessionContainer from supertokens_python.recipe.session.asyncio import ( create_new_session, @@ -376,3 +380,10 @@ async def test_create_reset_password_link( assert url.path == "/auth/reset-password" assert "tenantId=public" in queries assert "rid=emailpassword" in queries + + link = await create_reset_password_link("public", "invalidUserId") + assert isinstance(link, CreateResetPasswordLinkUnknownUserIdError) + + with raises(GeneralError) as err: + await create_reset_password_link("invalidTenantId", user_info["id"]) + assert "status code: 400" in str(err.value) diff --git a/tests/thirdpartyemailpassword/test_email_delivery.py b/tests/thirdpartyemailpassword/test_email_delivery.py index 49b16861d..6528cc4ff 100644 --- a/tests/thirdpartyemailpassword/test_email_delivery.py +++ b/tests/thirdpartyemailpassword/test_email_delivery.py @@ -20,10 +20,11 @@ from fastapi import FastAPI from fastapi.requests import Request from fastapi.testclient import TestClient -from pytest import fixture, mark +from pytest import fixture, mark, raises from urllib.parse import urlparse from supertokens_python import InputAppInfo, SupertokensConfig, init +from supertokens_python.exceptions import GeneralError from supertokens_python.framework.fastapi import get_middleware from supertokens_python.ingredients.emaildelivery import EmailDeliveryInterface from supertokens_python.ingredients.emaildelivery.types import ( @@ -41,6 +42,9 @@ from supertokens_python.recipe.thirdpartyemailpassword.asyncio import ( create_reset_password_link, ) +from supertokens_python.recipe.thirdpartyemailpassword.interfaces import ( + CreateResetPasswordLinkUnknownUserIdError, +) from supertokens_python.recipe.emailverification.emaildelivery.services import ( SMTPService as EVSMTPService, ) @@ -1075,3 +1079,10 @@ async def test_create_reset_password_link( assert url.path == "/auth/reset-password" assert "tenantId=public" in queries assert "rid=thirdpartyemailpassword" in queries + + link = await create_reset_password_link("public", "invalidUserId") + assert isinstance(link, CreateResetPasswordLinkUnknownUserIdError) + + with raises(GeneralError) as err: + await create_reset_password_link("invalidTenantId", user_info["id"]) + assert "status code: 400" in str(err.value) From 3d487b7523ebccf4874e6e47f888a955141272f6 Mon Sep 17 00:00:00 2001 From: Mayank Thakur Date: Thu, 16 Nov 2023 16:50:33 +0530 Subject: [PATCH 4/8] test: adds test for sendResetPasswordEmail --- tests/emailpassword/test_passwordreset.py | 13 +++++- .../test_email_delivery.py | 40 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/emailpassword/test_passwordreset.py b/tests/emailpassword/test_passwordreset.py index f9a10dcd1..dddaeb249 100644 --- a/tests/emailpassword/test_passwordreset.py +++ b/tests/emailpassword/test_passwordreset.py @@ -130,6 +130,7 @@ async def test_that_generated_password_link_is_correct( reset_url = None token_info: Union[None, str] = None rid_info: Union[None, str] = None + tenant_info: Union[None, str] = None class CustomEmailService( emailpassword.EmailDeliveryInterface[emailpassword.EmailTemplateVars] @@ -139,11 +140,12 @@ async def send_email( template_vars: emailpassword.EmailTemplateVars, user_context: Dict[str, Any], ) -> None: - nonlocal reset_url, token_info, rid_info + nonlocal reset_url, token_info, rid_info, tenant_info password_reset_url_with_token = template_vars.password_reset_link reset_url = password_reset_url_with_token.split("?")[0] token_info = password_reset_url_with_token.split("?")[1].split("&")[0] rid_info = password_reset_url_with_token.split("?")[1].split("&")[1] + tenant_info = password_reset_url_with_token.split("?")[1].split("&")[2] init( supertokens_config=SupertokensConfig("http://localhost:3567"), @@ -178,6 +180,7 @@ async def send_email( assert reset_url == "http://supertokens.io/auth/reset-password" assert token_info is not None and "token=" in token_info # type: ignore pylint: disable=unsupported-membership-test assert rid_info is not None and "rid=emailpassword" in rid_info # type: ignore pylint: disable=unsupported-membership-test + assert tenant_info is not None and "tenantId=" in tenant_info # type: ignore pylint: disable=unsupported-membership-test @mark.asyncio @@ -264,6 +267,14 @@ async def send_email( token_info = ( password_reset_url_with_token.split("?")[1].split("&")[0].split("=")[1] ) + assert ( + password_reset_url_with_token.split("?")[1].split("&")[2].split("=")[1] + == "public" + ) + assert ( + password_reset_url_with_token.split("?")[1].split("&")[1].split("=")[1] + == "emailpassword" + ) init( supertokens_config=SupertokensConfig("http://localhost:3567"), diff --git a/tests/thirdpartyemailpassword/test_email_delivery.py b/tests/thirdpartyemailpassword/test_email_delivery.py index 6528cc4ff..d2d2d49b2 100644 --- a/tests/thirdpartyemailpassword/test_email_delivery.py +++ b/tests/thirdpartyemailpassword/test_email_delivery.py @@ -41,9 +41,11 @@ ) from supertokens_python.recipe.thirdpartyemailpassword.asyncio import ( create_reset_password_link, + send_reset_password_email, ) from supertokens_python.recipe.thirdpartyemailpassword.interfaces import ( CreateResetPasswordLinkUnknownUserIdError, + SendResetPasswordEmailEmailOkResult, ) from supertokens_python.recipe.emailverification.emaildelivery.services import ( SMTPService as EVSMTPService, @@ -1086,3 +1088,41 @@ async def test_create_reset_password_link( with raises(GeneralError) as err: await create_reset_password_link("invalidTenantId", user_info["id"]) assert "status code: 400" in str(err.value) + + +@mark.asyncio +async def test_send_reset_password_email( + driver_config_client: TestClient, +): + init( + supertokens_config=SupertokensConfig("http://localhost:3567"), + app_info=InputAppInfo( + app_name="SuperTokens Demo", + api_domain="http://api.supertokens.io", + website_domain="http://supertokens.io", + api_base_path="/auth", + ), + framework="fastapi", + recipe_list=[ + thirdpartyemailpassword.init(), + session.init(get_token_transfer_method=lambda _, __, ___: "cookie"), + ], + ) + start_st() + + response_1 = sign_up_request( + driver_config_client, "random@gmail.com", "validpass123" + ) + assert response_1.status_code == 200 + dict_response = json.loads(response_1.text) + user_info = dict_response["user"] + assert dict_response["status"] == "OK" + resp = await send_reset_password_email("public", user_info["id"]) + assert isinstance(resp, SendResetPasswordEmailEmailOkResult) + + link = await create_reset_password_link("public", "invalidUserId") + assert isinstance(link, CreateResetPasswordLinkUnknownUserIdError) + + with raises(GeneralError) as err: + await create_reset_password_link("invalidTenantId", user_info["id"]) + assert "status code: 400" in str(err.value) From 42fc65b8cc53fd8a406078f3cb12a4ce1d7e75e6 Mon Sep 17 00:00:00 2001 From: Mayank Thakur Date: Thu, 16 Nov 2023 17:00:48 +0530 Subject: [PATCH 5/8] test: fix test_send_reset_password_email --- tests/thirdpartyemailpassword/test_email_delivery.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/thirdpartyemailpassword/test_email_delivery.py b/tests/thirdpartyemailpassword/test_email_delivery.py index d2d2d49b2..c551cfcf1 100644 --- a/tests/thirdpartyemailpassword/test_email_delivery.py +++ b/tests/thirdpartyemailpassword/test_email_delivery.py @@ -46,6 +46,7 @@ from supertokens_python.recipe.thirdpartyemailpassword.interfaces import ( CreateResetPasswordLinkUnknownUserIdError, SendResetPasswordEmailEmailOkResult, + SendResetPasswordEmailUnknownUserIdError, ) from supertokens_python.recipe.emailverification.emaildelivery.services import ( SMTPService as EVSMTPService, @@ -1120,9 +1121,9 @@ async def test_send_reset_password_email( resp = await send_reset_password_email("public", user_info["id"]) assert isinstance(resp, SendResetPasswordEmailEmailOkResult) - link = await create_reset_password_link("public", "invalidUserId") - assert isinstance(link, CreateResetPasswordLinkUnknownUserIdError) + link = await send_reset_password_email("public", "invalidUserId") + assert isinstance(link, SendResetPasswordEmailUnknownUserIdError) with raises(GeneralError) as err: - await create_reset_password_link("invalidTenantId", user_info["id"]) + await send_reset_password_email("invalidTenantId", user_info["id"]) assert "status code: 400" in str(err.value) From b03b4fb678c563e2d0a26971a235b6905dd3e8c0 Mon Sep 17 00:00:00 2001 From: Mayank Thakur Date: Fri, 17 Nov 2023 12:27:40 +0530 Subject: [PATCH 6/8] test: fixes test,to actually test the values in the reset link --- CHANGELOG.md | 3 - setup.py | 2 +- supertokens_python/constants.py | 2 +- tests/emailpassword/test_passwordreset.py | 2 +- .../test_email_delivery.py | 65 ++++++++++++++++++- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6ac9828e..5f23e0687 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] -## [0.17.1] - 2023-11-15 -- Added test for `create_reset_password_link` in both `emailpassword` and `thirdpartyemailpassword` recipes. - ## [0.17.0] - 2023-11-14 - Fixes `create_reset_password_link` in the emailpassword recipe wherein we passed the `rid` instead of the token in the link diff --git a/setup.py b/setup.py index 397cb82ef..e129656a7 100644 --- a/setup.py +++ b/setup.py @@ -70,7 +70,7 @@ setup( name="supertokens_python", - version="0.17.1", + version="0.17.0", author="SuperTokens", license="Apache 2.0", author_email="team@supertokens.com", diff --git a/supertokens_python/constants.py b/supertokens_python/constants.py index a1d716086..2eb0fe55b 100644 --- a/supertokens_python/constants.py +++ b/supertokens_python/constants.py @@ -14,7 +14,7 @@ from __future__ import annotations SUPPORTED_CDI_VERSIONS = ["3.0"] -VERSION = "0.17.1" +VERSION = "0.17.0" TELEMETRY = "/telemetry" USER_COUNT = "/users/count" USER_DELETE = "/user/remove" diff --git a/tests/emailpassword/test_passwordreset.py b/tests/emailpassword/test_passwordreset.py index dddaeb249..c9d8aca01 100644 --- a/tests/emailpassword/test_passwordreset.py +++ b/tests/emailpassword/test_passwordreset.py @@ -180,7 +180,7 @@ async def send_email( assert reset_url == "http://supertokens.io/auth/reset-password" assert token_info is not None and "token=" in token_info # type: ignore pylint: disable=unsupported-membership-test assert rid_info is not None and "rid=emailpassword" in rid_info # type: ignore pylint: disable=unsupported-membership-test - assert tenant_info is not None and "tenantId=" in tenant_info # type: ignore pylint: disable=unsupported-membership-test + assert tenant_info is not None and "tenantId=public" in tenant_info # type: ignore pylint: disable=unsupported-membership-test @mark.asyncio diff --git a/tests/thirdpartyemailpassword/test_email_delivery.py b/tests/thirdpartyemailpassword/test_email_delivery.py index c551cfcf1..e43681523 100644 --- a/tests/thirdpartyemailpassword/test_email_delivery.py +++ b/tests/thirdpartyemailpassword/test_email_delivery.py @@ -1095,6 +1095,24 @@ async def test_create_reset_password_link( async def test_send_reset_password_email( driver_config_client: TestClient, ): + + tenant_info, token_info, rid_info, reset_url = "", "", "", "" + + class CustomEmailDeliveryService( + thirdpartyemailpassword.EmailDeliveryInterface[PasswordResetEmailTemplateVars] + ): + async def send_email( + self, + template_vars: PasswordResetEmailTemplateVars, + user_context: Dict[str, Any], + ): + nonlocal reset_url, token_info, rid_info, tenant_info + password_reset_url = template_vars.password_reset_link + reset_url = password_reset_url.split("?")[0] + token_info = password_reset_url.split("?")[1].split("&")[0] + rid_info = password_reset_url.split("?")[1].split("&")[1] + tenant_info = password_reset_url.split("?")[1].split("&")[2] + init( supertokens_config=SupertokensConfig("http://localhost:3567"), app_info=InputAppInfo( @@ -1105,7 +1123,11 @@ async def test_send_reset_password_email( ), framework="fastapi", recipe_list=[ - thirdpartyemailpassword.init(), + thirdpartyemailpassword.init( + email_delivery=thirdpartyemailpassword.EmailDeliveryConfig( + CustomEmailDeliveryService() + ) + ), session.init(get_token_transfer_method=lambda _, __, ___: "cookie"), ], ) @@ -1121,6 +1143,47 @@ async def test_send_reset_password_email( resp = await send_reset_password_email("public", user_info["id"]) assert isinstance(resp, SendResetPasswordEmailEmailOkResult) + assert reset_url == "http://supertokens.io/auth/reset-password" + assert token_info is not None and "token=" in token_info + assert rid_info is not None and "rid=thirdpartyemailpassword" in rid_info + assert tenant_info is not None and "tenantId=public" in tenant_info + + link = await send_reset_password_email("public", "invalidUserId") + assert isinstance(link, SendResetPasswordEmailUnknownUserIdError) + + with raises(GeneralError) as err: + await send_reset_password_email("invalidTenantId", user_info["id"]) + assert "status code: 400" in str(err.value) + + +@mark.asyncio +async def test_send_reset_password_email_invalid_input( + driver_config_client: TestClient, +): + + init( + supertokens_config=SupertokensConfig("http://localhost:3567"), + app_info=InputAppInfo( + app_name="SuperTokens Demo", + api_domain="http://api.supertokens.io", + website_domain="http://supertokens.io", + api_base_path="/auth", + ), + framework="fastapi", + recipe_list=[ + thirdpartyemailpassword.init(), + session.init(get_token_transfer_method=lambda _, __, ___: "cookie"), + ], + ) + start_st() + + response_1 = sign_up_request( + driver_config_client, "random@gmail.com", "validpass123" + ) + assert response_1.status_code == 200 + dict_response = json.loads(response_1.text) + user_info = dict_response["user"] + link = await send_reset_password_email("public", "invalidUserId") assert isinstance(link, SendResetPasswordEmailUnknownUserIdError) From 63626d9a6a3f3898cec40e4645b05e361c6d3d4a Mon Sep 17 00:00:00 2001 From: Mayank Thakur Date: Fri, 17 Nov 2023 12:30:57 +0530 Subject: [PATCH 7/8] test: fixes test,to actually test the values in the reset link --- tests/thirdpartyemailpassword/test_email_delivery.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/thirdpartyemailpassword/test_email_delivery.py b/tests/thirdpartyemailpassword/test_email_delivery.py index e43681523..3a34f6e3c 100644 --- a/tests/thirdpartyemailpassword/test_email_delivery.py +++ b/tests/thirdpartyemailpassword/test_email_delivery.py @@ -1148,13 +1148,6 @@ async def send_email( assert rid_info is not None and "rid=thirdpartyemailpassword" in rid_info assert tenant_info is not None and "tenantId=public" in tenant_info - link = await send_reset_password_email("public", "invalidUserId") - assert isinstance(link, SendResetPasswordEmailUnknownUserIdError) - - with raises(GeneralError) as err: - await send_reset_password_email("invalidTenantId", user_info["id"]) - assert "status code: 400" in str(err.value) - @mark.asyncio async def test_send_reset_password_email_invalid_input( From 8c4aaee6bd897f4af2796f2d8e459a88cb2fcfc1 Mon Sep 17 00:00:00 2001 From: Mayank Thakur Date: Fri, 17 Nov 2023 12:39:51 +0530 Subject: [PATCH 8/8] test: fixes test,to actually test the values in the reset link --- tests/emailpassword/test_passwordreset.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/emailpassword/test_passwordreset.py b/tests/emailpassword/test_passwordreset.py index c9d8aca01..fe8283c47 100644 --- a/tests/emailpassword/test_passwordreset.py +++ b/tests/emailpassword/test_passwordreset.py @@ -389,6 +389,7 @@ async def test_create_reset_password_link( url = urlparse(link.link) # type: ignore queries = url.query.strip("&").split("&") assert url.path == "/auth/reset-password" + assert "token=" in queries[0] assert "tenantId=public" in queries assert "rid=emailpassword" in queries