diff --git a/CHANGELOG.md b/CHANGELOG.md index 562876542..349b0142d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,9 @@ 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). -## [unreleased] +## [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) ## [7.0.0] - 2023-09-19 diff --git a/build.gradle b/build.gradle index a2c2d397a..19d47cbc5 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ compileTestJava { options.encoding = "UTF-8" } // } //} -version = "7.0.0" +version = "7.0.1" repositories { diff --git a/src/main/java/io/supertokens/passwordless/Passwordless.java b/src/main/java/io/supertokens/passwordless/Passwordless.java index 798d0b6ae..0e3b2e454 100644 --- a/src/main/java/io/supertokens/passwordless/Passwordless.java +++ b/src/main/java/io/supertokens/passwordless/Passwordless.java @@ -316,7 +316,7 @@ public static ConsumeCodeResponse consumeCode(TenantIdentifierWithStorage tenant linkCodeHash = parsedDeviceId.getLinkCode(linkCodeSalt, userInputCode).getHash(); } - if (!deviceIdHash.encode().equals(deviceIdHashFromUser)) { + if (!deviceIdHash.encode().equals(deviceIdHashFromUser.replaceAll("=", ""))) { throw new DeviceIdHashMismatchException(); } diff --git a/src/main/java/io/supertokens/passwordless/PasswordlessDeviceIdHash.java b/src/main/java/io/supertokens/passwordless/PasswordlessDeviceIdHash.java index 8716ea39d..d5fff5282 100644 --- a/src/main/java/io/supertokens/passwordless/PasswordlessDeviceIdHash.java +++ b/src/main/java/io/supertokens/passwordless/PasswordlessDeviceIdHash.java @@ -8,7 +8,7 @@ public class PasswordlessDeviceIdHash { public PasswordlessDeviceIdHash(byte[] bytes) { // We never do anything further with the bytes, so we can just encode, store and reuse it. // If we choose to do storage based on bytes this can change. - this.encodedValue = Base64.getUrlEncoder().encodeToString(bytes); + this.encodedValue = Base64.getUrlEncoder().encodeToString(bytes).replaceAll("=", ""); } public PasswordlessDeviceIdHash(String encodedValue) { diff --git a/src/main/java/io/supertokens/passwordless/PasswordlessLinkCode.java b/src/main/java/io/supertokens/passwordless/PasswordlessLinkCode.java index e00c54fca..e987d9234 100644 --- a/src/main/java/io/supertokens/passwordless/PasswordlessLinkCode.java +++ b/src/main/java/io/supertokens/passwordless/PasswordlessLinkCode.java @@ -23,7 +23,7 @@ public static PasswordlessLinkCode decodeString(String linkCode) throws Base64En } public String encode() { - return Base64.getUrlEncoder().encodeToString(bytes); + return Base64.getUrlEncoder().encodeToString(bytes).replaceAll("=", ""); } public PasswordlessLinkCodeHash getHash() throws NoSuchAlgorithmException { diff --git a/src/test/java/io/supertokens/test/passwordless/PasswordlessConsumeCodeTest.java b/src/test/java/io/supertokens/test/passwordless/PasswordlessConsumeCodeTest.java index 884799871..db3d56272 100644 --- a/src/test/java/io/supertokens/test/passwordless/PasswordlessConsumeCodeTest.java +++ b/src/test/java/io/supertokens/test/passwordless/PasswordlessConsumeCodeTest.java @@ -96,6 +96,81 @@ public void testConsumeLinkCode() throws Exception { assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); } + /** + * success without existing user - link code with equal signs removed + * + * @throws Exception + */ + @Test + public void testConsumeLinkCodeWithoutEqualSigns() 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; + } + + PasswordlessStorage storage = (PasswordlessStorage) StorageLayer.getStorage(process.getProcess()); + + Passwordless.CreateCodeResponse createCodeResponse = Passwordless.createCode(process.getProcess(), EMAIL, null, + null, null); + assertNotNull(createCodeResponse); + + assert(!createCodeResponse.deviceIdHash.contains("=")); + assert(!createCodeResponse.linkCode.contains("=")); + + long consumeStart = System.currentTimeMillis(); + Passwordless.ConsumeCodeResponse consumeCodeResponse = Passwordless.consumeCode(process.getProcess(), null, + createCodeResponse.deviceIdHash, null, createCodeResponse.linkCode); + + assertNotNull(consumeCodeResponse); + checkUserWithConsumeResponse(storage, consumeCodeResponse, EMAIL, null, consumeStart); + + PasswordlessDevice[] devices = storage.getDevicesByEmail(new TenantIdentifier(null, null, null), EMAIL); + assertEquals(0, devices.length); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + + /** + * success without existing user - link code with equal signs (padding) + * + * @throws Exception + */ + @Test + public void testConsumeLinkCodeWithEqualSigns() 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; + } + + PasswordlessStorage storage = (PasswordlessStorage) StorageLayer.getStorage(process.getProcess()); + + Passwordless.CreateCodeResponse createCodeResponse = Passwordless.createCode(process.getProcess(), EMAIL, null, + null, null); + assertNotNull(createCodeResponse); + + long consumeStart = System.currentTimeMillis(); + Passwordless.ConsumeCodeResponse consumeCodeResponse = Passwordless.consumeCode(process.getProcess(), null, + createCodeResponse.deviceIdHash + "=", null, createCodeResponse.linkCode + "="); + + assertNotNull(consumeCodeResponse); + checkUserWithConsumeResponse(storage, consumeCodeResponse, EMAIL, null, consumeStart); + + PasswordlessDevice[] devices = storage.getDevicesByEmail(new TenantIdentifier(null, null, null), EMAIL); + assertEquals(0, devices.length); + + process.kill(); + assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED)); + } + /** * Success without existing user - input code *