diff --git a/.travis.yml b/.travis.yml
index b0df96c..eefe331 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,21 +11,9 @@ env:
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
-before_install:
- - nvm i node
-install:
- - npm install github:GoogleChromeLabs/web-push-testing-service -g
-before_script:
- - "export DISPLAY=:99.0"
- - "sh -e /etc/init.d/xvfb start || echo \"Unable to start virtual display.\""
- - sleep 3
script:
- - web-push-testing-service start wpts
- ./gradlew clean check
- - web-push-testing-service stop wpts
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
- - ~/.selenium-assistant
- - node_modules
diff --git a/README.md b/README.md
index b9e31cd..746878b 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ A Web Push library for Java 8. Supports payloads and VAPID.
For Gradle, add the following dependency to `build.gradle`:
```groovy
-compile group: 'nl.martijndwars', name: 'web-push', version: '5.1.1'
+compile group: 'nl.martijndwars', name: 'web-push', version: '5.1.2'
```
For Maven, add the following dependency to `pom.xml`:
@@ -19,7 +19,7 @@ For Maven, add the following dependency to `pom.xml`:
- * Note: Once upgrading to Java 8+, replace by native Base64 encoder. - *
- */ -public class Base64Encoder { - - public static byte[] decode(String base64Encoded) { - return Base64.decodeBase64(base64Encoded); - } - - public static String encodeWithoutPadding(byte[] bytes) { - return unpad(Base64.encodeBase64String(bytes)); - } - - public static String encodeUrl(byte[] bytes) { - return pad(Base64.encodeBase64URLSafeString(bytes)); - } - - public static String encodeUrlWithoutPadding(byte[] bytes) { - return Base64.encodeBase64URLSafeString(bytes); - } - - private static String pad(String base64Encoded) { - int m = base64Encoded.length() % 4; - if (m == 2) { - return base64Encoded + "=="; - } else if (m == 3) { - return base64Encoded + "="; - } else { - return base64Encoded; - } - } - - private static String unpad(String base64Encoded) { - if (base64Encoded.endsWith("==")) { - return base64Encoded.substring(0, base64Encoded.length() - 2); - } else if (base64Encoded.endsWith("=")) { - return base64Encoded.substring(0, base64Encoded.length() - 1); - } else { - return base64Encoded; - } - } -} diff --git a/src/main/java/nl/martijndwars/webpush/HttpEce.java b/src/main/java/nl/martijndwars/webpush/HttpEce.java index 4aacdc0..b9e9436 100644 --- a/src/main/java/nl/martijndwars/webpush/HttpEce.java +++ b/src/main/java/nl/martijndwars/webpush/HttpEce.java @@ -12,6 +12,7 @@ import java.nio.ByteBuffer; import java.security.*; import java.util.Arrays; +import java.util.Base64; import java.util.HashMap; import java.util.Map; @@ -437,7 +438,7 @@ private static byte[] intToBytes(int number) { */ private static byte[] log(String info, byte[] array) { if ("1".equals(System.getenv("ECE_KEYLOG"))) { - System.out.println(info + " [" + array.length + "]: " + Base64Encoder.encodeUrlWithoutPadding(array)); + System.out.println(info + " [" + array.length + "]: " + Base64.getUrlEncoder().withoutPadding().encodeToString(array)); } return array; diff --git a/src/main/java/nl/martijndwars/webpush/Notification.java b/src/main/java/nl/martijndwars/webpush/Notification.java index 50ab0c9..6fdc493 100644 --- a/src/main/java/nl/martijndwars/webpush/Notification.java +++ b/src/main/java/nl/martijndwars/webpush/Notification.java @@ -8,6 +8,7 @@ import java.security.NoSuchProviderException; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; +import java.util.Base64; import static java.nio.charset.StandardCharsets.UTF_8; @@ -71,7 +72,7 @@ public Notification(String endpoint, PublicKey userPublicKey, byte[] userAuth, b } public Notification(String endpoint, String userPublicKey, String userAuth, byte[] payload, int ttl) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException { - this(endpoint, Utils.loadPublicKey(userPublicKey), Base64Encoder.decode(userAuth), payload, ttl); + this(endpoint, Utils.loadPublicKey(userPublicKey), Base64.getUrlDecoder().decode(userAuth), payload, ttl); } public Notification(String endpoint, PublicKey userPublicKey, byte[] userAuth, byte[] payload) { @@ -79,15 +80,15 @@ public Notification(String endpoint, PublicKey userPublicKey, byte[] userAuth, b } public Notification(String endpoint, String userPublicKey, String userAuth, byte[] payload) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException { - this(endpoint, Utils.loadPublicKey(userPublicKey), Base64Encoder.decode(userAuth), payload); + this(endpoint, Utils.loadPublicKey(userPublicKey), Base64.getUrlDecoder().decode(userAuth), payload); } public Notification(String endpoint, String userPublicKey, String userAuth, String payload) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException { - this(endpoint, Utils.loadPublicKey(userPublicKey), Base64Encoder.decode(userAuth), payload.getBytes(UTF_8)); + this(endpoint, Utils.loadPublicKey(userPublicKey), Base64.getUrlDecoder().decode(userAuth), payload.getBytes(UTF_8)); } public Notification(String endpoint, String userPublicKey, String userAuth, String payload, Urgency urgency) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException { - this(endpoint, Utils.loadPublicKey(userPublicKey), Base64Encoder.decode(userAuth), payload.getBytes(UTF_8)); + this(endpoint, Utils.loadPublicKey(userPublicKey), Base64.getUrlDecoder().decode(userAuth), payload.getBytes(UTF_8)); this.urgency = urgency; } @@ -200,7 +201,7 @@ public NotificationBuilder userPublicKey(byte[] publicKey) throws NoSuchAlgorith } public NotificationBuilder userAuth(String userAuth) { - this.userAuth = Base64Encoder.decode(userAuth); + this.userAuth = Base64.getUrlDecoder().decode(userAuth); return this; } diff --git a/src/main/java/nl/martijndwars/webpush/PushService.java b/src/main/java/nl/martijndwars/webpush/PushService.java index cd117dc..e15647b 100644 --- a/src/main/java/nl/martijndwars/webpush/PushService.java +++ b/src/main/java/nl/martijndwars/webpush/PushService.java @@ -65,7 +65,7 @@ public HttpResponse send(Notification notification, Encoding encoding) throws Ge } public HttpResponse send(Notification notification) throws GeneralSecurityException, IOException, JoseException, ExecutionException, InterruptedException { - return send(notification, Encoding.AESGCM); + return send(notification, Encoding.AES128GCM); } /** diff --git a/src/main/java/nl/martijndwars/webpush/Utils.java b/src/main/java/nl/martijndwars/webpush/Utils.java index aa625e5..d135f38 100644 --- a/src/main/java/nl/martijndwars/webpush/Utils.java +++ b/src/main/java/nl/martijndwars/webpush/Utils.java @@ -15,6 +15,7 @@ import java.nio.ByteBuffer; import java.security.*; import java.security.spec.InvalidKeySpecException; +import java.util.Base64; import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME; @@ -45,7 +46,7 @@ public static byte[] encode(ECPrivateKey privateKey) { * @param encodedPublicKey */ public static PublicKey loadPublicKey(String encodedPublicKey) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException { - byte[] decodedPublicKey = Base64Encoder.decode(encodedPublicKey); + byte[] decodedPublicKey = Base64.getUrlDecoder().decode(encodedPublicKey); return loadPublicKey(decodedPublicKey); } @@ -74,7 +75,7 @@ public static PublicKey loadPublicKey(byte[] decodedPublicKey) throws NoSuchProv * @throws InvalidKeySpecException */ public static PrivateKey loadPrivateKey(String encodedPrivateKey) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException { - byte[] decodedPrivateKey = Base64Encoder.decode(encodedPrivateKey); + byte[] decodedPrivateKey = Base64.getUrlDecoder().decode(encodedPrivateKey); return loadPrivateKey(decodedPrivateKey); } diff --git a/src/main/java/nl/martijndwars/webpush/cli/handlers/GenerateKeyHandler.java b/src/main/java/nl/martijndwars/webpush/cli/handlers/GenerateKeyHandler.java index 68bfd99..1747adf 100644 --- a/src/main/java/nl/martijndwars/webpush/cli/handlers/GenerateKeyHandler.java +++ b/src/main/java/nl/martijndwars/webpush/cli/handlers/GenerateKeyHandler.java @@ -1,6 +1,5 @@ package nl.martijndwars.webpush.cli.handlers; -import nl.martijndwars.webpush.Base64Encoder; import nl.martijndwars.webpush.Utils; import nl.martijndwars.webpush.cli.commands.GenerateKeyCommand; import org.bouncycastle.jce.ECNamedCurveTable; @@ -15,6 +14,7 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.security.*; +import java.util.Base64; import static nl.martijndwars.webpush.Utils.ALGORITHM; import static nl.martijndwars.webpush.Utils.CURVE; @@ -42,10 +42,10 @@ public void run() throws InvalidAlgorithmParameterException, NoSuchAlgorithmExce } System.out.println("PublicKey:"); - System.out.println(Base64Encoder.encodeUrl(encodedPublicKey)); + System.out.println(Base64.getUrlEncoder().withoutPadding().encodeToString(encodedPublicKey)); System.out.println("PrivateKey:"); - System.out.println(Base64Encoder.encodeUrl(encodedPrivateKey)); + System.out.println(Base64.getUrlEncoder().withoutPadding().encodeToString(encodedPrivateKey)); } /** diff --git a/src/test/java/nl/martijndwars/webpush/Base64EncoderTest.java b/src/test/java/nl/martijndwars/webpush/Base64EncoderTest.java deleted file mode 100644 index 962e405..0000000 --- a/src/test/java/nl/martijndwars/webpush/Base64EncoderTest.java +++ /dev/null @@ -1,128 +0,0 @@ -package nl.martijndwars.webpush; - -import org.junit.jupiter.api.Test; - -import static com.google.common.io.BaseEncoding.base64; -import static com.google.common.io.BaseEncoding.base64Url; -import static java.nio.charset.StandardCharsets.UTF_8; -import static nl.martijndwars.webpush.Base64Encoder.*; -import static org.junit.jupiter.api.Assertions.assertEquals; - -class Base64EncoderTest { - - @Test - void decodeTest() { - // first compare with previous guava implementation, make sure non-breaking changes - assertEquals(new String(base64().decode("")), new String(decode(""))); - assertEquals(new String(base64().decode("dw")), new String(decode("dw"))); - assertEquals(new String(base64().decode("dw==")), new String(decode("dw=="))); - assertEquals(new String(base64().decode("d2U")), new String(decode("d2U"))); - assertEquals(new String(base64().decode("d2Vi")), new String(decode("d2Vi"))); - assertEquals(new String(base64().decode("d2ViLQ")), new String(decode("d2ViLQ"))); - assertEquals(new String(base64().decode("d2ViLQ==")), new String(decode("d2ViLQ=="))); - assertEquals(new String(base64().decode("d2ViLXA")), new String(decode("d2ViLXA"))); - assertEquals(new String(base64().decode("d2ViLXA=")), new String(decode("d2ViLXA="))); - assertEquals(new String(base64().decode("d2ViLXB1")), new String(decode("d2ViLXB1"))); - assertEquals(new String(base64().decode("d2ViLXB1cw")), new String(decode("d2ViLXB1cw"))); - assertEquals(new String(base64().decode("d2ViLXB1cw==")), new String(decode("d2ViLXB1cw=="))); - assertEquals(new String(base64().decode("d2ViLXB1c2g")), new String(decode("d2ViLXB1c2g"))); - assertEquals(new String(base64().decode("d2ViLXB1c2g=")), new String(decode("d2ViLXB1c2g="))); - assertEquals(new String(base64().decode("d2ViLXB1c2g/")), new String(decode("d2ViLXB1c2g/"))); - assertEquals(new String(base64Url().decode("d2ViLXB1c2g_")), new String(decode("d2ViLXB1c2g_"))); - - assertEquals("", new String(decode(""))); - assertEquals("w", new String(decode("dw"))); - assertEquals("w", new String(decode("dw=="))); - assertEquals("we", new String(decode("d2U"))); - assertEquals("web", new String(decode("d2Vi"))); - assertEquals("web-", new String(decode("d2ViLQ"))); - assertEquals("web-", new String(decode("d2ViLQ=="))); - assertEquals("web-p", new String(decode("d2ViLXA"))); - assertEquals("web-p", new String(decode("d2ViLXA="))); - assertEquals("web-pu", new String(decode("d2ViLXB1"))); - assertEquals("web-pus", new String(decode("d2ViLXB1cw"))); - assertEquals("web-pus", new String(decode("d2ViLXB1cw=="))); - assertEquals("web-push", new String(decode("d2ViLXB1c2g"))); - assertEquals("web-push", new String(decode("d2ViLXB1c2g="))); - assertEquals("web-push?", new String(decode("d2ViLXB1c2g/"))); - assertEquals("web-push?", new String(decode("d2ViLXB1c2g_"))); - } - - @Test - void encodeWithoutPaddingTest() { - // first verify non breaking changes after removing guava as compile dependency - assertEquals(base64().omitPadding().encode("".getBytes()), encodeWithoutPadding("".getBytes(UTF_8))); - assertEquals(base64().omitPadding().encode("w".getBytes()), encodeWithoutPadding("w".getBytes(UTF_8))); - assertEquals(base64().omitPadding().encode("we".getBytes()), encodeWithoutPadding("we".getBytes(UTF_8))); - assertEquals(base64().omitPadding().encode("web".getBytes()), encodeWithoutPadding("web".getBytes(UTF_8))); - assertEquals(base64().omitPadding().encode("web-".getBytes()), encodeWithoutPadding("web-".getBytes(UTF_8))); - assertEquals(base64().omitPadding().encode("web-p".getBytes()), encodeWithoutPadding("web-p".getBytes(UTF_8))); - assertEquals(base64().omitPadding().encode("web-pu".getBytes()), encodeWithoutPadding("web-pu".getBytes(UTF_8))); - assertEquals(base64().omitPadding().encode("web-pus".getBytes()), encodeWithoutPadding("web-pus".getBytes(UTF_8))); - assertEquals(base64().omitPadding().encode("web-push".getBytes()), encodeWithoutPadding("web-push".getBytes(UTF_8))); - assertEquals(base64().omitPadding().encode("web-push?".getBytes()), encodeWithoutPadding("web-push?".getBytes(UTF_8))); - - assertEquals("", encodeWithoutPadding("".getBytes(UTF_8))); - assertEquals("dw", encodeWithoutPadding("w".getBytes(UTF_8))); - assertEquals("d2U", encodeWithoutPadding("we".getBytes(UTF_8))); - assertEquals("d2Vi", encodeWithoutPadding("web".getBytes(UTF_8))); - assertEquals("d2ViLQ", encodeWithoutPadding("web-".getBytes(UTF_8))); - assertEquals("d2ViLXA", encodeWithoutPadding("web-p".getBytes(UTF_8))); - assertEquals("d2ViLXB1", encodeWithoutPadding("web-pu".getBytes(UTF_8))); - assertEquals("d2ViLXB1cw", encodeWithoutPadding("web-pus".getBytes(UTF_8))); - assertEquals("d2ViLXB1c2g", encodeWithoutPadding("web-push".getBytes(UTF_8))); - assertEquals("d2ViLXB1c2g/", encodeWithoutPadding("web-push?".getBytes(UTF_8))); - } - - @Test - void encodeUrlTest() { - // first verify non breaking changes after removing guava as compile dependency - assertEquals(base64Url().encode("".getBytes()), encodeUrl("".getBytes(UTF_8))); - assertEquals(base64Url().encode("w".getBytes()), encodeUrl("w".getBytes(UTF_8))); - assertEquals(base64Url().encode("we".getBytes()), encodeUrl("we".getBytes(UTF_8))); - assertEquals(base64Url().encode("web".getBytes()), encodeUrl("web".getBytes(UTF_8))); - assertEquals(base64Url().encode("web-".getBytes()), encodeUrl("web-".getBytes(UTF_8))); - assertEquals(base64Url().encode("web-p".getBytes()), encodeUrl("web-p".getBytes(UTF_8))); - assertEquals(base64Url().encode("web-pu".getBytes()), encodeUrl("web-pu".getBytes(UTF_8))); - assertEquals(base64Url().encode("web-pus".getBytes()), encodeUrl("web-pus".getBytes(UTF_8))); - assertEquals(base64Url().encode("web-push".getBytes()), encodeUrl("web-push".getBytes(UTF_8))); - assertEquals(base64Url().encode("web-push?".getBytes()), encodeUrl("web-push?".getBytes(UTF_8))); - - assertEquals("", encodeUrl("".getBytes(UTF_8))); - assertEquals("dw==", encodeUrl("w".getBytes(UTF_8))); - assertEquals("d2U=", encodeUrl("we".getBytes(UTF_8))); - assertEquals("d2Vi", encodeUrl("web".getBytes(UTF_8))); - assertEquals("d2ViLQ==", encodeUrl("web-".getBytes(UTF_8))); - assertEquals("d2ViLXA=", encodeUrl("web-p".getBytes(UTF_8))); - assertEquals("d2ViLXB1", encodeUrl("web-pu".getBytes(UTF_8))); - assertEquals("d2ViLXB1cw==", encodeUrl("web-pus".getBytes(UTF_8))); - assertEquals("d2ViLXB1c2g=", encodeUrl("web-push".getBytes(UTF_8))); - assertEquals("d2ViLXB1c2g_", encodeUrl("web-push?".getBytes(UTF_8))); - } - - @Test - void encodeUrlWithoutPaddingTest() { - // first verify non breaking changes after removing guava as compile dependency - assertEquals(base64Url().omitPadding().encode("".getBytes()), encodeUrlWithoutPadding("".getBytes(UTF_8))); - assertEquals(base64Url().omitPadding().encode("w".getBytes()), encodeUrlWithoutPadding("w".getBytes(UTF_8))); - assertEquals(base64Url().omitPadding().encode("we".getBytes()), encodeUrlWithoutPadding("we".getBytes(UTF_8))); - assertEquals(base64Url().omitPadding().encode("web".getBytes()), encodeUrlWithoutPadding("web".getBytes(UTF_8))); - assertEquals(base64Url().omitPadding().encode("web-".getBytes()), encodeUrlWithoutPadding("web-".getBytes(UTF_8))); - assertEquals(base64Url().omitPadding().encode("web-p".getBytes()), encodeUrlWithoutPadding("web-p".getBytes(UTF_8))); - assertEquals(base64Url().omitPadding().encode("web-pu".getBytes()), encodeUrlWithoutPadding("web-pu".getBytes(UTF_8))); - assertEquals(base64Url().omitPadding().encode("web-pus".getBytes()), encodeUrlWithoutPadding("web-pus".getBytes(UTF_8))); - assertEquals(base64Url().omitPadding().encode("web-push".getBytes()), encodeUrlWithoutPadding("web-push".getBytes(UTF_8))); - assertEquals(base64Url().omitPadding().encode("web-push?".getBytes()), encodeUrlWithoutPadding("web-push?".getBytes(UTF_8))); - - assertEquals("", encodeUrlWithoutPadding("".getBytes(UTF_8))); - assertEquals("dw", encodeUrlWithoutPadding("w".getBytes(UTF_8))); - assertEquals("d2U", encodeUrlWithoutPadding("we".getBytes(UTF_8))); - assertEquals("d2Vi", encodeUrlWithoutPadding("web".getBytes(UTF_8))); - assertEquals("d2ViLQ", encodeUrlWithoutPadding("web-".getBytes(UTF_8))); - assertEquals("d2ViLXA", encodeUrlWithoutPadding("web-p".getBytes(UTF_8))); - assertEquals("d2ViLXB1", encodeUrlWithoutPadding("web-pu".getBytes(UTF_8))); - assertEquals("d2ViLXB1cw", encodeUrlWithoutPadding("web-pus".getBytes(UTF_8))); - assertEquals("d2ViLXB1c2g", encodeUrlWithoutPadding("web-push".getBytes(UTF_8))); - assertEquals("d2ViLXB1c2g_", encodeUrlWithoutPadding("web-push?".getBytes(UTF_8))); - } -} \ No newline at end of file diff --git a/src/test/java/nl/martijndwars/webpush/HttpEceTest.java b/src/test/java/nl/martijndwars/webpush/HttpEceTest.java index fadc408..c3f6884 100644 --- a/src/test/java/nl/martijndwars/webpush/HttpEceTest.java +++ b/src/test/java/nl/martijndwars/webpush/HttpEceTest.java @@ -7,9 +7,9 @@ import org.junit.jupiter.api.Test; import java.security.*; +import java.util.Base64; import java.util.HashMap; -import static nl.martijndwars.webpush.Base64Encoder.decode; import static nl.martijndwars.webpush.Encoding.AES128GCM; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -19,6 +19,10 @@ public static void addSecurityProvider() { Security.addProvider(new BouncyCastleProvider()); } + private byte[] decode(String s) { + return Base64.getUrlDecoder().decode(s); + } + @Test public void testZeroSaltAndKey() throws GeneralSecurityException { HttpEce httpEce = new HttpEce(); diff --git a/src/test/java/nl/martijndwars/webpush/selenium/SeleniumTests.java b/src/test/java/nl/martijndwars/webpush/selenium/SeleniumTests.java index de1353e..1054486 100644 --- a/src/test/java/nl/martijndwars/webpush/selenium/SeleniumTests.java +++ b/src/test/java/nl/martijndwars/webpush/selenium/SeleniumTests.java @@ -1,6 +1,5 @@ package nl.martijndwars.webpush.selenium; -import nl.martijndwars.webpush.Base64Encoder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.DynamicTest; @@ -8,6 +7,7 @@ import java.io.IOException; import java.security.Security; +import java.util.Base64; import java.util.stream.Stream; import static org.junit.jupiter.api.DynamicTest.dynamicTest; @@ -58,8 +58,8 @@ public Stream