package org.carlspring.strongbox.io; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import org.apache.commons.codec.digest.MessageDigestAlgorithms; import org.carlspring.commons.encryption.EncryptionAlgorithmsEnum; import org.carlspring.commons.util.MessageDigestUtils; import org.carlspring.strongbox.artifact.coordinates.ArtifactCoordinates; /** * @author mtodorov */ public class ArtifactInputStream extends FilterInputStream { public static final String[] DEFAULT_ALGORITHMS = { EncryptionAlgorithmsEnum.MD5.getAlgorithm(), EncryptionAlgorithmsEnum.SHA1.getAlgorithm(), }; private ArtifactCoordinates artifactCoordinates; private Map<String, MessageDigest> digests = new LinkedHashMap<>(); private Map<String, String> hexDigests = new LinkedHashMap<>(); public ArtifactInputStream(ArtifactCoordinates coordinates, InputStream is, Set<String> checkSumDigestAlgorithmSet) throws NoSuchAlgorithmException { super(is); this.artifactCoordinates = coordinates; for (String algorithm : checkSumDigestAlgorithmSet) { addAlgorithm(algorithm); } } public ArtifactInputStream(ArtifactCoordinates coordinates, InputStream is) throws NoSuchAlgorithmException { this(coordinates, is, new HashSet<String>() { { add(MessageDigestAlgorithms.MD5); add(MessageDigestAlgorithms.SHA_1); } }); } public ArtifactCoordinates getArtifactCoordinates() { return artifactCoordinates; } public final void addAlgorithm(String algorithm) throws NoSuchAlgorithmException { MessageDigest digest = MessageDigest.getInstance(algorithm); digests.put(algorithm, digest); } public MessageDigest getMessageDigest(String algorithm) { return digests.get(algorithm); } public Map<String, MessageDigest> getDigests() { return digests; } public void resetHexDidests() { hexDigests.clear(); } public Map<String, String> getHexDigests() { return hexDigests; } public String getMessageDigestAsHexadecimalString(String algorithm) { if (hexDigests.containsKey(algorithm)) { return hexDigests.get(algorithm); } else { // This method will invoke MessageDigest.digest() which will reset the bytes when it's done // and thus this data will no longer be available, so we'll need to cache the calculated digest String hexDigest = MessageDigestUtils.convertToHexadecimalString(getMessageDigest(algorithm)); hexDigests.put(algorithm, hexDigest); return hexDigest; } } public void setDigests(Map<String, MessageDigest> digests) { this.digests = digests; } @Override public int read() throws IOException { int ch = in.read(); if (ch != -1) { for (Map.Entry entry : digests.entrySet()) { MessageDigest digest = (MessageDigest) entry.getValue(); digest.update((byte) ch); } } return ch; } @Override public int read(byte[] bytes, int off, int len) throws IOException { int numberOfBytesRead = in.read(bytes, off, len); if (numberOfBytesRead != -1) { for (Map.Entry entry : digests.entrySet()) { MessageDigest digest = (MessageDigest) entry.getValue(); digest.update(bytes, off, numberOfBytesRead); } } return numberOfBytesRead; } @Override public int read(byte[] bytes) throws IOException { int len = in.read(bytes); for (Map.Entry entry : digests.entrySet()) { MessageDigest digest = (MessageDigest) entry.getValue(); digest.update(bytes); } return len; } InputStream getTarget() { return in; } }