View Javadoc
1   package org.apache.maven.plugin.install;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.codec.binary.Hex;
23  import org.apache.maven.plugin.MojoExecutionException;
24  import org.codehaus.plexus.util.IOUtil;
25  import org.codehaus.plexus.util.StringUtils;
26  
27  import java.io.*;
28  import java.security.MessageDigest;
29  import java.util.regex.Matcher;
30  import java.util.regex.Pattern;
31  
32  /**
33   * @author Kristian Rosenvold
34   */
35  public class SimpleDigester
36  {
37  
38      private final MessageDigest messageDigest;
39  
40      private static final int bufsize = 65536;
41  
42      public SimpleDigester( String algorithm )
43      {
44          messageDigest = DualDigester.getDigester( algorithm );
45      }
46  
47      public static SimpleDigester md5()
48      {
49          return new SimpleDigester( "MD5" );
50      }
51  
52      public static SimpleDigester sha1()
53      {
54          return new SimpleDigester( "SHA-1" );
55      }
56  
57      public String calculate( File file )
58          throws MojoExecutionException
59      {
60          FileInputStream fis = null;
61          BufferedInputStream bis = null;
62  
63          try
64          {
65              fis = new FileInputStream( file );
66              int bufsiz = (int) Math.min( file.length(), bufsize );
67              bis = new BufferedInputStream( fis, bufsiz );
68              messageDigest.reset();
69              update( bis );
70              return Hex.encodeHexString( messageDigest.digest() );
71          }
72          catch ( IOException e )
73          {
74              throw new MojoExecutionException(
75                  "Failed to calculate " + messageDigest.getAlgorithm() + " checksum for " + file, e );
76          }
77          finally
78          {
79              IOUtil.close( bis );
80              IOUtil.close( fis );
81          }
82      }
83  
84      private void update( InputStream is )
85          throws IOException
86      {
87          byte[] buffer = new byte[bufsize];
88          int size = is.read( buffer, 0, bufsize );
89          while ( size >= 0 )
90          {
91              messageDigest.update( buffer, 0, size );
92              size = is.read( buffer, 0, bufsize );
93          }
94      }
95  
96      public void verify( File file, String checksum )
97          throws MojoExecutionException
98      {
99          String trimmed = cleanChecksum( checksum, messageDigest.getAlgorithm(), file.getName() );
100         String sum = calculate( file );
101         if ( !StringUtils.equalsIgnoreCase( trimmed, sum ) )
102         {
103             throw new RuntimeException( "Checksum failed (expected=" + trimmed + ", actual=" + sum + ")" );
104         }
105     }
106 
107     private static String cleanChecksum( String checksum, String algorithm, String path )
108     {
109         String trimmed = checksum.replace( '\n', ' ' ).trim();
110 
111         // Free-BSD / openssl
112         String regex = algorithm.replaceAll( "-", "" ) + "\\s*\\((.*?)\\)\\s*=\\s*([a-fA-F0-9]+)";
113         Matcher m = Pattern.compile( regex ).matcher( trimmed );
114         if ( m.matches() )
115         {
116             String filename = m.group( 1 );
117             if ( !isValidChecksumPattern( filename, path ) )
118             {
119                 throw new RuntimeException( "Supplied checksum does not match checksum pattern" );
120             }
121             trimmed = m.group( 2 );
122         }
123         else
124         {
125             // GNU tools
126             m = Pattern.compile( "([a-fA-F0-9]+)\\s+\\*?(.+)" ).matcher( trimmed );
127             if ( m.matches() )
128             {
129                 String filename = m.group( 2 );
130                 if ( !isValidChecksumPattern( filename, path ) )
131                 {
132                     throw new RuntimeException( "Supplied checksum does not match checksum pattern" );
133                 }
134                 trimmed = m.group( 1 );
135             }
136         }
137         return trimmed;
138     }
139 
140     private static boolean isValidChecksumPattern( String filename, String path )
141     {
142         return filename.endsWith( path ) || filename.equals( "-" );
143     }
144 
145 }