Skip to content

Commit c95f6ab

Browse files
authored
Merge pull request zaproxy#9284 from psiinon/build/base64-fix
Common Codec PR fixes
2 parents f407893 + a64f81f commit c95f6ab

8 files changed

Lines changed: 111 additions & 89 deletions

File tree

LEGALNOTICE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ and subject to their respective licenses.
3232
| Library | License |
3333
|-------------------------------------|---------------------------|
3434
| commons-beanutils-1.11.0.jar | Apache 2.0 |
35+
| commons-codec-1.20.0.jar | Apache 2.0 |
3536
| commons-collections-3.2.2.jar | Apache 2.0 |
3637
| commons-configuration-1.10.jar | Apache 2.0 |
3738
| commons-csv-1.14.1.jar | Apache 2.0 |

buildSrc/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ tasks.withType<JavaCompile>().configureEach {
2424
dependencies {
2525
implementation("com.github.javaparser:javaparser-core:3.15.21")
2626
implementation("com.github.zafarkhaja:java-semver:0.9.0")
27+
implementation("commons-codec:commons-codec:1.20.0")
2728
implementation("commons-configuration:commons-configuration:1.10")
2829
implementation("commons-collections:commons-collections:3.2.2")
2930
implementation("commons-io:commons-io:2.13.0")

buildSrc/src/main/java/org/zaproxy/zap/tasks/CreateGitHubRelease.java

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,10 @@
2424
import java.nio.charset.StandardCharsets;
2525
import java.nio.file.Files;
2626
import java.nio.file.Path;
27-
import java.security.MessageDigest;
28-
import java.security.NoSuchAlgorithmException;
2927
import java.util.ArrayList;
3028
import java.util.List;
31-
import java.util.HexFormat;
3229
import java.util.stream.Collectors;
30+
import org.zaproxy.zap.tasks.internal.Utils;
3331
import org.gradle.api.Action;
3432
import org.gradle.api.DefaultTask;
3533
import org.gradle.api.InvalidUserDataException;
@@ -228,21 +226,15 @@ private void appendChecksumsTable(StringBuilder body) throws IOException {
228226
.collect(Collectors.toList());
229227
for (File file : files) {
230228
String fileName = file.getName();
231-
try {
232-
byte[] digest =
233-
MessageDigest.getInstance(algorithm)
234-
.digest(Files.readAllBytes(file.toPath()));
235-
body.append("| [")
236-
.append(fileName)
237-
.append("](")
238-
.append(baseDownloadLink)
239-
.append(fileName)
240-
.append(") | `")
241-
.append(HexFormat.of().formatHex(digest))
242-
.append("` |\n");
243-
} catch (NoSuchAlgorithmException e) {
244-
throw new IOException("Unsupported digest algorithm: " + algorithm, e);
245-
}
229+
String hexDigest = Utils.digest(file.toPath(), algorithm);
230+
body.append("| [")
231+
.append(fileName)
232+
.append("](")
233+
.append(baseDownloadLink)
234+
.append(fileName)
235+
.append(") | `")
236+
.append(hexDigest)
237+
.append("` |\n");
246238
}
247239
}
248240
}

buildSrc/src/main/java/org/zaproxy/zap/tasks/HandleWeeklyRelease.java

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,9 @@
2525
import java.net.URL;
2626
import java.nio.file.Files;
2727
import java.nio.file.Path;
28-
import java.security.MessageDigest;
29-
import java.security.NoSuchAlgorithmException;
3028
import java.util.HashMap;
3129
import java.util.Map;
32-
import java.util.HexFormat;
30+
import org.zaproxy.zap.tasks.internal.Utils;
3331
import org.gradle.api.provider.Property;
3432
import org.gradle.api.tasks.Input;
3533

@@ -66,7 +64,7 @@ public HandleWeeklyRelease() {
6664
private void createPayloadData() {
6765
String checksum;
6866
try {
69-
checksum = createChecksum(getChecksumAlgorithm().get(), downloadRelease());
67+
checksum = Utils.digest(downloadRelease(), getChecksumAlgorithm().get());
7068
} catch (Exception e) {
7169
throw new BuildException(e);
7270
}
@@ -107,15 +105,4 @@ private static String extractFileName(String url) {
107105
}
108106
return url.substring(idx + 1);
109107
}
110-
111-
private static String createChecksum(String algorithm, Path file) throws IOException {
112-
try {
113-
byte[] digest =
114-
MessageDigest.getInstance(algorithm)
115-
.digest(Files.readAllBytes(file));
116-
return HexFormat.of().formatHex(digest);
117-
} catch (NoSuchAlgorithmException e) {
118-
throw new IOException("Unsupported digest algorithm: " + algorithm, e);
119-
}
120-
}
121108
}

buildSrc/src/main/java/org/zaproxy/zap/tasks/UploadAssetsGitHubRelease.java

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,10 @@
2121

2222
import java.io.File;
2323
import java.io.IOException;
24-
import java.nio.file.Files;
25-
import java.security.MessageDigest;
26-
import java.security.NoSuchAlgorithmException;
2724
import java.util.ArrayList;
2825
import java.util.List;
29-
import java.util.HexFormat;
3026
import java.util.stream.Collectors;
27+
import org.zaproxy.zap.tasks.internal.Utils;
3128
import org.gradle.api.Action;
3229
import org.gradle.api.DefaultTask;
3330
import org.gradle.api.InvalidUserDataException;
@@ -185,21 +182,15 @@ private String updateChecksumsTable(String previousBody) throws IOException {
185182
.collect(Collectors.toList());
186183
for (File file : files) {
187184
String fileName = file.getName();
188-
try {
189-
byte[] digest =
190-
MessageDigest.getInstance(algorithm)
191-
.digest(Files.readAllBytes(file.toPath()));
192-
body.append("| [")
193-
.append(fileName)
194-
.append("](")
195-
.append(baseDownloadLink)
196-
.append(fileName)
197-
.append(") | `")
198-
.append(HexFormat.of().formatHex(digest))
199-
.append("` |\n");
200-
} catch (NoSuchAlgorithmException e) {
201-
throw new IOException("Unsupported digest algorithm: " + algorithm, e);
202-
}
185+
String hexDigest = Utils.digest(file.toPath(), algorithm);
186+
body.append("| [")
187+
.append(fileName)
188+
.append("](")
189+
.append(baseDownloadLink)
190+
.append(fileName)
191+
.append(") | `")
192+
.append(hexDigest)
193+
.append("` |\n");
203194
}
204195
body.append(previousBody.substring(idx));
205196
return body.toString();

buildSrc/src/main/java/org/zaproxy/zap/tasks/internal/Utils.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,12 @@ public static MainAddOnsData parseData(Path file) throws IOException {
7373
}
7474

7575
public static String hash(Path file, MainAddOn addOn) throws IOException {
76-
String hash = addOn.getHash();
77-
String algorithm = hash.substring(0, hash.indexOf(':'));
76+
String existingHash = addOn.getHash();
77+
String algorithm = existingHash.substring(0, existingHash.indexOf(':'));
78+
return algorithm + ":" + digest(file, algorithm);
79+
}
80+
81+
public static String digest(Path file, String algorithm) throws IOException {
7882
try (InputStream is = new BufferedInputStream(Files.newInputStream(file))) {
7983
MessageDigest diggest = MessageDigest.getInstance(algorithm);
8084

@@ -84,8 +88,7 @@ public static String hash(Path file, MainAddOn addOn) throws IOException {
8488
diggest.update(buffer, 0, read);
8589
}
8690

87-
StringBuilder sb = new StringBuilder(algorithm);
88-
sb.append(':');
91+
StringBuilder sb = new StringBuilder();
8992
for (byte b : diggest.digest()) {
9093
sb.append(String.format("%02x", b));
9194
}

zap/src/main/java/org/apache/commons/httpclient/URI.java

Lines changed: 77 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
* - Use neutral Locale when converting to lower case.
5858
* - Allow to create a URI from the authority component.
5959
* - Replace usages of StringBuffer with StringBuilder.
60+
* - Include URL encode/decode logic from Apache Commons Codec URLCodec (see encodeUrl/decodeUrl).
6061
*/
6162
/**
6263
* The interface for the URI(Uniform Resource Identifiers) version of RFC 2396.
@@ -1702,19 +1703,70 @@ public URI(URI base, URI relative) throws URIException {
17021703
* @return URI character sequence
17031704
* @throws URIException null component or unsupported character encoding
17041705
*/
1706+
protected static char[] encode(String original, BitSet allowed,
1707+
String charset) throws URIException {
1708+
if (original == null) {
1709+
throw new IllegalArgumentException("Original string may not be null");
1710+
}
1711+
if (allowed == null) {
1712+
throw new IllegalArgumentException("Allowed bitset may not be null");
1713+
}
1714+
byte[] rawdata = encodeUrl(allowed, EncodingUtil.getBytes(original, charset));
1715+
return EncodingUtil.getAsciiString(rawdata).toCharArray();
1716+
}
1717+
1718+
/*
1719+
* The following encodeUrl and decodeUrl methods are from Apache Commons Codec
1720+
* org.apache.commons.codec.net.URLCodec, licensed under the Apache License, Version 2.0.
1721+
* See https://commons.apache.org/proper/commons-codec/
1722+
* Adapted to throw URIException instead of DecoderException.
1723+
*/
1724+
private static final byte ESCAPE_CHAR = '%';
1725+
1726+
private static final BitSet WWW_FORM_URL_SAFE;
1727+
static {
1728+
BitSet safe = new BitSet(256);
1729+
for (int i = 'a'; i <= 'z'; i++) {
1730+
safe.set(i);
1731+
}
1732+
for (int i = 'A'; i <= 'Z'; i++) {
1733+
safe.set(i);
1734+
}
1735+
for (int i = '0'; i <= '9'; i++) {
1736+
safe.set(i);
1737+
}
1738+
safe.set('-');
1739+
safe.set('_');
1740+
safe.set('.');
1741+
safe.set('*');
1742+
safe.set(' ');
1743+
WWW_FORM_URL_SAFE = safe;
1744+
}
1745+
17051746
private static byte[] encodeUrl(BitSet urlsafe, byte[] bytes) {
17061747
if (bytes == null) {
17071748
return null;
17081749
}
1709-
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
1710-
for (byte c : bytes) {
1711-
int b = c & 0xff;
1750+
if (urlsafe == null) {
1751+
urlsafe = WWW_FORM_URL_SAFE;
1752+
}
1753+
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
1754+
for (final byte c : bytes) {
1755+
int b = c;
1756+
if (b < 0) {
1757+
b = 256 + b;
1758+
}
17121759
if (urlsafe.get(b)) {
1713-
buffer.write(b == ' ' ? '+' : b);
1760+
if (b == ' ') {
1761+
b = '+';
1762+
}
1763+
buffer.write(b);
17141764
} else {
1715-
buffer.write('%');
1716-
buffer.write(Character.toUpperCase(Character.forDigit(b >> 4, 16)));
1717-
buffer.write(Character.toUpperCase(Character.forDigit(b & 0x0f, 16)));
1765+
buffer.write(ESCAPE_CHAR);
1766+
final char hex1 = hexChar(b >> 4);
1767+
final char hex2 = hexChar(b);
1768+
buffer.write(hex1);
1769+
buffer.write(hex2);
17181770
}
17191771
}
17201772
return buffer.toByteArray();
@@ -1724,38 +1776,36 @@ private static byte[] decodeUrl(byte[] bytes) throws URIException {
17241776
if (bytes == null) {
17251777
return null;
17261778
}
1727-
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
1779+
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
17281780
for (int i = 0; i < bytes.length; i++) {
1729-
int b = bytes[i] & 0xff;
1781+
final int b = bytes[i];
17301782
if (b == '+') {
17311783
buffer.write(' ');
1732-
} else if (b == '%') {
1733-
if (i + 2 >= bytes.length) {
1734-
throw new URIException("Invalid URL encoding: incomplete trailing escape");
1735-
}
1736-
int u = Character.digit((char) bytes[++i], 16);
1737-
int l = Character.digit((char) bytes[++i], 16);
1738-
if (u < 0 || l < 0) {
1739-
throw new URIException("Invalid URL encoding: invalid hex digit");
1784+
} else if (b == ESCAPE_CHAR) {
1785+
try {
1786+
final int u = digit16(bytes[++i]);
1787+
final int l = digit16(bytes[++i]);
1788+
buffer.write((char) ((u << 4) + l));
1789+
} catch (final ArrayIndexOutOfBoundsException e) {
1790+
throw new URIException("Invalid URL encoding: " + e.getMessage());
17401791
}
1741-
buffer.write((u << 4) + l);
17421792
} else {
17431793
buffer.write(b);
17441794
}
17451795
}
17461796
return buffer.toByteArray();
17471797
}
17481798

1749-
protected static char[] encode(String original, BitSet allowed,
1750-
String charset) throws URIException {
1751-
if (original == null) {
1752-
throw new IllegalArgumentException("Original string may not be null");
1753-
}
1754-
if (allowed == null) {
1755-
throw new IllegalArgumentException("Allowed bitset may not be null");
1799+
private static int digit16(byte b) throws URIException {
1800+
final int i = Character.digit((char) b, 16);
1801+
if (i == -1) {
1802+
throw new URIException("Invalid URL encoding: not a valid digit (radix 16): " + b);
17561803
}
1757-
byte[] rawdata = encodeUrl(allowed, EncodingUtil.getBytes(original, charset));
1758-
return EncodingUtil.getAsciiString(rawdata).toCharArray();
1804+
return i;
1805+
}
1806+
1807+
private static char hexChar(int b) {
1808+
return Character.toUpperCase(Character.forDigit(b & 0xF, 16));
17591809
}
17601810

17611811
/**

zap/zap.gradle.kts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,8 @@ spotless {
7272
mapOf(
7373
"import org.apache.commons.lang." to
7474
"Import/use classes from Commons Lang 3, instead of Lang 2.",
75-
"import org.apache.commons.codec.binary.Base64" to
76-
"Use java.util.Base64 instead.",
77-
"import org.apache.commons.codec.binary.Hex" to
78-
"Use java.util.HexFormat instead.",
79-
"import org.apache.commons.codec.digest.DigestUtils" to
80-
"Use org.zaproxy.zap.utils.DigestUtils instead.",
75+
"import org.apache.commons.codec." to
76+
"Do not use import org.apache.commons.codec.",
8177
),
8278
),
8379
)
@@ -96,6 +92,7 @@ dependencies {
9692
api("com.fifesoft:rsyntaxtextarea:3.6.0")
9793
api("com.github.zafarkhaja:java-semver:0.10.2")
9894
implementation("commons-beanutils:commons-beanutils:1.11.0")
95+
implementation("commons-codec:commons-codec:1.20.0")
9996
api("commons-collections:commons-collections:3.2.2")
10097
api("commons-configuration:commons-configuration:1.10")
10198
api("commons-httpclient:commons-httpclient:3.1")

0 commit comments

Comments
 (0)