PageRenderTime 32ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/MCU-API/src/org/mcupdater/util/MCUpdater.java

https://gitlab.com/Slind/MCUpdater
Java | 1309 lines | 920 code | 74 blank | 315 comment | 118 complexity | ac6bb65f7862326593ef1a8ade40ffa5 MD5 | raw file
  1. package org.mcupdater.util;
  2. import java.awt.image.BufferedImage;
  3. import java.io.BufferedReader;
  4. import java.io.BufferedWriter;
  5. import java.io.File;
  6. import java.io.FileInputStream;
  7. import java.io.FileNotFoundException;
  8. import java.io.FileOutputStream;
  9. import java.io.IOException;
  10. import java.io.InputStream;
  11. import java.io.InputStreamReader;
  12. import java.io.OutputStream;
  13. import java.net.MalformedURLException;
  14. import java.net.URI;
  15. import java.net.URISyntaxException;
  16. import java.net.URL;
  17. import java.net.URLConnection;
  18. //import j7compat.Files;
  19. import java.nio.charset.StandardCharsets;
  20. import java.nio.file.Files;
  21. import java.nio.file.Path;
  22. import java.nio.file.StandardCopyOption;
  23. //import java.nio.file.StandardCopyOption;
  24. //import java.nio.file.StandardOpenOption;
  25. //import j7compat.Path;
  26. import java.security.MessageDigest;
  27. import java.security.NoSuchAlgorithmException;
  28. import java.util.ArrayList;
  29. import java.util.Arrays;
  30. import java.util.Collections;
  31. import java.util.HashMap;
  32. import java.util.HashSet;
  33. import java.util.Iterator;
  34. import java.util.List;
  35. import java.util.ListIterator;
  36. import java.util.Map;
  37. import java.util.Map.Entry;
  38. import java.util.Properties;
  39. import java.util.Random;
  40. import java.util.Set;
  41. import java.util.TreeMap;
  42. import java.util.UUID;
  43. import java.util.logging.FileHandler;
  44. import java.util.logging.Level;
  45. import java.util.logging.Logger;
  46. import javax.crypto.Cipher;
  47. import javax.crypto.SecretKey;
  48. import javax.crypto.SecretKeyFactory;
  49. import javax.crypto.spec.PBEKeySpec;
  50. import javax.crypto.spec.PBEParameterSpec;
  51. import javax.swing.ImageIcon;
  52. import org.apache.commons.codec.binary.Base64;
  53. import org.apache.commons.codec.binary.Hex;
  54. import org.apache.commons.codec.digest.DigestUtils;
  55. import org.apache.commons.io.FileUtils;
  56. import org.mcupdater.DownloadQueue;
  57. import org.mcupdater.Downloadable;
  58. import org.mcupdater.FMLStyleFormatter;
  59. import org.mcupdater.MCUApp;
  60. import org.mcupdater.TaskableExecutor;
  61. import org.mcupdater.Version;
  62. import org.mcupdater.instance.FileInfo;
  63. import org.mcupdater.instance.Instance;
  64. import org.mcupdater.model.Backup;
  65. import org.mcupdater.model.ConfigFile;
  66. import org.mcupdater.model.GenericModule;
  67. import org.mcupdater.model.ModSide;
  68. import org.mcupdater.model.ServerList;
  69. import org.mcupdater.mojang.AssetIndex;
  70. import org.mcupdater.mojang.AssetIndex.Asset;
  71. import org.mcupdater.mojang.Library;
  72. import org.mcupdater.mojang.MinecraftVersion;
  73. import org.w3c.dom.Document;
  74. import org.w3c.dom.Element;
  75. import org.w3c.dom.NodeList;
  76. import com.google.gson.Gson;
  77. import com.google.gson.GsonBuilder;
  78. public class MCUpdater {
  79. //public static final ResourceBundle Customization = ResourceBundle.getBundle("customization");
  80. //private List<Module> modList = new ArrayList<Module>();
  81. private Path MCFolder;
  82. private Path archiveFolder;
  83. private Path instanceRoot;
  84. private MCUApp parent;
  85. private final String sep = System.getProperty("file.separator");
  86. public MessageDigest md5;
  87. public ImageIcon defaultIcon;
  88. private String newestMC = "";
  89. private final Map<String,String> versionMap = new HashMap<String,String>();
  90. public static Logger apiLogger;
  91. //private Path lwjglFolder;
  92. private int timeoutLength = 5000;
  93. private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
  94. private static MCUpdater INSTANCE;
  95. public static File getJarFile() {
  96. try {
  97. return new File(MCUpdater.class.getProtectionDomain().getCodeSource().getLocation().toURI());
  98. } catch (URISyntaxException e) {
  99. apiLogger.log(Level.SEVERE, "Error getting MCUpdater JAR URI", e);
  100. }
  101. return null;
  102. }
  103. public static MCUpdater getInstance(File file) {
  104. if( INSTANCE == null ) {
  105. INSTANCE = new MCUpdater(file);
  106. }
  107. return INSTANCE;
  108. }
  109. public static MCUpdater getInstance() {
  110. if( INSTANCE == null ) {
  111. INSTANCE = new MCUpdater(null);
  112. }
  113. return INSTANCE;
  114. }
  115. public static String cpDelimiter() {
  116. String osName = System.getProperty("os.name");
  117. if (osName.startsWith("Windows")) {
  118. return ";";
  119. } else {
  120. return ":";
  121. }
  122. }
  123. private MCUpdater(File desiredRoot)
  124. {
  125. apiLogger = Logger.getLogger("MCU-API");
  126. apiLogger.setLevel(Level.ALL);
  127. //String[] nativeNames;
  128. //String nativePrefix;
  129. if(System.getProperty("os.name").startsWith("Windows"))
  130. {
  131. MCFolder = new File(System.getenv("APPDATA")).toPath().resolve(".minecraft");
  132. archiveFolder = new File(System.getenv("APPDATA")).toPath().resolve(".MCUpdater");
  133. //nativePrefix = "lwjgl-2.9.0/native/windows/";
  134. //nativeNames = new String[] {"jinput-dx8.dll","jinput-dx8_64.dll","jinput-raw.dll","jinput-raw_64.dll","lwjgl.dll","lwjgl64.dll","OpenAL32.dll","OpenAL64.dll"};
  135. } else if(System.getProperty("os.name").startsWith("Mac"))
  136. {
  137. MCFolder = new File(System.getProperty("user.home")).toPath().resolve("Library").resolve("Application Support").resolve("minecraft");
  138. archiveFolder = new File(System.getProperty("user.home")).toPath().resolve("Library").resolve("Application Support").resolve("MCUpdater");
  139. //nativePrefix = "lwjgl-2.9.0/native/macosx/";
  140. //nativeNames = new String[] {"libjinput-osx.jnilib","liblwjgl.jnilib","openal.dylib"};
  141. }
  142. else
  143. {
  144. MCFolder = new File(System.getProperty("user.home")).toPath().resolve(".minecraft");
  145. archiveFolder = new File(System.getProperty("user.home")).toPath().resolve(".MCUpdater");
  146. //nativePrefix = "lwjgl-2.9.0/native/linux/";
  147. //nativeNames = new String[] {"libjinput-linux.so","libjinput-linux64.so","liblwjgl.so","liblwjgl64.so","libopenal.so","libopenal64.so"};
  148. }
  149. if (!(desiredRoot == null)) {
  150. archiveFolder = desiredRoot.toPath();
  151. }
  152. //lwjglFolder = this.archiveFolder.resolve("LWJGL");
  153. try {
  154. FileHandler apiHandler = new FileHandler(archiveFolder.resolve("MCU-API.log").toString(), 0, 3);
  155. apiHandler.setFormatter(new FMLStyleFormatter());
  156. apiLogger.addHandler(apiHandler);
  157. } catch (SecurityException e1) {
  158. e1.printStackTrace(); // Will only be thrown if there is a problem with logging.
  159. } catch (IOException e1) {
  160. e1.printStackTrace(); // Will only be thrown if there is a problem with logging.
  161. }
  162. try {
  163. md5 = MessageDigest.getInstance("MD5");
  164. } catch (NoSuchAlgorithmException e) {
  165. apiLogger.log(Level.SEVERE, "No MD5 support!", e);
  166. }
  167. try {
  168. defaultIcon = new ImageIcon(MCUpdater.class.getResource("/minecraft.png"));
  169. } catch( NullPointerException e ) {
  170. _debug( "Unable to load default icon?!" );
  171. defaultIcon = new ImageIcon(new BufferedImage(32,32,BufferedImage.TYPE_INT_ARGB));
  172. }
  173. // configure the download cache
  174. try {
  175. DownloadCache.init(archiveFolder.resolve("cache").toFile());
  176. } catch (IllegalArgumentException e) {
  177. _debug( "Suppressed attempt to re-init download cache?!" );
  178. }
  179. try {
  180. long start = System.currentTimeMillis();
  181. URL md5s = new URL("http://files.mcupdater.com/md5.dat");
  182. URLConnection md5Con = md5s.openConnection();
  183. md5Con.setConnectTimeout(this.timeoutLength);
  184. md5Con.setReadTimeout(this.timeoutLength);
  185. InputStreamReader input = new InputStreamReader(md5Con.getInputStream());
  186. BufferedReader buffer = new BufferedReader(input);
  187. String currentLine = null;
  188. while(true){
  189. currentLine = buffer.readLine();
  190. if(currentLine != null){
  191. String entry[] = currentLine.split("\\|");
  192. versionMap.put(entry[0], entry[1]);
  193. newestMC = entry[1]; // Most recent entry in md5.dat is the current release
  194. } else {
  195. break;
  196. }
  197. }
  198. buffer.close();
  199. input.close();
  200. apiLogger.fine("Took "+(System.currentTimeMillis()-start)+"ms to load md5.dat");
  201. apiLogger.fine("newest Minecraft in md5.dat: " + newestMC);
  202. } catch (MalformedURLException e) {
  203. apiLogger.log(Level.SEVERE, "Bad URL", e);
  204. } catch (IOException e) {
  205. apiLogger.log(Level.SEVERE, "I/O Error", e);
  206. }
  207. /* Download LWJGL
  208. File tempFile = this.archiveFolder.resolve("lwjgl-2.9.0.zip").toFile();
  209. if (!tempFile.exists()) {
  210. try {
  211. String jarPrefix = "lwjgl-2.9.0/jar/";
  212. String[] jarNames = new String[] {"lwjgl.jar","lwjgl_util.jar","jinput.jar"};
  213. URL lwjglURL = new URL("http://sourceforge.net/projects/java-game-lib/files/Official%20Releases/LWJGL%202.9.0/lwjgl-2.9.0.zip/download");
  214. apiLogger.info("Downloading " + lwjglURL.getPath());
  215. FileUtils.copyURLToFile(lwjglURL, tempFile);
  216. Path nativePath = lwjglFolder.resolve("natives");
  217. Files.createDirectories(nativePath);
  218. ZipFile zf = new ZipFile(tempFile);
  219. ZipEntry entry;
  220. for (int index=0; index < jarNames.length; index++) {
  221. entry = zf.getEntry(jarPrefix + jarNames[index]);
  222. File outFile = lwjglFolder.resolve(jarNames[index]).toFile();
  223. apiLogger.finest(" Extract: " + outFile.getPath());
  224. FileOutputStream fos = new FileOutputStream(outFile);
  225. InputStream zis = zf.getInputStream(entry);
  226. int len;
  227. byte[] buf = new byte[1024];
  228. while((len = zis.read(buf, 0, 1024)) > -1) {
  229. fos.write(buf, 0, len);
  230. }
  231. fos.close();
  232. zis.close();
  233. }
  234. for (int index=0; index < nativeNames.length; index++) {
  235. entry = zf.getEntry(nativePrefix + nativeNames[index]);
  236. File outFile = nativePath.resolve(nativeNames[index]).toFile();
  237. apiLogger.finest(" Extract: " + outFile.getPath());
  238. FileOutputStream fos = new FileOutputStream(outFile);
  239. InputStream zis = zf.getInputStream(entry);
  240. int len;
  241. byte[] buf = new byte[1024];
  242. while((len = zis.read(buf, 0, 1024)) > -1) {
  243. fos.write(buf, 0, len);
  244. }
  245. fos.close();
  246. zis.close();
  247. }
  248. zf.close();
  249. } catch (MalformedURLException e) {
  250. apiLogger.log(Level.SEVERE, "Bad URL", e);
  251. } catch (IOException e) {
  252. apiLogger.log(Level.SEVERE, "I/O Error", e);
  253. }
  254. }
  255. */
  256. }
  257. public MCUApp getParent() {
  258. return parent;
  259. }
  260. public void setParent(MCUApp parent) {
  261. this.parent = parent;
  262. }
  263. public void writeServerList(List<ServerList> serverlist)
  264. {
  265. try
  266. {
  267. archiveFolder.toFile().mkdirs();
  268. BufferedWriter writer = Files.newBufferedWriter(archiveFolder.resolve("mcuServers.dat"), StandardCharsets.UTF_8);
  269. Iterator<ServerList> it = serverlist.iterator();
  270. Set<String> urls = new HashSet<String>();
  271. while(it.hasNext())
  272. {
  273. ServerList entry = it.next();
  274. urls.add(entry.getPackUrl());
  275. }
  276. Iterator<String> urlIterator = urls.iterator();
  277. while (urlIterator.hasNext())
  278. {
  279. writer.write(urlIterator.next());
  280. writer.newLine();
  281. }
  282. writer.close();
  283. }
  284. catch( IOException x)
  285. {
  286. apiLogger.log(Level.SEVERE, "I/O Error", x);
  287. }
  288. }
  289. public List<Backup> loadBackupList() {
  290. List<Backup> bList = new ArrayList<Backup>();
  291. try {
  292. BufferedReader reader = Files.newBufferedReader(archiveFolder.resolve("mcuBackups.dat"), StandardCharsets.UTF_8);
  293. String entry = reader.readLine();
  294. while(entry != null) {
  295. String[] ele = entry.split("~~~~~");
  296. bList.add(new Backup(ele[0], ele[1]));
  297. entry = reader.readLine();
  298. }
  299. reader.close();
  300. return bList;
  301. } catch(FileNotFoundException notfound) {
  302. apiLogger.log(Level.SEVERE, "File not found", notfound);
  303. } catch(IOException ioe) {
  304. apiLogger.log(Level.SEVERE, "I/O Error", ioe);
  305. }
  306. return bList;
  307. }
  308. public void writeBackupList(List<Backup> backupList) {
  309. try {
  310. BufferedWriter writer = Files.newBufferedWriter(archiveFolder.resolve("mcuBackups.dat"), StandardCharsets.UTF_8);
  311. Iterator<Backup> it = backupList.iterator();
  312. while(it.hasNext()) {
  313. Backup entry = it.next();
  314. writer.write(entry.getDescription() + "~~~~~" + entry.getFilename());
  315. writer.newLine();
  316. }
  317. writer.close();
  318. } catch(IOException ioe) {
  319. apiLogger.log(Level.SEVERE, "I/O Error", ioe);
  320. }
  321. }
  322. public List<ServerList> loadServerList(String defaultUrl)
  323. {
  324. List<ServerList> slList = new ArrayList<ServerList>();
  325. try
  326. {
  327. Set<String> urls = new HashSet<String>();
  328. urls.add(defaultUrl);
  329. BufferedReader reader = Files.newBufferedReader(archiveFolder.resolve("mcuServers.dat"), StandardCharsets.UTF_8);
  330. String entry = reader.readLine();
  331. while(entry != null)
  332. {
  333. urls.add(entry);
  334. entry = reader.readLine();
  335. }
  336. reader.close();
  337. Iterator<String> it = urls.iterator();
  338. while (it.hasNext()){
  339. String serverUrl = it.next();
  340. try {
  341. Element docEle = null;
  342. Document serverHeader = ServerPackParser.readXmlFromUrl(serverUrl);
  343. if (!(serverHeader == null)) {
  344. Element parent = serverHeader.getDocumentElement();
  345. if (parent.getNodeName().equals("ServerPack")){
  346. String mcuVersion = parent.getAttribute("version");
  347. NodeList servers = parent.getElementsByTagName("Server");
  348. for (int i = 0; i < servers.getLength(); i++){
  349. docEle = (Element)servers.item(i);
  350. System.out.println(serverUrl + ": " + docEle.getAttribute("id"));
  351. ServerList sl = new ServerList(docEle.getAttribute("id"), docEle.getAttribute("name"), serverUrl, docEle.getAttribute("newsUrl"), docEle.getAttribute("iconUrl"), docEle.getAttribute("version"), docEle.getAttribute("serverAddress"), ServerPackParser.parseBoolean(docEle.getAttribute("generateList"), true), ServerPackParser.parseBoolean(docEle.getAttribute("autoConnect"), true), docEle.getAttribute("revision"), ServerPackParser.parseBoolean(docEle.getAttribute("abstract"), false), docEle.getAttribute("mainClass"));
  352. sl.setMCUVersion(mcuVersion);
  353. slList.add(sl);
  354. }
  355. } else {
  356. System.out.println(serverUrl + ": *** " + parent.getAttribute("id"));
  357. ServerList sl = new ServerList(parent.getAttribute("id"), parent.getAttribute("name"), serverUrl, parent.getAttribute("newsUrl"), parent.getAttribute("iconUrl"), parent.getAttribute("version"), parent.getAttribute("serverAddress"), ServerPackParser.parseBoolean(parent.getAttribute("generateList"), true), ServerPackParser.parseBoolean(parent.getAttribute("autoConnect"), true), parent.getAttribute("revision"), ServerPackParser.parseBoolean(parent.getAttribute("abstract"), false), parent.getAttribute("mainClass"));
  358. sl.setMCUVersion("1.0");
  359. slList.add(sl);
  360. }
  361. } else {
  362. apiLogger.warning("Unable to get server information from " + serverUrl);
  363. }
  364. } catch (Exception e) {
  365. apiLogger.log(Level.SEVERE, "General Error", e);
  366. }
  367. }
  368. // String[] arrString = entry.split("\\|");
  369. // slList.add(new ServerList(arrString[0], arrString[1], arrString[2]));
  370. return slList;
  371. }
  372. catch( FileNotFoundException notfound)
  373. {
  374. apiLogger.log(Level.SEVERE, "File not found", notfound);
  375. }
  376. catch (IOException x)
  377. {
  378. apiLogger.log(Level.SEVERE, "I/O Error", x);
  379. }
  380. return slList;
  381. }
  382. public Path getMCFolder()
  383. {
  384. return MCFolder;
  385. }
  386. public Path getArchiveFolder() {
  387. return archiveFolder;
  388. }
  389. // public Path getLWJGLFolder() {
  390. // return lwjglFolder;
  391. // }
  392. public Path getInstanceRoot() {
  393. return instanceRoot;
  394. }
  395. public void setInstanceRoot(Path instanceRoot) {
  396. this.instanceRoot = instanceRoot;
  397. }
  398. public String getMCVersion() {
  399. File jar = MCFolder.resolve("bin").resolve("minecraft.jar").toFile();
  400. byte[] hash;
  401. try {
  402. InputStream is = new FileInputStream(jar);
  403. hash = DigestUtils.md5(is);
  404. is.close();
  405. } catch (FileNotFoundException e) {
  406. return "Not found";
  407. } catch (IOException e) {
  408. apiLogger.log(Level.SEVERE, "I/O Error", e);
  409. return "Error reading file";
  410. }
  411. String hashString = new String(Hex.encodeHex(hash));
  412. String version = lookupHash(hashString);
  413. if(!version.isEmpty()) {
  414. File backupJar = archiveFolder.resolve("mc-" + version + ".jar").toFile();
  415. if(!backupJar.exists()) {
  416. backupJar.getParentFile().mkdirs();
  417. copyFile(jar, backupJar);
  418. }
  419. return version;
  420. } else {
  421. return "Unknown version";
  422. }
  423. }
  424. private String lookupHash(String hash) {
  425. String out = versionMap.get(hash);
  426. if (out == null) {
  427. out = "";
  428. }
  429. return out;
  430. }
  431. private void copyFile(File jar, File backupJar) {
  432. try {
  433. InputStream in = new FileInputStream(jar);
  434. OutputStream out = new FileOutputStream(backupJar);
  435. byte[] buf = new byte[1024];
  436. int len;
  437. while ((len = in.read(buf)) > 0) {
  438. out.write(buf, 0, len);
  439. }
  440. in.close();
  441. out.close();
  442. } catch(IOException ioe) {
  443. apiLogger.log(Level.SEVERE, "I/O Error", ioe);
  444. }
  445. }
  446. public void saveConfig(String description) {
  447. File folder = MCFolder.toFile();
  448. List<File> contents = recurseFolder(folder, false);
  449. try {
  450. String uniqueName = UUID.randomUUID().toString() + ".zip";
  451. Iterator<File> it = new ArrayList<File>(contents).iterator();
  452. while(it.hasNext()) {
  453. File entry = it.next();
  454. if(getExcludedNames(entry.getPath(), false) || entry.getPath().contains("temp")){
  455. contents.remove(entry);
  456. }
  457. }
  458. Archive.createZip(archiveFolder.resolve(uniqueName).toFile(), contents, MCFolder, parent);
  459. Backup entry = new Backup(description, uniqueName);
  460. _debug("DEBUG: LoadBackupList");
  461. List<Backup> bList = loadBackupList();
  462. _debug("DEBUG: add");
  463. bList.add(entry);
  464. _debug("DEBUG: writeBackupList");
  465. writeBackupList(bList);
  466. } catch (IOException e) {
  467. apiLogger.log(Level.SEVERE, "I/O Error", e);
  468. }
  469. }
  470. private boolean getExcludedNames(String path, boolean forDelete) {
  471. if(path.contains("mcu" + sep)) {
  472. // never delete from the mcu folder
  473. return true;
  474. }
  475. if (path.contains("mods") && (path.contains(".zip") || path.contains(".jar"))) {
  476. // always delete mods in archive form
  477. return false;
  478. }
  479. if(path.contains("bin" + sep + "minecraft.jar")) {
  480. // always delete bin/minecraft.jar
  481. return false;
  482. }
  483. if(path.contains("bin" + sep)) {
  484. // never delete anything else in bin/
  485. return true;
  486. }
  487. if(path.contains("resources") && !path.contains("mods")) {
  488. // never delete resources unless it is under the mods directory
  489. return true;
  490. }
  491. if(path.contains("lib" + sep)) {
  492. // never delete the lib/ folder
  493. return true;
  494. }
  495. if(path.contains("saves")) {
  496. // never delete saves
  497. return true;
  498. }
  499. if(path.contains("screenshots")) {
  500. // never delete screenshots
  501. return true;
  502. }
  503. if(path.contains("stats")) {
  504. return true;
  505. }
  506. if(path.contains("texturepacks")) {
  507. return true;
  508. }
  509. if(path.contains("lastlogin")) {
  510. return true;
  511. }
  512. if(path.contains("mcuServers.dat")) {
  513. return true;
  514. }
  515. if(path.contains("instance.dat")) {
  516. return true;
  517. }
  518. if(path.contains("minecraft.jar")) {
  519. return true;
  520. }
  521. if(path.contains("options.txt")) {
  522. return forDelete;
  523. }
  524. if(path.contains("META-INF" + sep)) {
  525. return true;
  526. }
  527. // Temporary hardcoding of client specific mod configs (i.e. Don't clobber on update)
  528. if(path.contains("rei_minimap" + sep)) {
  529. return true;
  530. }
  531. if(path.contains("macros" + sep)) {
  532. return true;
  533. }
  534. if(path.contains("InvTweaks")) {
  535. return true;
  536. }
  537. if(path.contains("optionsof.txt")){
  538. return true;
  539. }
  540. if(path.contains("voxelMap")) {
  541. return true;
  542. }
  543. //
  544. return false;
  545. }
  546. private List<File> recurseFolder(File folder, boolean includeFolders)
  547. {
  548. List<File> output = new ArrayList<File>();
  549. List<File> input = new ArrayList<File>(Arrays.asList(folder.listFiles()));
  550. Iterator<File> fi = input.iterator();
  551. if(includeFolders) {
  552. output.add(folder);
  553. }
  554. while(fi.hasNext())
  555. {
  556. File entry = fi.next();
  557. if(entry.isDirectory())
  558. {
  559. List<File> subfolder = recurseFolder(entry, includeFolders);
  560. Iterator<File> sfiterator = subfolder.iterator();
  561. while(sfiterator.hasNext())
  562. {
  563. output.add(sfiterator.next());
  564. }
  565. } else {
  566. output.add(entry);
  567. }
  568. }
  569. return output;
  570. }
  571. public void restoreBackup(File archive) {
  572. File folder = MCFolder.toFile();
  573. List<File> contents = recurseFolder(folder, true);
  574. Iterator<File> it = new ArrayList<File>(contents).iterator();
  575. while(it.hasNext()) {
  576. File entry = it.next();
  577. if(getExcludedNames(entry.getPath(), true)){
  578. contents.remove(entry);
  579. }
  580. }
  581. ListIterator<File> liClear = contents.listIterator(contents.size());
  582. while(liClear.hasPrevious()) {
  583. File entry = liClear.previous();
  584. entry.delete();
  585. }
  586. Archive.extractZip(archive, MCFolder.toFile());
  587. }
  588. public boolean checkForBackup(ServerList server) {
  589. File jar = archiveFolder.resolve("mc-" + server.getVersion() + ".jar").toFile();
  590. return jar.exists();
  591. }
  592. public boolean installMods(final ServerList server, List<GenericModule> toInstall, List<ConfigFile> configs, boolean clearExisting, final Instance instData, ModSide side) throws FileNotFoundException {
  593. if (Version.requestedFeatureLevel(server.getMCUVersion(), "2.2")) {
  594. // Sort mod list for InJar
  595. //Collections.sort(toInstall, new ModuleComparator());
  596. }
  597. final Path instancePath = instanceRoot.resolve(server.getServerId());
  598. Path binPath = instancePath.resolve("bin");
  599. final Path productionJar;
  600. //File jar = null;
  601. final File tmpFolder = instancePath.resolve("temp").toFile();
  602. tmpFolder.mkdirs();
  603. Set<Downloadable> jarMods = new HashSet<Downloadable>();
  604. Set<Downloadable> generalFiles = new HashSet<Downloadable>();
  605. DownloadQueue assetsQueue = null;
  606. DownloadQueue jarQueue = null;
  607. DownloadQueue generalQueue = null;
  608. DownloadQueue libraryQueue = null;
  609. final List<String> libExtract = new ArrayList<String>();
  610. final Map<String,Boolean> modExtract = new HashMap<String,Boolean>();
  611. final Map<String,Boolean> keepMeta = new TreeMap<String,Boolean>();
  612. Downloadable baseJar = null;
  613. final MinecraftVersion version = MinecraftVersion.loadVersion(server.getVersion());
  614. switch (side){
  615. case CLIENT:
  616. assetsQueue = parent.submitAssetsQueue("Assets", server.getServerId(), version);
  617. //executor = new ThreadPoolExecutor(0, 8, 30000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
  618. // jar = archiveFolder.resolve("mc-" + server.getVersion() + ".jar").toFile();
  619. // if(!jar.exists()) {
  620. // parent.log("! Unable to find a backup copy of minecraft.jar for "+server.getVersion());
  621. // throw new FileNotFoundException("A backup copy of minecraft.jar for version " + server.getVersion() + " was not found.");
  622. // }
  623. Set<Downloadable> libSet = new HashSet<Downloadable>();
  624. for (Library lib : version.getLibraries()) {
  625. if (lib.validForOS()) {
  626. List<URL> urls = new ArrayList<URL>();
  627. try {
  628. urls.add(new URL(lib.getDownloadUrl()));
  629. } catch (MalformedURLException e) {
  630. apiLogger.log(Level.SEVERE, "Bad URL", e);
  631. }
  632. Downloadable entry = new Downloadable(lib.getName(),lib.getFilename(),"",100000,urls);
  633. libSet.add(entry);
  634. if (lib.hasNatives()) {
  635. libExtract.add(lib.getFilename());
  636. }
  637. }
  638. }
  639. libraryQueue = parent.submitNewQueue("Libraries", server.getServerId(), libSet, instancePath.resolve("lib").toFile(), DownloadCache.getDir());
  640. productionJar = binPath.resolve("minecraft.jar");
  641. List<URL> jarUrl = new ArrayList<URL>();
  642. try {
  643. jarUrl.add(new URL("https://s3.amazonaws.com/Minecraft.Download/versions/" + server.getVersion() + "/" + server.getVersion() + ".jar"));
  644. } catch (MalformedURLException e2) {
  645. apiLogger.log(Level.SEVERE, "Bad URL", e2);
  646. }
  647. String jarMD5 = "";
  648. for (Entry<String,String> entry : versionMap.entrySet()) {
  649. if (entry.getValue().equals(server.getVersion())) {
  650. jarMD5 = entry.getKey();
  651. break;
  652. }
  653. }
  654. baseJar = new Downloadable("Minecraft jar","0.jar",jarMD5,3000000,jarUrl);
  655. keepMeta.put("0.jar", Version.requestedFeatureLevel(server.getVersion(), "1.6"));
  656. break;
  657. case SERVER:
  658. //jar = archiveFolder.resolve("mc-server-" + server.getVersion() + ".jar").toFile();
  659. productionJar = instancePath.resolve("minecraft_server.jar");
  660. break;
  661. default:
  662. apiLogger.severe("Invalid API call to MCUpdater.installMods! (side cannot be " + side.toString() + ")");
  663. return false;
  664. }
  665. Boolean updateJar = clearExisting;
  666. if (side == ModSide.CLIENT) {
  667. if (!productionJar.toFile().exists()) {
  668. updateJar = true;
  669. }
  670. } else {
  671. //TODO:Server jar detection
  672. }
  673. Iterator<GenericModule> iMods = toInstall.iterator();
  674. List<String> modIds = new ArrayList<String>();
  675. int jarModCount = 0;
  676. while (iMods.hasNext() && !updateJar) {
  677. GenericModule current = iMods.next();
  678. if (current.getInJar()) {
  679. FileInfo jarMod = instData.findJarMod(current.getId());
  680. if (jarMod == null) {
  681. updateJar = true;
  682. } else if (current.getMD5().isEmpty() || (!current.getMD5().equalsIgnoreCase(jarMod.getMD5()))) {
  683. updateJar = true;
  684. }
  685. jarModCount++;
  686. } else {
  687. modIds.add(current.getId());
  688. }
  689. }
  690. if (jarModCount != instData.getJarMods().size()) {
  691. updateJar = true;
  692. }
  693. if (updateJar && baseJar != null) {
  694. jarMods.add(baseJar);
  695. }
  696. Iterator<FileInfo> itExisting = instData.getInstanceFiles().iterator();
  697. while (itExisting.hasNext()) {
  698. FileInfo entry = itExisting.next();
  699. if (!modIds.contains(entry.getModId())) {
  700. instancePath.resolve(entry.getFilename()).toFile().delete();
  701. }
  702. }
  703. instData.setJarMods(new ArrayList<FileInfo>());
  704. instData.setInstanceFiles(new ArrayList<FileInfo>());
  705. jarModCount = 0;
  706. apiLogger.info("Instance path: " + instancePath.toString());
  707. List<File> contents = recurseFolder(instancePath.toFile(), true);
  708. if (clearExisting){
  709. parent.setStatus("Clearing existing configuration");
  710. parent.log("Clearing existing configuration...");
  711. Iterator<File> it = new ArrayList<File>(contents).iterator();
  712. while(it.hasNext()) {
  713. File entry = it.next();
  714. if(getExcludedNames(entry.getPath(), true)){
  715. contents.remove(entry);
  716. }
  717. }
  718. ListIterator<File> liClear = contents.listIterator(contents.size());
  719. while(liClear.hasPrevious()) {
  720. File entry = liClear.previous();
  721. entry.delete();
  722. }
  723. }
  724. Iterator<GenericModule> itMods = toInstall.iterator();
  725. final File buildJar = archiveFolder.resolve("build.jar").toFile();
  726. if(buildJar.exists()) {
  727. buildJar.delete();
  728. }
  729. int modCount = toInstall.size();
  730. int modsLoaded = 0;
  731. int errorCount = 0;
  732. while(itMods.hasNext()) {
  733. GenericModule entry = itMods.next();
  734. parent.setStatus("Mod: " + entry.getName());
  735. parent.log("Mod: "+entry.getName());
  736. Collections.sort(entry.getPrioritizedUrls());
  737. if (entry.getInJar()) {
  738. if (updateJar) {
  739. jarMods.add(new Downloadable(entry.getName(),String.valueOf(entry.getJarOrder()) + "-" + entry.getId() + ".jar",entry.getMD5(),100000,entry.getUrls()));
  740. keepMeta.put(String.valueOf(entry.getJarOrder()) + "-" + cleanForFile(entry.getId()) + ".jar", entry.getKeepMeta());
  741. instData.addJarMod(entry.getId(), entry.getMD5());
  742. jarModCount++;
  743. }
  744. } else if (entry.getCoreMod()) {
  745. String filename = "coremods/" + cleanForFile(entry.getId()) + ".jar";
  746. generalFiles.add(new Downloadable(entry.getName(),filename,entry.getMD5(),100000,entry.getUrls()));
  747. instData.addMod(entry.getId(), entry.getMD5(), filename);
  748. } else if (entry.getIsLibrary()) {
  749. String filename = "lib/" + cleanForFile(entry.getId()) + ".jar";
  750. generalFiles.add(new Downloadable(entry.getName(),filename,entry.getMD5(),100000,entry.getUrls()));
  751. instData.addMod(entry.getId(), entry.getMD5(), filename);
  752. } else if (entry.getExtract()) {
  753. generalFiles.add(new Downloadable(entry.getName(),cleanForFile(entry.getId()) + ".zip",entry.getMD5(),100000,entry.getUrls()));
  754. modExtract.put(cleanForFile(entry.getId()) + ".zip", entry.getInRoot());
  755. } else {
  756. String filename = entry.getPath().isEmpty() ? "mods/" + cleanForFile(entry.getId()) + (entry.isLitemod() ? ".litemod" : ".jar") : entry.getPath();
  757. generalFiles.add(new Downloadable(entry.getName(),filename,entry.getMD5(),100000,entry.getUrls()));
  758. instData.addMod(entry.getId(), entry.getMD5(), filename);
  759. }
  760. // 0
  761. modsLoaded++;
  762. // parent.setProgressBar((int)( (65 / modCount) * modsLoaded + 25));
  763. parent.log(" Done ("+modsLoaded+"/"+modCount+")");
  764. }
  765. Iterator<ConfigFile> itConfigs = configs.iterator();
  766. while(itConfigs.hasNext()) {
  767. final ConfigFile cfEntry = itConfigs.next();
  768. final File confFile = instancePath.resolve(cfEntry.getPath()).toFile();
  769. if (confFile.exists() && cfEntry.isNoOverwrite()) { continue; }
  770. List<URL> configUrl = new ArrayList<URL>();
  771. try {
  772. configUrl.add(new URL(cfEntry.getUrl()));
  773. } catch (MalformedURLException e) {
  774. ++errorCount;
  775. apiLogger.log(Level.SEVERE, "General Error", e);
  776. }
  777. generalFiles.add(new Downloadable(cfEntry.getPath(),cfEntry.getPath(),cfEntry.getMD5(),10000,configUrl));
  778. //1
  779. // save in cache for future reference
  780. // if( MD5 != null ) {
  781. // final boolean cached = DownloadCache.cacheFile(confFile, MD5);
  782. // if( cached ) {
  783. // _debug(confFile.getName() + " saved in cache");
  784. // }
  785. // }
  786. }
  787. generalQueue = parent.submitNewQueue("Instance files", server.getServerId(), generalFiles, instancePath.toFile(), DownloadCache.getDir());
  788. jarQueue = parent.submitNewQueue("Jar build files", server.getServerId(), jarMods, tmpFolder, DownloadCache.getDir());
  789. TaskableExecutor libExecutor = new TaskableExecutor(2, new Runnable(){
  790. @Override
  791. public void run() {
  792. for (String entry : libExtract){
  793. Archive.extractZip(instancePath.resolve("lib").resolve(entry).toFile(), instancePath.resolve("lib").resolve("natives").toFile(), false);
  794. }
  795. }});
  796. libraryQueue.processQueue(libExecutor);
  797. final File branding = new File(tmpFolder, "fmlbranding.properties");
  798. try {
  799. branding.createNewFile();
  800. Properties propBrand = new Properties();
  801. propBrand.setProperty("fmlbranding", "MCUpdater: " + server.getName() + " (rev " + server.getRevision() + ")");
  802. propBrand.store(new FileOutputStream(branding), "MCUpdater ServerPack branding");
  803. } catch (IOException e1) {
  804. apiLogger.log(Level.SEVERE, "I/O Error", e1);
  805. }
  806. final boolean doJarUpdate = updateJar;
  807. TaskableExecutor jarExecutor = new TaskableExecutor(2, new Runnable() {
  808. @Override
  809. public void run() {
  810. if (!doJarUpdate) {
  811. try {
  812. Archive.updateArchive(productionJar.toFile(), new File[]{ branding });
  813. } catch (IOException e1) {
  814. apiLogger.log(Level.SEVERE, "I/O Error", e1);
  815. }
  816. } else {
  817. for (Map.Entry<String,Boolean> entry : keepMeta.entrySet()) {
  818. File entryFile = new File(tmpFolder,entry.getKey());
  819. Archive.extractZip(entryFile, tmpFolder, entry.getValue());
  820. entryFile.delete();
  821. }
  822. try {
  823. buildJar.createNewFile();
  824. } catch (IOException e) {
  825. apiLogger.log(Level.SEVERE, "I/O Error", e);
  826. }
  827. boolean doManifest = true;
  828. List<File> buildList = recurseFolder(tmpFolder,true);
  829. Iterator<File> blIt = new ArrayList<File>(buildList).iterator();
  830. while(blIt.hasNext()) {
  831. File entry = blIt.next();
  832. if(entry.getPath().contains("META-INF")) {
  833. doManifest = false;
  834. }
  835. }
  836. parent.log("Packaging updated jar...");
  837. try {
  838. Archive.createJar(buildJar, buildList, tmpFolder.getPath() + sep, doManifest);
  839. } catch (IOException e1) {
  840. parent.log("Failed to create jar!");
  841. apiLogger.log(Level.SEVERE, "I/O Error", e1);
  842. }
  843. //Archive.patchJar(jar, buildJar, new ArrayList<File>(Arrays.asList(tmpFolder.listFiles())));
  844. //copyFile(buildJar, new File(MCFolder + sep + "bin" + sep + "minecraft.jar"));
  845. try {
  846. Files.createDirectories(productionJar.getParent());
  847. Files.copy(buildJar.toPath(), productionJar, StandardCopyOption.REPLACE_EXISTING);
  848. } catch (IOException e) {
  849. apiLogger.log(Level.SEVERE, "Failed to copy new jar to instance!", e);
  850. }
  851. }
  852. List<File> tempFiles = recurseFolder(tmpFolder,true);
  853. ListIterator<File> li = tempFiles.listIterator(tempFiles.size());
  854. while(li.hasPrevious()) {
  855. File entry = li.previous();
  856. entry.delete();
  857. }
  858. if (server.isGenerateList()) { writeMCServerFile(server.getName(), server.getAddress(), server.getServerId()); }
  859. instData.setMCVersion(server.getVersion());
  860. instData.setRevision(server.getRevision());
  861. String jsonOut = gson.toJson(instData);
  862. try {
  863. BufferedWriter writer = Files.newBufferedWriter(getInstanceRoot().resolve(server.getServerId()).resolve("instance.json"), StandardCharsets.UTF_8);
  864. writer.append(jsonOut);
  865. writer.close();
  866. } catch (IOException e) {
  867. apiLogger.log(Level.SEVERE, "I/O error", e);
  868. }
  869. }
  870. });
  871. jarQueue.processQueue(jarExecutor);
  872. TaskableExecutor genExecutor = new TaskableExecutor(12, new Runnable(){
  873. @Override
  874. public void run() {
  875. for (Map.Entry<String,Boolean> entry : modExtract.entrySet()) {
  876. if (entry.getValue()) {
  877. Archive.extractZip(instancePath.resolve(entry.getKey()).toFile(), instancePath.toFile());
  878. } else {
  879. Archive.extractZip(instancePath.resolve(entry.getKey()).toFile(), instancePath.resolve("mods").toFile());
  880. }
  881. instancePath.resolve(entry.getKey()).toFile().delete();
  882. }
  883. }
  884. });
  885. generalQueue.processQueue(genExecutor);
  886. TaskableExecutor assetsExecutor = new TaskableExecutor(8, new Runnable(){
  887. @Override
  888. public void run() {
  889. //check virtual
  890. Gson gson = new Gson();
  891. String indexName = version.getAssets();
  892. if (indexName == null) {
  893. indexName = "legacy";
  894. }
  895. File indexesPath = archiveFolder.resolve("assets").resolve("indexes").toFile();
  896. File indexFile = new File(indexesPath, indexName + ".json");
  897. String json;
  898. try {
  899. json = FileUtils.readFileToString(indexFile);
  900. AssetIndex index = gson.fromJson(json, AssetIndex.class);
  901. parent.log("Assets virtual: " + index.isVirtual());
  902. if (index.isVirtual()) {
  903. //Test symlink support
  904. boolean doLinks = true;
  905. try {
  906. java.nio.file.Files.createSymbolicLink(archiveFolder.resolve("linktest"), archiveFolder.resolve("MCUpdater.log.0"));
  907. archiveFolder.resolve("linktest").toFile().delete();
  908. } catch (Exception e) {
  909. doLinks = false;
  910. }
  911. Path assetsPath = archiveFolder.resolve("assets");
  912. Path virtualPath = assetsPath.resolve("virtual");
  913. for (Map.Entry<String, Asset> entry : index.getObjects().entrySet()) {
  914. Path target = virtualPath.resolve(entry.getKey());
  915. Path original = assetsPath.resolve("objects").resolve(entry.getValue().getHash().substring(0,2)).resolve(entry.getValue().getHash());
  916. if (!Files.exists(target)) {
  917. Files.createDirectories(target.getParent());
  918. if (doLinks) {
  919. Files.createSymbolicLink(target, original);
  920. } else {
  921. Files.copy(original, target);
  922. }
  923. }
  924. }
  925. }
  926. } catch (IOException e) {
  927. parent.baseLogger.log(Level.SEVERE, "Assets exception! " + e.getMessage());
  928. }
  929. }
  930. });
  931. assetsQueue.processQueue(assetsExecutor);
  932. if( errorCount > 0 ) {
  933. parent.baseLogger.severe("Errors were detected with this update, please verify your files. There may be a problem with the serverpack configuration or one of your download sites.");
  934. return false;
  935. }
  936. //copyFile(jar, buildJar);
  937. return true;
  938. }
  939. private String cleanForFile(String id) {
  940. return id.replaceAll("[^a-zA-Z_0-9\\-.]", "_");
  941. }
  942. public void writeMCServerFile(String name, String ip, String instance) {
  943. byte[] header = new byte[]{
  944. 0x0A,0x00,0x00,0x09,0x00,0x07,0x73,0x65,0x72,0x76,0x65,0x72,0x73,0x0A,
  945. 0x00,0x00,0x00,0x01,0x01,0x00,0x0B,0x68,0x69,0x64,0x65,0x41,0x64,0x64,
  946. 0x72,0x65,0x73,0x73,0x01,0x08,0x00,0x04,0x6E,0x61,0x6D,0x65,0x00,
  947. (byte) (name.length() + 12), (byte) 0xC2,(byte) 0xA7,0x41,0x5B,0x4D,0x43,0x55,0x5D,0x20,(byte) 0xC2,(byte) 0xA7,0x46
  948. };
  949. byte[] nameBytes = name.getBytes();
  950. byte[] ipBytes = ip.getBytes();
  951. byte[] middle = new byte[]{0x08,0x00,0x02,0x69,0x70,0x00,(byte) ip.length()};
  952. byte[] end = new byte[]{0x00,0x00};
  953. int size = header.length + nameBytes.length + middle.length + ipBytes.length + end.length;
  954. byte[] full = new byte[size];
  955. int pos = 0;
  956. System.arraycopy(header, 0, full, pos, header.length);
  957. pos += header.length;
  958. System.arraycopy(nameBytes, 0, full, pos, nameBytes.length);
  959. pos += nameBytes.length;
  960. System.arraycopy(middle, 0, full, pos, middle.length);
  961. pos += middle.length;
  962. System.arraycopy(ipBytes, 0, full, pos, ipBytes.length);
  963. pos += ipBytes.length;
  964. System.arraycopy(end, 0, full, pos, end.length);
  965. File serverFile = instanceRoot.resolve(instance).resolve("servers.dat").toFile();
  966. try {
  967. serverFile.createNewFile();
  968. FileOutputStream fos = new FileOutputStream(serverFile);
  969. fos.write(full,0,full.length);
  970. fos.close();
  971. } catch (IOException e) {
  972. apiLogger.log(Level.SEVERE, "I/O Error", e);
  973. }
  974. }
  975. public static void openLink(URI uri) {
  976. try {
  977. Object o = Class.forName("java.awt.Desktop").getMethod("getDesktop", new Class[0]).invoke(null, new Object[0]);
  978. o.getClass().getMethod("browse", new Class[] { URI.class }).invoke(o, new Object[] { uri });
  979. } catch (Throwable e) {
  980. _log("Failed to open link " + uri.toString());
  981. }
  982. }
  983. private static void _log(String msg) {
  984. apiLogger.info(msg);
  985. }
  986. private static void _debug(String msg) {
  987. apiLogger.fine(msg);
  988. }
  989. /*
  990. public boolean checkVersionCache(String version, ModSide side) {
  991. File requestedJar;
  992. switch (side) {
  993. case CLIENT:
  994. requestedJar = archiveFolder.resolve("mc-" + version + ".jar").toFile();
  995. File newestJar = archiveFolder.resolve("mc-" + newestMC + ".jar").toFile();
  996. if (requestedJar.exists()) return true;
  997. if (newestJar.exists()) {
  998. doPatch(requestedJar, newestJar, version);
  999. return true;
  1000. } else {
  1001. if (this.getParent().requestLogin()) {
  1002. try {
  1003. parent.setStatus("Downloading Minecraft");
  1004. apiLogger.info("Downloading Minecraft (" + newestMC + ")");
  1005. FileUtils.copyURLToFile(new URL("http://assets.minecraft.net/" + newestMC.replace(".","_") + "/minecraft.jar"), newestJar);
  1006. } catch (MalformedURLException e) {
  1007. apiLogger.log(Level.SEVERE, "Bad URL", e);
  1008. return false;
  1009. } catch (IOException e) {
  1010. apiLogger.log(Level.SEVERE, "I/O Error", e);
  1011. return false;
  1012. }
  1013. if (!requestedJar.toString().equals(newestJar.toString())) {
  1014. doPatch(requestedJar, newestJar, version);
  1015. }
  1016. return true;
  1017. } else {
  1018. return false;
  1019. }
  1020. }
  1021. case SERVER:
  1022. requestedJar = archiveFolder.resolve("mc-server-" + version + ".jar").toFile();
  1023. if (requestedJar.exists()) return true;
  1024. try {
  1025. apiLogger.info("Downloading server jar (" + version + ")");
  1026. FileUtils.copyURLToFile(new URL("http://assets.minecraft.net/" + version.replace(".","_") + "/minecraft_server.jar"), requestedJar);
  1027. } catch (MalformedURLException e) {
  1028. apiLogger.log(Level.SEVERE, "Bad URL", e);
  1029. return false;
  1030. } catch (IOException e) {
  1031. apiLogger.log(Level.SEVERE, "I/O Error", e);
  1032. return false;
  1033. }
  1034. return true;
  1035. default:
  1036. break;
  1037. }
  1038. return false;
  1039. }
  1040. */
  1041. /*
  1042. private void doPatch(File requestedJar, File newestJar, String version) {
  1043. try {
  1044. URL patchURL;
  1045. File patchFile = archiveFolder.resolve("temp.patch").toFile();
  1046. try {
  1047. patchURL = new URL("http://files.mcupdater.com/mcu_patches/" + newestMC.replace(".", "") + "to" + version.replace(".","") + ".patch");
  1048. patchURL.openConnection().connect();
  1049. } catch (IOException ioe) {
  1050. patchURL = new URL("https://dl.dropboxusercontent.com/u/75552727/mcu_patches/" + newestMC.replace(".", "") + "to" + version.replace(".","") + ".patch");
  1051. }
  1052. _debug(patchURL.toString());
  1053. parent.setStatus("Downloading downgrade patch");
  1054. apiLogger.info("Downloading downgrade patch (" + newestMC + " -> " + version + ")");
  1055. FileUtils.copyURLToFile(patchURL, patchFile, 2000, 5000);
  1056. parent.setStatus("Applying downgrade patch");
  1057. apiLogger.info("Applying downgrade patch");
  1058. Transmogrify.applyPatch(new Path(newestJar), new Path(requestedJar), new Path(patchFile));
  1059. patchFile.delete();
  1060. } catch (Exception e) {
  1061. apiLogger.log(Level.SEVERE, "General Error", e);
  1062. }
  1063. }
  1064. */
  1065. private Cipher getCipher(int mode, String password) throws Exception {
  1066. Random random = new Random(92845025L);
  1067. byte[] salt = new byte[8];
  1068. random.nextBytes(salt);
  1069. PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 5);
  1070. SecretKey pbeKey = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(new PBEKeySpec(password.toCharArray()));
  1071. Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
  1072. cipher.init(mode, pbeKey, pbeParamSpec);
  1073. return cipher;
  1074. }
  1075. public String encrypt(String password) {
  1076. try {
  1077. Cipher cipher = getCipher(Cipher.ENCRYPT_MODE, "MCUpdater");
  1078. byte[] utf8 = password.getBytes("UTF8");
  1079. byte[] enc = cipher.doFinal(utf8);
  1080. return Base64.encodeBase64String(enc);
  1081. } catch (Exception e) {
  1082. apiLogger.log(Level.SEVERE, "General error", e);
  1083. }
  1084. return null;
  1085. }
  1086. public String decrypt(String property) {
  1087. try {
  1088. Cipher cipher = getCipher(Cipher.DECRYPT_MODE, "MCUpdater");
  1089. byte[] dec = Base64.decodeBase64(property);
  1090. byte[] utf8 = cipher.doFinal(dec);
  1091. return new String(utf8, "UTF8");
  1092. } catch (Exception e) {
  1093. apiLogger.log(Level.SEVERE, "General error", e);
  1094. }
  1095. return null;
  1096. }
  1097. public void setTimeout(int timeout) {
  1098. this.timeoutLength = timeout;
  1099. }
  1100. public int getTimeout() {
  1101. return this.timeoutLength;
  1102. }
  1103. }
  1104. /* 0
  1105. //for (PrioritizedURL pUrl : entry.getUrls()) {
  1106. // _debug("Mod @ "+pUrl.getUrl());
  1107. // URL modURL = new URL(pUrl.getUrl());
  1108. //String modFilename = modURL.getFile().substring(modURL.getFile().lastIndexOf('/'));
  1109. File modPath;
  1110. if(entry.getInJar()) {
  1111. if (updateJar) {
  1112. //modPath = new File(tmpFolder.getPath() + sep + loadOrder + ".zip");
  1113. //loadOrder++;
  1114. //_log(modPath.getPath());
  1115. ModDownload jarMod;
  1116. try {
  1117. jarMod = new ModDownload(modURL, File.createTempFile(entry.getId(), ".jar"), entry.getMD5());
  1118. if( jarMod.cacheHit ) {
  1119. parent.log(" Adding to jar (cached).");
  1120. } else {
  1121. parent.log(" Adding to jar (downloaded).");
  1122. }
  1123. _debug(jarMod.url + " -> " + jarMod.getDestFile().getPath());
  1124. //FileUtils.copyURLToFile(modURL, modPath);
  1125. Archive.extractZip(jarMod.getDestFile(), tmpFolder, entry.getKeepMeta());
  1126. jarMod.getDestFile().delete();
  1127. instData.setProperty("mod:" + entry.getId(), entry.getMD5());
  1128. jarModCount++;
  1129. } catch (Exception e) {
  1130. ++errorCount;
  1131. apiLogger.log(Level.SEVERE, "General Error", e); }
  1132. } else {
  1133. parent.log("Skipping jar mod: " + entry.getName());
  1134. }
  1135. } else if (entry.getExtract()) {
  1136. //modPath = new File(tmpFolder.getPath() + sep + modFilename);
  1137. //modPath.getParentFile().mkdirs();
  1138. //_log(modPath.getPath());
  1139. ModDownload extractMod;
  1140. try {
  1141. extractMod = new ModDownload(modURL, File.createTempFile(entry.getId(), ".jar") , entry.getMD5());
  1142. if( extractMod.cacheHit ) {
  1143. parent.log(" Extracting to filesystem (cached).");
  1144. } else {
  1145. parent.log(" Extracting to filesystem (downloaded).");
  1146. }
  1147. _debug(extractMod.url + " -> " + extractMod.getDestFile().getPath());
  1148. //FileUtils.copyURLToFile(modURL, modPath);
  1149. Path destPath = instancePath;
  1150. if(!entry.getInRoot()) destPath = instancePath.resolve("mods");
  1151. Archive.extractZip(extractMod.getDestFile(), destPath.toFile());
  1152. extractMod.getDestFile().delete();
  1153. } catch (Exception e) {
  1154. ++errorCount;
  1155. apiLogger.log(Level.SEVERE, "General Error", e);
  1156. }
  1157. } else if (entry.getCoreMod()) {
  1158. modPath = instancePath.resolve("coremods").resolve(cleanForFile(entry.getId()) + ".jar").toFile();
  1159. modPath.getParentFile().mkdirs();
  1160. try {
  1161. ModDownload normalMod = new ModDownload(modURL, modPath, entry.getMD5());
  1162. if( normalMod.cacheHit ) {
  1163. parent.log(" Installing in /coremods (cached).");
  1164. } else {
  1165. parent.log(" Installing in /coremods (downloaded).");
  1166. }
  1167. _debug(normalMod.url + " -> " + normalMod.getDestFile().getPath());
  1168. } catch (Exception e) {
  1169. ++errorCount;
  1170. apiLogger.log(Level.SEVERE, "General Error", e);
  1171. }
  1172. } else {
  1173. if (entry.getPath().equals("")){
  1174. modPath = instancePath.resolve("mods").resolve(cleanForFile(entry.getId()) + ".jar").toFile();
  1175. } else {
  1176. modPath = instancePath.resolve(entry.getPath()).toFile();
  1177. }
  1178. modPath.getParentFile().mkdirs();
  1179. //_log("~~~ " + modPath.getPath());
  1180. try {
  1181. ModDownload normalMod = new ModDownload(modURL, modPath, entry.getMD5());
  1182. if( normalMod.cacheHit ) {
  1183. parent.log(" Installing in /mods (cached).");
  1184. } else {
  1185. parent.log(" Installing in /mods (downloaded).");
  1186. }
  1187. _debug(normalMod.url + " -> " + normalMod.getDestFile().getPath());
  1188. } catch (Exception e) {
  1189. ++errorCount;
  1190. apiLogger.log(Level.SEVERE, "General Error", e);
  1191. }
  1192. //FileUtils.copyURLToFile(modURL, modPath);
  1193. }
  1194. }*/
  1195. /* 1
  1196. final String MD5 = cfEntry.getMD5();
  1197. _debug(cfEntry.getUrl());
  1198. URL configURL = new URL(cfEntry.getUrl());
  1199. final File confFile = instancePath.resolve(cfEntry.getPath()).toFile();
  1200. confFile.getParentFile().mkdirs();
  1201. // if( MD5 != null ) {
  1202. // final File cacheFile = DownloadCache.getFile(MD5);
  1203. // if( cacheFile.exists() ) {
  1204. // parent.log(" Found config for "+cfEntry.getPath()+" (cached)");
  1205. // FileUtils.copyFile(cacheFile, confFile);
  1206. // continue;
  1207. // }
  1208. // }
  1209. //_debug(confFile.getPath());
  1210. if (cfEntry.isNoOverwrite() && confFile.exists()) {
  1211. parent.log(" Config for "+cfEntry.getPath()+" skipped - NoOverwrite is true");
  1212. } else {
  1213. //parent.log(" Found config for "+cfEntry.getPath()+", downloading...");
  1214. try {
  1215. ModDownload configDL = new ModDownload(configURL, confFile, MD5);
  1216. if( configDL.cacheHit ) {
  1217. parent.log(" Found config for "+cfEntry.getPath()+" (cached).");
  1218. } else {
  1219. parent.log(" Found config for "+cfEntry.getPath()+" (downloaded).");
  1220. }
  1221. String strPath = configDL.getDestFile() == null ? "???" : configDL.getDestFile().getPath();
  1222. _debug(configDL.url + " -> " + strPath);
  1223. } catch (Exception e) {
  1224. ++errorCount;
  1225. apiLogger.log(Level.SEVERE, "General Error", e);
  1226. }
  1227. //FileUtils.copyURLToFile(configURL, confFile);
  1228. }
  1229. */