diff --git a/LEGALNOTICE.md b/LEGALNOTICE.md index ee05ff2a85c..2f8bfd62877 100644 --- a/LEGALNOTICE.md +++ b/LEGALNOTICE.md @@ -32,7 +32,6 @@ and subject to their respective licenses. | Library | License | |-------------------------------------|---------------------------| | commons-beanutils-1.11.0.jar | Apache 2.0 | -| commons-codec-1.20.0.jar | Apache 2.0 | | commons-collections-3.2.2.jar | Apache 2.0 | | commons-configuration-1.10.jar | Apache 2.0 | | commons-csv-1.14.1.jar | Apache 2.0 | diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 16abd3db875..2ac59570ccb 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,6 @@ tasks.withType().configureEach { dependencies { implementation("com.github.javaparser:javaparser-core:3.15.21") implementation("com.github.zafarkhaja:java-semver:0.9.0") - implementation("commons-codec:commons-codec:1.17.1") implementation("commons-configuration:commons-configuration:1.10") implementation("commons-collections:commons-collections:3.2.2") implementation("commons-io:commons-io:2.13.0") diff --git a/buildSrc/src/main/java/org/zaproxy/zap/tasks/CreateGitHubRelease.java b/buildSrc/src/main/java/org/zaproxy/zap/tasks/CreateGitHubRelease.java index ff941c74305..b469c974096 100644 --- a/buildSrc/src/main/java/org/zaproxy/zap/tasks/CreateGitHubRelease.java +++ b/buildSrc/src/main/java/org/zaproxy/zap/tasks/CreateGitHubRelease.java @@ -24,10 +24,12 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; +import java.util.HexFormat; import java.util.stream.Collectors; -import org.apache.commons.codec.digest.DigestUtils; import org.gradle.api.Action; import org.gradle.api.DefaultTask; import org.gradle.api.InvalidUserDataException; @@ -218,7 +220,6 @@ private void appendChecksumsTable(StringBuilder body) throws IOException { String baseDownloadLink = "https://github.com/" + repo.get() + "/releases/download/" + tag.get() + "/"; - DigestUtils digestUtils = new DigestUtils(algorithm); List files = assets.stream() @@ -227,14 +228,21 @@ private void appendChecksumsTable(StringBuilder body) throws IOException { .collect(Collectors.toList()); for (File file : files) { String fileName = file.getName(); - body.append("| [") - .append(fileName) - .append("](") - .append(baseDownloadLink) - .append(fileName) - .append(") | `") - .append(digestUtils.digestAsHex(file)) - .append("` |\n"); + try { + byte[] digest = + MessageDigest.getInstance(algorithm) + .digest(Files.readAllBytes(file.toPath())); + body.append("| [") + .append(fileName) + .append("](") + .append(baseDownloadLink) + .append(fileName) + .append(") | `") + .append(HexFormat.of().formatHex(digest)) + .append("` |\n"); + } catch (NoSuchAlgorithmException e) { + throw new IOException("Unsupported digest algorithm: " + algorithm, e); + } } } } diff --git a/buildSrc/src/main/java/org/zaproxy/zap/tasks/HandleWeeklyRelease.java b/buildSrc/src/main/java/org/zaproxy/zap/tasks/HandleWeeklyRelease.java index e4e9a6b6b28..2c65b55bafb 100644 --- a/buildSrc/src/main/java/org/zaproxy/zap/tasks/HandleWeeklyRelease.java +++ b/buildSrc/src/main/java/org/zaproxy/zap/tasks/HandleWeeklyRelease.java @@ -25,9 +25,11 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; -import org.apache.commons.codec.digest.DigestUtils; +import java.util.HexFormat; import org.gradle.api.provider.Property; import org.gradle.api.tasks.Input; @@ -107,6 +109,13 @@ private static String extractFileName(String url) { } private static String createChecksum(String algorithm, Path file) throws IOException { - return new DigestUtils(algorithm).digestAsHex(file.toFile()); + try { + byte[] digest = + MessageDigest.getInstance(algorithm) + .digest(Files.readAllBytes(file)); + return HexFormat.of().formatHex(digest); + } catch (NoSuchAlgorithmException e) { + throw new IOException("Unsupported digest algorithm: " + algorithm, e); + } } } diff --git a/buildSrc/src/main/java/org/zaproxy/zap/tasks/UploadAssetsGitHubRelease.java b/buildSrc/src/main/java/org/zaproxy/zap/tasks/UploadAssetsGitHubRelease.java index 6b2835d26db..4eb515c2633 100644 --- a/buildSrc/src/main/java/org/zaproxy/zap/tasks/UploadAssetsGitHubRelease.java +++ b/buildSrc/src/main/java/org/zaproxy/zap/tasks/UploadAssetsGitHubRelease.java @@ -21,10 +21,13 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; +import java.util.HexFormat; import java.util.stream.Collectors; -import org.apache.commons.codec.digest.DigestUtils; import org.gradle.api.Action; import org.gradle.api.DefaultTask; import org.gradle.api.InvalidUserDataException; @@ -173,7 +176,7 @@ private String updateChecksumsTable(String previousBody) throws IOException { String baseDownloadLink = "https://github.com/" + repo.get() + "/releases/download/" + tag.get() + "/"; - DigestUtils digestUtils = new DigestUtils(checksumAlgorithm.get()); + String algorithm = checksumAlgorithm.get(); List files = assets.stream() @@ -182,14 +185,21 @@ private String updateChecksumsTable(String previousBody) throws IOException { .collect(Collectors.toList()); for (File file : files) { String fileName = file.getName(); - body.append("| [") - .append(fileName) - .append("](") - .append(baseDownloadLink) - .append(fileName) - .append(") | `") - .append(digestUtils.digestAsHex(file)) - .append("` |\n"); + try { + byte[] digest = + MessageDigest.getInstance(algorithm) + .digest(Files.readAllBytes(file.toPath())); + body.append("| [") + .append(fileName) + .append("](") + .append(baseDownloadLink) + .append(fileName) + .append(") | `") + .append(HexFormat.of().formatHex(digest)) + .append("` |\n"); + } catch (NoSuchAlgorithmException e) { + throw new IOException("Unsupported digest algorithm: " + algorithm, e); + } } body.append(previousBody.substring(idx)); return body.toString(); diff --git a/zap/src/main/java/org/apache/commons/httpclient/URI.java b/zap/src/main/java/org/apache/commons/httpclient/URI.java index 27657b1fd48..f8363194f61 100644 --- a/zap/src/main/java/org/apache/commons/httpclient/URI.java +++ b/zap/src/main/java/org/apache/commons/httpclient/URI.java @@ -39,8 +39,7 @@ import java.util.BitSet; import java.util.Hashtable; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.net.URLCodec; +import java.io.ByteArrayOutputStream; import org.apache.commons.httpclient.util.EncodingUtil; /* @@ -1703,7 +1702,50 @@ public URI(URI base, URI relative) throws URIException { * @return URI character sequence * @throws URIException null component or unsupported character encoding */ - + private static byte[] encodeUrl(BitSet urlsafe, byte[] bytes) { + if (bytes == null) { + return null; + } + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + for (byte c : bytes) { + int b = c & 0xff; + if (urlsafe.get(b)) { + buffer.write(b == ' ' ? '+' : b); + } else { + buffer.write('%'); + buffer.write(Character.toUpperCase(Character.forDigit(b >> 4, 16))); + buffer.write(Character.toUpperCase(Character.forDigit(b & 0x0f, 16))); + } + } + return buffer.toByteArray(); + } + + private static byte[] decodeUrl(byte[] bytes) throws URIException { + if (bytes == null) { + return null; + } + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + for (int i = 0; i < bytes.length; i++) { + int b = bytes[i] & 0xff; + if (b == '+') { + buffer.write(' '); + } else if (b == '%') { + if (i + 2 >= bytes.length) { + throw new URIException("Invalid URL encoding: incomplete trailing escape"); + } + int u = Character.digit((char) bytes[++i], 16); + int l = Character.digit((char) bytes[++i], 16); + if (u < 0 || l < 0) { + throw new URIException("Invalid URL encoding: invalid hex digit"); + } + buffer.write((u << 4) + l); + } else { + buffer.write(b); + } + } + return buffer.toByteArray(); + } + protected static char[] encode(String original, BitSet allowed, String charset) throws URIException { if (original == null) { @@ -1712,7 +1754,7 @@ protected static char[] encode(String original, BitSet allowed, if (allowed == null) { throw new IllegalArgumentException("Allowed bitset may not be null"); } - byte[] rawdata = URLCodec.encodeUrl(allowed, EncodingUtil.getBytes(original, charset)); + byte[] rawdata = encodeUrl(allowed, EncodingUtil.getBytes(original, charset)); return EncodingUtil.getAsciiString(rawdata).toCharArray(); } @@ -1791,12 +1833,7 @@ protected static String decode(String component, String charset) if (component == null) { throw new IllegalArgumentException("Component array of chars may not be null"); } - byte[] rawdata = null; - try { - rawdata = URLCodec.decodeUrl(EncodingUtil.getAsciiBytes(component)); - } catch (DecoderException e) { - throw new URIException(e.getMessage()); - } + byte[] rawdata = decodeUrl(EncodingUtil.getAsciiBytes(component)); return EncodingUtil.getString(rawdata, charset); } /** diff --git a/zap/src/main/java/org/parosproxy/paros/core/scanner/VariantCustom.java b/zap/src/main/java/org/parosproxy/paros/core/scanner/VariantCustom.java index 70b19dc964c..e62106a62d4 100644 --- a/zap/src/main/java/org/parosproxy/paros/core/scanner/VariantCustom.java +++ b/zap/src/main/java/org/parosproxy/paros/core/scanner/VariantCustom.java @@ -20,10 +20,10 @@ package org.parosproxy.paros.core.scanner; import java.util.ArrayList; +import java.util.Base64; import java.util.List; import java.util.concurrent.Callable; import java.util.regex.Pattern; -import org.apache.commons.codec.binary.Base64; import org.parosproxy.paros.Constant; import org.parosproxy.paros.network.HttpMessage; import org.zaproxy.zap.extension.script.ExtensionScript; @@ -235,7 +235,7 @@ public void addParamHeader(String name, String value) { * @return the encoded string */ public String encodeBase64(String value) { - return Base64.encodeBase64String(value.getBytes()); + return Base64.getEncoder().encodeToString(value.getBytes()); } /** @@ -245,7 +245,7 @@ public String encodeBase64(String value) { * @return the decoded string */ public String decodeBase64(String value) { - return new String(Base64.decodeBase64(value)); + return new String(Base64.getDecoder().decode(value)); } /** diff --git a/zap/src/main/java/org/zaproxy/zap/authentication/ManualAuthenticationMethodType.java b/zap/src/main/java/org/zaproxy/zap/authentication/ManualAuthenticationMethodType.java index 963e3cb7d2a..d5d90e87785 100644 --- a/zap/src/main/java/org/zaproxy/zap/authentication/ManualAuthenticationMethodType.java +++ b/zap/src/main/java/org/zaproxy/zap/authentication/ManualAuthenticationMethodType.java @@ -21,6 +21,7 @@ import java.awt.Component; import java.awt.GridBagLayout; +import java.util.Base64; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,7 +31,6 @@ import javax.swing.JList; import javax.swing.plaf.basic.BasicComboBoxRenderer; import net.sf.json.JSONObject; -import org.apache.commons.codec.binary.Base64; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.httpclient.Cookie; @@ -211,7 +211,7 @@ public String encode(String parentStringSeparator) { if (selectedSession == null) { return ""; } - return Base64.encodeBase64String(selectedSession.getName().getBytes()); + return Base64.getEncoder().encodeToString(selectedSession.getName().getBytes()); } @Override diff --git a/zap/src/main/java/org/zaproxy/zap/authentication/UsernamePasswordAuthenticationCredentials.java b/zap/src/main/java/org/zaproxy/zap/authentication/UsernamePasswordAuthenticationCredentials.java index d3fee747026..c37bd238e2c 100644 --- a/zap/src/main/java/org/zaproxy/zap/authentication/UsernamePasswordAuthenticationCredentials.java +++ b/zap/src/main/java/org/zaproxy/zap/authentication/UsernamePasswordAuthenticationCredentials.java @@ -22,6 +22,7 @@ import java.awt.GridBagLayout; import java.awt.Insets; import java.util.Arrays; +import java.util.Base64; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,7 +32,6 @@ import javax.swing.JPanel; import javax.swing.JPasswordField; import net.sf.json.JSONObject; -import org.apache.commons.codec.binary.Base64; import org.parosproxy.paros.Constant; import org.parosproxy.paros.control.Control; import org.zaproxy.zap.extension.api.ApiDynamicActionImplementor; @@ -139,8 +139,8 @@ public String encode(String parentStringSeparator) { } StringBuilder out = new StringBuilder(); - out.append(Base64.encodeBase64String(username.getBytes())).append(FIELD_SEPARATOR); - out.append(Base64.encodeBase64String(password.getBytes())).append(FIELD_SEPARATOR); + out.append(Base64.getEncoder().encodeToString(username.getBytes())).append(FIELD_SEPARATOR); + out.append(Base64.getEncoder().encodeToString(password.getBytes())).append(FIELD_SEPARATOR); encodeTotpData(out, FIELD_SEPARATOR); return out.toString(); } @@ -160,8 +160,8 @@ public void decode(String encodedCredentials) { return; } - this.username = new String(Base64.decodeBase64(pieces[0])); - if (pieces.length > 1) this.password = new String(Base64.decodeBase64(pieces[1])); + this.username = new String(Base64.getDecoder().decode(pieces[0])); + if (pieces.length > 1) this.password = new String(Base64.getDecoder().decode(pieces[1])); else this.password = ""; if (pieces.length > 2) { diff --git a/zap/src/main/java/org/zaproxy/zap/network/ZapNTLMEngineImpl.java b/zap/src/main/java/org/zaproxy/zap/network/ZapNTLMEngineImpl.java index 081643bc463..54e27fb4621 100644 --- a/zap/src/main/java/org/zaproxy/zap/network/ZapNTLMEngineImpl.java +++ b/zap/src/main/java/org/zaproxy/zap/network/ZapNTLMEngineImpl.java @@ -40,7 +40,7 @@ import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; -import org.apache.commons.codec.binary.Base64; +import java.util.Base64; import org.apache.commons.httpclient.auth.AuthenticationException; /* @@ -1098,7 +1098,7 @@ static class NTLMMessage { /** Constructor taking a string */ NTLMMessage(final String messageBody, final int expectedType) throws AuthenticationException { - this(Base64.decodeBase64(messageBody.getBytes(DEFAULT_CHARSET)), expectedType); + this(Base64.getDecoder().decode(messageBody.getBytes(DEFAULT_CHARSET)), expectedType); } /** Constructor to use when message bytes are known */ @@ -1234,7 +1234,7 @@ protected void addULong(final int value) { * @return The response as above. */ public String getResponse() { - return new String(Base64.encodeBase64(getBytes()), StandardCharsets.US_ASCII); + return new String(Base64.getEncoder().encode(getBytes()), StandardCharsets.US_ASCII); } public byte[] getBytes() { @@ -1382,7 +1382,7 @@ static class Type2Message extends NTLMMessage { protected final int flags; Type2Message(final String messageBody) throws AuthenticationException { - this(Base64.decodeBase64(messageBody.getBytes(DEFAULT_CHARSET))); + this(Base64.getDecoder().decode(messageBody.getBytes(DEFAULT_CHARSET))); } Type2Message(final byte[] message) throws AuthenticationException { diff --git a/zap/src/main/java/org/zaproxy/zap/users/User.java b/zap/src/main/java/org/zaproxy/zap/users/User.java index e312fded471..825f9322d5b 100644 --- a/zap/src/main/java/org/zaproxy/zap/users/User.java +++ b/zap/src/main/java/org/zaproxy/zap/users/User.java @@ -19,8 +19,8 @@ */ package org.zaproxy.zap.users; +import java.util.Base64; import java.util.List; -import org.apache.commons.codec.binary.Base64; import org.apache.commons.httpclient.HttpState; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -310,7 +310,8 @@ public static String encode(User user) { StringBuilder out = new StringBuilder(); out.append(user.id).append(FIELD_SEPARATOR); out.append(user.isEnabled()).append(FIELD_SEPARATOR); - out.append(Base64.encodeBase64String(user.name.getBytes())).append(FIELD_SEPARATOR); + out.append(Base64.getEncoder().encodeToString(user.name.getBytes())) + .append(FIELD_SEPARATOR); out.append(user.getContext().getAuthenticationMethod().getType().getUniqueIdentifier()) .append(FIELD_SEPARATOR); if (user.authenticationCredentials != null) { @@ -351,7 +352,7 @@ protected static User decode( int id = Integer.parseInt(pieces[0]); if (id >= ID_SOURCE) ID_SOURCE = id + 1; boolean enabled = pieces[1].equals("true"); - String name = new String(Base64.decodeBase64(pieces[2])); + String name = new String(Base64.getDecoder().decode(pieces[2])); int authTypeId = Integer.parseInt(pieces[3]); user = new User(contextId, name, id); user.setEnabled(enabled); diff --git a/zap/src/main/java/org/zaproxy/zap/utils/EncodingUtils.java b/zap/src/main/java/org/zaproxy/zap/utils/EncodingUtils.java index 5797ce3eee8..7b35f20d18d 100644 --- a/zap/src/main/java/org/zaproxy/zap/utils/EncodingUtils.java +++ b/zap/src/main/java/org/zaproxy/zap/utils/EncodingUtils.java @@ -19,9 +19,9 @@ */ package org.zaproxy.zap.utils; +import java.util.Base64; import java.util.HashMap; import java.util.Map; -import org.apache.commons.codec.binary.Base64; public class EncodingUtils { @@ -33,9 +33,11 @@ public static String mapToString(Map map) { stringBuilder.append("&"); } String value = map.get(key); - stringBuilder.append(key != null ? Base64.encodeBase64String(key.getBytes()) : ""); + stringBuilder.append( + key != null ? Base64.getEncoder().encodeToString(key.getBytes()) : ""); stringBuilder.append(":"); - stringBuilder.append(value != null ? Base64.encodeBase64String(value.getBytes()) : ""); + stringBuilder.append( + value != null ? Base64.getEncoder().encodeToString(value.getBytes()) : ""); } return stringBuilder.toString(); @@ -51,8 +53,10 @@ public static Map stringToMap(String input) { for (String nameValuePair : nameValuePairs) { String[] nameValue = nameValuePair.split(":", 2); map.put( - new String(Base64.decodeBase64(nameValue[0])), - nameValue.length > 1 ? new String(Base64.decodeBase64(nameValue[1])) : ""); + new String(Base64.getDecoder().decode(nameValue[0])), + nameValue.length > 1 + ? new String(Base64.getDecoder().decode(nameValue[1])) + : ""); } return map; diff --git a/zap/zap.gradle.kts b/zap/zap.gradle.kts index 284781f2961..54aaf3a61b7 100644 --- a/zap/zap.gradle.kts +++ b/zap/zap.gradle.kts @@ -65,13 +65,19 @@ tasks.named("jacocoTestReport") { spotless { java { - bumpThisNumberIfACustomStepChanges(1) + bumpThisNumberIfACustomStepChanges(2) custom( "validateImports", ValidateImports( mapOf( "import org.apache.commons.lang." to "Import/use classes from Commons Lang 3, instead of Lang 2.", + "import org.apache.commons.codec.binary.Base64" to + "Use java.util.Base64 instead.", + "import org.apache.commons.codec.binary.Hex" to + "Use java.util.HexFormat instead.", + "import org.apache.commons.codec.digest.DigestUtils" to + "Use org.zaproxy.zap.utils.DigestUtils instead.", ), ), ) @@ -90,7 +96,6 @@ dependencies { api("com.fifesoft:rsyntaxtextarea:3.6.0") api("com.github.zafarkhaja:java-semver:0.10.2") implementation("commons-beanutils:commons-beanutils:1.11.0") - api("commons-codec:commons-codec:1.20.0") api("commons-collections:commons-collections:3.2.2") api("commons-configuration:commons-configuration:1.10") api("commons-httpclient:commons-httpclient:3.1")