--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2006 The Codehaus.
+ ~
+ ~ Licensed 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.archiva</groupId>
+ <artifactId>archiva-modules</artifactId>
+ <version>1.1-SNAPSHOT</version>
+ </parent>
+ <artifactId>archiva-checksum</artifactId>
+ <name>Archiva Checksum</name>
+ <version>1.0-SNAPSHOT</version>
+
+ <packaging>jar</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>1.3.2</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
--- /dev/null
+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 <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class Checksum
+{
+ private static final int BUFFER_SIZE = 32768;
+
+ public static void update( List<Checksum> 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;
+ }
+}
--- /dev/null
+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 <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @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;
+ }
+
+
+}
--- /dev/null
+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
+ *
+ * <dl>
+ * <lh>Terminology:</lh>
+ * <dt>Checksum File</dt>
+ * <dd>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.
+ * </dd>
+ * <dt>Reference File</dt>
+ * <dd>The file that is being referenced in the checksum file.</dd>
+ * </dl>
+ *
+ * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @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() );
+ }
+
+ /**
+ * <p>
+ * Given a checksum file, check to see if the file it represents is valid according to the checksum.
+ * </p>
+ *
+ * <p>
+ * NOTE: Only supports single file checksums of type MD5 or SHA1.
+ * </p>
+ *
+ * @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<Checksum> checksums = new ArrayList<Checksum>();
+ // 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<Checksum> checksums = new ArrayList<Checksum>();
+ // 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;
+ }
+}
--- /dev/null
+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() );
+ }
+
+}
--- /dev/null
+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 <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @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;
+ }
+}
--- /dev/null
+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 <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @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 */
+ }
+ }
+}
--- /dev/null
+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 <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @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<Checksum> checksums = new ArrayList<Checksum>();
+ 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 );
+ }
+}
--- /dev/null
+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 <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @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 );
+ }
+
+}
--- /dev/null
+f42047fe2e177ac04d0df7aa44d408be redback-authz-open.jar
--- /dev/null
+2bb14b388973351b0a4dfe11d171965f59cc61a1 redback-authz-open.jar
--- /dev/null
+MD5 ("redback-keys-api.jar") = 5628d13ea40c238a049d8f104811485c
--- /dev/null
+SHA1 ("redback-keys-api.jar") = 266548fcba2c32b3999291e8303d58813c3794e3