View Javadoc

1   package org.apache.maven.shared.jarsigner;
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.codehaus.plexus.util.FileUtils;
23  import org.codehaus.plexus.util.IOUtil;
24  
25  import java.io.BufferedInputStream;
26  import java.io.BufferedOutputStream;
27  import java.io.File;
28  import java.io.FileInputStream;
29  import java.io.FileOutputStream;
30  import java.io.IOException;
31  import java.util.zip.ZipEntry;
32  import java.util.zip.ZipInputStream;
33  import java.util.zip.ZipOutputStream;
34  
35  /**
36   * Useful methods.
37   *
38   * @author tchemit <chemit@codelutin.com>
39   * @version $Id: JarSignerUtil.java 1195937 2011-11-01 11:38:37Z olamy $
40   * @since 1.0
41   */
42  public class JarSignerUtil
43  {
44  
45      private JarSignerUtil()
46      {
47          // static class
48      }
49  
50      /**
51       * Checks whether the specified file is a JAR file. For our purposes, a ZIP file is a ZIP stream with at least one
52       * entry.
53       *
54       * @param file The file to check, must not be <code>null</code>.
55       * @return <code>true</code> if the file looks like a ZIP file, <code>false</code> otherwise.
56       */
57      public static boolean isZipFile( final File file )
58      {
59          try
60          {
61              ZipInputStream zis = new ZipInputStream( new FileInputStream( file ) );
62              try
63              {
64                  return zis.getNextEntry() != null;
65              }
66              finally
67              {
68                  zis.close();
69              }
70          }
71          catch ( Exception e )
72          {
73              // ignore, will fail below
74          }
75  
76          return false;
77      }
78  
79      /**
80       * Removes any existing signatures from the specified JAR file. We will stream from the input JAR directly to the
81       * output JAR to retain as much metadata from the original JAR as possible.
82       *
83       * @param jarFile The JAR file to unsign, must not be <code>null</code>.
84       * @throws java.io.IOException
85       */
86      public static void unsignArchive( File jarFile )
87          throws IOException
88      {
89  
90          File unsignedFile = new File( jarFile.getAbsolutePath() + ".unsigned" );
91  
92          ZipInputStream zis = null;
93          ZipOutputStream zos = null;
94          try
95          {
96              zis = new ZipInputStream( new BufferedInputStream( new FileInputStream( jarFile ) ) );
97              zos = new ZipOutputStream( new BufferedOutputStream( new FileOutputStream( unsignedFile ) ) );
98  
99              for ( ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry() )
100             {
101                 if ( isSignatureFile( ze.getName() ) )
102                 {
103 
104                     continue;
105                 }
106 
107                 zos.putNextEntry( ze );
108 
109                 IOUtil.copy( zis, zos );
110             }
111 
112         }
113         finally
114         {
115             IOUtil.close( zis );
116             IOUtil.close( zos );
117         }
118 
119         FileUtils.rename( unsignedFile, jarFile );
120 
121     }
122 
123     /**
124      * Checks whether the specified JAR file entry denotes a signature-related file, i.e. matches
125      * <code>META-INF/*.SF</code>, <code>META-INF/*.DSA</code> or <code>META-INF/*.RSA</code>.
126      *
127      * @param entryName The name of the JAR file entry to check, must not be <code>null</code>.
128      * @return <code>true</code> if the entry is related to a signature, <code>false</code> otherwise.
129      */
130     private static boolean isSignatureFile( String entryName )
131     {
132         if ( entryName.regionMatches( true, 0, "META-INF", 0, 8 ) )
133         {
134             entryName = entryName.replace( '\\', '/' );
135 
136             if ( entryName.indexOf( '/' ) == 8 && entryName.lastIndexOf( '/' ) == 8 )
137             {
138                 if ( entryName.regionMatches( true, entryName.length() - 3, ".SF", 0, 3 ) )
139                 {
140                     return true;
141                 }
142                 if ( entryName.regionMatches( true, entryName.length() - 4, ".DSA", 0, 4 ) )
143                 {
144                     return true;
145                 }
146                 if ( entryName.regionMatches( true, entryName.length() - 4, ".RSA", 0, 4 ) )
147                 {
148                     return true;
149                 }
150             }
151         }
152         return false;
153     }
154 }