Java tutorial
/***************************************************************************\ * Copyright 2016 [Lyonlancer5] * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * \***************************************************************************/ package net.lyonlancer5.mcmp.karasu.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.util.List; import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.commons.codec.digest.DigestUtils; import net.minecraftforge.common.config.Configuration; public class ModFileUtils { private static final ModFileUtils instance = new ModFileUtils(); private static final Logger LOGGER = LogManager.getLogger("Project Karasu ~ Utils"); public static boolean doDisplayNewDebug; static volatile boolean isDevEnv = false; private final File remoteHashes; public boolean doUpdateCheck; boolean checkForPreReleases; private boolean hasInitialized; private boolean doHashCheck; private ModFileUtils() { remoteHashes = new File(Constants.MAIN_DIR, "hash"); doUpdateCheck = true; checkForPreReleases = false; hasInitialized = false; doHashCheck = true; } public static ModFileUtils instance() { return instance; } private void initialize() { LOGGER.info("Initializing mod utilities"); //MARKER: Load configuration Configuration config = new Configuration(new File(Constants.MAIN_DIR, "config.properties")); try { config.load(); config.addCustomCategoryComment("General", "These determine which functions of this mod are enabled or not"); doDisplayNewDebug = config.getBoolean("Use Minecraft 1.8+ Debug Overlay", "General", true, "Uses the almost-complete debug overlay found in Minecraft 1.8+"); config.addCustomCategoryComment("Utilities", "These determine which technical add-ons of this mod are used"); doHashCheck = config.getBoolean("Utilities", "Perform Integrity Check", true, "Performs an integrity check of this mod's files to preserve " + "integrity. The checks performed are MD5 and SHA-1 " + "hash comparisons"); doUpdateCheck = config.getBoolean("Utilities", "Do Update Checks", true, "Checks for updates by querying the main repository for " + "information regarding new releases."); checkForPreReleases = config.getBoolean("Utilities", "Include Pre-release Versions", false, "Checks for pre-release builds along with the stable release checks. This " + "option does not enable checking for development/snapshot builds. " + "This option is ignored if performing update checks are disabled."); } catch (Exception e) { Constants.LOGGER.warn("Mod configuration failed", e); } finally { config.save(); } //MARKER: Grab a copy of the hash files try { if (remoteHashes.exists()) { remoteHashes.delete(); } remoteHashes.getParentFile().mkdirs(); remoteHashes.createNewFile(); remoteHashes.deleteOnExit(); download("https://raw.githubusercontent.com/Lyonlancer5/Project-Karasu/master/hash", remoteHashes); LOGGER.info("Retrieved remote hash cache"); } catch (Exception e) { LOGGER.warn("Failed to retrieve hash cache"); doHashCheck = false; return; } hasInitialized = true; } public void doHashCheck(File jarFile) { if (!hasInitialized) initialize(); if (doHashCheck) { LOGGER.info("Mod source file located at " + jarFile.getPath()); if (jarFile.isFile() && !jarFile.getName().endsWith("bin")) { try { List<String> lines = IOUtils.readLines(new FileInputStream(remoteHashes)); for (String s : lines) { //version:jarName:md5:sha1:sha256:sha512 String[] params = s.split(":"); if (params[0].equals(Constants.VERSION)) { if (!params[1].equals(jarFile.getName())) LOGGER.warn("JAR filename has been changed!"); FileInputStream fis = new FileInputStream(jarFile); String var0 = DigestUtils.md5Hex(fis); String var1 = DigestUtils.sha1Hex(fis); String var2 = DigestUtils.sha256Hex(fis); String var3 = DigestUtils.sha512Hex(fis); assert ((params[2].equals(var0)) && (params[3].equals(var1)) && (params[4].equals(var2)) && (params[5].equals(var3))) : new ValidationError( "Mod integrity check FAILED: mismatched hashes (Has the mod file been edited?)"); LOGGER.info("Validation success!"); return; } } } catch (IOException e) { throw new ValidationError("Validation FAILED - I/O error", e); } } else { isDevEnv = true; LOGGER.warn( "The mod is currently running on a development environment - Integrity checking will not proceed"); } } else { LOGGER.warn("#########################################################################"); LOGGER.warn("WARNING: Integrity checks have been DISABLED!"); LOGGER.warn("Hash checks will not be performed - this mod may not run as intended"); LOGGER.warn("Any changes made to this mod will not be validated, whether it came from"); LOGGER.warn("a legitimate source or an attempt to insert code into this modification"); LOGGER.warn("#########################################################################"); } } static long download(String url, File output) throws IOException { URL url1 = new URL(url); ReadableByteChannel rbc = Channels.newChannel(url1.openStream()); FileOutputStream fos = new FileOutputStream(output); if (!output.exists()) { output.getParentFile().mkdirs(); output.createNewFile(); } long f = fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); fos.close(); return f; } public static class ValidationError extends Error { private static final long serialVersionUID = -4092923822851832743L; public ValidationError() { super(); } public ValidationError(String message) { super(message); } public ValidationError(String message, Throwable cause) { super(message, cause); } public ValidationError(Throwable cause) { super(cause); } } }