diff options
Diffstat (limited to 'archiva-modules/archiva-base/archiva-checksum')
15 files changed, 1096 insertions, 0 deletions
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 @@ +<?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 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 <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 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 <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 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 + * + * <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 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 <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 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 <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 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 <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 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 <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 Binary files differnew file mode 100644 index 000000000..fada8a200 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-authz-open.jar 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 Binary files differnew file mode 100644 index 000000000..a7db699d1 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-checksum/src/test/resources/examples/redback-keys-api.jar 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 |