diff --git a/README.md b/README.md
index d1d8c54..e8c3693 100644
--- a/README.md
+++ b/README.md
@@ -30,23 +30,23 @@ The following features are supported:
com.github.bastiaanjansen
otp-java
- 2.0.1
+ 2.0.2
```
### 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
-
+
```
Or you can download the source from the [GitHub releases page](https://github.com/BastiaanJansen/OTP-Java/releases).
diff --git a/pom.xml b/pom.xml
index 05514bb..f4809c5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
com.github.bastiaanjansen
otp-java
- 2.0.1
+ 2.0.2
OTP-Java
A small and easy-to-use one-time password generator for Java according to RFC 4226 (HOTP) and RFC 6238 (TOTP).
diff --git a/src/main/java/com/bastiaanjansen/otp/HOTPGenerator.java b/src/main/java/com/bastiaanjansen/otp/HOTPGenerator.java
index ae8ade0..aefdc82 100644
--- a/src/main/java/com/bastiaanjansen/otp/HOTPGenerator.java
+++ b/src/main/java/com/bastiaanjansen/otp/HOTPGenerator.java
@@ -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);
}
diff --git a/src/main/java/com/bastiaanjansen/otp/helpers/URIHelper.java b/src/main/java/com/bastiaanjansen/otp/helpers/URIHelper.java
index b90acaa..4e3dc45 100644
--- a/src/main/java/com/bastiaanjansen/otp/helpers/URIHelper.java
+++ b/src/main/java/com/bastiaanjansen/otp/helpers/URIHelper.java
@@ -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
@@ -61,20 +62,20 @@ public static Map queryItems(URI uri) {
* @throws URISyntaxException when URI cannot be created
*/
public static URI createURI(String scheme, String host, String path, Map 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());
}
}
diff --git a/src/test/java/com/bastiaanjansen/otp/HOTPGeneratorTest.java b/src/test/java/com/bastiaanjansen/otp/HOTPGeneratorTest.java
index d49e29a..a293f95 100644
--- a/src/test/java/com/bastiaanjansen/otp/HOTPGeneratorTest.java
+++ b/src/test/java/com/bastiaanjansen/otp/HOTPGeneratorTest.java
@@ -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();
@@ -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"));
}
@@ -145,7 +161,8 @@ void getURIWithIssuerAndAccountWithUrlUnsafeCharacters() throws URISyntaxExcepti
HOTPGenerator generator = new HOTPGenerator.Builder(secret.getBytes()).build();
URI uri = generator.getURI(100, "mac&cheese", "ac@cou.nt");
- assertThat(uri.toString(), is("otpauth://hotp/mac&cheese:ac@cou.nt?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
diff --git a/src/test/java/com/bastiaanjansen/otp/TOTPGeneratorTest.java b/src/test/java/com/bastiaanjansen/otp/TOTPGeneratorTest.java
index c9a94c2..ae32145 100644
--- a/src/test/java/com/bastiaanjansen/otp/TOTPGeneratorTest.java
+++ b/src/test/java/com/bastiaanjansen/otp/TOTPGeneratorTest.java
@@ -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
@@ -192,7 +192,7 @@ void getURIWithIssuerAndAccountWithUrlUnsafeCharacters() throws URISyntaxExcepti
URI uri = generator.getURI("mac&cheese", "ac@cou.nt");
- 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