From 71c6fa88a0de68d6bdab113436b4f0f4978ee11e Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Wed, 1 Nov 2023 12:38:19 +0530 Subject: [PATCH] fix: email verified in login methods (#82) --- CHANGELOG.md | 4 + build.gradle | 2 +- .../queries/EmailVerificationQueries.java | 86 ++++++++++++++----- .../mysql/queries/UserIdMappingQueries.java | 36 +++++++- 4 files changed, 105 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b75f691..4c6e681 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [5.0.2] - 2023-11-01 + +- Fixes `verified` in `loginMethods` for users with userId mapping + ## [5.0.1] - 2023-10-12 - Fixes user info from primary user id query diff --git a/build.gradle b/build.gradle index f0727de..5b5aeb2 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java-library' } -version = "5.0.1" +version = "5.0.2" repositories { mavenCentral() diff --git a/src/main/java/io/supertokens/storage/mysql/queries/EmailVerificationQueries.java b/src/main/java/io/supertokens/storage/mysql/queries/EmailVerificationQueries.java index d439222..e66d014 100644 --- a/src/main/java/io/supertokens/storage/mysql/queries/EmailVerificationQueries.java +++ b/src/main/java/io/supertokens/storage/mysql/queries/EmailVerificationQueries.java @@ -238,26 +238,50 @@ public static List isEmailVerified_transaction(Start start, Connection s return new ArrayList<>(); } List emails = new ArrayList<>(); - List userIds = new ArrayList<>(); - Map userIdToEmailMap = new HashMap<>(); + List supertokensUserIds = new ArrayList<>(); for (UserIdAndEmail ue : userIdAndEmail) { emails.add(ue.email); - userIds.add(ue.userId); + supertokensUserIds.add(ue.userId); } + + // We have external user id stored in the email verification table, so we need to fetch the mapped userids for + // calculating the verified emails + + HashMap supertokensUserIdToExternalUserIdMap = UserIdMappingQueries.getUserIdMappingWithUserIds_Transaction(start, + sqlCon, supertokensUserIds); + HashMap externalUserIdToSupertokensUserIdMap = new HashMap<>(); + + List supertokensOrExternalUserIdsToQuery = new ArrayList<>(); + for (String userId : supertokensUserIds) { + if (supertokensUserIdToExternalUserIdMap.containsKey(userId)) { + supertokensOrExternalUserIdsToQuery.add(supertokensUserIdToExternalUserIdMap.get(userId)); + externalUserIdToSupertokensUserIdMap.put(supertokensUserIdToExternalUserIdMap.get(userId), userId); + } else { + supertokensOrExternalUserIdsToQuery.add(userId); + externalUserIdToSupertokensUserIdMap.put(userId, userId); + } + } + + Map supertokensOrExternalUserIdToEmailMap = new HashMap<>(); for (UserIdAndEmail ue : userIdAndEmail) { - if (userIdToEmailMap.containsKey(ue.userId)) { + String supertokensOrExternalUserId = ue.userId; + if (supertokensUserIdToExternalUserIdMap.containsKey(supertokensOrExternalUserId)) { + supertokensOrExternalUserId = supertokensUserIdToExternalUserIdMap.get(supertokensOrExternalUserId); + } + if (supertokensOrExternalUserIdToEmailMap.containsKey(supertokensOrExternalUserId)) { throw new RuntimeException("Found a bug!"); } - userIdToEmailMap.put(ue.userId, ue.email); + supertokensOrExternalUserIdToEmailMap.put(supertokensOrExternalUserId, ue.email); } + String QUERY = "SELECT * FROM " + getConfig(start).getEmailVerificationTable() - + " WHERE app_id = ? AND user_id IN (" + Utils.generateCommaSeperatedQuestionMarks(userIds.size()) + + + " WHERE app_id = ? AND user_id IN (" + Utils.generateCommaSeperatedQuestionMarks(supertokensOrExternalUserIdsToQuery.size()) + ") AND email IN (" + Utils.generateCommaSeperatedQuestionMarks(emails.size()) + ")"; return execute(sqlCon, QUERY, pst -> { pst.setString(1, appIdentifier.getAppId()); int index = 2; - for (String userId : userIds) { + for (String userId : supertokensOrExternalUserIdsToQuery) { pst.setString(index++, userId); } for (String email : emails) { @@ -266,10 +290,10 @@ public static List isEmailVerified_transaction(Start start, Connection s }, result -> { List res = new ArrayList<>(); while (result.next()) { - String userId = result.getString("user_id"); + String supertokensOrExternalUserId = result.getString("user_id"); String email = result.getString("email"); - if (Objects.equals(userIdToEmailMap.get(userId), email)) { - res.add(userId); + if (Objects.equals(supertokensOrExternalUserIdToEmailMap.get(supertokensOrExternalUserId), email)) { + res.add(externalUserIdToSupertokensUserIdMap.get(supertokensOrExternalUserId)); } } return res; @@ -283,26 +307,46 @@ public static List isEmailVerified(Start start, AppIdentifier appIdentif return new ArrayList<>(); } List emails = new ArrayList<>(); - List userIds = new ArrayList<>(); - Map userIdToEmailMap = new HashMap<>(); + List supertokensUserIds = new ArrayList<>(); + for (UserIdAndEmail ue : userIdAndEmail) { emails.add(ue.email); - userIds.add(ue.userId); + supertokensUserIds.add(ue.userId); + } + // We have external user id stored in the email verification table, so we need to fetch the mapped userids for + // calculating the verified emails + HashMap supertokensUserIdToExternalUserIdMap = UserIdMappingQueries.getUserIdMappingWithUserIds(start, + supertokensUserIds); + HashMap externalUserIdToSupertokensUserIdMap = new HashMap<>(); + List supertokensOrExternalUserIdsToQuery = new ArrayList<>(); + for (String userId : supertokensUserIds) { + if (supertokensUserIdToExternalUserIdMap.containsKey(userId)) { + supertokensOrExternalUserIdsToQuery.add(supertokensUserIdToExternalUserIdMap.get(userId)); + externalUserIdToSupertokensUserIdMap.put(supertokensUserIdToExternalUserIdMap.get(userId), userId); + } else { + supertokensOrExternalUserIdsToQuery.add(userId); + externalUserIdToSupertokensUserIdMap.put(userId, userId); + } } + + Map supertokensOrExternalUserIdToEmailMap = new HashMap<>(); for (UserIdAndEmail ue : userIdAndEmail) { - if (userIdToEmailMap.containsKey(ue.userId)) { + String supertokensOrExternalUserId = ue.userId; + if (supertokensUserIdToExternalUserIdMap.containsKey(supertokensOrExternalUserId)) { + supertokensOrExternalUserId = supertokensUserIdToExternalUserIdMap.get(supertokensOrExternalUserId); + } + if (supertokensOrExternalUserIdToEmailMap.containsKey(supertokensOrExternalUserId)) { throw new RuntimeException("Found a bug!"); } - userIdToEmailMap.put(ue.userId, ue.email); + supertokensOrExternalUserIdToEmailMap.put(supertokensOrExternalUserId, ue.email); } String QUERY = "SELECT * FROM " + getConfig(start).getEmailVerificationTable() - + " WHERE app_id = ? AND user_id IN (" + Utils.generateCommaSeperatedQuestionMarks(userIds.size()) + + + " WHERE app_id = ? AND user_id IN (" + Utils.generateCommaSeperatedQuestionMarks(supertokensOrExternalUserIdsToQuery.size()) + ") AND email IN (" + Utils.generateCommaSeperatedQuestionMarks(emails.size()) + ")"; - return execute(start, QUERY, pst -> { pst.setString(1, appIdentifier.getAppId()); int index = 2; - for (String userId : userIds) { + for (String userId : supertokensOrExternalUserIdsToQuery) { pst.setString(index++, userId); } for (String email : emails) { @@ -311,10 +355,10 @@ public static List isEmailVerified(Start start, AppIdentifier appIdentif }, result -> { List res = new ArrayList<>(); while (result.next()) { - String userId = result.getString("user_id"); + String supertokensOrExternalUserId = result.getString("user_id"); String email = result.getString("email"); - if (Objects.equals(userIdToEmailMap.get(userId), email)) { - res.add(userId); + if (Objects.equals(supertokensOrExternalUserIdToEmailMap.get(supertokensOrExternalUserId), email)) { + res.add(externalUserIdToSupertokensUserIdMap.get(supertokensOrExternalUserId)); } } return res; diff --git a/src/main/java/io/supertokens/storage/mysql/queries/UserIdMappingQueries.java b/src/main/java/io/supertokens/storage/mysql/queries/UserIdMappingQueries.java index 4f6e80d..973c030 100644 --- a/src/main/java/io/supertokens/storage/mysql/queries/UserIdMappingQueries.java +++ b/src/main/java/io/supertokens/storage/mysql/queries/UserIdMappingQueries.java @@ -29,6 +29,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import static io.supertokens.storage.mysql.QueryExecutorTemplate.execute; import static io.supertokens.storage.mysql.QueryExecutorTemplate.update; @@ -116,7 +117,7 @@ public static UserIdMapping[] getUserIdMappingWithEitherSuperTokensUserIdOrExter } - public static HashMap getUserIdMappingWithUserIds(Start start, ArrayList userIds) + public static HashMap getUserIdMappingWithUserIds(Start start, List userIds) throws SQLException, StorageQueryException { if (userIds.size() == 0) { @@ -149,6 +150,39 @@ public static HashMap getUserIdMappingWithUserIds(Start start, A }); } + public static HashMap getUserIdMappingWithUserIds_Transaction(Start start, Connection sqlCon, List userIds) + throws SQLException, StorageQueryException { + + if (userIds.size() == 0) { + return new HashMap<>(); + } + + // No need to filter based on tenantId because the id list is already filtered for a tenant + StringBuilder QUERY = new StringBuilder( + "SELECT * FROM " + Config.getConfig(start).getUserIdMappingTable() + " WHERE supertokens_user_id IN ("); + for (int i = 0; i < userIds.size(); i++) { + QUERY.append("?"); + if (i != userIds.size() - 1) { + // not the last element + QUERY.append(","); + } + } + QUERY.append(")"); + return execute(sqlCon, QUERY.toString(), pst -> { + for (int i = 0; i < userIds.size(); i++) { + // i+1 cause this starts with 1 and not 0 + pst.setString(i + 1, userIds.get(i)); + } + }, result -> { + HashMap userIdMappings = new HashMap<>(); + while (result.next()) { + UserIdMapping temp = UserIdMappingRowMapper.getInstance().mapOrThrow(result); + userIdMappings.put(temp.superTokensUserId, temp.externalUserId); + } + return userIdMappings; + }); + } + public static boolean deleteUserIdMappingWithSuperTokensUserId(Start start, AppIdentifier appIdentifier, String userId) throws SQLException, StorageQueryException { String QUERY = "DELETE FROM " + Config.getConfig(start).getUserIdMappingTable()