]> source.dussan.org Git - archiva.git/blob
7e2a5e5c14ee19de40d9aa3389143edd98a3795a
[archiva.git] /
1 package org.apache.maven.repository.reporting;
2
3 /*
4  * Copyright 2005-2006 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 import org.apache.maven.artifact.Artifact;
20 import org.apache.maven.artifact.repository.ArtifactRepository;
21 import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
22 import org.apache.maven.model.Model;
23
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.FileNotFoundException;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.InputStreamReader;
30 import java.net.URL;
31 import java.security.MessageDigest;
32 import java.security.NoSuchAlgorithmException;
33
34 /**
35  * This class reports invalid and mismatched checksums of artifacts and metadata files.
36  * It validates MD5 and SHA-1 checksums.
37  */
38 public class ChecksumArtifactReporter
39     implements ArtifactReportProcessor, MetadataReportProcessor
40 {
41     String ROLE = ChecksumArtifactReporter.class.getName();
42
43     protected InputStream md5InputStream;
44
45     protected InputStream sha1InputStream;
46
47     private boolean isLocal = true;
48
49     /**
50      * Validate the checksum of the specified artifact.
51      *
52      * @param model
53      * @param artifact
54      * @param reporter
55      * @param repository
56      */
57     public void processArtifact( Model model, Artifact artifact, ArtifactReporter reporter,
58                                  ArtifactRepository repository )
59     {
60         //System.out.println( " " );
61         //System.out
62         //   .println( "===================================== +++++  PROCESS ARTIFACT +++++ ====================================" );
63
64         String artifactUrl = "";
65         String repositoryUrl = "";
66
67         if ( !"file".equals( repository.getProtocol() ) )
68         {
69             isLocal = false;
70             repositoryUrl = repository.getUrl();
71         }
72         else
73         {
74             repositoryUrl = repository.getBasedir();
75         }
76
77         artifactUrl = repositoryUrl + artifact.getGroupId() + "/" + artifact.getArtifactId() + "/" +
78             artifact.getBaseVersion() + "/" + artifact.getArtifactId() + "-" + artifact.getBaseVersion() + "." +
79             artifact.getType();
80
81         //check if checksum files exist
82         boolean md5Exists = getMD5File( artifactUrl );
83         boolean sha1Exists = getSHA1File( artifactUrl );
84
85         if ( md5Exists )
86         {
87             if ( validateChecksum( artifactUrl, "MD5" ) )
88             {
89                 reporter.addSuccess( artifact );
90             }
91             else
92             {
93                 reporter.addFailure( artifact, "MD5 checksum does not match." );
94             }
95         }
96         else
97         {
98             reporter.addFailure( artifact, "MD5 checksum file does not exist." );
99         }
100
101         if ( sha1Exists )
102         {
103             if ( validateChecksum( artifactUrl, "SHA-1" ) )
104             {
105                 reporter.addSuccess( artifact );
106             }
107             else
108             {
109                 reporter.addFailure( artifact, "SHA-1 checksum does not match." );
110             }
111         }
112         else
113         {
114             reporter.addFailure( artifact, "SHA-1 checksum file does not exist." );
115         }
116     }
117
118     /**
119      * Validate the checksums of the metadata. Get the metadata file from the
120      * repository then validate the checksum.
121      */
122     public void processMetadata( RepositoryMetadata metadata, ArtifactRepository repository, ArtifactReporter reporter )
123     {
124         // System.out.println( " " );
125         // System.out
126         //   .println( "====================================== +++++  PROCESS METADATA +++++ ==============================" );
127
128         String metadataUrl = "", repositoryUrl = "", filename = "";
129         if ( !"file".equals( repository.getProtocol() ) )
130         {
131             isLocal = false;
132             repositoryUrl = repository.getUrl() + "/";
133             filename = metadata.getRemoteFilename();
134         }
135         else
136         {
137             repositoryUrl = repository.getBasedir() + "/";
138             filename = metadata.getLocalFilename( repository );
139         }
140
141         if ( metadata.storedInArtifactVersionDirectory() == true && metadata.storedInGroupDirectory() == false )
142         {
143             //version metadata
144             metadataUrl = repositoryUrl + metadata.getGroupId() + "/" + metadata.getArtifactId() + "/" +
145                 metadata.getBaseVersion() + "/";
146         }
147         else if ( metadata.storedInArtifactVersionDirectory() == false && metadata.storedInGroupDirectory() == true )
148         {
149             //group metadata
150             metadataUrl = repositoryUrl + metadata.getGroupId() + "/";
151         }
152         else
153         {
154             //artifact metadata
155             metadataUrl = repositoryUrl + metadata.getGroupId() + "/" + metadata.getArtifactId() + "/";
156         }
157
158         //add the file name of the metadata
159         metadataUrl = metadataUrl + filename;
160
161         //check if checksum files exist
162         boolean md5Exists = getMD5File( metadataUrl );
163         boolean sha1Exists = getSHA1File( metadataUrl );
164
165         if ( md5Exists )
166         {
167             if ( validateChecksum( metadataUrl, "MD5" ) )
168             {
169                 reporter.addSuccess( metadata );
170             }
171             else
172             {
173                 reporter.addFailure( metadata, "MD5 checksum does not match." );
174             }
175         }
176         else
177         {
178             reporter.addFailure( metadata, "MD5 checksum file does not exist." );
179         }
180
181         if ( sha1Exists )
182         {
183             if ( validateChecksum( metadataUrl, "SHA-1" ) )
184             {
185                 reporter.addSuccess( metadata );
186             }
187             else
188             {
189                 reporter.addFailure( metadata, "SHA-1 checksum does not match." );
190             }
191         }
192         else
193         {
194             reporter.addFailure( metadata, "SHA-1 checksum file does not exist." );
195         }
196
197     }
198
199     /**
200      * Get the MD5 Checksum file. If not found, return false.
201      *
202      * @param filename The name of the artifact whose MD5 Checksum file will be retrieved.
203      * @return
204      */
205     public boolean getMD5File( String filename )
206     {
207         try
208         {
209             if ( isLocal )
210             {
211                 md5InputStream = new FileInputStream( filename + ".md5" );
212             }
213             else
214             {
215                 URL url = new URL( filename );
216                 md5InputStream = url.openStream();
217             }
218
219             md5InputStream.close();
220         }
221         catch ( Exception e )
222         {
223             return false;
224         }
225         return true;
226     }
227
228     /**
229      * Get the SHA1 Checksum file. If not found, return false.
230      *
231      * @param filename The name of the artifact whose SHA-1 Checksum file will be retrieved.
232      * @return
233      */
234     public boolean getSHA1File( String filename )
235     {
236         try
237         {
238             if ( isLocal )
239             {
240                 sha1InputStream = new FileInputStream( filename + ".sha1" );
241             }
242             else
243             {
244                 URL url = new URL( filename );
245                 sha1InputStream = url.openStream();
246             }
247             sha1InputStream.close();
248         }
249         catch ( Exception e )
250         {
251             return false;
252         }
253         return true;
254     }
255
256     /**
257      * Validate the checksum of the file.
258      *
259      * @param fileUrl The file to be validated.
260      * @param algo    The checksum algorithm used.
261      * @return
262      */
263     protected boolean validateChecksum( String fileUrl, String algo )
264     {
265         boolean valid = false;
266         byte[] chk1 = null, chk2 = null;
267
268         try
269         {
270             //Create checksum for jar file
271             String ext = ".md5";
272             if ( "SHA-1".equals( algo ) )
273             {
274                 ext = ".sha1";
275             }
276             chk1 = createChecksum( fileUrl, algo );
277             if ( chk1 != null )
278             {
279
280                 //read the md5 file
281                 chk2 = new byte[chk1.length];
282                 File f = new File( fileUrl + ext );
283                 InputStream is = null;
284
285                 //check whether the file is located locally or remotely
286                 if ( isLocal )
287                 {
288                     is = new FileInputStream( f );
289                 }
290                 else
291                 {
292                     URL url = new URL( fileUrl + ext );
293                     is = url.openStream();
294                 }
295
296                 char[] chars = new char[is.available()];
297                 InputStreamReader isr = new InputStreamReader( is );
298                 isr.read( chars );
299                 isr.close();
300
301                 String chk2Str = new String( chars );
302                 //System.out.println( "-----" + algo + " Checksum value (CHK1 - created checksum for jar file) ::::: "
303                 //   + byteArrayToHexStr( chk1 ) );
304                 // System.out.println( "-----" + algo + " Checksum value (CHK2 - content of CHECKSUM file) ::::: "
305                 //     + chk2Str );
306
307                 if ( chk2Str.toUpperCase().equals( byteArrayToHexStr( chk1 ).toUpperCase() ) )
308                 {
309                     valid = true;
310                 }
311                 else
312                 {
313                     valid = false;
314                 }
315             }
316             return valid;
317
318         }
319         catch ( Exception e )
320         {
321             //e.printStackTrace();
322             return valid;
323         }
324     }
325
326     /**
327      * Create a checksum from the specified metadata file.
328      *
329      * @param filename The file that will be created a checksum.
330      * @param algo     The algorithm to be used (MD5, SHA-1)
331      * @return
332      * @throws FileNotFoundException
333      * @throws NoSuchAlgorithmException
334      * @throws IOException
335      */
336     protected byte[] createChecksum( String filename, String algo )
337         throws FileNotFoundException, NoSuchAlgorithmException, IOException
338     {
339
340         InputStream fis = null;
341         byte[] buffer = new byte[1024];
342
343         //check whether file is located locally or remotely
344         if ( isLocal )
345         {
346             fis = new FileInputStream( filename );
347         }
348         else
349         {
350             URL url = new URL( filename );
351             fis = url.openStream();
352         }
353
354         MessageDigest complete = MessageDigest.getInstance( algo );
355         int numRead;
356         do
357         {
358             numRead = fis.read( buffer );
359             if ( numRead > 0 )
360             {
361                 complete.update( buffer, 0, numRead );
362             }
363         }
364         while ( numRead != -1 );
365         fis.close();
366
367         return complete.digest();
368     }
369
370     /**
371      * Convert an incoming array of bytes into a string that represents each of
372      * the bytes as two hex characters.
373      *
374      * @param data
375      * @return
376      */
377     public String byteArrayToHexStr( byte[] data )
378     {
379         String output = "";
380         String tempStr = "";
381         int tempInt = 0;
382
383         for ( int cnt = 0; cnt < data.length; cnt++ )
384         {
385             //Deposit a byte into the 8 lsb of an int.
386             tempInt = data[cnt] & 0xFF;
387
388             //Get hex representation of the int as a string.
389             tempStr = Integer.toHexString( tempInt );
390
391             //Append a leading 0 if necessary so that each hex string will contain 2 characters.
392             if ( tempStr.length() == 1 )
393             {
394                 tempStr = "0" + tempStr;
395             }
396
397             //Concatenate the two characters to the output string.
398             output = output + tempStr;
399         }
400
401         return output.toUpperCase();
402     }
403
404 }