Skip to content

Commit

Permalink
fix: simplifying email verification token creation (#1016)
Browse files Browse the repository at this point in the history
* #334 - simplify email verification token creation

* Update tests.yml

updating github action `checkout` to version 4

* reverting workflow modifications

* #334 - simplify email verification token creation tests

* chore: bumping version number, writing changelog
  • Loading branch information
tamassoltesz authored Jul 24, 2024
1 parent 2f99bf9 commit 43a5a68
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

- Account linking now properly checks if the login methods of the primary user can be shared with the tenants of the
recipe user we are trying to link
- Simplifying email verification token creation

## [9.1.0] - 2024-05-24

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,22 +82,11 @@ public static String generateEmailVerificationToken(TenantIdentifier tenantIdent
while (true) {

// we first generate a email verification token
byte[] random = new byte[64];
byte[] salt = new byte[64];
byte[] random = new byte[48];

new SecureRandom().nextBytes(random);
new SecureRandom().nextBytes(salt);

int iterations = 1000;
String token = Utils
.toHex(Utils.pbkdf2(Utils.bytesToString(random).toCharArray(), salt, iterations, 64 * 6));

// we make it URL safe:
token = Utils.convertToBase64(token);
token = token.replace("=", "");
token = token.replace("/", "");
token = token.replace("+", "");

String token = Utils.convertToBase64Url(Utils.bytesToString(random));
String hashedToken = getHashedToken(token);

try {
Expand Down Expand Up @@ -234,6 +223,42 @@ public static void unverifyEmail(AppIdentifier appIdentifier, Storage storage, S
.unverifyEmail(appIdentifier, userId, email);
}

@TestOnly
public static String generateEmailVerificationTokenTheOldWay(Main main, String userId, String email)
throws NoSuchAlgorithmException, InvalidKeySpecException, StorageQueryException,
TenantOrAppNotFoundException {
while(true) {
// we first generate a email verification token
byte[] random = new byte[64];
byte[] salt = new byte[64];

new SecureRandom().nextBytes(random);
new SecureRandom().nextBytes(salt);

int iterations = 1000;
String token = io.supertokens.utils.Utils
.toHex(io.supertokens.utils.Utils.pbkdf2(io.supertokens.utils.Utils.bytesToString(random).toCharArray(), salt, iterations, 64 * 6));

// we make it URL safe:
token = io.supertokens.utils.Utils.convertToBase64(token);
token = token.replace("=", "");
token = token.replace("/", "");
token = token.replace("+", "");

String hashedToken = EmailVerification.getHashedToken(token);

try {
StorageUtils.getEmailVerificationStorage(StorageLayer.getStorage(main))
.addEmailVerificationToken(new TenantIdentifier(null, null, null),
new EmailVerificationTokenInfo(userId, hashedToken,
System.currentTimeMillis() +
EmailVerification.getEmailVerificationTokenLifetimeForTests(main), email));
return token;
} catch (DuplicateEmailVerificationTokenException ignored) {
}
}
}

private static String getHashedToken(String token) throws NoSuchAlgorithmException {
return Utils.hashSHA256(token);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ public void testFormatOfEmailVerificationToken() throws Exception {
String verifyToken = EmailVerification.generateEmailVerificationToken(process.getProcess(),
user.getSupertokensUserId(),
user.loginMethods[0].email);
assertEquals(verifyToken.length(), 128);
assertEquals(128, verifyToken.length());
assertFalse(verifyToken.contains("+"));
assertFalse(verifyToken.contains("="));
assertFalse(verifyToken.contains("/"));
Expand Down Expand Up @@ -316,6 +316,36 @@ public void verifyEmail() throws Exception {
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}

@Test
public void verifyEmailWithOldTokenAfterTokenGenerationChanged() throws Exception {
String[] args = {"../"};

TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) {
return;
}

AuthRecipeUserInfo user = EmailPassword.signUp(process.getProcess(), "[email protected]", "password");

assert (!EmailVerification.isEmailVerified(process.getProcess(), user.getSupertokensUserId(),
user.loginMethods[0].email));

String token = EmailVerification.generateEmailVerificationTokenTheOldWay(process.getProcess(),
user.getSupertokensUserId(), user.loginMethods[0].email);

assert (token != null);

EmailVerification.verifyEmail(process.getProcess(), token);

assert (EmailVerification.isEmailVerified(process.getProcess(), user.getSupertokensUserId(),
user.loginMethods[0].email));

process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}

// Verify the email successfully, then unverify and check that its unverified
@Test
public void testVerifyingEmailAndThenUnverify() throws Exception {
Expand Down

0 comments on commit 43a5a68

Please sign in to comment.