From: Joakim Erdfelt Date: Mon, 14 Apr 2008 02:43:41 +0000 (+0000) Subject: Moving archiva-checksum into place in trunk. (will enable it into the build in a... X-Git-Tag: archiva-r676265~196 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=7e654c7bbbe92e13430752d8ebdf0f80b121e6f6;p=archiva.git Moving archiva-checksum into place in trunk. (will enable it into the build in a future commit) git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@647648 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/archiva-modules/archiva-base/archiva-checksum/pom.xml b/archiva-modules/archiva-base/archiva-checksum/pom.xml new file mode 100644 index 000000000..fb23cc6bf --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/pom.xml @@ -0,0 +1,65 @@ + + + + 4.0.0 + + org.apache.archiva + archiva-modules + 1.1-SNAPSHOT + + archiva-checksum + Archiva Checksum + 1.0-SNAPSHOT + + jar + + + + + maven-compiler-plugin + + 1.5 + 1.5 + + + + + + + + org.slf4j + slf4j-api + + + commons-lang + commons-lang + 2.1 + + + org.apache.commons + commons-io + 1.3.2 + + + junit + junit + 3.8.1 + test + + + + diff --git a/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/Checksum.java b/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/Checksum.java new file mode 100644 index 000000000..fd6943260 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/Checksum.java @@ -0,0 +1,105 @@ +package org.apache.archiva.checksum; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.IOException; +import java.io.InputStream; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.output.NullOutputStream; + +/** + * Checksum - simple checksum hashing routines. + * + * @author Joakim Erdfelt + * @version $Id$ + */ +public class Checksum +{ + private static final int BUFFER_SIZE = 32768; + + public static void update( List checksums, InputStream stream ) + throws IOException + { + byte[] buffer = new byte[BUFFER_SIZE]; + int size = stream.read( buffer, 0, BUFFER_SIZE ); + while ( size >= 0 ) + { + for ( Checksum checksum : checksums ) + { + checksum.update( buffer, 0, size ); + } + size = stream.read( buffer, 0, BUFFER_SIZE ); + } + } + + protected final MessageDigest md; + + private ChecksumAlgorithm checksumAlgorithm; + + public Checksum( ChecksumAlgorithm checksumAlgorithm ) + { + this.checksumAlgorithm = checksumAlgorithm; + try + { + md = MessageDigest.getInstance( checksumAlgorithm.getAlgorithm() ); + } + catch ( NoSuchAlgorithmException e ) + { + // Not really possible, but here none-the-less + throw new IllegalStateException( "Unable to initialize MessageDigest algorithm " + checksumAlgorithm.getAlgorithm() + + " : " + e.getMessage(), e ); + } + } + + public String getChecksum() + { + return Hex.encode( md.digest() ); + } + + public ChecksumAlgorithm getAlgorithm() + { + return this.checksumAlgorithm; + } + + public void reset() + { + md.reset(); + } + + public Checksum update( byte[] buffer, int offset, int size ) + { + md.update( buffer, 0, size ); + return this; + } + + public Checksum update( InputStream stream ) + throws IOException + { + DigestInputStream dig = new DigestInputStream( stream, md ); + IOUtils.copy( dig, new NullOutputStream() ); + + return this; + } +} diff --git a/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/ChecksumAlgorithm.java b/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/ChecksumAlgorithm.java new file mode 100644 index 000000000..69be9df06 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/ChecksumAlgorithm.java @@ -0,0 +1,96 @@ +package org.apache.archiva.checksum; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; + +import org.apache.commons.io.FilenameUtils; + +/** + * Enumeration of available ChecksumAlgorithm techniques. + * + * @author Joakim Erdfelt + * @version $Id$ + */ +public enum ChecksumAlgorithm { + SHA1("SHA-1", "sha1", "SHA1"), + MD5("MD5", "md5", "MD5"); + + public static ChecksumAlgorithm getByExtension( File file ) + { + String ext = FilenameUtils.getExtension( file.getName() ).toLowerCase(); + if ( ChecksumAlgorithm.SHA1.getExt().equals( ext ) ) + { + return ChecksumAlgorithm.SHA1; + } + else if ( ChecksumAlgorithm.MD5.getExt().equals( ext ) ) + { + return ChecksumAlgorithm.MD5; + } + + throw new IllegalArgumentException( "Filename " + file.getName() + " has no associated extension." ); + } + + /** + * The MessageDigest algorithm for this hash. + */ + private String algorithm; + + /** + * The file extension for this ChecksumAlgorithm. + */ + private String ext; + + /** + * The checksum type, the key that you see in checksum files. + */ + private String type; + + /** + * Construct a ChecksumAlgorithm + * + * @param algorithm the MessageDigest algorithm + * @param ext the file extension. + * @param type the checksum type. + */ + private ChecksumAlgorithm( String algorithm, String ext, String type ) + { + this.algorithm = algorithm; + this.ext = ext; + this.type = type; + } + + public String getAlgorithm() + { + return algorithm; + } + + public String getExt() + { + return ext; + } + + public String getType() + { + return type; + } + + +} diff --git a/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/ChecksummedFile.java b/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/ChecksummedFile.java new file mode 100644 index 000000000..4f6b4276a --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/ChecksummedFile.java @@ -0,0 +1,329 @@ +package org.apache.archiva.checksum; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ChecksummedFile + * + *
+ * Terminology: + *
Checksum File
+ *
The file that contains the previously calculated checksum value for the reference file. + * This is a text file with the extension ".sha1" or ".md5", and contains a single entry + * consisting of an optional reference filename, and a checksum string. + *
+ *
Reference File
+ *
The file that is being referenced in the checksum file.
+ *
+ * + * @author Joakim Erdfelt + * @version $Id$ + */ +public class ChecksummedFile +{ + private Logger log = LoggerFactory.getLogger( ChecksummedFile.class ); + + private final File referenceFile; + + /** + * Construct a ChecksummedFile object. + * + * @param referenceFile + */ + public ChecksummedFile( final File referenceFile ) + { + this.referenceFile = referenceFile; + } + + /** + * Calculate the checksum based on a given checksum. + * + * @param checksumAlgorithm the algorithm to use. + * @return the checksum string for the file. + * @throws IOException if unable to calculate the checksum. + */ + public String calculateChecksum( ChecksumAlgorithm checksumAlgorithm ) + throws IOException + { + FileInputStream fis = null; + try + { + Checksum checksum = new Checksum( checksumAlgorithm ); + fis = new FileInputStream( referenceFile ); + checksum.update( fis ); + return checksum.getChecksum(); + } + finally + { + IOUtils.closeQuietly( fis ); + } + } + + /** + * Creates a checksum file of the provided referenceFile. + * @param checksumAlgorithm the hash to use. + * + * @return the checksum File that was created. + * @throws IOException if there was a problem either reading the referenceFile, or writing the checksum file. + */ + public File createChecksum( ChecksumAlgorithm checksumAlgorithm ) + throws IOException + { + File checksumFile = new File( referenceFile.getAbsolutePath() + "." + checksumAlgorithm.getExt() ); + String checksum = calculateChecksum( checksumAlgorithm ); + FileUtils.writeStringToFile( checksumFile, checksum + " " + referenceFile.getName() ); + return checksumFile; + } + + /** + * Get the checksum file for the reference file and hash. + * + * @param checksumAlgorithm the hash that we are interested in. + * @return the checksum file to return + */ + public File getChecksumFile( ChecksumAlgorithm checksumAlgorithm ) + { + return new File( referenceFile.getAbsolutePath() + "." + checksumAlgorithm.getExt() ); + } + + /** + *

+ * Given a checksum file, check to see if the file it represents is valid according to the checksum. + *

+ * + *

+ * NOTE: Only supports single file checksums of type MD5 or SHA1. + *

+ * + * @param checksumFile the algorithms to check for. + * @return true if the checksum is valid for the file it represents. or if the checksum file does not exist. + * @throws IOException if the reading of the checksumFile or the file it refers to fails. + */ + public boolean isValidChecksum( ChecksumAlgorithm algorithm ) + throws IOException + { + return isValidChecksums( new ChecksumAlgorithm[] { algorithm } ); + } + + /** + * Of any checksum files present, validate that the reference file conforms + * the to the checksum. + * + * @param algorithms the algorithms to check for. + * @return true if the checksums report that the the reference file is valid. + * @throws IOException if unable to validate the checksums. + */ + public boolean isValidChecksums( ChecksumAlgorithm algorithms[] ) + throws IOException + { + FileInputStream fis = null; + try + { + List checksums = new ArrayList(); + // Create checksum object for each algorithm. + for ( ChecksumAlgorithm checksumAlgorithm : algorithms ) + { + File checksumFile = getChecksumFile( checksumAlgorithm ); + + // Only add algorithm if checksum file exists. + if ( checksumFile.exists() ) + { + checksums.add( new Checksum( checksumAlgorithm ) ); + } + } + + // Any checksums? + if ( checksums.isEmpty() ) + { + // No checksum objects, no checksum files, default to is valid. + return true; + } + + // Parse file once, for all checksums. + fis = new FileInputStream( referenceFile ); + Checksum.update( checksums, fis ); + + boolean valid = true; + + // check the checksum files + for ( Checksum checksum : checksums ) + { + ChecksumAlgorithm checksumAlgorithm = checksum.getAlgorithm(); + File checksumFile = getChecksumFile( checksumAlgorithm ); + + String rawChecksum = FileUtils.readFileToString( checksumFile ); + String expectedChecksum = parseChecksum( rawChecksum, checksumAlgorithm, referenceFile.getName() ); + + if ( StringUtils.equalsIgnoreCase( expectedChecksum, checksum.getChecksum() ) == false ) + { + valid = false; + } + } + + return valid; + } + finally + { + IOUtils.closeQuietly( fis ); + } + } + + /** + * Fix or create checksum files for the reference file. + * + * @param algorithms the hashes to check for. + * @return true if checksums were created successfully. + */ + public boolean fixChecksums( ChecksumAlgorithm algorithms[] ) + { + List checksums = new ArrayList(); + // Create checksum object for each algorithm. + for ( ChecksumAlgorithm checksumAlgorithm : algorithms ) + { + checksums.add( new Checksum( checksumAlgorithm ) ); + } + + // Any checksums? + if ( checksums.isEmpty() ) + { + // No checksum objects, no checksum files, default to is valid. + return true; + } + + FileInputStream fis = null; + try + { + // Parse file once, for all checksums. + fis = new FileInputStream( referenceFile ); + Checksum.update( checksums, fis ); + } + catch ( IOException e ) + { + log.warn( e.getMessage(), e ); + return false; + } + finally + { + IOUtils.closeQuietly( fis ); + } + + boolean valid = true; + + // check the hash files + for ( Checksum checksum : checksums ) + { + ChecksumAlgorithm checksumAlgorithm = checksum.getAlgorithm(); + try + { + File checksumFile = getChecksumFile( checksumAlgorithm ); + String actualChecksum = checksum.getChecksum(); + + if ( checksumFile.exists() ) + { + String rawChecksum = FileUtils.readFileToString( checksumFile ); + String expectedChecksum = parseChecksum( rawChecksum, checksumAlgorithm, referenceFile.getName() ); + + if ( StringUtils.equalsIgnoreCase( expectedChecksum, actualChecksum ) == false ) + { + // create checksum (again) + FileUtils.writeStringToFile( checksumFile, actualChecksum + " " + referenceFile.getName() ); + } + } + else + { + FileUtils.writeStringToFile( checksumFile, actualChecksum + " " + referenceFile.getName() ); + } + } + catch ( IOException e ) + { + log.warn( e.getMessage(), e ); + valid = false; + } + } + + return valid; + + } + + private boolean isValidChecksumPattern( String filename, String path ) + { + return filename.endsWith( path ) || ( "-".equals( filename ) ); + } + + /** + * Parse a checksum string. + * + * Validate the expected path, and expected checksum algorithm, then return + * the trimmed checksum hex string. + * + * @param rawChecksumString + * @param expectedHash + * @param expectedPath + * @return + * @throws IOException + */ + public String parseChecksum( String rawChecksumString, ChecksumAlgorithm expectedHash, String expectedPath ) + throws IOException + { + String trimmedChecksum = rawChecksumString.replace( '\n', ' ' ).trim(); + + // Free-BSD / openssl + String regex = expectedHash.getType() + "\\s*\\(([^)]*)\\)\\s*=\\s*([a-fA-F0-9]+)"; + Matcher m = Pattern.compile( regex ).matcher( trimmedChecksum ); + if ( m.matches() ) + { + String filename = m.group( 1 ); + if ( !isValidChecksumPattern( filename, expectedPath ) ) + { + throw new IOException( "Supplied checksum does not match checksum pattern" ); + } + trimmedChecksum = m.group( 2 ); + } + else + { + // GNU tools + m = Pattern.compile( "([a-fA-F0-9]+)\\s+\\*?(.+)" ).matcher( trimmedChecksum ); + if ( m.matches() ) + { + String filename = m.group( 2 ); + if ( !isValidChecksumPattern( filename, expectedPath ) ) + { + throw new IOException( "Supplied checksum does not match checksum pattern" ); + } + trimmedChecksum = m.group( 1 ); + } + } + return trimmedChecksum; + } +} diff --git a/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/Hex.java b/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/Hex.java new file mode 100644 index 000000000..03f65290e --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/Hex.java @@ -0,0 +1,32 @@ +package org.apache.archiva.checksum; + +/** + * Hex - simple hex conversions. + * + * @version $Id$ + */ +public class Hex +{ + private static final byte[] DIGITS = "0123456789abcdef".getBytes(); + + public static String encode( byte[] data ) + { + int l = data.length; + + byte[] raw = new byte[l * 2]; + + for ( int i = 0, j = 0; i < l; i++ ) + { + raw[j++] = DIGITS[( 0xF0 & data[i] ) >>> 4]; + raw[j++] = DIGITS[0x0F & data[i]]; + } + + return new String( raw ); + } + + public static String encode( String raw ) + { + return encode( raw.getBytes() ); + } + +} diff --git a/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/AbstractChecksumTestCase.java b/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/AbstractChecksumTestCase.java new file mode 100644 index 000000000..73f163672 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/AbstractChecksumTestCase.java @@ -0,0 +1,77 @@ +package org.apache.archiva.checksum; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; + +import junit.framework.TestCase; + +/** + * AbstractChecksumTestCase + * + * @author Joakim Erdfelt + * @version $Id$ + */ +public abstract class AbstractChecksumTestCase + extends TestCase +{ + private File basedir; + + public File getBasedir() + { + if ( basedir == null ) + { + String sysprop = System.getProperty( "basedir" ); + if ( sysprop != null ) + { + basedir = new File( sysprop ); + } + else + { + basedir = new File( System.getProperty( "user.dir" ) ); + } + } + return basedir; + } + + public File getTestOutputDir() + { + File dir = new File( getBasedir(), "target/test-output/" + getName() ); + if ( dir.exists() == false ) + { + if ( dir.mkdirs() == false ) + { + fail( "Unable to create test output directory: " + dir.getAbsolutePath() ); + } + } + return dir; + } + + public File getTestResource( String filename ) + { + File dir = new File( getBasedir(), "src/test/resources" ); + File file = new File( dir, filename ); + if ( file.exists() == false ) + { + fail( "Test Resource does not exist: " + file.getAbsolutePath() ); + } + return file; + } +} diff --git a/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksumAlgorithmTest.java b/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksumAlgorithmTest.java new file mode 100644 index 000000000..f6b91ac97 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksumAlgorithmTest.java @@ -0,0 +1,59 @@ +package org.apache.archiva.checksum; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; + +import junit.framework.TestCase; + +/** + * ChecksumAlgorithmTest + * + * @author Joakim Erdfelt + * @version $Id$ + */ +public class ChecksumAlgorithmTest + extends TestCase +{ + public void testGetHashByExtensionSha1() + { + assertEquals( ChecksumAlgorithm.SHA1, ChecksumAlgorithm.getByExtension( new File( "something.jar.sha1" ) ) ); + assertEquals( ChecksumAlgorithm.SHA1, ChecksumAlgorithm.getByExtension( new File( "OTHER.JAR.SHA1" ) ) ); + } + + public void testGetHashByExtensionMd5() + { + assertEquals( ChecksumAlgorithm.MD5, ChecksumAlgorithm.getByExtension( new File( "something.jar.md5" ) ) ); + assertEquals( ChecksumAlgorithm.MD5, ChecksumAlgorithm.getByExtension( new File( "OTHER.JAR.MD5" ) ) ); + } + + public void testGetHashByExtensionInvalid() + { + try + { + ChecksumAlgorithm.getByExtension( new File( "something.jar" ) ); + fail( "Expected " + IllegalArgumentException.class.getName() ); + } + catch ( IllegalArgumentException e ) + { + /* expected path */ + } + } +} diff --git a/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksumTest.java b/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksumTest.java new file mode 100644 index 000000000..f8889e70a --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksumTest.java @@ -0,0 +1,103 @@ +package org.apache.archiva.checksum; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * ChecksumTest + * + * @author Joakim Erdfelt + * @version $Id$ + */ +public class ChecksumTest + extends AbstractChecksumTestCase +{ + private static final String UNSET_SHA1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; + + public void testConstructSha1() + { + Checksum checksum = new Checksum( ChecksumAlgorithm.SHA1 ); + assertEquals( "Checksum.algorithm", checksum.getAlgorithm().getAlgorithm(), ChecksumAlgorithm.SHA1 + .getAlgorithm() ); + } + + public void testConstructMd5() + { + Checksum checksum = new Checksum( ChecksumAlgorithm.MD5 ); + assertEquals( "Checksum.algorithm", checksum.getAlgorithm().getAlgorithm(), ChecksumAlgorithm.MD5 + .getAlgorithm() ); + } + + public void testUpdate() + { + Checksum checksum = new Checksum( ChecksumAlgorithm.SHA1 ); + byte buf[] = ( "You know, I'm sick of following my dreams, man. " + + "I'm just going to ask where they're going and hook up with 'em later. - Mitch Hedberg" ).getBytes(); + checksum.update( buf, 0, buf.length ); + assertEquals( "Checksum", "e396119ae0542e85a74759602fd2f81e5d36d762", checksum.getChecksum() ); + } + + public void testUpdateMany() + throws IOException + { + Checksum checksumSha1 = new Checksum( ChecksumAlgorithm.SHA1 ); + Checksum checksumMd5 = new Checksum( ChecksumAlgorithm.MD5 ); + List checksums = new ArrayList(); + checksums.add( checksumSha1 ); + checksums.add( checksumMd5 ); + + byte buf[] = ( "You know, I'm sick of following my dreams, man. " + + "I'm just going to ask where they're going and hook up with 'em later. - Mitch Hedberg" ).getBytes(); + + ByteArrayInputStream stream = new ByteArrayInputStream( buf ); + Checksum.update( checksums, stream ); + + assertEquals( "Checksum SHA1", "e396119ae0542e85a74759602fd2f81e5d36d762", checksumSha1.getChecksum() ); + assertEquals( "Checksum MD5", "21c2c5ca87ec018adacb2e2fb3432219", checksumMd5.getChecksum() ); + } + + public void testUpdateWholeUpdatePartial() + { + Checksum checksum = new Checksum( ChecksumAlgorithm.SHA1 ); + assertEquals( "Checksum unset", UNSET_SHA1, checksum.getChecksum() ); + + String expected = "066c2cbbc8cdaecb8ff97dcb84502462d6f575f3"; + byte reesepieces[] = "eatagramovabits".getBytes(); + checksum.update( reesepieces, 0, reesepieces.length ); + String actual = checksum.getChecksum(); + + assertEquals( "Expected", expected, actual ); + + // Reset the checksum. + checksum.reset(); + assertEquals( "Checksum unset", UNSET_SHA1, checksum.getChecksum() ); + + // Now parse it again in 3 pieces. + checksum.update( reesepieces, 0, 5 ); + checksum.update( reesepieces, 5, 5 ); + checksum.update( reesepieces, 10, reesepieces.length - 10 ); + + assertEquals( "Expected", expected, actual ); + } +} diff --git a/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksummedFileTest.java b/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksummedFileTest.java new file mode 100644 index 000000000..3b3c93512 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksummedFileTest.java @@ -0,0 +1,226 @@ +package org.apache.archiva.checksum; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; + +/** + * ChecksummedFileTest + * + * @author Joakim Erdfelt + * @version $Id$ + */ +public class ChecksummedFileTest + extends AbstractChecksumTestCase +{ + /** SHA1 checksum from www.ibiblio.org/maven2, incuding file path */ + private static final String SERVLETAPI_SHA1 = "bcc82975c0f9c681fcb01cc38504c992553e93ba"; + + private File createTestableJar( String filename ) + throws IOException + { + File srcFile = getTestResource( filename ); + File destFile = new File( getTestOutputDir(), srcFile.getName() ); + FileUtils.copyFile( srcFile, destFile ); + return destFile; + } + + private File createTestableJar( String filename, boolean copySha1, boolean copyMd5 ) + throws IOException + { + File srcFile = getTestResource( filename ); + File jarFile = new File( getTestOutputDir(), srcFile.getName() ); + FileUtils.copyFile( srcFile, jarFile ); + + if ( copySha1 ) + { + File srcSha1 = new File( srcFile.getAbsolutePath() + ".sha1" ); + File sha1File = new File( jarFile.getAbsolutePath() + ".sha1" ); + + FileUtils.copyFile( srcSha1, sha1File ); + } + + if ( copyMd5 ) + { + File srcMd5 = new File( srcFile.getAbsolutePath() + ".md5" ); + File md5File = new File( jarFile.getAbsolutePath() + ".md5" ); + + FileUtils.copyFile( srcMd5, md5File ); + } + + return jarFile; + } + + public void testCalculateChecksumMd5() + throws IOException + { + File testfile = getTestResource( "examples/redback-authz-open.jar" ); + ChecksummedFile checksummedFile = new ChecksummedFile( testfile ); + String expectedChecksum = "f42047fe2e177ac04d0df7aa44d408be"; + String actualChecksum = checksummedFile.calculateChecksum( ChecksumAlgorithm.MD5 ); + assertEquals( expectedChecksum, actualChecksum ); + } + + public void testCalculateChecksumSha1() + throws IOException + { + File testfile = getTestResource( "examples/redback-authz-open.jar" ); + ChecksummedFile checksummedFile = new ChecksummedFile( testfile ); + String expectedChecksum = "2bb14b388973351b0a4dfe11d171965f59cc61a1"; + String actualChecksum = checksummedFile.calculateChecksum( ChecksumAlgorithm.SHA1 ); + assertEquals( expectedChecksum, actualChecksum ); + } + + public void testCreateChecksum() + throws IOException + { + File testableJar = createTestableJar( "examples/redback-authz-open.jar" ); + ChecksummedFile checksummedFile = new ChecksummedFile( testableJar ); + checksummedFile.createChecksum( ChecksumAlgorithm.SHA1 ); + File hashFile = checksummedFile.getChecksumFile( ChecksumAlgorithm.SHA1 ); + assertTrue( "ChecksumAlgorithm file should exist.", hashFile.exists() ); + String hashContents = FileUtils.readFileToString( hashFile ); + hashContents = StringUtils.trim( hashContents ); + assertEquals( "2bb14b388973351b0a4dfe11d171965f59cc61a1 redback-authz-open.jar", hashContents ); + } + + public void testFixChecksum() + throws IOException + { + File jarFile = createTestableJar( "examples/redback-authz-open.jar" ); + File sha1File = new File( jarFile.getAbsolutePath() + ".sha1" ); + + // A typical scenario seen in the wild. + FileUtils.writeStringToFile( sha1File, "sha1sum: redback-authz-open.jar: No such file or directory" ); + + ChecksummedFile checksummedFile = new ChecksummedFile( jarFile ); + assertFalse( "ChecksummedFile.isValid(SHA1) == false", checksummedFile.isValidChecksum( ChecksumAlgorithm.SHA1 ) ); + + boolean fixed = checksummedFile.fixChecksums( new ChecksumAlgorithm[] { ChecksumAlgorithm.SHA1 } ); + assertTrue( "ChecksummedFile.fixChecksums() == true", fixed ); + + assertTrue( "ChecksummedFile.isValid(SHA1) == true", checksummedFile.isValidChecksum( ChecksumAlgorithm.SHA1 ) ); + } + + public void testGetChecksumFile() + { + ChecksummedFile checksummedFile = new ChecksummedFile( new File( "test.jar" ) ); + assertEquals( "test.jar.sha1", checksummedFile.getChecksumFile( ChecksumAlgorithm.SHA1 ).getName() ); + } + + public void testIsValidChecksum() + throws IOException + { + File jarFile = createTestableJar( "examples/redback-authz-open.jar", true, false ); + + ChecksummedFile checksummedFile = new ChecksummedFile( jarFile ); + assertTrue( "ChecksummedFile.isValid(SHA1)", checksummedFile.isValidChecksum( ChecksumAlgorithm.SHA1 ) ); + } + + public void testIsValidChecksumInvalidSha1Format() + throws IOException + { + File jarFile = createTestableJar( "examples/redback-authz-open.jar" ); + File sha1File = new File( jarFile.getAbsolutePath() + ".sha1" ); + + // A typical scenario seen in the wild. + FileUtils.writeStringToFile( sha1File, "sha1sum: redback-authz-open.jar: No such file or directory" ); + + ChecksummedFile checksummedFile = new ChecksummedFile( jarFile ); + assertFalse( "ChecksummedFile.isValid(SHA1)", checksummedFile.isValidChecksum( ChecksumAlgorithm.SHA1 ) ); + + } + + public void testIsValidChecksumNoChecksumFiles() + throws IOException + { + File jarFile = createTestableJar( "examples/redback-authz-open.jar", false, false ); + + ChecksummedFile checksummedFile = new ChecksummedFile( jarFile ); + assertTrue( "ChecksummedFile.isValid(SHA1,MD5)", checksummedFile.isValidChecksums( new ChecksumAlgorithm[] { + ChecksumAlgorithm.SHA1, + ChecksumAlgorithm.MD5 } ) ); + + } + + public void testIsValidChecksumSha1AndMd5() + throws IOException + { + File jarFile = createTestableJar( "examples/redback-authz-open.jar", true, true ); + + ChecksummedFile checksummedFile = new ChecksummedFile( jarFile ); + assertTrue( "ChecksummedFile.isValid(SHA1,MD5)", checksummedFile.isValidChecksums( new ChecksumAlgorithm[] { + ChecksumAlgorithm.SHA1, + ChecksumAlgorithm.MD5 } ) ); + } + + public void testIsValidChecksumSha1NoMd5() + throws IOException + { + File jarFile = createTestableJar( "examples/redback-authz-open.jar", true, false ); + + ChecksummedFile checksummedFile = new ChecksummedFile( jarFile ); + assertTrue( "ChecksummedFile.isValid(SHA1)", checksummedFile.isValidChecksums( new ChecksumAlgorithm[] { + ChecksumAlgorithm.SHA1, + ChecksumAlgorithm.MD5 } ) ); + + } + + public void testParseChecksum() + throws IOException + { + String expected = SERVLETAPI_SHA1 + + " /home/projects/maven/repository-staging/to-ibiblio/maven2/servletapi/servletapi/2.4/servletapi-2.4.pom"; + + File testfile = getTestResource( "examples/redback-authz-open.jar" ); + ChecksummedFile checksummedFile = new ChecksummedFile( testfile ); + String s = checksummedFile.parseChecksum( expected, ChecksumAlgorithm.SHA1, + "servletapi/servletapi/2.4/servletapi-2.4.pom" ); + assertEquals( "Checksum doesn't match", SERVLETAPI_SHA1, s ); + + } + + public void testParseChecksumAltDash1() + throws IOException + { + String expected = SERVLETAPI_SHA1 + " -"; + File testfile = getTestResource( "examples/redback-authz-open.jar" ); + ChecksummedFile checksummedFile = new ChecksummedFile( testfile ); + String s = checksummedFile.parseChecksum( expected, ChecksumAlgorithm.SHA1, + "servletapi/servletapi/2.4/servletapi-2.4.pom" ); + assertEquals( "Checksum doesn't match", SERVLETAPI_SHA1, s ); + } + + public void testParseChecksumAltDash2() + throws IOException + { + String expected = "SHA1(-)=" + SERVLETAPI_SHA1; + File testfile = getTestResource( "examples/redback-authz-open.jar" ); + ChecksummedFile checksummedFile = new ChecksummedFile( testfile ); + String s = checksummedFile.parseChecksum( expected, ChecksumAlgorithm.SHA1, + "servletapi/servletapi/2.4/servletapi-2.4.pom" ); + assertEquals( "Checksum doesn't match", SERVLETAPI_SHA1, s ); + } + +} diff --git a/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar new file mode 100644 index 000000000..fada8a200 Binary files /dev/null and b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar differ diff --git a/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar.md5 b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar.md5 new file mode 100644 index 000000000..51fd87406 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar.md5 @@ -0,0 +1 @@ +f42047fe2e177ac04d0df7aa44d408be redback-authz-open.jar diff --git a/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar.sha1 b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar.sha1 new file mode 100644 index 000000000..3381c3c4a --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar.sha1 @@ -0,0 +1 @@ +2bb14b388973351b0a4dfe11d171965f59cc61a1 redback-authz-open.jar diff --git a/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar new file mode 100644 index 000000000..a7db699d1 Binary files /dev/null and b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar differ diff --git a/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar.md5 b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar.md5 new file mode 100644 index 000000000..e5e4348c6 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar.md5 @@ -0,0 +1 @@ +MD5 ("redback-keys-api.jar") = 5628d13ea40c238a049d8f104811485c diff --git a/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar.sha1 b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar.sha1 new file mode 100644 index 000000000..d9395602d --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar.sha1 @@ -0,0 +1 @@ +SHA1 ("redback-keys-api.jar") = 266548fcba2c32b3999291e8303d58813c3794e3