diff --git a/CHANGELOG.md b/CHANGELOG.md index 349b0142d..f6571ffad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [7.0.2] = 2023-10-05 + +- Fixes `500` error for passwordless login in certain cases - https://github.com/supertokens/supertokens-core/issues/828 + ## [7.0.1] - 2023-10-04 - Remove padding from link codes and pre-auth session ids in passwordless, but keep support for old format that included padding (`=` signs) diff --git a/build.gradle b/build.gradle index 19d47cbc5..d09ceec96 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ compileTestJava { options.encoding = "UTF-8" } // } //} -version = "7.0.1" +version = "7.0.2" repositories { diff --git a/src/main/java/io/supertokens/passwordless/Passwordless.java b/src/main/java/io/supertokens/passwordless/Passwordless.java index 0e3b2e454..bff70d3cf 100644 --- a/src/main/java/io/supertokens/passwordless/Passwordless.java +++ b/src/main/java/io/supertokens/passwordless/Passwordless.java @@ -399,7 +399,7 @@ public static ConsumeCodeResponse consumeCode(TenantIdentifierWithStorage tenant consumedDevice.email); for (AuthRecipeUserInfo currUser : users) { for (LoginMethod currLM : currUser.loginMethods) { - if (currLM.recipeId == RECIPE_ID.PASSWORDLESS && currLM.email.equals(consumedDevice.email) && currLM.tenantIds.contains(tenantIdentifierWithStorage.getTenantId())) { + if (currLM.recipeId == RECIPE_ID.PASSWORDLESS && currLM.email != null && currLM.email.equals(consumedDevice.email) && currLM.tenantIds.contains(tenantIdentifierWithStorage.getTenantId())) { user = currUser; loginMethod = currLM; break; @@ -412,7 +412,7 @@ public static ConsumeCodeResponse consumeCode(TenantIdentifierWithStorage tenant for (AuthRecipeUserInfo currUser : users) { for (LoginMethod currLM : currUser.loginMethods) { if (currLM.recipeId == RECIPE_ID.PASSWORDLESS && - currLM.phoneNumber.equals(consumedDevice.phoneNumber) && currLM.tenantIds.contains(tenantIdentifierWithStorage.getTenantId())) { + currLM.phoneNumber != null && currLM.phoneNumber.equals(consumedDevice.phoneNumber) && currLM.tenantIds.contains(tenantIdentifierWithStorage.getTenantId())) { user = currUser; loginMethod = currLM; break; diff --git a/src/test/java/io/supertokens/test/accountlinking/EmailPasswordTests.java b/src/test/java/io/supertokens/test/accountlinking/EmailPasswordTests.java index 191ffc33e..094fc4bf8 100644 --- a/src/test/java/io/supertokens/test/accountlinking/EmailPasswordTests.java +++ b/src/test/java/io/supertokens/test/accountlinking/EmailPasswordTests.java @@ -21,6 +21,7 @@ import io.supertokens.emailpassword.EmailPassword; import io.supertokens.featureflag.EE_FEATURES; import io.supertokens.featureflag.FeatureFlagTestContent; +import io.supertokens.passwordless.Passwordless; import io.supertokens.pluginInterface.STORAGE_TYPE; import io.supertokens.pluginInterface.authRecipe.AuthRecipeUserInfo; import io.supertokens.pluginInterface.emailpassword.exceptions.UnknownUserIdException; @@ -83,4 +84,70 @@ public void testUpdatePasswordWithDifferentValidUserId() throws Exception { process.kill(); assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); } + + @Test + public void testPasswordlessUserWithSameEmail() throws Exception { + String[] args = {"../"}; + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); + FeatureFlagTestContent.getInstance(process.getProcess()) + .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ + EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); + process.startProcess(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) { + return; + } + + AuthRecipeUserInfo user1 = EmailPassword.signUp(process.getProcess(), "test@example.com", "password"); + Passwordless.CreateCodeResponse code = Passwordless.createCode(process.getProcess(), null, "+919876543210", + null, null); + AuthRecipeUserInfo user2 = Passwordless.consumeCode(process.getProcess(), code.deviceId, code.deviceIdHash, code.userInputCode, null).user; + + AuthRecipe.createPrimaryUser(process.getProcess(), user1.getSupertokensUserId()); + AuthRecipe.linkAccounts(process.getProcess(), user2.getSupertokensUserId(), user1.getSupertokensUserId()); + + Passwordless.CreateCodeResponse code1 = Passwordless.createCode(process.getProcess(), "test@example.com", null, + null, null); + AuthRecipeUserInfo user3 = Passwordless.consumeCode(process.getProcess(), code1.deviceId, code1.deviceIdHash, code1.userInputCode, null).user; + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + @Test + public void testPasswordlessUsersLinked() throws Exception { + String[] args = {"../"}; + TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false); + FeatureFlagTestContent.getInstance(process.getProcess()) + .setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{ + EE_FEATURES.ACCOUNT_LINKING, EE_FEATURES.MULTI_TENANCY}); + process.startProcess(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED)); + + if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) { + return; + } + + Passwordless.CreateCodeResponse code1 = Passwordless.createCode(process.getProcess(), "test@example.com", null, + null, null); + AuthRecipeUserInfo user1 = Passwordless.consumeCode(process.getProcess(), code1.deviceId, code1.deviceIdHash, code1.userInputCode, null).user; + + Thread.sleep(50); + + Passwordless.CreateCodeResponse code2 = Passwordless.createCode(process.getProcess(), null, "+919876543210", + null, null); + AuthRecipeUserInfo user2 = Passwordless.consumeCode(process.getProcess(), code2.deviceId, code2.deviceIdHash, code2.userInputCode, null).user; + + AuthRecipe.createPrimaryUser(process.getProcess(), user1.getSupertokensUserId()); + AuthRecipe.linkAccounts(process.getProcess(), user2.getSupertokensUserId(), user1.getSupertokensUserId()); + + Passwordless.CreateCodeResponse code3 = Passwordless.createCode(process.getProcess(), null, "+919876543210", + null, null); + AuthRecipeUserInfo user3 = Passwordless.consumeCode(process.getProcess(), code3.deviceId, code3.deviceIdHash, code3.userInputCode, null).user; + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + + } }