git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@647648 13f79535-47bb-0310-9956-ffa450edef68tags/archiva-r676265
@@ -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> |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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() ); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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 */ | |||
} | |||
} | |||
} |
@@ -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 ); | |||
} | |||
} |
@@ -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 ); | |||
} | |||
} |
@@ -0,0 +1 @@ | |||
f42047fe2e177ac04d0df7aa44d408be redback-authz-open.jar |
@@ -0,0 +1 @@ | |||
2bb14b388973351b0a4dfe11d171965f59cc61a1 redback-authz-open.jar |
@@ -0,0 +1 @@ | |||
MD5 ("redback-keys-api.jar") = 5628d13ea40c238a049d8f104811485c |
@@ -0,0 +1 @@ | |||
SHA1 ("redback-keys-api.jar") = 266548fcba2c32b3999291e8303d58813c3794e3 |