Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,23 @@ The following features are supported:
<dependency>
<groupId>com.github.bastiaanjansen</groupId>
<artifactId>otp-java</artifactId>
<version>2.0.1</version>
<version>2.0.2</version>
</dependency>
```

### Gradle
```gradle
implementation 'com.github.bastiaanjansen:otp-java:2.0.1'
implementation 'com.github.bastiaanjansen:otp-java:2.0.2'
```

### Scala SBT
```scala
libraryDependencies += "com.github.bastiaanjansen" % "otp-java" % "2.0.1"
libraryDependencies += "com.github.bastiaanjansen" % "otp-java" % "2.0.2"
```

### Apache Ivy
```xml
<dependency org="com.github.bastiaanjansen" name="otp-java" rev="2.0.1" />
<dependency org="com.github.bastiaanjansen" name="otp-java" rev="2.0.2" />
```

Or you can download the source from the [GitHub releases page](https://github.com/BastiaanJansen/OTP-Java/releases).
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<groupId>com.github.bastiaanjansen</groupId>
<artifactId>otp-java</artifactId>
<version>2.0.1</version>
<version>2.0.2</version>

<name>OTP-Java</name>
<description>A small and easy-to-use one-time password generator for Java according to RFC 4226 (HOTP) and RFC 6238 (TOTP).</description>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/bastiaanjansen/otp/HOTPGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public URI getURI(final String type, final String issuer, final String account,
query.put(URIHelper.SECRET, new String(secret, StandardCharsets.UTF_8));
query.put(URIHelper.ISSUER, issuer);

String path = account.isEmpty() ? issuer : String.format("%s:%s", issuer, account);
String path = account.isEmpty() ? URIHelper.encode(issuer) : String.format("%s:%s", URIHelper.encode(issuer), URIHelper.encode(account));

return URIHelper.createURI(URL_SCHEME, type, path, query);
}
Expand Down
21 changes: 11 additions & 10 deletions src/main/java/com/bastiaanjansen/otp/helpers/URIHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
* A URI utility class with helper methods
Expand Down Expand Up @@ -61,20 +62,20 @@ public static Map<String, String> queryItems(URI uri) {
* @throws URISyntaxException when URI cannot be created
*/
public static URI createURI(String scheme, String host, String path, Map<String, String> query) throws URISyntaxException {
StringBuilder uriString = new StringBuilder(String.format("%s://%s/%s", scheme, host, path));
String[] queryKeys = query.keySet().toArray(new String[0]);
String uriString = String.format("%s://%s/%s?", scheme, host, path);

String uri = query.keySet().stream()
.map(key -> String.format("%s=%s", key, encode(query.get(key))))
.collect(Collectors.joining("&", uriString, ""));

return new URI(uri);
}

public static String encode(String value) {
try {
for (int i = 0; i < queryKeys.length; i++) {
String sign = i == 0 ? "?" : "&";
String key = queryKeys[i];
uriString.append(String.format("%s%s=%s", sign, key, URLEncoder.encode(query.get(key), StandardCharsets.UTF_8.toString())));
}
return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
} catch (UnsupportedEncodingException e) {
// Highly unlikely
throw new IllegalArgumentException(e);
}

return new URI(uriString.toString());
}
}
21 changes: 19 additions & 2 deletions src/test/java/com/bastiaanjansen/otp/HOTPGeneratorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,22 @@ void getURIWithIssuer_doesNotThrow() {
});
}

@Test
void getURIWithIssuerWithSpace_doesNotThrow() {
HOTPGenerator generator = new HOTPGenerator.Builder(secret.getBytes()).build();

assertDoesNotThrow(() -> generator.getURI(10, "issuer with space"));
}

@Test
void getURIWithIssuerWithSpace_doesEscapeIssuer() throws URISyntaxException {
HOTPGenerator generator = new HOTPGenerator.Builder(secret.getBytes()).build();

String url = generator.getURI(10, "issuer with space").toString();

assertThat(url, is("otpauth://hotp/issuer+with+space?digits=6&counter=10&secret=vv3kox7uqj4kyakohmzpph3us4cjimh6f3zknb5c2oobq6v2kiyhm27q&issuer=issuer+with+space&algorithm=SHA1"));
}

@Test
void getURIWithIssuer() throws URISyntaxException {
HOTPGenerator generator = new HOTPGenerator.Builder(secret.getBytes()).build();
Expand All @@ -119,7 +135,7 @@ void getURIWithIssuerWithUrlUnsafeCharacters() throws URISyntaxException {
HOTPGenerator generator = new HOTPGenerator.Builder(secret.getBytes()).build();
URI uri = generator.getURI(10, "mac&cheese");

assertThat(uri.toString(), is("otpauth://hotp/mac&cheese?digits=6&counter=10&secret=" + secret + "&issuer=mac%26cheese&algorithm=SHA1"));
assertThat(uri.toString(), is("otpauth://hotp/mac%26cheese?digits=6&counter=10&secret=" + secret + "&issuer=mac%26cheese&algorithm=SHA1"));
}


Expand All @@ -145,7 +161,8 @@ void getURIWithIssuerAndAccountWithUrlUnsafeCharacters() throws URISyntaxExcepti
HOTPGenerator generator = new HOTPGenerator.Builder(secret.getBytes()).build();

URI uri = generator.getURI(100, "mac&cheese", "[email protected]");
assertThat(uri.toString(), is("otpauth://hotp/mac&cheese:[email protected]?digits=6&counter=100&secret=" + secret + "&issuer=mac%26cheese&algorithm=SHA1"));

assertThat(uri.toString(), is("otpauth://hotp/mac%26cheese:ac%40cou.nt?digits=6&counter=100&secret=" + secret + "&issuer=mac%26cheese&algorithm=SHA1"));
}

@Test
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/com/bastiaanjansen/otp/TOTPGeneratorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ void getURIWithIssuerWithUrlUnsafeCharacters() throws URISyntaxException {
TOTPGenerator generator = new TOTPGenerator.Builder(secret.getBytes()).build();

URI uri = generator.getURI("mac&cheese");
assertThat(uri.toString(), is("otpauth://totp/mac&cheese?period=30&digits=6&secret=" + secret + "&issuer=mac%26cheese&algorithm=SHA1"));
assertThat(uri.toString(), is("otpauth://totp/mac%26cheese?period=30&digits=6&secret=" + secret + "&issuer=mac%26cheese&algorithm=SHA1"));
}

@Test
Expand All @@ -192,7 +192,7 @@ void getURIWithIssuerAndAccountWithUrlUnsafeCharacters() throws URISyntaxExcepti


URI uri = generator.getURI("mac&cheese", "[email protected]");
assertThat(uri.toString(), is("otpauth://totp/mac&cheese:ac@cou.nt?period=30&digits=6&secret=" + secret + "&issuer=mac%26cheese&algorithm=SHA1"));
assertThat(uri.toString(), is("otpauth://totp/mac%26cheese:ac%40cou.nt?period=30&digits=6&secret=" + secret + "&issuer=mac%26cheese&algorithm=SHA1"));
}

@Test
Expand Down