Skip to content

Commit d9d53f6

Browse files
committed
[CODEC-337] Digest ALL reuses System.in, so only the first algorithm
sees the real input
1 parent d317962 commit d9d53f6

2 files changed

Lines changed: 79 additions & 31 deletions

File tree

src/main/java/org/apache/commons/codec/cli/Digest.java

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17+
1718
package org.apache.commons.codec.cli;
1819

20+
import java.io.BufferedInputStream;
1921
import java.io.File;
2022
import java.io.IOException;
2123
import java.nio.charset.Charset;
@@ -36,18 +38,17 @@
3638
*/
3739
public class Digest {
3840

41+
private static final String EMPTY = "";
42+
3943
/**
40-
* Runs the digest algorithm in {@code args[0]} on the file in {@code args[1]}. If there is no {@code args[1]}, use
41-
* standard input.
44+
* Runs the digest algorithm in {@code args[0]} on the file in {@code args[1]}. If there is no {@code args[1]}, use standard input.
4245
*
4346
* <p>
4447
* The algorithm can also be {@code ALL} or {@code *} to output one line for each known algorithm.
4548
* </p>
4649
*
47-
* @param args
48-
* {@code args[0]} is one of {@link MessageDigestAlgorithms} name,
49-
* {@link MessageDigest} name, {@code ALL}, or {@code *}.
50-
* {@code args[1+]} is a FILE/DIRECTORY/String.
50+
* @param args {@code args[0]} is one of {@link MessageDigestAlgorithms} name, {@link MessageDigest} name, {@code ALL}, or {@code *}. {@code args[1+]} is a
51+
* FILE/DIRECTORY/String.
5152
* @throws IOException if an error occurs.
5253
*/
5354
public static void main(final String[] args) throws IOException {
@@ -62,16 +63,11 @@ private Digest(final String[] args) {
6263
Objects.requireNonNull(args);
6364
final int argsLength = args.length;
6465
if (argsLength == 0) {
65-
throw new IllegalArgumentException(
66-
String.format("Usage: java %s [algorithm] [FILE|DIRECTORY|string] ...", Digest.class.getName()));
66+
throw new IllegalArgumentException(String.format("Usage: java %s [algorithm] [FILE|DIRECTORY|string] ...", Digest.class.getName()));
6767
}
6868
this.args = args;
6969
this.algorithm = args[0];
70-
if (argsLength <= 1) {
71-
this.inputs = null;
72-
} else {
73-
this.inputs = Arrays.copyOfRange(args, 1, argsLength);
74-
}
70+
this.inputs = argsLength > 1 ? Arrays.copyOfRange(args, 1, argsLength) : null;
7571
}
7672

7773
private void println(final String prefix, final byte[] digest) {
@@ -84,25 +80,26 @@ private void println(final String prefix, final byte[] digest, final String file
8480
// where '*' is used for binary files
8581
// shasum(1) has a -b option which generates " *" separator
8682
// we don't distinguish binary files at present
87-
System.out.println(prefix + Hex.encodeHexString(digest) + (fileName != null ? " " + fileName : ""));
83+
System.out.println(prefix + Hex.encodeHexString(digest) + (fileName != null ? " " + fileName : EMPTY));
8884
}
8985

9086
private void run() throws IOException {
87+
final BufferedInputStream systemIn = inputs != null ? null : new BufferedInputStream(System.in);
9188
if (algorithm.equalsIgnoreCase("ALL") || algorithm.equals("*")) {
92-
run(MessageDigestAlgorithms.values());
89+
run(systemIn, MessageDigestAlgorithms.values());
9390
return;
9491
}
9592
final MessageDigest messageDigest = DigestUtils.getDigest(algorithm, null);
9693
if (messageDigest != null) {
97-
run("", messageDigest);
94+
run(systemIn, EMPTY, messageDigest);
9895
} else {
99-
run("", DigestUtils.getDigest(algorithm.toUpperCase(Locale.ROOT)));
96+
run(systemIn, EMPTY, DigestUtils.getDigest(algorithm.toUpperCase(Locale.ROOT)));
10097
}
10198
}
10299

103-
private void run(final String prefix, final MessageDigest messageDigest) throws IOException {
100+
private void run(final BufferedInputStream systemIn, final String prefix, final MessageDigest messageDigest) throws IOException {
104101
if (inputs == null) {
105-
println(prefix, DigestUtils.digest(messageDigest, System.in));
102+
println(prefix, DigestUtils.digest(messageDigest, systemIn));
106103
return;
107104
}
108105
for (final String source : inputs) {
@@ -122,22 +119,29 @@ private void run(final String prefix, final MessageDigest messageDigest) throws
122119
}
123120
}
124121

125-
private void run(final String prefix, final MessageDigest messageDigest, final File[] files) throws IOException {
126-
for (final File file : files) {
127-
if (file.isFile()) {
128-
println(prefix, DigestUtils.digest(messageDigest, file), file.getName());
129-
}
130-
}
131-
}
132-
133-
private void run(final String prefix, final String messageDigestAlgorithm) throws IOException {
134-
run(prefix, DigestUtils.getDigest(messageDigestAlgorithm));
122+
private void run(final BufferedInputStream systemIn, final String prefix, final String messageDigestAlgorithm) throws IOException {
123+
run(systemIn, prefix, DigestUtils.getDigest(messageDigestAlgorithm));
135124
}
136125

137-
private void run(final String[] digestAlgorithms) throws IOException {
126+
private void run(final BufferedInputStream systemIn, final String[] digestAlgorithms) throws IOException {
138127
for (final String messageDigestAlgorithm : digestAlgorithms) {
139128
if (DigestUtils.isAvailable(messageDigestAlgorithm)) {
140-
run(messageDigestAlgorithm + " ", messageDigestAlgorithm);
129+
if (systemIn != null) {
130+
// 1 GB arbitrary default.
131+
systemIn.mark(Integer.getInteger(getClass().getName() + ".markReadLimit", 1_073_741_824));
132+
}
133+
run(systemIn, messageDigestAlgorithm + " ", messageDigestAlgorithm);
134+
if (systemIn != null) {
135+
systemIn.reset();
136+
}
137+
}
138+
}
139+
}
140+
141+
private void run(final String prefix, final MessageDigest messageDigest, final File[] files) throws IOException {
142+
for (final File file : files) {
143+
if (file.isFile()) {
144+
println(prefix, DigestUtils.digest(messageDigest, file), file.getName());
141145
}
142146
}
143147
}

src/test/java/org/apache/commons/codec/cli/DigestTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,58 @@
1818
package org.apache.commons.codec.cli;
1919

2020
import static org.junit.jupiter.api.Assertions.assertThrows;
21+
import static org.junit.jupiter.api.Assertions.assertTrue;
2122

23+
import java.io.ByteArrayInputStream;
24+
import java.io.ByteArrayOutputStream;
25+
import java.io.InputStream;
26+
import java.io.PrintStream;
27+
import java.nio.charset.StandardCharsets;
28+
29+
import org.apache.commons.lang3.JavaVersion;
30+
import org.apache.commons.lang3.SystemUtils;
2231
import org.junit.jupiter.api.Test;
2332

2433
/**
2534
* Tests {@link Digest}.
2635
*/
2736
class DigestTest {
2837

38+
@Test
39+
void testAllAlgorithmsUseTheSameStandardInput() throws Exception {
40+
final InputStream originalIn = System.in;
41+
final PrintStream originalOut = System.out;
42+
final ByteArrayOutputStream captured = new ByteArrayOutputStream();
43+
try {
44+
System.setIn(new ByteArrayInputStream("abc".getBytes(StandardCharsets.UTF_8)));
45+
System.setOut(new PrintStream(captured, true, StandardCharsets.UTF_8.name()));
46+
Digest.main(new String[] { "ALL" });
47+
} finally {
48+
System.setIn(originalIn);
49+
System.setOut(originalOut);
50+
}
51+
final String output = captured.toString(StandardCharsets.UTF_8.name());
52+
assertTrue(output.contains("MD2 da853b0d3f88d99b30283a69e6ded6bb"), output);
53+
assertTrue(output.contains("MD5 900150983cd24fb0d6963f7d28e17f72"), output);
54+
assertTrue(output.contains("SHA-1 a9993e364706816aba3e25717850c26c9cd0d89d"), output);
55+
assertTrue(output.contains("SHA-224 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"), output);
56+
assertTrue(output.contains("SHA-256 ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"), output);
57+
assertTrue(output.contains("SHA-384 cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"), output);
58+
assertTrue(output.contains(
59+
"SHA-512 ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"),
60+
output);
61+
assertTrue(output.contains("SHA-512/224 4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"), output);
62+
assertTrue(output.contains("SHA-512/256 53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"), output);
63+
if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_9)) {
64+
assertTrue(output.contains("SHA3-224 e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf"), output);
65+
assertTrue(output.contains("SHA3-256 3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"), output);
66+
assertTrue(output.contains("SHA3-384 ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"), output);
67+
assertTrue(output.contains(
68+
"SHA3-512 b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"),
69+
output);
70+
}
71+
}
72+
2973
/**
3074
* Tests if empty arguments are handled correctly.
3175
*/

0 commit comments

Comments
 (0)