Skip to content

Commit 481191a

Browse files
authored
Refactor Encoding util for easier replacement of Base64 encoding class (#1121)
1 parent 1907a43 commit 481191a

24 files changed

+304
-100
lines changed

src/main/java/io/nats/client/Connection.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,8 +548,8 @@ enum Status {
548548
/**
549549
* Forces reconnect behavior. Stops the current connection including the reading and writing,
550550
* copies already queued outgoing messages, and then begins the reconnect logic.
551-
* @throws IOException
552-
* @throws InterruptedException
551+
* @throws IOException the force reconnected fails
552+
* @throws InterruptedException if one is thrown, in order to propagate it up
553553
*/
554554
void forceReconnect() throws IOException, InterruptedException;
555555

src/main/java/io/nats/client/ErrorListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ default void socketWriteTimeout(Connection conn) {}
146146
* @param sub the JetStreamSubscription that this occurred on, if applicable
147147
* @param pairs custom string pairs. I.E. "foo: ", fooObject, "bar-", barObject will be appended
148148
* to the message like ", foo: <fooValue>, bar-<barValue>".
149-
* @return
149+
* @return the message
150150
*/
151151
default String supplyMessage(String label, Connection conn, Consumer consumer, Subscription sub, Object... pairs) {
152152
StringBuilder sb = new StringBuilder(label == null ? "" : label);

src/main/java/io/nats/client/Options.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.util.concurrent.*;
3939
import java.util.concurrent.atomic.AtomicInteger;
4040

41+
import static io.nats.client.support.Encoding.base64UrlEncodeToString;
4142
import static io.nats.client.support.Encoding.uriDecode;
4243
import static io.nats.client.support.NatsConstants.*;
4344
import static io.nats.client.support.SSLUtils.DEFAULT_TLS_ALGORITHM;
@@ -2367,7 +2368,7 @@ public CharBuffer buildProtocolConnectOptionsString(String serverURI, boolean in
23672368
nkey = new char[0];
23682369
}
23692370

2370-
String encodedSig = Base64.getUrlEncoder().withoutPadding().encodeToString(sig);
2371+
String encodedSig = base64UrlEncodeToString(sig);
23712372

23722373
appendOption(connectString, Options.OPTION_NKEY, nkey, true, true);
23732374
appendOption(connectString, Options.OPTION_SIG, encodedSig, true, true);

src/main/java/io/nats/client/support/Encoding.java

Lines changed: 117 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,32 @@
2222
public abstract class Encoding {
2323
private Encoding() {} /* ensures cannot be constructed */
2424

25+
/**
26+
* base64 encode a byte array to a byte array
27+
* @param input the input byte array to encode
28+
* @return the encoded byte array
29+
*/
30+
public static byte[] base64BasicEncode(byte[] input) {
31+
return Base64.getEncoder().encode(input);
32+
}
33+
34+
/**
35+
* base64 encode a byte array to a byte array
36+
* @param input the input byte array to encode
37+
* @return the encoded byte array
38+
*/
39+
public static String base64BasicEncodeToString(byte[] input) {
40+
return Base64.getEncoder().encodeToString(input);
41+
}
42+
2543
/**
2644
* base64 url encode a byte array to a byte array
2745
* @param input the input byte array to encode
2846
* @return the encoded byte array
29-
* @deprecated prefer base64UrlEncode
3047
*/
31-
@Deprecated
32-
public static byte[] base64Encode(byte[] input) {
33-
return Base64.getUrlEncoder().withoutPadding().encode(input);
48+
public static String base64BasicEncodeToString(String input) {
49+
return Base64.getEncoder()
50+
.encodeToString(input.getBytes(StandardCharsets.UTF_8));
3451
}
3552

3653
/**
@@ -43,21 +60,50 @@ public static byte[] base64UrlEncode(byte[] input) {
4360
}
4461

4562
/**
46-
* base64 url encode a byte array to a string
63+
* base64 url encode a byte array to a byte array
4764
* @param input the input byte array to encode
48-
* @return the encoded string
65+
* @return the encoded byte array
4966
*/
50-
public static String toBase64Url(byte[] input) {
51-
return new String(base64UrlEncode(input));
67+
public static String base64UrlEncodeToString(byte[] input) {
68+
return Base64.getUrlEncoder().withoutPadding().encodeToString(input);
5269
}
5370

5471
/**
55-
* base64 url encode a string to a string
56-
* @param input the input string to encode
57-
* @return the encoded string
72+
* base64 url encode a byte array to a byte array
73+
* @param input the input byte array to encode
74+
* @return the encoded byte array
5875
*/
59-
public static String toBase64Url(String input) {
60-
return new String(base64UrlEncode(input.getBytes(StandardCharsets.US_ASCII)));
76+
public static String base64UrlEncodeToString(String input) {
77+
return Base64.getUrlEncoder()
78+
.withoutPadding()
79+
.encodeToString(input.getBytes(StandardCharsets.UTF_8));
80+
}
81+
82+
/**
83+
* base64 decode a byte array
84+
* @param input the input byte array to decode
85+
* @return the decoded byte array
86+
*/
87+
public static byte[] base64BasicDecode(byte[] input) {
88+
return Base64.getDecoder().decode(input);
89+
}
90+
91+
/**
92+
* base64 decode a base64 encoded string
93+
* @param input the input string to decode
94+
* @return the decoded byte array
95+
*/
96+
public static byte[] base64BasicDecode(String input) {
97+
return Base64.getDecoder().decode(input);
98+
}
99+
100+
/**
101+
* base64 decode a base64 encoded string
102+
* @param input the input string to decode
103+
* @return the decoded string
104+
*/
105+
public static String base64BasicDecodeToString(String input) {
106+
return new String(Base64.getDecoder().decode(input));
61107
}
62108

63109
/**
@@ -70,12 +116,21 @@ public static byte[] base64UrlDecode(byte[] input) {
70116
}
71117

72118
/**
73-
* get a string from a base64 url encoded byte array
119+
* base64 url decode a base64 url encoded string
120+
* @param input the input string to decode
121+
* @return the decoded byte array
122+
*/
123+
public static byte[] base64UrlDecode(String input) {
124+
return Base64.getUrlDecoder().decode(input);
125+
}
126+
127+
/**
128+
* base64 url decode a base64 url encoded string
74129
* @param input the input string to decode
75130
* @return the decoded string
76131
*/
77-
public static String fromBase64Url(String input) {
78-
return new String(base64UrlDecode(input.getBytes(StandardCharsets.US_ASCII)));
132+
public static String base64UrlDecodeToString(String input) {
133+
return new String(Base64.getUrlDecoder().decode(input));
79134
}
80135

81136
// http://en.wikipedia.org/wiki/Base_32
@@ -142,8 +197,8 @@ public static byte[] base32Decode(final char[] input) {
142197
int next = 0;
143198
int bitsLeft = 0;
144199

145-
for (int i = 0; i < input.length; i++) {
146-
int lookup = input[i] - '0';
200+
for (char value : input) {
201+
int lookup = value - '0';
147202

148203
if (lookup < 0 || lookup >= BASE32_LOOKUP.length) {
149204
continue;
@@ -170,7 +225,6 @@ public static String jsonDecode(String s) {
170225
char nextChar = (x == len - 1) ? '\\' : s.charAt(x + 1);
171226
switch (nextChar) {
172227
case '\\':
173-
ch = '\\';
174228
break;
175229
case 'b':
176230
ch = '\b';
@@ -262,4 +316,48 @@ public static String uriDecode(String source) {
262316
return source;
263317
}
264318
}
319+
320+
/**
321+
* @deprecated Use {@link #base64UrlEncode(byte[])} instead.
322+
* base64 url encode a byte array to a byte array
323+
* @param input the input byte array to encode
324+
* @return the encoded byte array
325+
*/
326+
@Deprecated
327+
public static byte[] base64Encode(byte[] input) {
328+
return base64UrlEncode(input);
329+
}
330+
331+
/**
332+
* @deprecated Use {@link #base64UrlEncodeToString(byte[])} instead.
333+
* base64 url encode a byte array to a string
334+
* @param input the input byte array to encode
335+
* @return the encoded string
336+
*/
337+
@Deprecated
338+
public static String toBase64Url(byte[] input) {
339+
return base64UrlEncodeToString(input);
340+
}
341+
342+
/**
343+
* @deprecated Use {@link #base64UrlEncodeToString(String)} instead.
344+
* base64 url encode a string to a string
345+
* @param input the input string to encode
346+
* @return the encoded string
347+
*/
348+
@Deprecated
349+
public static String toBase64Url(String input) {
350+
return base64UrlEncodeToString(input);
351+
}
352+
353+
/**
354+
* @deprecated Use {@link #base64UrlDecodeToString(String)} instead.
355+
* get a string from a base64 url encoded byte array
356+
* @param input the input string to decode
357+
* @return the decoded string
358+
*/
359+
@Deprecated
360+
public static String fromBase64Url(String input) {
361+
return base64UrlDecodeToString(input);
362+
}
265363
}

src/main/java/io/nats/client/support/JsonValueUtils.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.*;
2222
import java.util.function.Function;
2323

24+
import static io.nats.client.support.Encoding.base64BasicDecode;
2425
import static io.nats.client.support.JsonValue.*;
2526

2627
/**
@@ -192,7 +193,7 @@ public static byte[] readBytes(JsonValue jsonValue, String key) {
192193

193194
public static byte[] readBase64(JsonValue jsonValue, String key) {
194195
String b64 = readString(jsonValue, key);
195-
return b64 == null ? null : Base64.getDecoder().decode(b64);
196+
return b64 == null ? null : base64BasicDecode(b64);
196197
}
197198

198199
public static Integer getInteger(JsonValue v) {

src/main/java/io/nats/client/support/JwtUtils.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public abstract class JwtUtils {
3434
private JwtUtils() {} /* ensures cannot be constructed */
3535

3636
private static final String ENCODED_CLAIM_HEADER =
37-
toBase64Url("{\"typ\":\"JWT\", \"alg\":\"ed25519-nkey\"}");
37+
base64UrlEncodeToString("{\"typ\":\"JWT\", \"alg\":\"ed25519-nkey\"}");
3838

3939
private static final long NO_LIMIT = -1;
4040

@@ -251,11 +251,11 @@ public static String issueJWT(NKey signingKey, String publicUserKey, String name
251251
claimJson = claim.toJson();
252252

253253
// all three components (header/body/signature) are base64url encoded
254-
String encBody = toBase64Url(claimJson);
254+
String encBody = base64UrlEncodeToString(claimJson);
255255

256256
// compute the signature off of header + body (. included on purpose)
257257
byte[] sig = (ENCODED_CLAIM_HEADER + "." + encBody).getBytes(StandardCharsets.UTF_8);
258-
String encSig = toBase64Url(signingKey.sign(sig));
258+
String encSig = base64UrlEncodeToString(signingKey.sign(sig));
259259

260260
// append signature to header and body and return it
261261
return ENCODED_CLAIM_HEADER + "." + encBody + "." + encSig;
@@ -267,7 +267,7 @@ public static String issueJWT(NKey signingKey, String publicUserKey, String name
267267
* @return the claim body json
268268
*/
269269
public static String getClaimBody(String jwt) {
270-
return fromBase64Url(jwt.split("\\.")[1]);
270+
return base64UrlDecodeToString(jwt.split("\\.")[1]);
271271
}
272272

273273
public static class UserClaim implements JsonSerializable {

src/main/java/io/nats/client/support/NatsObjectStoreUtil.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@
1515

1616
import io.nats.client.impl.Headers;
1717

18-
import java.nio.charset.StandardCharsets;
19-
import java.util.Base64;
20-
18+
import static io.nats.client.support.Encoding.base64BasicEncodeToString;
2119
import static io.nats.client.support.NatsConstants.DOT;
2220
import static io.nats.client.support.NatsJetStreamConstants.ROLLUP_HDR;
2321
import static io.nats.client.support.NatsJetStreamConstants.ROLLUP_HDR_SUBJECT;
@@ -59,7 +57,7 @@ public static String toChunkPrefix(String bucketName) {
5957
}
6058

6159
public static String encodeForSubject(String name) {
62-
return Base64.getEncoder().encodeToString(name.getBytes(StandardCharsets.UTF_8));
60+
return base64BasicEncodeToString(name);
6361
}
6462

6563
public static Headers getMetaHeaders() {

src/main/java/io/nats/client/support/WebSocket.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@
2525
import java.security.MessageDigest;
2626
import java.security.NoSuchAlgorithmException;
2727
import java.security.SecureRandom;
28-
import java.util.Base64;
2928
import java.util.HashMap;
3029
import java.util.List;
3130
import java.util.Map;
3231
import java.util.concurrent.locks.ReentrantLock;
3332
import java.util.function.Consumer;
3433

34+
import static io.nats.client.support.Encoding.base64BasicEncodeToString;
3535
import static java.nio.charset.StandardCharsets.UTF_8;
3636

3737
public class WebSocket extends Socket {
@@ -63,7 +63,7 @@ private static void handshake(Socket socket, String host, List<Consumer<HttpRequ
6363
// been base64-encoded
6464
byte[] keyBytes = new byte[16];
6565
new SecureRandom().nextBytes(keyBytes);
66-
String key = Base64.getEncoder().encodeToString(keyBytes);
66+
String key = base64BasicEncodeToString(keyBytes);
6767

6868
request.getHeaders()
6969
.add("Host", host)
@@ -130,8 +130,7 @@ private static void handshake(Socket socket, String host, List<Consumer<HttpRequ
130130
}
131131
sha1.update(key.getBytes(UTF_8));
132132
sha1.update("258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes(UTF_8));
133-
String acceptKey = Base64.getEncoder().encodeToString(
134-
sha1.digest());
133+
String acceptKey = base64BasicEncodeToString(sha1.digest());
135134
String gotAcceptKey = headers.get("sec-websocket-accept");
136135
if (!acceptKey.equals(gotAcceptKey)) {
137136
throw new IllegalStateException(

src/test/java/io/nats/client/NKeyTests.java

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,10 @@
2020
import java.nio.file.Paths;
2121
import java.security.SecureRandom;
2222
import java.util.Arrays;
23-
import java.util.Base64;
2423
import java.util.List;
2524

2625
import static io.nats.client.NKey.removePaddingAndClear;
27-
import static io.nats.client.support.Encoding.base32Decode;
28-
import static io.nats.client.support.Encoding.base32Encode;
26+
import static io.nats.client.support.Encoding.*;
2927
import static io.nats.client.utils.ResourceUtils.dataAsLines;
3028
import static org.junit.jupiter.api.Assertions.*;
3129

@@ -519,12 +517,12 @@ public void testInterop() throws Exception {
519517

520518
assertEquals(fromSeed.getType(), NKey.Type.USER);
521519

522-
byte[] nonceData = Base64.getUrlDecoder().decode(nonce);
523-
byte[] nonceSig = Base64.getUrlDecoder().decode(nonceEncodedSig);
520+
byte[] nonceData = base64UrlDecode(nonce);
521+
byte[] nonceSig = base64UrlDecode(nonceEncodedSig);
524522
byte[] seedNonceSig = fromSeed.sign(nonceData);
525-
String encodedSeedNonceSig = Base64.getUrlEncoder().withoutPadding().encodeToString(seedNonceSig);
523+
String encodedSeedNonceSig = base64UrlEncodeToString(seedNonceSig);
526524

527-
assertTrue(Arrays.equals(seedNonceSig, nonceSig));
525+
assertArrayEquals(seedNonceSig, nonceSig);
528526
assertEquals(nonceEncodedSig, encodedSeedNonceSig);
529527

530528
assertTrue(fromSeed.verify(nonceData, nonceSig));
@@ -533,10 +531,10 @@ public void testInterop() throws Exception {
533531
assertTrue(fromPublicKey.verify(nonceData, seedNonceSig));
534532

535533
byte[] seedSig = fromSeed.sign(data);
536-
byte[] sig = Base64.getUrlDecoder().decode(encodedSig);
537-
String encodedSeedSig = Base64.getUrlEncoder().withoutPadding().encodeToString(seedSig);
534+
byte[] sig = base64UrlDecode(encodedSig);
535+
String encodedSeedSig = base64UrlEncodeToString(seedSig);
538536

539-
assertTrue(Arrays.equals(seedSig, sig));
537+
assertArrayEquals(seedSig, sig);
540538
assertEquals(encodedSig, encodedSeedSig);
541539

542540
assertTrue(fromSeed.verify(data, sig));
@@ -545,13 +543,13 @@ public void testInterop() throws Exception {
545543
assertTrue(fromPublicKey.verify(data, seedSig));
546544

547545
// Make sure generation is the same
548-
assertTrue(Arrays.equals(fromSeed.getSeed(), seed));
549-
assertTrue(Arrays.equals(fromSeed.getPublicKey(), publicKey));
550-
assertTrue(Arrays.equals(fromSeed.getPrivateKey(), privateKey));
546+
assertArrayEquals(fromSeed.getSeed(), seed);
547+
assertArrayEquals(fromSeed.getPublicKey(), publicKey);
548+
assertArrayEquals(fromSeed.getPrivateKey(), privateKey);
551549

552550
DecodedSeed decoded = NKey.decodeSeed(seed);
553551
char[] encodedSeed = NKey.encodeSeed(NKey.Type.fromPrefix(decoded.prefix), decoded.bytes);
554-
assertTrue(Arrays.equals(encodedSeed, seed));
552+
assertArrayEquals(encodedSeed, seed);
555553
}
556554

557555
@Test

0 commit comments

Comments
 (0)