Skip to content

Commit 457d880

Browse files
authored
feat: linkcodes and preauthsessionids should not use padding (#825)
* feat: linkcodes and preauthsessionids should not use padding * test: check that new linkCodes and preAuthSessionIds do not contain = * chore: update changelog * chore: bump patch version
1 parent 295aefb commit 457d880

File tree

6 files changed

+82
-5
lines changed

6 files changed

+82
-5
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ 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-
## [unreleased]
8+
## [7.0.1] - 2023-10-04
9+
10+
- Remove padding from link codes and pre-auth session ids in passwordless, but keep support for old format that included padding (`=` signs)
911

1012
## [7.0.0] - 2023-09-19
1113

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.0"
22+
version = "7.0.1"
2323

2424

2525
repositories {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ public static ConsumeCodeResponse consumeCode(TenantIdentifierWithStorage tenant
316316
linkCodeHash = parsedDeviceId.getLinkCode(linkCodeSalt, userInputCode).getHash();
317317
}
318318

319-
if (!deviceIdHash.encode().equals(deviceIdHashFromUser)) {
319+
if (!deviceIdHash.encode().equals(deviceIdHashFromUser.replaceAll("=", ""))) {
320320
throw new DeviceIdHashMismatchException();
321321
}
322322

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public class PasswordlessDeviceIdHash {
88
public PasswordlessDeviceIdHash(byte[] bytes) {
99
// We never do anything further with the bytes, so we can just encode, store and reuse it.
1010
// If we choose to do storage based on bytes this can change.
11-
this.encodedValue = Base64.getUrlEncoder().encodeToString(bytes);
11+
this.encodedValue = Base64.getUrlEncoder().encodeToString(bytes).replaceAll("=", "");
1212
}
1313

1414
public PasswordlessDeviceIdHash(String encodedValue) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public static PasswordlessLinkCode decodeString(String linkCode) throws Base64En
2323
}
2424

2525
public String encode() {
26-
return Base64.getUrlEncoder().encodeToString(bytes);
26+
return Base64.getUrlEncoder().encodeToString(bytes).replaceAll("=", "");
2727
}
2828

2929
public PasswordlessLinkCodeHash getHash() throws NoSuchAlgorithmException {

src/test/java/io/supertokens/test/passwordless/PasswordlessConsumeCodeTest.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,81 @@ public void testConsumeLinkCode() throws Exception {
9696
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
9797
}
9898

99+
/**
100+
* success without existing user - link code with equal signs removed
101+
*
102+
* @throws Exception
103+
*/
104+
@Test
105+
public void testConsumeLinkCodeWithoutEqualSigns() throws Exception {
106+
String[] args = {"../"};
107+
108+
TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
109+
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
110+
111+
if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) {
112+
return;
113+
}
114+
115+
PasswordlessStorage storage = (PasswordlessStorage) StorageLayer.getStorage(process.getProcess());
116+
117+
Passwordless.CreateCodeResponse createCodeResponse = Passwordless.createCode(process.getProcess(), EMAIL, null,
118+
null, null);
119+
assertNotNull(createCodeResponse);
120+
121+
assert(!createCodeResponse.deviceIdHash.contains("="));
122+
assert(!createCodeResponse.linkCode.contains("="));
123+
124+
long consumeStart = System.currentTimeMillis();
125+
Passwordless.ConsumeCodeResponse consumeCodeResponse = Passwordless.consumeCode(process.getProcess(), null,
126+
createCodeResponse.deviceIdHash, null, createCodeResponse.linkCode);
127+
128+
assertNotNull(consumeCodeResponse);
129+
checkUserWithConsumeResponse(storage, consumeCodeResponse, EMAIL, null, consumeStart);
130+
131+
PasswordlessDevice[] devices = storage.getDevicesByEmail(new TenantIdentifier(null, null, null), EMAIL);
132+
assertEquals(0, devices.length);
133+
134+
process.kill();
135+
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
136+
}
137+
138+
/**
139+
* success without existing user - link code with equal signs (padding)
140+
*
141+
* @throws Exception
142+
*/
143+
@Test
144+
public void testConsumeLinkCodeWithEqualSigns() throws Exception {
145+
String[] args = {"../"};
146+
147+
TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
148+
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));
149+
150+
if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) {
151+
return;
152+
}
153+
154+
PasswordlessStorage storage = (PasswordlessStorage) StorageLayer.getStorage(process.getProcess());
155+
156+
Passwordless.CreateCodeResponse createCodeResponse = Passwordless.createCode(process.getProcess(), EMAIL, null,
157+
null, null);
158+
assertNotNull(createCodeResponse);
159+
160+
long consumeStart = System.currentTimeMillis();
161+
Passwordless.ConsumeCodeResponse consumeCodeResponse = Passwordless.consumeCode(process.getProcess(), null,
162+
createCodeResponse.deviceIdHash + "=", null, createCodeResponse.linkCode + "=");
163+
164+
assertNotNull(consumeCodeResponse);
165+
checkUserWithConsumeResponse(storage, consumeCodeResponse, EMAIL, null, consumeStart);
166+
167+
PasswordlessDevice[] devices = storage.getDevicesByEmail(new TenantIdentifier(null, null, null), EMAIL);
168+
assertEquals(0, devices.length);
169+
170+
process.kill();
171+
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
172+
}
173+
99174
/**
100175
* Success without existing user - input code
101176
*

0 commit comments

Comments
 (0)