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 lyonlancer5.karasu.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.util.HashMap; import net.minecraftforge.common.config.Configuration; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.ho.yaml.Yaml; import lyonlancer5.karasu.LL5_Karasu; public class ModFileUtils { private static final ModFileUtils instance = new ModFileUtils(); private static final Logger LOGGER = LogManager.getLogger("Project Karasu ~ Utils"); private final File yamlConfig; private final File remoteHashes; private boolean hasInitialized = false; private boolean doHashCheck; public boolean doUpdateCheck, checkForPreReleases; private ModFileUtils() { remoteHashes = new File(Constants.MAIN_DIR, "hash.yml"); yamlConfig = new File("jyaml.yml"); } public static ModFileUtils getInstance() { return instance; } public void initialize() { LOGGER.info("Initializing mod utilities"); //MARKER: Load configuration (VERY early stage) Configuration config = new Configuration(new File(Constants.MAIN_DIR, "config.properties")); try { config.load(); doHashCheck = config .get("General", "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") .getBoolean(); doUpdateCheck = config.get("General", "Do Update Checks", true, "Checks for updates by querying the main repository for " + "information regarding new releases.") .getBoolean(); checkForPreReleases = config .get("General", "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.") .getBoolean(); } catch (Exception e) { Constants.LOGGER.warn("Mod configuration failed", e); } finally { config.save(); } //MARKER: Now write settings for the YAML reader try { if (!yamlConfig.exists()) { yamlConfig.createNewFile(); try { download("https://raw.githubusercontent.com/Lyonlancer5/Project-Karasu/master/jyaml.yml", yamlConfig); } catch (Exception e) { try { InputStream in = LL5_Karasu.class.getResourceAsStream("/assets/ll5_karasu/jyaml.yml"); PrintWriter writer = new PrintWriter(yamlConfig); for (String s : IOUtils.readLines(in)) writer.print(s); writer.flush(); writer.close(); } catch (Exception e1) { PrintWriter writer = new PrintWriter(yamlConfig); writer.println("minimalOutput: false"); writer.println("# Indentation per line would only be two spaces"); writer.println("indentAmount: \" \""); writer.println("suppressWarnings: false"); writer.println("encoding: \"UTF-8\""); writer.println("transfers:"); writer.println(" keymap: java.util.HashMap"); writer.flush(); writer.close(); } } LOGGER.info("Created default YAML parser configuration"); } } catch (Exception e) { return; } //MARKER: Then 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.yml", remoteHashes); LOGGER.info("Retrieved remote hash cache"); } catch (Exception e) { return; } hasInitialized = true; } /* * Notes: * * Maybe instead of using an outdated YAML parser to check for our files, why don't * we use something simpler like reading each line of the hash file and comparing EACH instead? * * Or study how the JSON library works :3 */ @SuppressWarnings({ "rawtypes", "unchecked" }) public synchronized void doHashCheck(File jarFile) { if (doHashCheck) { if (hasInitialized) { LOGGER.info("Mod source file " + jarFile.getName() + " located at " + jarFile.getParent()); if (jarFile.isFile() && !jarFile.getName().endsWith("bin")) { try { HashMap params = (HashMap) ((HashMap) Yaml.loadType(remoteHashes, HashMap.class) .get("version")).get(Constants.VERSION); if (!params.get("jar").equals(jarFile.getName())) { LOGGER.warn("JAR filename has been changed"); } FileInputStream fis = new FileInputStream(jarFile); HashMap<String, String> theHashes = (HashMap<String, String>) params.get("hash"); String md5 = DigestUtils.md5Hex(fis); String sha1 = DigestUtils.sha1Hex(fis); fis.close(); if (md5.equals(theHashes.get("md5"))) { LOGGER.info("Validated MD5 hash - " + md5); } else { throw new RuntimeException( "MD5 check FAILED: Expected " + md5 + " - Received " + theHashes.get("md5")); } if (sha1.equals(theHashes.get("sha1"))) { LOGGER.info("Validated SHA1 hash - " + sha1); } else { throw new RuntimeException( "SHA1 check FAILED: Expected " + sha1 + " - Received " + theHashes.get("sha1")); } } catch (IOException e) { throw new RuntimeException("Validation FAILED - I/O error", e); } } else { LOGGER.warn( "The mod is currently running on a development environment - Integrity checking will not proceed"); } } else { throw new RuntimeException("Validation FAILED - Validation utilites have not been initialized!"); } } else { LOGGER.warn("#########################################################################"); LOGGER.warn("WARNING: Integrity checks have been DISABLED!"); LOGGER.warn("Hash checks will not be performed - this mod may not run correctly"); LOGGER.warn("Any changes made to this mod will not be validated, whether it came from"); LOGGER.warn("a legitimate edit or an attempt to insert code into this modification"); LOGGER.warn("#########################################################################"); } } static void 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(); } fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); fos.close(); } }