]> source.dussan.org Git - archiva.git/commitdiff
Moving archiva-checksum into place in trunk. (will enable it into the build in a...
authorJoakim Erdfelt <joakime@apache.org>
Mon, 14 Apr 2008 02:43:41 +0000 (02:43 +0000)
committerJoakim Erdfelt <joakime@apache.org>
Mon, 14 Apr 2008 02:43:41 +0000 (02:43 +0000)
git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@647648 13f79535-47bb-0310-9956-ffa450edef68

15 files changed:
archiva-modules/archiva-base/archiva-checksum/pom.xml [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/Checksum.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/ChecksumAlgorithm.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/ChecksummedFile.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/main/java/org/apache/archiva/checksum/Hex.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/AbstractChecksumTestCase.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksumAlgorithmTest.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksumTest.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/test/java/org/apache/archiva/checksum/ChecksummedFileTest.java [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar.md5 [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar.sha1 [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar.md5 [new file with mode: 0644]
archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar.sha1 [new file with mode: 0644]

diff --git a/archiva-modules/archiva-base/archiva-checksum/pom.xml b/archiva-modules/archiva-base/archiva-checksum/pom.xml
new file mode 100644 (file)
index 0000000..fb23cc6
--- /dev/null
@@ -0,0 +1,65 @@
+<?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>
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 (file)
index 0000000..fd69432
--- /dev/null
@@ -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 <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;
+    }
+}
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 (file)
index 0000000..69be9df
--- /dev/null
@@ -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 <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;
+    }
+    
+    
+}
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 (file)
index 0000000..4f6b427
--- /dev/null
@@ -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
+ *
+ * <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;
+    }
+}
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 (file)
index 0000000..03f6529
--- /dev/null
@@ -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 (file)
index 0000000..73f1636
--- /dev/null
@@ -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 <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;
+    }
+}
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 (file)
index 0000000..f6b91ac
--- /dev/null
@@ -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 <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 */
+        }
+    }
+}
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 (file)
index 0000000..f8889e7
--- /dev/null
@@ -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 <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 );
+    }
+}
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 (file)
index 0000000..3b3c935
--- /dev/null
@@ -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 <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 );
+    }
+
+}
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 (file)
index 0000000..fada8a2
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 (file)
index 0000000..51fd874
--- /dev/null
@@ -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 (file)
index 0000000..3381c3c
--- /dev/null
@@ -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 (file)
index 0000000..a7db699
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 (file)
index 0000000..e5e4348
--- /dev/null
@@ -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 (file)
index 0000000..d939560
--- /dev/null
@@ -0,0 +1 @@
+SHA1 ("redback-keys-api.jar") = 266548fcba2c32b3999291e8303d58813c3794e3