Skip to content

Commit 540d9ef

Browse files
authored
fix: email verification fix with user id mapping (#877)
* fix: email verification for userid mapping fix * fix: version update
1 parent b9d2044 commit 540d9ef

File tree

11 files changed

+367
-42
lines changed

11 files changed

+367
-42
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
66
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [7.0.11] - 2023-11-10
9+
10+
- Fixes email verification behaviour with user id mapping
11+
812
## [7.0.10] - 2023-11-03
913

1014
- Collects requests stats per app

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ compileTestJava { options.encoding = "UTF-8" }
1919
// }
2020
//}
2121

22-
version = "7.0.10"
22+
version = "7.0.11"
2323

2424

2525
repositories {

src/main/java/io/supertokens/inmemorydb/Start.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,11 @@ public boolean isEmailVerified(AppIdentifier appIdentifier, String userId, Strin
10581058
}
10591059
}
10601060

1061+
@Override
1062+
public void updateIsEmailVerifiedToExternalUserId(AppIdentifier appIdentifier, String supertokensUserId, String externalUserId) throws StorageQueryException {
1063+
EmailVerificationQueries.updateIsEmailVerifiedToExternalUserId(this, appIdentifier, supertokensUserId, externalUserId);
1064+
}
1065+
10611066
@Override
10621067
public void deleteExpiredPasswordResetTokens() throws StorageQueryException {
10631068
try {

src/main/java/io/supertokens/inmemorydb/queries/EmailVerificationQueries.java

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import io.supertokens.pluginInterface.exceptions.StorageTransactionLogicException;
2727
import io.supertokens.pluginInterface.multitenancy.AppIdentifier;
2828
import io.supertokens.pluginInterface.multitenancy.TenantIdentifier;
29+
import io.supertokens.pluginInterface.sqlStorage.TransactionConnection;
2930

3031
import java.sql.Connection;
3132
import java.sql.ResultSet;
@@ -225,6 +226,41 @@ public static boolean isEmailVerified(Start start, AppIdentifier appIdentifier,
225226
}, result -> result.next());
226227
}
227228

229+
public static void updateIsEmailVerifiedToExternalUserId(Start start, AppIdentifier appIdentifier, String supertokensUserId, String externalUserId)
230+
throws StorageQueryException {
231+
try {
232+
start.startTransaction((TransactionConnection con) -> {
233+
Connection sqlCon = (Connection) con.getConnection();
234+
try {
235+
{
236+
String QUERY = "UPDATE " + getConfig(start).getEmailVerificationTable()
237+
+ " SET user_id = ? WHERE app_id = ? AND user_id = ?";
238+
update(sqlCon, QUERY, pst -> {
239+
pst.setString(1, externalUserId);
240+
pst.setString(2, appIdentifier.getAppId());
241+
pst.setString(3, supertokensUserId);
242+
});
243+
}
244+
{
245+
String QUERY = "UPDATE " + getConfig(start).getEmailVerificationTokensTable()
246+
+ " SET user_id = ? WHERE app_id = ? AND user_id = ?";
247+
update(sqlCon, QUERY, pst -> {
248+
pst.setString(1, externalUserId);
249+
pst.setString(2, appIdentifier.getAppId());
250+
pst.setString(3, supertokensUserId);
251+
});
252+
}
253+
} catch (SQLException e) {
254+
throw new StorageTransactionLogicException(e);
255+
}
256+
257+
return null;
258+
});
259+
} catch (StorageTransactionLogicException e) {
260+
throw new StorageQueryException(e.actualException);
261+
}
262+
}
263+
228264
public static class UserIdAndEmail {
229265
public String userId;
230266
public String email;
@@ -433,13 +469,28 @@ public static void revokeAllTokens(Start start, TenantIdentifier tenantIdentifie
433469

434470
public static boolean isUserIdBeingUsedForEmailVerification(Start start, AppIdentifier appIdentifier, String userId)
435471
throws SQLException, StorageQueryException {
436-
String QUERY = "SELECT * FROM " + getConfig(start).getEmailVerificationTokensTable()
437-
+ " WHERE app_id = ? AND user_id = ?";
472+
{
473+
String QUERY = "SELECT * FROM " + getConfig(start).getEmailVerificationTokensTable()
474+
+ " WHERE app_id = ? AND user_id = ?";
438475

439-
return execute(start, QUERY, pst -> {
440-
pst.setString(1, appIdentifier.getAppId());
441-
pst.setString(2, userId);
442-
}, ResultSet::next);
476+
boolean isUsed = execute(start, QUERY, pst -> {
477+
pst.setString(1, appIdentifier.getAppId());
478+
pst.setString(2, userId);
479+
}, ResultSet::next);
480+
if (isUsed) {
481+
return true;
482+
}
483+
}
484+
485+
{
486+
String QUERY = "SELECT * FROM " + getConfig(start).getEmailVerificationTable()
487+
+ " WHERE app_id = ? AND user_id = ?";
488+
489+
return execute(start, QUERY, pst -> {
490+
pst.setString(1, appIdentifier.getAppId());
491+
pst.setString(2, userId);
492+
}, ResultSet::next);
493+
}
443494
}
444495

445496
private static class EmailVerificationTokenInfoRowMapper

src/main/java/io/supertokens/passwordless/Passwordless.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,23 @@ public static ConsumeCodeResponse consumeCode(Main main,
256256
}
257257
}
258258

259+
@TestOnly
260+
public static ConsumeCodeResponse consumeCode(Main main,
261+
String deviceId, String deviceIdHashFromUser,
262+
String userInputCode, String linkCode, boolean setEmailVerified)
263+
throws RestartFlowException, ExpiredUserInputCodeException,
264+
IncorrectUserInputCodeException, DeviceIdHashMismatchException, StorageTransactionLogicException,
265+
StorageQueryException, NoSuchAlgorithmException, InvalidKeyException, IOException, Base64EncodingException {
266+
try {
267+
Storage storage = StorageLayer.getStorage(main);
268+
return consumeCode(
269+
new TenantIdentifierWithStorage(null, null, null, storage),
270+
main, deviceId, deviceIdHashFromUser, userInputCode, linkCode, setEmailVerified);
271+
} catch (TenantOrAppNotFoundException | BadPermissionException e) {
272+
throw new IllegalStateException(e);
273+
}
274+
}
275+
259276
@TestOnly
260277
public static ConsumeCodeResponse consumeCode(TenantIdentifierWithStorage tenantIdentifierWithStorage, Main main,
261278
String deviceId, String deviceIdHashFromUser,

src/main/java/io/supertokens/storageLayer/StorageLayer.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,8 @@ public static TenantIdentifierWithStorageAndUserIdMapping getTenantIdentifierWit
415415
}
416416
if (userIdType != UserIdType.SUPERTOKENS) {
417417
try {
418-
io.supertokens.useridmapping.UserIdMapping.assertThatUserIdIsNotBeingUsedInNonAuthRecipes(
419-
tenantIdentifierWithStorage.toAppIdentifierWithStorage(), userId);
418+
io.supertokens.useridmapping.UserIdMapping.findNonAuthStoragesWhereUserIdIsUsedOrAssertIfUsed(
419+
tenantIdentifierWithStorage.toAppIdentifierWithStorage(), userId, true);
420420
} catch (ServletException e) {
421421
// this means that the userId is being used for a non auth recipe.
422422
return new TenantIdentifierWithStorageAndUserIdMapping(
@@ -457,8 +457,8 @@ public static AppIdentifierWithStorageAndUserIdMapping getAppIdentifierWithStora
457457
if (userIdType != UserIdType.SUPERTOKENS) {
458458
AppIdentifierWithStorage appIdentifierWithStorage = appIdentifier.withStorage(priorityStorage);
459459
try {
460-
io.supertokens.useridmapping.UserIdMapping.assertThatUserIdIsNotBeingUsedInNonAuthRecipes(
461-
appIdentifierWithStorage, userId);
460+
io.supertokens.useridmapping.UserIdMapping.findNonAuthStoragesWhereUserIdIsUsedOrAssertIfUsed(
461+
appIdentifierWithStorage, userId, true);
462462
} catch (ServletException e) {
463463
// this means that the userId is being used for a non auth recipe.
464464
return new AppIdentifierWithStorageAndUserIdMapping(appIdentifierWithStorage, null);
@@ -488,8 +488,8 @@ public static AppIdentifierWithStorageAndUserIdMapping getAppIdentifierWithStora
488488
if (userIdType != UserIdType.SUPERTOKENS) {
489489
AppIdentifierWithStorage appIdentifierWithStorage = appIdentifier.withStorage(storage);
490490
try {
491-
io.supertokens.useridmapping.UserIdMapping.assertThatUserIdIsNotBeingUsedInNonAuthRecipes(
492-
appIdentifierWithStorage, userId);
491+
io.supertokens.useridmapping.UserIdMapping.findNonAuthStoragesWhereUserIdIsUsedOrAssertIfUsed(
492+
appIdentifierWithStorage, userId, true);
493493
} catch (ServletException e) {
494494
// this means that the userId is being used for a non auth recipe.
495495
return new AppIdentifierWithStorageAndUserIdMapping(appIdentifierWithStorage, null);

src/main/java/io/supertokens/thirdparty/ThirdParty.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,19 @@ public static SignInUpResponse signInUp(Main main, String thirdPartyId, String t
126126
}
127127
}
128128

129+
@TestOnly
130+
public static SignInUpResponse signInUp(Main main, String thirdPartyId, String thirdPartyUserId, String email, boolean isEmailVerified)
131+
throws StorageQueryException, EmailChangeNotAllowedException {
132+
try {
133+
Storage storage = StorageLayer.getStorage(main);
134+
return signInUp(
135+
new TenantIdentifierWithStorage(null, null, null, storage), main,
136+
thirdPartyId, thirdPartyUserId, email, isEmailVerified);
137+
} catch (TenantOrAppNotFoundException | BadPermissionException e) {
138+
throw new IllegalStateException(e);
139+
}
140+
}
141+
129142
@TestOnly
130143
public static SignInUpResponse signInUp(TenantIdentifierWithStorage tenantIdentifierWithStorage, Main main,
131144
String thirdPartyId,

0 commit comments

Comments
 (0)