Skip to content

Commit c120521

Browse files
add sample code generator to assist with setup verification work flow
1 parent 6a04769 commit c120521

File tree

4 files changed

+99
-0
lines changed

4 files changed

+99
-0
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ dependencies {
5252
- [Generating QR codes](#generating-a-qr-code)
5353
- [Verifying one time passwords](#verifying-one-time-passwords)
5454
- [Using different time providers](#using-different-time-providers)
55+
- [Sample codes](#sample-codes)
5556
- [Recovery codes](#recovery-codes)
5657

5758

@@ -228,6 +229,20 @@ dependencies {
228229
}
229230
```
230231

232+
### Sample Codes
233+
234+
Sample codes can be used to help verify that a totp device has been setup correctly.
235+
236+
```java
237+
import dev.samstevens.totp.code.SampleCodeGenerator;
238+
...
239+
// Generate sample codes
240+
final SampleCodeGenerator sampleGenerator = new SampleCodeGenerator(
241+
new DefaultCodeGenerator(), timeProvider);
242+
List<String> sampleCodes = sampleGenerator.generateCodes(secret, 2);
243+
// codes = ["tf8i-exmo-3lcb-slkm", "boyv-yq75-z99k-r308", "w045-mq6w-mg1i-q12o", ...]
244+
```
245+
231246
### Recovery Codes
232247

233248
Recovery codes can be used to allow users to gain access to their MFA protected account without providing a TOTP, bypassing the MFA process. This is usually given as an option to the user so that in the event of losing access to the device which they have registered the MFA secret with, they are still able to log in.

totp/pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
33
<modelVersion>4.0.0</modelVersion>
4+
<build>
5+
<plugins>
6+
<plugin>
7+
<groupId>org.apache.maven.plugins</groupId>
8+
<artifactId>maven-compiler-plugin</artifactId>
9+
<configuration>
10+
<source>9</source>
11+
<target>9</target>
12+
</configuration>
13+
</plugin>
14+
</plugins>
15+
</build>
416

517
<parent>
618
<groupId>dev.samstevens.totp</groupId>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package dev.samstevens.totp.code;
2+
3+
import dev.samstevens.totp.exceptions.CodeGenerationException;
4+
import dev.samstevens.totp.time.TimeProvider;
5+
6+
public class SampleCodeGenerator {
7+
private final CodeGenerator codeGenerator;
8+
private final TimeProvider timeProvider;
9+
private int timePeriod = 30;
10+
private int allowedTimePeriodDiscrepancy = 1;
11+
12+
public SampleCodeGenerator(final CodeGenerator codeGenerator,
13+
final TimeProvider timeProvider) {
14+
this.codeGenerator = codeGenerator;
15+
this.timeProvider = timeProvider;
16+
}
17+
18+
public void setTimePeriod(int timePeriod) {
19+
this.timePeriod = timePeriod;
20+
}
21+
22+
public void setAllowedTimePeriodDiscrepancy(int allowedTimePeriodDiscrepancy) {
23+
this.allowedTimePeriodDiscrepancy = allowedTimePeriodDiscrepancy;
24+
}
25+
26+
/**
27+
* Generate sample codes based on the current time.
28+
*/
29+
public String[] generateCodes(final String secret) throws CodeGenerationException {
30+
final String[] sampleCodes = new String[allowedTimePeriodDiscrepancy + allowedTimePeriodDiscrepancy + 1];
31+
long currentBucket = Math.floorDiv(timeProvider.getTime(), timePeriod);
32+
33+
for (int x = 0, i = -allowedTimePeriodDiscrepancy; i <= allowedTimePeriodDiscrepancy; i++, x++) {
34+
sampleCodes[x] = codeGenerator.generate(secret, currentBucket + i);
35+
}
36+
return sampleCodes;
37+
}
38+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package dev.samstevens.totp.code;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
import org.junit.jupiter.api.Test;
5+
6+
import dev.samstevens.totp.exceptions.CodeGenerationException;
7+
import dev.samstevens.totp.secret.DefaultSecretGenerator;
8+
import dev.samstevens.totp.time.SystemTimeProvider;
9+
import dev.samstevens.totp.time.TimeProvider;
10+
11+
public class SampleCodeGeneratorTest {
12+
@Test
13+
public void testGenerateSampleCodes() throws CodeGenerationException {
14+
final DefaultSecretGenerator generator = new DefaultSecretGenerator();
15+
final String secret = generator.generate();
16+
17+
final TimeProvider timeProvider = new SystemTimeProvider();
18+
19+
final SampleCodeGenerator sampleGenerator = new SampleCodeGenerator(
20+
new DefaultCodeGenerator(), timeProvider);
21+
sampleGenerator.setTimePeriod(30);
22+
sampleGenerator.setAllowedTimePeriodDiscrepancy(2);
23+
24+
final DefaultCodeVerifier verifier = new DefaultCodeVerifier(new DefaultCodeGenerator(), timeProvider);
25+
verifier.setTimePeriod(30);
26+
verifier.setAllowedTimePeriodDiscrepancy(2);
27+
28+
final String[] sampleCodes = sampleGenerator.generateCodes(secret);
29+
assertEquals(5, sampleCodes.length);
30+
for (String sampleCode: sampleCodes) {
31+
assertTrue(verifier.isValidCode(secret, sampleCode));
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)