Skip to content

Commit

Permalink
Dropped commons-codec as a dependency.
Browse files Browse the repository at this point in the history
  • Loading branch information
jchambers committed Apr 11, 2018
1 parent 4ea1831 commit 104fe56
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 34 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ If you don't use Maven (or something else that understands Maven dependencies, l

- [netty 4.1.23](http://netty.io/)
- [netty-tcnative-2.0.8.Final](http://netty.io/wiki/forked-tomcat-native.html)
- [Apache Commons Codec 1.10](https://commons.apache.org/proper/commons-codec/)
- [gson 2.6](https://github.com/google/gson)
- [slf4j 1.7](http://www.slf4j.org/) (and possibly an SLF4J binding, as described in the [logging](#logging) section below)
- [fast-uuid 0.1](https://github.com/jchambers/fast-uuid)
Expand Down
5 changes: 0 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,6 @@
<artifactId>gson</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down
4 changes: 0 additions & 4 deletions pushy/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down
22 changes: 21 additions & 1 deletion pushy/src/main/java/com/turo/pushy/apns/auth/ApnsKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@

package com.turo.pushy.apns.auth;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.base64.Base64;

import java.nio.charset.StandardCharsets;
import java.security.interfaces.ECKey;
import java.security.spec.ECParameterSpec;
import java.util.Objects;
Expand All @@ -37,7 +42,7 @@
*
* @since 0.10
*/
public abstract class ApnsKey implements ECKey {
abstract class ApnsKey implements ECKey {

private final String teamId;
private final String keyId;
Expand Down Expand Up @@ -96,4 +101,19 @@ protected ECKey getKey() {
public ECParameterSpec getParams() {
return this.key.getParams();
}

protected static byte[] decodeBase64EncodedString(final String base64EncodedString) {
final ByteBuf base64EncodedByteBuf =
Unpooled.wrappedBuffer(base64EncodedString.getBytes(StandardCharsets.US_ASCII));

final ByteBuf decodedByteBuf = Base64.decode(base64EncodedByteBuf);
final byte[] decodedBytes = new byte[decodedByteBuf.readableBytes()];

decodedByteBuf.readBytes(decodedBytes);

base64EncodedByteBuf.release();
decodedByteBuf.release();

return decodedBytes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@

package com.turo.pushy.apns.auth;

import org.apache.commons.codec.binary.Base64;

import java.io.*;
import java.math.BigInteger;
import java.security.InvalidKeyException;
Expand Down Expand Up @@ -155,7 +153,7 @@ public static ApnsSigningKey loadFromInputStream(final InputStream inputStream,
base64EncodedPrivateKey = privateKeyBuilder.toString();
}

final byte[] keyBytes = Base64.decodeBase64(base64EncodedPrivateKey);
final byte[] keyBytes = decodeBase64EncodedString(base64EncodedPrivateKey);

final PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
final KeyFactory keyFactory = KeyFactory.getInstance("EC");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
package com.turo.pushy.apns.auth;

import com.turo.pushy.apns.ApnsClient;
import org.apache.commons.codec.binary.Base64;

import java.io.*;
import java.security.InvalidKeyException;
Expand Down Expand Up @@ -160,7 +159,7 @@ public static ApnsVerificationKey loadFromInputStream(final InputStream inputStr
base64EncodedPublicKey = publicKeyBuilder.toString();
}

final byte[] keyBytes = Base64.decodeBase64(base64EncodedPublicKey);
final byte[] keyBytes = decodeBase64EncodedString(base64EncodedPublicKey);

final X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
final KeyFactory keyFactory = KeyFactory.getInstance("EC");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import com.turo.pushy.apns.util.DateAsTimeSinceEpochTypeAdapter;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.base64.Base64;
import io.netty.handler.codec.base64.Base64Dialect;
import io.netty.util.AsciiString;
import org.apache.commons.codec.binary.Base64;

import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
Expand Down Expand Up @@ -135,9 +138,9 @@ public AuthenticationToken(final ApnsSigningKey signingKey, final Date issuedAt)
final String claimsJson = GSON.toJson(this.claims);

final StringBuilder payloadBuilder = new StringBuilder();
payloadBuilder.append(Base64.encodeBase64URLSafeString(headerJson.getBytes(StandardCharsets.US_ASCII)));
payloadBuilder.append(encodeUnpaddedBase64UrlString(headerJson.getBytes(StandardCharsets.US_ASCII)));
payloadBuilder.append('.');
payloadBuilder.append(Base64.encodeBase64URLSafeString(claimsJson.getBytes(StandardCharsets.US_ASCII)));
payloadBuilder.append(encodeUnpaddedBase64UrlString(claimsJson.getBytes(StandardCharsets.US_ASCII)));

{
final Signature signature = Signature.getInstance(ApnsKey.APNS_SIGNATURE_ALGORITHM);
Expand All @@ -148,7 +151,7 @@ public AuthenticationToken(final ApnsSigningKey signingKey, final Date issuedAt)
}

payloadBuilder.append('.');
payloadBuilder.append(Base64.encodeBase64URLSafeString(this.signatureBytes));
payloadBuilder.append(encodeUnpaddedBase64UrlString(this.signatureBytes));

this.base64EncodedToken = payloadBuilder.toString();
this.authorizationHeader = new AsciiString("bearer " + payloadBuilder.toString());
Expand All @@ -172,9 +175,9 @@ public AuthenticationToken(final String base64EncodedToken) {
throw new IllegalArgumentException();
}

this.header = GSON.fromJson(new String(Base64.decodeBase64(jwtSegments[0]), StandardCharsets.US_ASCII), AuthenticationTokenHeader.class);
this.claims = GSON.fromJson(new String(Base64.decodeBase64(jwtSegments[1]), StandardCharsets.US_ASCII), AuthenticationTokenClaims.class);
this.signatureBytes = Base64.decodeBase64(jwtSegments[2]);
this.header = GSON.fromJson(new String(decodeBase64UrlEncodedString(jwtSegments[0]), StandardCharsets.US_ASCII), AuthenticationTokenHeader.class);
this.claims = GSON.fromJson(new String(decodeBase64UrlEncodedString(jwtSegments[1]), StandardCharsets.US_ASCII), AuthenticationTokenClaims.class);
this.signatureBytes = decodeBase64UrlEncodedString(jwtSegments[2]);
}

/**
Expand Down Expand Up @@ -230,13 +233,11 @@ public boolean verifySignature(final ApnsVerificationKey verificationKey) throws
final String headerJson = GSON.toJson(this.header);
final String claimsJson = GSON.toJson(this.claims);

final StringBuilder headerAndClaimsBuilder = new StringBuilder();
final String encodedHeaderAndClaims =
encodeUnpaddedBase64UrlString(headerJson.getBytes(StandardCharsets.US_ASCII)) + '.' +
encodeUnpaddedBase64UrlString(claimsJson.getBytes(StandardCharsets.US_ASCII));

headerAndClaimsBuilder.append(Base64.encodeBase64URLSafeString(headerJson.getBytes(StandardCharsets.US_ASCII)));
headerAndClaimsBuilder.append('.');
headerAndClaimsBuilder.append(Base64.encodeBase64URLSafeString(claimsJson.getBytes(StandardCharsets.US_ASCII)));

headerAndClaimsBytes = headerAndClaimsBuilder.toString().getBytes(StandardCharsets.US_ASCII);
headerAndClaimsBytes = encodedHeaderAndClaims.getBytes(StandardCharsets.US_ASCII);

final Signature signature = Signature.getInstance(ApnsKey.APNS_SIGNATURE_ALGORITHM);
signature.initVerify(verificationKey);
Expand Down Expand Up @@ -282,12 +283,54 @@ public boolean equals(final Object obj) {
}
final AuthenticationToken other = (AuthenticationToken) obj;
if (this.base64EncodedToken == null) {
if (other.base64EncodedToken != null) {
return false;
return other.base64EncodedToken == null;
} else {
return this.base64EncodedToken.equals(other.base64EncodedToken);
}
}

static String encodeUnpaddedBase64UrlString(final byte[] data) {
final ByteBuf wrappedString = Unpooled.wrappedBuffer(data);
final ByteBuf encodedString = Base64.encode(wrappedString, Base64Dialect.URL_SAFE);

final String encodedUnpaddedString = encodedString.toString(StandardCharsets.US_ASCII).replace("=", "");

wrappedString.release();
encodedString.release();

return encodedUnpaddedString;
}

static byte[] decodeBase64UrlEncodedString(final String base64UrlEncodedString) {
final String paddedBase64UrlEncodedString;

switch (base64UrlEncodedString.length() % 4) {
case 2: {
paddedBase64UrlEncodedString = base64UrlEncodedString + "==";
break;
}

case 3: {
paddedBase64UrlEncodedString = base64UrlEncodedString + "=";
break;
}

default: {
paddedBase64UrlEncodedString = base64UrlEncodedString;
}
} else if (!this.base64EncodedToken.equals(other.base64EncodedToken)) {
return false;
}
return true;

final ByteBuf base64EncodedByteBuf =
Unpooled.wrappedBuffer(paddedBase64UrlEncodedString.getBytes(StandardCharsets.US_ASCII));

final ByteBuf decodedByteBuf = Base64.decode(base64EncodedByteBuf, Base64Dialect.URL_SAFE);
final byte[] decodedBytes = new byte[decodedByteBuf.readableBytes()];

decodedByteBuf.readBytes(decodedBytes);

base64EncodedByteBuf.release();
decodedByteBuf.release();

return decodedBytes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,14 @@ public void testToString() throws Exception {

assertTrue(Pattern.matches("^[a-zA-Z0-9_\\-]+\\.[a-zA-Z0-9_\\-]+\\.[a-zA-Z0-9_\\-]+$", token.toString()));
}

@Test
public void testEncodeDecodeBase64() {
final byte[] originalBytes =
"We expect to get these bytes back after encoding, then decoding as Base64.".getBytes();

final String encodedString = AuthenticationToken.encodeUnpaddedBase64UrlString(originalBytes);

assertArrayEquals(originalBytes, AuthenticationToken.decodeBase64UrlEncodedString(encodedString));
}
}

0 comments on commit 104fe56

Please sign in to comment.