Skip to content

Commit

Permalink
add sample code generator to assist with setup verification work flow
Browse files Browse the repository at this point in the history
  • Loading branch information
jason-adnuntius committed Jan 14, 2022
1 parent 6a04769 commit f144280
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ dependencies {
- [Generating QR codes](#generating-a-qr-code)
- [Verifying one time passwords](#verifying-one-time-passwords)
- [Using different time providers](#using-different-time-providers)
- [Sample codes](#sample-codes)
- [Recovery codes](#recovery-codes)


Expand Down Expand Up @@ -228,6 +229,20 @@ dependencies {
}
```

### Sample Codes

Sample codes can be used to help verify that a totp device has been setup correctly.

```java
import dev.samstevens.totp.code.SampleCodeGenerator;
...
// Generate sample codes
final SampleCodeGenerator sampleGenerator = new SampleCodeGenerator(
new DefaultCodeGenerator(), timeProvider);
List<String> sampleCodes = sampleGenerator.generateCodes(secret, 2);
// codes = ["tf8i-exmo-3lcb-slkm", "boyv-yq75-z99k-r308", "w045-mq6w-mg1i-q12o", ...]
```

### Recovery Codes

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.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package dev.samstevens.totp.code;

import dev.samstevens.totp.exceptions.CodeGenerationException;
import dev.samstevens.totp.time.TimeProvider;

public class SampleCodeGenerator {
private final CodeGenerator codeGenerator;
private final TimeProvider timeProvider;
private int timePeriod = 30;
private int allowedTimePeriodDiscrepancy = 1;

public SampleCodeGenerator(final CodeGenerator codeGenerator,
final TimeProvider timeProvider) {
this.codeGenerator = codeGenerator;
this.timeProvider = timeProvider;
}

public void setTimePeriod(int timePeriod) {
this.timePeriod = timePeriod;
}

public void setAllowedTimePeriodDiscrepancy(int allowedTimePeriodDiscrepancy) {
this.allowedTimePeriodDiscrepancy = allowedTimePeriodDiscrepancy;
}

/**
* Generate sample codes based on the current time.
*/
public String[] generateCodes(final String secret) throws CodeGenerationException {
final String[] sampleCodes = new String[allowedTimePeriodDiscrepancy + allowedTimePeriodDiscrepancy + 1];
long currentBucket = Math.floorDiv(timeProvider.getTime(), timePeriod);

for (int x = 0, i = -allowedTimePeriodDiscrepancy; i <= allowedTimePeriodDiscrepancy; i++, x++) {
sampleCodes[x] = codeGenerator.generate(secret, currentBucket + i);
}
return sampleCodes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package dev.samstevens.totp.code;

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

import dev.samstevens.totp.exceptions.CodeGenerationException;
import dev.samstevens.totp.secret.DefaultSecretGenerator;
import dev.samstevens.totp.time.SystemTimeProvider;
import dev.samstevens.totp.time.TimeProvider;

public class SampleCodeGeneratorTest {
@Test
public void testGenerateSampleCodes() throws CodeGenerationException {
final DefaultSecretGenerator generator = new DefaultSecretGenerator();
final String secret = generator.generate();

final TimeProvider timeProvider = new SystemTimeProvider();

final SampleCodeGenerator sampleGenerator = new SampleCodeGenerator(
new DefaultCodeGenerator(), timeProvider);
sampleGenerator.setTimePeriod(30);
sampleGenerator.setAllowedTimePeriodDiscrepancy(2);

final DefaultCodeVerifier verifier = new DefaultCodeVerifier(new DefaultCodeGenerator(), timeProvider);
verifier.setTimePeriod(30);
verifier.setAllowedTimePeriodDiscrepancy(2);

final String[] sampleCodes = sampleGenerator.generateCodes(secret);
assertEquals(5, sampleCodes.length);
for (String sampleCode: sampleCodes) {
assertTrue(verifier.isValidCode(secret, sampleCode));
}
}
}

0 comments on commit f144280

Please sign in to comment.