/*
* _____ __ _ _ _____ _
* | __|___ ___ _ _ ___ ___| | |_|___| |_| _ | |_ _ ___
* |__ | -_| _| | | -_| _| |__| |_ -| _| __| | | |_ -|
* |_____|___|_| \_/|___|_| |_____|_|___|_| |__| |_|___|___|
*
* ServerListPlus - http://git.io/slp
* Copyright (c) 2014, Minecrell <https://github.com/Minecrell>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.minecrell.serverlistplus.canary;
import com.google.common.io.BaseEncoding;
import lombok.SneakyThrows;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.Set;
public final class SnakeYAML {
private static final String MAVEN_CENTRAL = "https://repo1.maven.org/maven2/";
private static final String YAML_VERSION = "1.16";
private static final String SNAKE_YAML_JAR = "snakeyaml-" + YAML_VERSION + ".jar";
private static final String SNAKE_YAML =
MAVEN_CENTRAL + "org/yaml/snakeyaml/" + YAML_VERSION + '/' + SNAKE_YAML_JAR;
private static final String EXPECTED_HASH = "D64FB662C9E42789149F5078A62A22EDDA786C6A"; // SHA-1
private static boolean isLoaded(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException ignored) {
try {
// Remove the class from LaunchClassLoader cache if present
ClassLoader classLoader = SnakeYAML.class.getClassLoader();
Field invalidClasses = classLoader.getClass().getDeclaredField("invalidClasses");
invalidClasses.setAccessible(true);
@SuppressWarnings("unchecked")
Set<String> classes = (Set<String>) invalidClasses.get(classLoader);
if (classes != null) {
classes.remove(className);
}
} catch (Exception ignore) {
}
}
return false;
}
@SneakyThrows
public static void load() {
//if (isLoaded("org.yaml.snakeyaml.Yaml")) return;
Path path = Paths.get("lib", SNAKE_YAML_JAR);
if (Files.notExists(path)) {
Files.createDirectories(path.getParent());
URL url = new URL(SNAKE_YAML);
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
try (ReadableByteChannel source = Channels.newChannel(new DigestInputStream(url.openStream(), sha1));
FileChannel out = FileChannel.open(path, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
out.transferFrom(source, 0, Long.MAX_VALUE);
}
if (!BaseEncoding.base16().encode(sha1.digest()).equals(EXPECTED_HASH)) {
Files.delete(path);
throw new IllegalStateException("Downloaded SnakeYAML, but checksum check failed. Please try again later.");
}
}
loadJAR(path);
}
@SneakyThrows
private static void loadJAR(Path path) {
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(SnakeYAML.class.getClassLoader(), path.toUri().toURL());
}
}