View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  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,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.enforcer.rules.checksum;
20  
21  import javax.inject.Named;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.nio.file.Files;
27  
28  import org.apache.commons.codec.digest.DigestUtils;
29  import org.apache.maven.enforcer.rule.api.EnforcerRuleError;
30  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
31  import org.apache.maven.enforcer.rules.AbstractStandardEnforcerRule;
32  
33  /**
34   * Rule to validate a binary file to match the specified checksum.
35   *
36   * @author Edward Samson
37   * @author Lyubomyr Shaydariv
38   * @see RequireTextFileChecksum
39   */
40  @Named("requireFileChecksum")
41  public class RequireFileChecksum extends AbstractStandardEnforcerRule {
42  
43      private File file;
44  
45      private String checksum;
46  
47      private String type;
48  
49      private String nonexistentFileMessage;
50  
51      @Override
52      public void execute() throws EnforcerRuleException {
53          if (this.file == null) {
54              throw new EnforcerRuleError("Input file unspecified");
55          }
56  
57          if (this.type == null) {
58              throw new EnforcerRuleError("Hash type unspecified");
59          }
60  
61          if (this.checksum == null) {
62              throw new EnforcerRuleError("Checksum unspecified");
63          }
64  
65          if (!this.file.exists()) {
66              String message = nonexistentFileMessage;
67              if (message == null) {
68                  message = "File does not exist: " + this.file.getAbsolutePath();
69              }
70              throw new EnforcerRuleException(message);
71          }
72  
73          if (this.file.isDirectory()) {
74              throw new EnforcerRuleError("Cannot calculate the checksum of directory: " + this.file.getAbsolutePath());
75          }
76  
77          if (!this.file.canRead()) {
78              throw new EnforcerRuleError("Cannot read file: " + this.file.getAbsolutePath());
79          }
80  
81          String checksum = calculateChecksum();
82  
83          if (!checksum.equalsIgnoreCase(this.checksum)) {
84              String exceptionMessage = getMessage();
85              if (exceptionMessage == null) {
86                  exceptionMessage =
87                          this.type + " hash of " + this.file + " was " + checksum + " but expected " + this.checksum;
88              }
89              throw new EnforcerRuleException(exceptionMessage);
90          }
91      }
92  
93      /**
94       * The file to check.
95       *
96       * @param file file
97       */
98      public void setFile(File file) {
99          this.file = file;
100     }
101 
102     public File getFile() {
103         return file;
104     }
105 
106     /**
107      * The expected checksum value.
108      *
109      * @param checksum checksum
110      */
111     public void setChecksum(String checksum) {
112         this.checksum = checksum;
113     }
114 
115     public String getChecksum() {
116         return checksum;
117     }
118 
119     /**
120      * The checksum algorithm to use. Possible values: "md5", "sha1", "sha256", "sha384", "sha512".
121      *
122      * @param type algorithm
123      */
124     public void setType(String type) {
125         this.type = type;
126     }
127 
128     public String getType() {
129         return type;
130     }
131 
132     /**
133      * The friendly message to use when the file does not exist.
134      *
135      * @param nonexistentFileMessage message
136      */
137     public void setNonexistentFileMessage(String nonexistentFileMessage) {
138         this.nonexistentFileMessage = nonexistentFileMessage;
139     }
140 
141     public String getNonexistentFileMessage() {
142         return nonexistentFileMessage;
143     }
144 
145     protected String calculateChecksum() throws EnforcerRuleException {
146         try (InputStream inputStream = Files.newInputStream(this.file.toPath())) {
147             return calculateChecksum(inputStream);
148         } catch (IOException e) {
149             throw new EnforcerRuleError("Unable to calculate checksum", e);
150         }
151     }
152 
153     protected String calculateChecksum(InputStream inputStream) throws IOException, EnforcerRuleException {
154         String result;
155         if ("md5".equals(this.type)) {
156             result = DigestUtils.md5Hex(inputStream);
157         } else if ("sha1".equals(this.type)) {
158             result = DigestUtils.sha1Hex(inputStream);
159         } else if ("sha256".equals(this.type)) {
160             result = DigestUtils.sha256Hex(inputStream);
161         } else if ("sha384".equals(this.type)) {
162             result = DigestUtils.sha384Hex(inputStream);
163         } else if ("sha512".equals(this.type)) {
164             result = DigestUtils.sha512Hex(inputStream);
165         } else {
166             throw new EnforcerRuleError("Unsupported hash type: " + this.type);
167         }
168         return result;
169     }
170 
171     @Override
172     public String toString() {
173         return String.format(
174                 "RequireFileChecksum[message=%s, file=%s, checksum=%s, type=%s, nonexistentFileMessage=%s]",
175                 getMessage(), file, checksum, type, nonexistentFileMessage);
176     }
177 }