001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.maven.enforcer.rules.checksum; 020 021import javax.inject.Named; 022 023import java.io.File; 024import java.io.IOException; 025import java.io.InputStream; 026import java.nio.file.Files; 027 028import org.apache.commons.codec.digest.DigestUtils; 029import org.apache.maven.enforcer.rule.api.EnforcerRuleError; 030import org.apache.maven.enforcer.rule.api.EnforcerRuleException; 031import org.apache.maven.enforcer.rules.AbstractStandardEnforcerRule; 032 033/** 034 * Rule to validate a binary file to match the specified checksum. 035 * 036 * @author Edward Samson 037 * @author Lyubomyr Shaydariv 038 * @see RequireTextFileChecksum 039 */ 040@Named("requireFileChecksum") 041public class RequireFileChecksum extends AbstractStandardEnforcerRule { 042 043 private File file; 044 045 private String checksum; 046 047 private String type; 048 049 private String nonexistentFileMessage; 050 051 @Override 052 public void execute() throws EnforcerRuleException { 053 if (this.file == null) { 054 throw new EnforcerRuleError("Input file unspecified"); 055 } 056 057 if (this.type == null) { 058 throw new EnforcerRuleError("Hash type unspecified"); 059 } 060 061 if (this.checksum == null) { 062 throw new EnforcerRuleError("Checksum unspecified"); 063 } 064 065 if (!this.file.exists()) { 066 String message = nonexistentFileMessage; 067 if (message == null) { 068 message = "File does not exist: " + this.file.getAbsolutePath(); 069 } 070 throw new EnforcerRuleException(message); 071 } 072 073 if (this.file.isDirectory()) { 074 throw new EnforcerRuleError("Cannot calculate the checksum of directory: " + this.file.getAbsolutePath()); 075 } 076 077 if (!this.file.canRead()) { 078 throw new EnforcerRuleError("Cannot read file: " + this.file.getAbsolutePath()); 079 } 080 081 String checksum = calculateChecksum(); 082 083 if (!checksum.equalsIgnoreCase(this.checksum)) { 084 String exceptionMessage = getMessage(); 085 if (exceptionMessage == null) { 086 exceptionMessage = 087 this.type + " hash of " + this.file + " was " + checksum + " but expected " + this.checksum; 088 } 089 throw new EnforcerRuleException(exceptionMessage); 090 } 091 } 092 093 /** 094 * The file to check. 095 * 096 * @param file file 097 */ 098 public void setFile(File file) { 099 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}