/* * This file is part of FTB Launcher. * * Copyright © 2012-2016, FTB Launcher Contributors <https://github.com/Slowpoke101/FTBLaunch/> * FTB Launcher is 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.ftb.workers; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.SocketException; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLException; import javax.swing.SwingWorker; import net.ftb.download.Locations; import net.ftb.log.Logger; import net.ftb.main.Main; import net.ftb.util.Benchmark; import net.ftb.util.DownloadUtils; import net.ftb.util.SSLUtils; /** * SwingWorker that downloads Authlib. Returns true if successful, false if it * fails. */ public class AuthlibDLWorker extends SwingWorker<Boolean, Void> { protected String status, reqVersion; protected File binDir; protected String authlibVersion; protected URL jarURLs; public AuthlibDLWorker (String DLFolder, String authver) { this.binDir = new File(DLFolder); this.authlibVersion = authver; this.status = ""; } @Override protected Boolean doInBackground () { Benchmark.start("Authlib"); Logger.logDebug("Loading Authlib..."); if (!binDir.exists()) { binDir.mkdirs(); } if (!downloadJars()) { Logger.logError("Authlib Download Failed"); if (!new File(binDir + File.separator + "authlib-" + authlibVersion + ".jar").exists()) { return false; } Logger.logInfo("Local Authlib copy exists: trying to load it anyway"); } setStatus("Adding Authlib to Classpath"); Logger.logInfo("Adding Authlib to Classpath"); return addToClasspath(binDir + File.separator + "authlib-" + authlibVersion + ".jar"); } protected boolean addToClasspath (String location) { File f = new File(location); try { if (f.exists()) { addURL(f.toURI().toURL()); this.getClass().forName("com.mojang.authlib.exceptions.AuthenticationException"); // will fail if not properly added to classpath this.getClass().forName("com.mojang.authlib.Agent"); this.getClass().forName("com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService"); this.getClass().forName("com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication"); } else { Logger.logError("Authlib file does not exist"); } } catch (Throwable t) { Logger.logError(t.getMessage(), t); return false; } Main.setAuthlibReadyToUse(true); Benchmark.logBenchAs("Authlib", "Authlib DL Worker Init"); return true; } public void addURL (URL u) throws IOException { URLClassLoader sysloader = (URLClassLoader)this.getClass().getClassLoader(); Class sysclass = URLClassLoader.class; try { Method method = sysclass.getDeclaredMethod("addURL", new Class[] {URL.class}); method.setAccessible(true); method.invoke(sysloader, u); } catch (Throwable t) { Logger.logWarn(t.getMessage(), t); throw new IOException("Error, could not add URL to system classloader"); } } protected boolean downloadJars () { try { jarURLs = new URL(Locations.mc_libs + "com/mojang/authlib/" + authlibVersion + "/authlib-" + authlibVersion + ".jar"); } catch (MalformedURLException e) { Logger.logError(e.getMessage(), e); return false; } double totalDownloadSize = 0, totalDownloadedSize = 0; int[] fileSizes = new int[1]; String hash = ""; HttpsURLConnection conn = null; for(int i = 0; i < 1; i++) { try { conn = (HttpsURLConnection)jarURLs.openConnection(); conn.setRequestProperty("Cache-Control", "no-transform"); conn.setRequestMethod("HEAD"); conn.connect(); hash = conn.getHeaderField("ETag").replace("\"", ""); fileSizes[i] = conn.getContentLength(); conn.disconnect(); totalDownloadSize += fileSizes[i]; // SSLUtils.printServerCertChain("libraries.minecraft.net", 443); } catch (SSLException e) { Logger.logWarn("Authlib checksum download failed, please check log for bad SSL certificates", e); SSLUtils.printServerCertChain("libraries.minecraft.net", 443); return false; } catch (SocketException e) { Logger.logWarn("Generic socket exception", e); Logger.logDebug("Trying to fetch cert chain"); SSLUtils.printServerCertChain("libraries.minecraft.net", 443); return false; } catch (Exception e) { Logger.logWarn("Authlib checksum download failed", e); return false; } } boolean downloadSuccess = false; if (hash != null && !hash.equals("") && new File(binDir, getFilename(jarURLs)).exists()) { try { if (hash.toLowerCase().equals(DownloadUtils.fileMD5(new File(binDir, getFilename(jarURLs))).toLowerCase())) { Logger.logInfo("Local Authlib Version is good, skipping Download"); return true; } } catch (Exception e1) {} } int attempt = 0; final int attempts = 5; while (!downloadSuccess && (attempt < attempts)) { try { attempt++; Logger.logDebug("Connecting.. Try " + attempt + " of " + attempts + " for: " + jarURLs.toURI()); URLConnection dlConnection = jarURLs.openConnection(); if (dlConnection instanceof HttpURLConnection) { dlConnection.setRequestProperty("Cache-Control", "no-cache, no-transform"); dlConnection.connect(); } String jarFileName = getFilename(jarURLs); if (new File(binDir, jarFileName).exists()) { new File(binDir, jarFileName).delete(); } InputStream dlStream = dlConnection.getInputStream(); FileOutputStream outStream; try { outStream = new FileOutputStream(new File(binDir, jarFileName)); } catch (Exception e) { downloadSuccess = false; Logger.logError("Error while opening authlib file for writing. Check your FTB installation location write access", e); break; } setStatus("Downloading " + jarFileName + "..."); byte[] buffer = new byte[24000]; int readLen; int currentDLSize = 0; while ((readLen = dlStream.read(buffer, 0, buffer.length)) != -1) { outStream.write(buffer, 0, readLen); currentDLSize += readLen; totalDownloadedSize += readLen; int prog = (int)((totalDownloadedSize / totalDownloadSize) * 100); if (prog > 100) { prog = 100; } else if (prog < 0) { prog = 0; } setProgress(prog); } dlStream.close(); outStream.close(); if (dlConnection instanceof HttpURLConnection && (currentDLSize == fileSizes[0] || fileSizes[0] <= 0)) { downloadSuccess = true; } } catch (Exception e) { downloadSuccess = false; Logger.logWarn("Connection failed, trying again", e); } } return downloadSuccess; } protected String getFilename (URL url) { String string = url.getFile(); if (string.contains("?")) { string = string.substring(0, string.indexOf('?')); } return string.substring(string.lastIndexOf('/') + 1); } protected void setStatus (String newStatus) { String oldStatus = status; status = newStatus; firePropertyChange("status", oldStatus, newStatus); } public String getStatus () { return status; } }