diff --git a/.idea/libraries/hikaricp_2_4_0.xml b/.idea/libraries/hikaricp_2_4_0.xml
index f250036..f0837f9 100644
--- a/.idea/libraries/hikaricp_2_4_0.xml
+++ b/.idea/libraries/hikaricp_2_4_0.xml
@@ -7,9 +7,6 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/.idea/libraries/jansi_1_11.xml b/.idea/libraries/jansi_1_11.xml
index 08d74af..15d915c 100644
--- a/.idea/libraries/jansi_1_11.xml
+++ b/.idea/libraries/jansi_1_11.xml
@@ -4,8 +4,6 @@
-
-
-
+
\ No newline at end of file
diff --git a/.idea/libraries/jline_2_12_1.xml b/.idea/libraries/jline_2_12_1.xml
index e4f7633..520f372 100644
--- a/.idea/libraries/jline_2_12_1.xml
+++ b/.idea/libraries/jline_2_12_1.xml
@@ -4,8 +4,6 @@
-
-
-
+
\ No newline at end of file
diff --git a/.idea/libraries/minimal_json_0_9_4.xml b/.idea/libraries/minimal_json_0_9_4.xml
index b1d6e1b..3eea58d 100644
--- a/.idea/libraries/minimal_json_0_9_4.xml
+++ b/.idea/libraries/minimal_json_0_9_4.xml
@@ -4,8 +4,6 @@
-
-
-
+
\ No newline at end of file
diff --git a/.idea/libraries/mysql_5_1_36.xml b/.idea/libraries/mysql_5_1_36.xml
index e539066..f6bb03a 100644
--- a/.idea/libraries/mysql_5_1_36.xml
+++ b/.idea/libraries/mysql_5_1_36.xml
@@ -4,8 +4,6 @@
-
-
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index fa95692..c0de29d 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -5,38 +5,11 @@
-
-
-
-
-
-
-
-
-
-
-
- Ant inspections
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/LaunchServer/source-testing/LaunchServerWrap.java b/LaunchServer/source-testing/LaunchServerWrap.java
index 0af7c53..18bb598 100644
--- a/LaunchServer/source-testing/LaunchServerWrap.java
+++ b/LaunchServer/source-testing/LaunchServerWrap.java
@@ -1,10 +1,10 @@
package launchserver;
public final class LaunchServerWrap {
- private LaunchServerWrap() {
- }
+ private LaunchServerWrap() {
+ }
- public static void main(String... args) throws Throwable {
- LaunchServer.main(args); // Just for test runtime
- }
+ public static void main(String... args) throws Throwable {
+ LaunchServer.main(args); // Just for test runtime
+ }
}
diff --git a/LaunchServer/source/LaunchServer.java b/LaunchServer/source/LaunchServer.java
index b1f718e..f89ae6d 100644
--- a/LaunchServer/source/LaunchServer.java
+++ b/LaunchServer/source/LaunchServer.java
@@ -1,9 +1,5 @@
package launchserver;
-import javax.script.Bindings;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
@@ -28,9 +24,14 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.CRC32;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
import launcher.Launcher;
import launcher.LauncherAPI;
@@ -66,407 +67,407 @@
import launchserver.command.handler.JLineCommandHandler;
import launchserver.command.handler.StdCommandHandler;
import launchserver.response.Response;
+import launchserver.response.Response.Factory;
import launchserver.response.ServerSocketHandler;
+import launchserver.response.ServerSocketHandler.Listener;
import launchserver.texture.TextureProvider;
public final class LaunchServer implements Runnable {
- // Constant paths
- @LauncherAPI public static final Path CONFIG_FILE = IOHelper.WORKING_DIR.resolve("LaunchServer.cfg");
- @LauncherAPI public static final Path PUBLIC_KEY_FILE = IOHelper.WORKING_DIR.resolve("public.key");
- @LauncherAPI public static final Path PRIVATE_KEY_FILE = IOHelper.WORKING_DIR.resolve("private.key");
- @LauncherAPI public static final Path UPDATES_DIR = IOHelper.WORKING_DIR.resolve("updates");
- @LauncherAPI public static final Path PROFILES_DIR = IOHelper.WORKING_DIR.resolve("profiles");
+ // Constant paths
+ @LauncherAPI public static final Path CONFIG_FILE = IOHelper.WORKING_DIR.resolve("LaunchServer.cfg");
+ @LauncherAPI public static final Path PUBLIC_KEY_FILE = IOHelper.WORKING_DIR.resolve("public.key");
+ @LauncherAPI public static final Path PRIVATE_KEY_FILE = IOHelper.WORKING_DIR.resolve("private.key");
+ @LauncherAPI public static final Path UPDATES_DIR = IOHelper.WORKING_DIR.resolve("updates");
+ @LauncherAPI public static final Path PROFILES_DIR = IOHelper.WORKING_DIR.resolve("profiles");
- // Server config
- @LauncherAPI public final Config config;
- @LauncherAPI public final RSAPublicKey publicKey;
- @LauncherAPI public final RSAPrivateKey privateKey;
+ // Server config
+ @LauncherAPI public final Config config;
+ @LauncherAPI public final RSAPublicKey publicKey;
+ @LauncherAPI public final RSAPrivateKey privateKey;
- // Launcher binary
- @LauncherAPI public final LauncherBinary launcherBinary = new JARLauncherBinary(this);
- @LauncherAPI public final LauncherBinary launcherEXEBinary;
+ // Launcher binary
+ @LauncherAPI public final LauncherBinary launcherBinary = new JARLauncherBinary(this);
+ @LauncherAPI public final LauncherBinary launcherEXEBinary;
- // Server
- @LauncherAPI public final CommandHandler commandHandler;
- @LauncherAPI public final ServerSocketHandler serverSocketHandler;
- private final AtomicBoolean started = new AtomicBoolean(false);
- private final ScriptEngine engine = CommonHelper.newScriptEngine();
+ // Server
+ @LauncherAPI public final CommandHandler commandHandler;
+ @LauncherAPI public final ServerSocketHandler serverSocketHandler;
+ private final AtomicBoolean started = new AtomicBoolean(false);
+ private final ScriptEngine engine = CommonHelper.newScriptEngine();
- // Updates and profiles
- private volatile List> profilesList;
- private volatile Map> updatesDirMap;
+ // Updates and profiles
+ private volatile List> profilesList;
+ private volatile Map> updatesDirMap;
- private LaunchServer() throws IOException, InvalidKeySpecException {
- setScriptBindings();
+ private LaunchServer() throws IOException, InvalidKeySpecException {
+ setScriptBindings();
- // Set command handler
- CommandHandler localCommandHandler;
- try {
- Class.forName("jline.Terminal");
+ // Set command handler
+ CommandHandler localCommandHandler;
+ try {
+ Class.forName("jline.Terminal");
- // JLine2 available
- localCommandHandler = new JLineCommandHandler(this);
- LogHelper.info("JLine2 terminal enabled");
- } catch (ClassNotFoundException ignored) {
- localCommandHandler = new StdCommandHandler(this);
- LogHelper.warning("JLine2 isn't in classpath, using std");
- }
- commandHandler = localCommandHandler;
+ // JLine2 available
+ localCommandHandler = new JLineCommandHandler(this);
+ LogHelper.info("JLine2 terminal enabled");
+ } catch (ClassNotFoundException ignored) {
+ localCommandHandler = new StdCommandHandler(this);
+ LogHelper.warning("JLine2 isn't in classpath, using std");
+ }
+ commandHandler = localCommandHandler;
- // Set key pair
- if (IOHelper.isFile(PUBLIC_KEY_FILE) && IOHelper.isFile(PRIVATE_KEY_FILE)) {
- LogHelper.info("Reading RSA keypair");
- publicKey = SecurityHelper.toPublicRSAKey(IOHelper.read(PUBLIC_KEY_FILE));
- privateKey = SecurityHelper.toPrivateRSAKey(IOHelper.read(PRIVATE_KEY_FILE));
- if (!publicKey.getModulus().equals(privateKey.getModulus())) {
- throw new IOException("Private and public key modulus mismatch");
- }
- } else {
- LogHelper.info("Generating RSA keypair");
- KeyPair pair = SecurityHelper.genRSAKeyPair();
- publicKey = (RSAPublicKey) pair.getPublic();
- privateKey = (RSAPrivateKey) pair.getPrivate();
+ // Set key pair
+ if (IOHelper.isFile(PUBLIC_KEY_FILE) && IOHelper.isFile(PRIVATE_KEY_FILE)) {
+ LogHelper.info("Reading RSA keypair");
+ publicKey = SecurityHelper.toPublicRSAKey(IOHelper.read(PUBLIC_KEY_FILE));
+ privateKey = SecurityHelper.toPrivateRSAKey(IOHelper.read(PRIVATE_KEY_FILE));
+ if (!publicKey.getModulus().equals(privateKey.getModulus())) {
+ throw new IOException("Private and public key modulus mismatch");
+ }
+ } else {
+ LogHelper.info("Generating RSA keypair");
+ KeyPair pair = SecurityHelper.genRSAKeyPair();
+ publicKey = (RSAPublicKey) pair.getPublic();
+ privateKey = (RSAPrivateKey) pair.getPrivate();
- // Write key pair files
- LogHelper.info("Writing RSA keypair files");
- IOHelper.write(PUBLIC_KEY_FILE, publicKey.getEncoded());
- IOHelper.write(PRIVATE_KEY_FILE, privateKey.getEncoded());
- }
+ // Write key pair files
+ LogHelper.info("Writing RSA keypair files");
+ IOHelper.write(PUBLIC_KEY_FILE, publicKey.getEncoded());
+ IOHelper.write(PRIVATE_KEY_FILE, privateKey.getEncoded());
+ }
- // Print keypair fingerprints
- CRC32 crc = new CRC32();
- crc.update(publicKey.getModulus().toByteArray());
- LogHelper.subInfo("Modulus CRC32: 0x%08x", crc.getValue());
+ // Print keypair fingerprints
+ CRC32 crc = new CRC32();
+ crc.update(publicKey.getModulus().toByteArray());
+ LogHelper.subInfo("Modulus CRC32: 0x%08x", crc.getValue());
- // Read LaunchServer config
- generateConfigIfNotExists();
- LogHelper.info("Reading LaunchServer config file");
- try (BufferedReader reader = IOHelper.newReader(CONFIG_FILE)) {
- config = new Config(TextConfigReader.read(reader, true));
- }
- config.verify();
+ // Read LaunchServer config
+ generateConfigIfNotExists();
+ LogHelper.info("Reading LaunchServer config file");
+ try (BufferedReader reader = IOHelper.newReader(CONFIG_FILE)) {
+ config = new Config(TextConfigReader.read(reader, true));
+ }
+ config.verify();
- // Set launcher EXE binary
- launcherEXEBinary = config.launch4J ? new EXEL4JLauncherBinary(this) : new EXELauncherBinary(this);
- syncLauncherBinaries();
+ // Set launcher EXE binary
+ launcherEXEBinary = config.launch4J ? new EXEL4JLauncherBinary(this) : new EXELauncherBinary(this);
+ syncLauncherBinaries();
- // Sync updates dir
- if (!IOHelper.isDir(UPDATES_DIR)) {
- Files.createDirectory(UPDATES_DIR);
- }
- syncUpdatesDir(null);
+ // Sync updates dir
+ if (!IOHelper.isDir(UPDATES_DIR)) {
+ Files.createDirectory(UPDATES_DIR);
+ }
+ syncUpdatesDir(null);
- // Sync profiles dir
- if (!IOHelper.isDir(PROFILES_DIR)) {
- Files.createDirectory(PROFILES_DIR);
- }
- syncProfilesDir();
+ // Sync profiles dir
+ if (!IOHelper.isDir(PROFILES_DIR)) {
+ Files.createDirectory(PROFILES_DIR);
+ }
+ syncProfilesDir();
- // Set server socket thread
- serverSocketHandler = new ServerSocketHandler(this);
- }
+ // Set server socket thread
+ serverSocketHandler = new ServerSocketHandler(this);
+ }
- @Override
- public void run() {
- if (started.getAndSet(true)) {
- throw new IllegalStateException("LaunchServer has been already started");
- }
+ @Override
+ public void run() {
+ if (started.getAndSet(true)) {
+ throw new IllegalStateException("LaunchServer has been already started");
+ }
- // Load plugin script if exist
- Path scriptFile = IOHelper.WORKING_DIR.resolve("plugin.js");
- if (IOHelper.isFile(scriptFile)) {
- LogHelper.info("Loading plugin.js script");
- try {
- loadScript(IOHelper.toURL(scriptFile));
- } catch (Exception e) {
- throw new RuntimeException("Error while loading plugin.js", e);
- }
- }
+ // Load plugin script if exist
+ Path scriptFile = IOHelper.WORKING_DIR.resolve("plugin.js");
+ if (IOHelper.isFile(scriptFile)) {
+ LogHelper.info("Loading plugin.js script");
+ try {
+ loadScript(IOHelper.toURL(scriptFile));
+ } catch (Exception e) {
+ throw new RuntimeException("Error while loading plugin.js", e);
+ }
+ }
- // Add shutdown hook, then start LaunchServer
- JVMHelper.RUNTIME.addShutdownHook(CommonHelper.newThread(null, false, this::shutdownHook));
- CommonHelper.newThread("Command Thread", true, commandHandler).start();
- rebindServerSocket();
- }
+ // Add shutdown hook, then start LaunchServer
+ JVMHelper.RUNTIME.addShutdownHook(CommonHelper.newThread(null, false, this::shutdownHook));
+ CommonHelper.newThread("Command Thread", true, commandHandler).start();
+ rebindServerSocket();
+ }
- @LauncherAPI
- public void buildLauncherBinaries() throws IOException {
- launcherBinary.build();
- launcherEXEBinary.build();
- }
+ @LauncherAPI
+ public void buildLauncherBinaries() throws IOException {
+ launcherBinary.build();
+ launcherEXEBinary.build();
+ }
- @LauncherAPI
- @SuppressWarnings("ReturnOfCollectionOrArrayField")
- public Collection> getProfiles() {
- return profilesList;
- }
+ @LauncherAPI
+ @SuppressWarnings("ReturnOfCollectionOrArrayField")
+ public Collection> getProfiles() {
+ return profilesList;
+ }
- @LauncherAPI
- public SignedObjectHolder getUpdateDir(String name) {
- return updatesDirMap.get(name);
- }
+ @LauncherAPI
+ public SignedObjectHolder getUpdateDir(String name) {
+ return updatesDirMap.get(name);
+ }
- @LauncherAPI
- public Set>> getUpdateDirs() {
- return updatesDirMap.entrySet();
- }
+ @LauncherAPI
+ public Set>> getUpdateDirs() {
+ return updatesDirMap.entrySet();
+ }
- @LauncherAPI
- public Object loadScript(URL url) throws IOException, ScriptException {
- LogHelper.debug("Loading server script: '%s'", url);
- try (BufferedReader reader = IOHelper.newReader(url)) {
- return engine.eval(reader);
- }
- }
+ @LauncherAPI
+ public Object loadScript(URL url) throws IOException, ScriptException {
+ LogHelper.debug("Loading server script: '%s'", url);
+ try (BufferedReader reader = IOHelper.newReader(url)) {
+ return engine.eval(reader);
+ }
+ }
- @LauncherAPI
- public void rebindServerSocket() {
- serverSocketHandler.close();
- CommonHelper.newThread("Server Socket Thread", false, serverSocketHandler).start();
- }
+ @LauncherAPI
+ public void rebindServerSocket() {
+ serverSocketHandler.close();
+ CommonHelper.newThread("Server Socket Thread", false, serverSocketHandler).start();
+ }
- @LauncherAPI
- public void syncLauncherBinaries() throws IOException {
- LogHelper.info("Syncing launcher binaries");
+ @LauncherAPI
+ public void syncLauncherBinaries() throws IOException {
+ LogHelper.info("Syncing launcher binaries");
- // Syncing launcher binary
- LogHelper.subInfo("Syncing launcher binary file");
- if (!launcherBinary.sync()) {
- LogHelper.subWarning("Missing launcher binary file");
- }
+ // Syncing launcher binary
+ LogHelper.subInfo("Syncing launcher binary file");
+ if (!launcherBinary.sync()) {
+ LogHelper.subWarning("Missing launcher binary file");
+ }
- // Syncing launcher EXE binary
- LogHelper.subInfo("Syncing launcher EXE binary file");
- if (!launcherEXEBinary.sync()) {
- LogHelper.subWarning("Missing launcher EXE binary file");
- }
- }
+ // Syncing launcher EXE binary
+ LogHelper.subInfo("Syncing launcher EXE binary file");
+ if (!launcherEXEBinary.sync()) {
+ LogHelper.subWarning("Missing launcher EXE binary file");
+ }
+ }
- @LauncherAPI
- public void syncProfilesDir() throws IOException {
- LogHelper.info("Syncing profiles dir");
- List> newProfies = new LinkedList<>();
- IOHelper.walk(PROFILES_DIR, new ProfilesFileVisitor(newProfies), false);
+ @LauncherAPI
+ public void syncProfilesDir() throws IOException {
+ LogHelper.info("Syncing profiles dir");
+ List> newProfies = new LinkedList<>();
+ IOHelper.walk(PROFILES_DIR, new ProfilesFileVisitor(newProfies), false);
- // Sort and set new profiles
- Collections.sort(newProfies, (a, b) -> a.object.compareTo(b.object));
- profilesList = Collections.unmodifiableList(newProfies);
- }
+ // Sort and set new profiles
+ Collections.sort(newProfies, (a, b) -> a.object.compareTo(b.object));
+ profilesList = Collections.unmodifiableList(newProfies);
+ }
- @LauncherAPI
- public void syncUpdatesDir(Collection dirs) throws IOException {
- LogHelper.info("Syncing updates dir");
- Map> newUpdatesDirMap = new HashMap<>(16);
- try (DirectoryStream dirStream = Files.newDirectoryStream(UPDATES_DIR)) {
- for (Path updateDir : dirStream) {
- if (Files.isHidden(updateDir)) {
- continue; // Skip hidden
- }
+ @LauncherAPI
+ public void syncUpdatesDir(Collection dirs) throws IOException {
+ LogHelper.info("Syncing updates dir");
+ Map> newUpdatesDirMap = new HashMap<>(16);
+ try (DirectoryStream dirStream = Files.newDirectoryStream(UPDATES_DIR)) {
+ for (Path updateDir : dirStream) {
+ if (Files.isHidden(updateDir)) {
+ continue; // Skip hidden
+ }
- // Resolve name and verify is dir
- String name = IOHelper.getFileName(updateDir);
- if (!IOHelper.isDir(updateDir)) {
- LogHelper.subWarning("Not update dir: '%s'", name);
- continue;
- }
+ // Resolve name and verify is dir
+ String name = IOHelper.getFileName(updateDir);
+ if (!IOHelper.isDir(updateDir)) {
+ LogHelper.subWarning("Not update dir: '%s'", name);
+ continue;
+ }
- // Add from previous map (it's guaranteed to be non-null)
- if (dirs != null && !dirs.contains(name)) {
- SignedObjectHolder hdir = updatesDirMap.get(name);
- if (hdir != null) {
- newUpdatesDirMap.put(name, hdir);
- continue;
- }
- }
+ // Add from previous map (it's guaranteed to be non-null)
+ if (dirs != null && !dirs.contains(name)) {
+ SignedObjectHolder hdir = updatesDirMap.get(name);
+ if (hdir != null) {
+ newUpdatesDirMap.put(name, hdir);
+ continue;
+ }
+ }
- // Sync and sign update dir
- LogHelper.subInfo("Syncing '%s' update dir", name);
- HashedDir updateHDir = new HashedDir(updateDir, null, true);
- newUpdatesDirMap.put(name, new SignedObjectHolder<>(updateHDir, privateKey));
- }
- }
- updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
- }
+ // Sync and sign update dir
+ LogHelper.subInfo("Syncing '%s' update dir", name);
+ HashedDir updateHDir = new HashedDir(updateDir, null, true);
+ newUpdatesDirMap.put(name, new SignedObjectHolder<>(updateHDir, privateKey));
+ }
+ }
+ updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
+ }
- private void generateConfigIfNotExists() throws IOException {
- if (IOHelper.isFile(CONFIG_FILE)) {
- return;
- }
+ private void generateConfigIfNotExists() throws IOException {
+ if (IOHelper.isFile(CONFIG_FILE)) {
+ return;
+ }
- // Create new config
- Config newConfig;
- LogHelper.info("Creating LaunchServer config");
- try (BufferedReader reader = IOHelper.newReader(IOHelper.getResourceURL("launchserver/defaults/config.cfg"))) {
- newConfig = new Config(TextConfigReader.read(reader, false));
- }
+ // Create new config
+ Config newConfig;
+ LogHelper.info("Creating LaunchServer config");
+ try (BufferedReader reader = IOHelper.newReader(IOHelper.getResourceURL("launchserver/defaults/config.cfg"))) {
+ newConfig = new Config(TextConfigReader.read(reader, false));
+ }
- // Set server address
- LogHelper.println("LaunchServer address: ");
- newConfig.setAddress(commandHandler.readLine());
+ // Set server address
+ LogHelper.println("LaunchServer address: ");
+ newConfig.setAddress(commandHandler.readLine());
- // Write LaunchServer config
- LogHelper.info("Writing LaunchServer config file");
- try (BufferedWriter writer = IOHelper.newWriter(CONFIG_FILE)) {
- TextConfigWriter.write(newConfig.block, writer, true);
- }
- }
+ // Write LaunchServer config
+ LogHelper.info("Writing LaunchServer config file");
+ try (BufferedWriter writer = IOHelper.newWriter(CONFIG_FILE)) {
+ TextConfigWriter.write(newConfig.block, writer, true);
+ }
+ }
- private void setScriptBindings() {
- LogHelper.info("Setting up server script engine bindings");
- Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
- bindings.put("server", this);
+ private void setScriptBindings() {
+ LogHelper.info("Setting up server script engine bindings");
+ Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
+ bindings.put("server", this);
- // Add launcher and launchserver class bindings
- Launcher.addLauncherClassBindings(bindings);
- addLaunchServerClassBindings(bindings);
- }
+ // Add launcher and launchserver class bindings
+ Launcher.addLauncherClassBindings(bindings);
+ addLaunchServerClassBindings(bindings);
+ }
- private void shutdownHook() {
- serverSocketHandler.close();
+ private void shutdownHook() {
+ serverSocketHandler.close();
- // Close handlers & providers
- try {
- config.authHandler.close();
- } catch (IOException e) {
- LogHelper.error(e);
- }
- try {
- config.authProvider.close();
- } catch (IOException e) {
- LogHelper.error(e);
- }
- try {
- config.textureProvider.close();
- } catch (IOException e) {
- LogHelper.error(e);
- }
+ // Close handlers & providers
+ try {
+ config.authHandler.close();
+ } catch (IOException e) {
+ LogHelper.error(e);
+ }
+ try {
+ config.authProvider.close();
+ } catch (IOException e) {
+ LogHelper.error(e);
+ }
+ try {
+ config.textureProvider.close();
+ } catch (IOException e) {
+ LogHelper.error(e);
+ }
- // Print last message before death :(
- LogHelper.info("LaunchServer stopped");
- }
+ // Print last message before death :(
+ LogHelper.info("LaunchServer stopped");
+ }
- public static void main(String... args) throws Throwable {
- JVMHelper.verifySystemProperties(LaunchServer.class);
- SecurityHelper.verifyCertificates(LaunchServer.class);
- LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log"));
- LogHelper.printVersion("LaunchServer");
+ public static void main(String... args) throws Throwable {
+ JVMHelper.verifySystemProperties(LaunchServer.class);
+ SecurityHelper.verifyCertificates(LaunchServer.class);
+ LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log"));
+ LogHelper.printVersion("LaunchServer");
- // Start LaunchServer
- Instant start = Instant.now();
- try {
- new LaunchServer().run();
- } catch (Exception e) {
- LogHelper.error(e);
- return;
- }
- Instant end = Instant.now();
- LogHelper.debug("LaunchServer started in %dms", Duration.between(start, end).toMillis());
- }
+ // Start LaunchServer
+ Instant start = Instant.now();
+ try {
+ new LaunchServer().run();
+ } catch (Exception e) {
+ LogHelper.error(e);
+ return;
+ }
+ Instant end = Instant.now();
+ LogHelper.debug("LaunchServer started in %dms", Duration.between(start, end).toMillis());
+ }
- private static void addLaunchServerClassBindings(Map bindings) {
- bindings.put("LaunchServerClass", LaunchServer.class);
+ private static void addLaunchServerClassBindings(Map bindings) {
+ bindings.put("LaunchServerClass", LaunchServer.class);
- // Set auth class bindings
- bindings.put("AuthHandlerClass", AuthHandler.class);
- bindings.put("FileAuthHandlerClass", FileAuthHandler.class);
- bindings.put("CachedAuthHandlerClass", CachedAuthHandler.class);
- bindings.put("AuthProviderClass", AuthProvider.class);
- bindings.put("DigestAuthProviderClass", AuthProvider.class);
- bindings.put("MySQLSourceConfigClass", MySQLSourceConfig.class);
- bindings.put("AuthExceptionClass", AuthException.class);
- bindings.put("TextureProviderClass", TextureProvider.class);
+ // Set auth class bindings
+ bindings.put("AuthHandlerClass", AuthHandler.class);
+ bindings.put("FileAuthHandlerClass", FileAuthHandler.class);
+ bindings.put("CachedAuthHandlerClass", CachedAuthHandler.class);
+ bindings.put("AuthProviderClass", AuthProvider.class);
+ bindings.put("DigestAuthProviderClass", AuthProvider.class);
+ bindings.put("MySQLSourceConfigClass", MySQLSourceConfig.class);
+ bindings.put("AuthExceptionClass", AuthException.class);
+ bindings.put("TextureProviderClass", TextureProvider.class);
- // Set command class bindings
- bindings.put("CommandClass", Command.class);
- bindings.put("CommandHandlerClass", CommandHandler.class);
- bindings.put("CommandExceptionClass", CommandException.class);
+ // Set command class bindings
+ bindings.put("CommandClass", Command.class);
+ bindings.put("CommandHandlerClass", CommandHandler.class);
+ bindings.put("CommandExceptionClass", CommandException.class);
- // Set response class bindings
- bindings.put("ResponseClass", Response.class);
- bindings.put("ResponseFactoryClass", Response.Factory.class);
- bindings.put("ServerSocketHandlerListenerClass", ServerSocketHandler.Listener.class);
- }
+ // Set response class bindings
+ bindings.put("ResponseClass", Response.class);
+ bindings.put("ResponseFactoryClass", Factory.class);
+ bindings.put("ServerSocketHandlerListenerClass", Listener.class);
+ }
- private final class ProfilesFileVisitor extends SimpleFileVisitor {
- private final Collection> result;
+ private final class ProfilesFileVisitor extends SimpleFileVisitor {
+ private final Collection> result;
- private ProfilesFileVisitor(Collection> result) {
- this.result = result;
- }
+ private ProfilesFileVisitor(Collection> result) {
+ this.result = result;
+ }
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- LogHelper.subInfo("Syncing '%s' profile", IOHelper.getFileName(file));
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ LogHelper.subInfo("Syncing '%s' profile", IOHelper.getFileName(file));
- // Read profile
- ClientProfile profile;
- try (BufferedReader reader = IOHelper.newReader(file)) {
- profile = new ClientProfile(TextConfigReader.read(reader, true));
- }
- profile.verify();
+ // Read profile
+ ClientProfile profile;
+ try (BufferedReader reader = IOHelper.newReader(file)) {
+ profile = new ClientProfile(TextConfigReader.read(reader, true));
+ }
+ profile.verify();
- // Add SIGNED profile to result list
- result.add(new SignedObjectHolder<>(profile, privateKey));
- return super.visitFile(file, attrs);
- }
- }
+ // Add SIGNED profile to result list
+ result.add(new SignedObjectHolder<>(profile, privateKey));
+ return super.visitFile(file, attrs);
+ }
+ }
- public static final class Config extends ConfigObject {
- @LauncherAPI public final int port;
- private final StringConfigEntry address;
- private final String bindAddress;
+ public static final class Config extends ConfigObject {
+ @LauncherAPI public final int port;
+ // Handlers & Providers
+ @LauncherAPI public final AuthHandler authHandler;
+ @LauncherAPI public final AuthProvider authProvider;
+ @LauncherAPI public final TextureProvider textureProvider;
+ // EXE binary building
+ @LauncherAPI public final boolean launch4J;
+ private final StringConfigEntry address;
+ private final String bindAddress;
- // Handlers & Providers
- @LauncherAPI public final AuthHandler authHandler;
- @LauncherAPI public final AuthProvider authProvider;
- @LauncherAPI public final TextureProvider textureProvider;
+ private Config(BlockConfigEntry block) {
+ super(block);
+ address = block.getEntry("address", StringConfigEntry.class);
+ port = VerifyHelper.verifyInt(block.getEntryValue("port", IntegerConfigEntry.class),
+ VerifyHelper.range(0, 65535), "Illegal LaunchServer port");
+ bindAddress = block.hasEntry("bindAddress") ?
+ block.getEntryValue("bindAddress", StringConfigEntry.class) : getAddress();
- // EXE binary building
- @LauncherAPI public final boolean launch4J;
+ // Set handlers & providers
+ authHandler = AuthHandler.newHandler(block.getEntryValue("authHandler", StringConfigEntry.class),
+ block.getEntry("authHandlerConfig", BlockConfigEntry.class));
+ authProvider = AuthProvider.newProvider(block.getEntryValue("authProvider", StringConfigEntry.class),
+ block.getEntry("authProviderConfig", BlockConfigEntry.class));
+ textureProvider = TextureProvider.newProvider(block.getEntryValue("textureProvider", StringConfigEntry.class),
+ block.getEntry("textureProviderConfig", BlockConfigEntry.class));
- private Config(BlockConfigEntry block) {
- super(block);
- address = block.getEntry("address", StringConfigEntry.class);
- port = VerifyHelper.verifyInt(block.getEntryValue("port", IntegerConfigEntry.class),
- VerifyHelper.range(0, 65535), "Illegal LaunchServer port");
- bindAddress = block.hasEntry("bindAddress") ?
- block.getEntryValue("bindAddress", StringConfigEntry.class) : getAddress();
+ // Set launch4J config
+ launch4J = block.getEntryValue("launch4J", BooleanConfigEntry.class);
+ }
- // Set handlers & providers
- authHandler = AuthHandler.newHandler(block.getEntryValue("authHandler", StringConfigEntry.class),
- block.getEntry("authHandlerConfig", BlockConfigEntry.class));
- authProvider = AuthProvider.newProvider(block.getEntryValue("authProvider", StringConfigEntry.class),
- block.getEntry("authProviderConfig", BlockConfigEntry.class));
- textureProvider = TextureProvider.newProvider(block.getEntryValue("textureProvider", StringConfigEntry.class),
- block.getEntry("textureProviderConfig", BlockConfigEntry.class));
+ @LauncherAPI
+ public String getAddress() {
+ return address.getValue();
+ }
- // Set launch4J config
- launch4J = block.getEntryValue("launch4J", BooleanConfigEntry.class);
- }
+ @LauncherAPI
+ public void setAddress(String address) {
+ this.address.setValue(address);
+ }
- @LauncherAPI
- public String getAddress() {
- return address.getValue();
- }
+ @LauncherAPI
+ public String getBindAddress() {
+ return bindAddress;
+ }
- @LauncherAPI
- public String getBindAddress() {
- return bindAddress;
- }
+ @LauncherAPI
+ public SocketAddress getSocketAddress() {
+ return new InetSocketAddress(bindAddress, port);
+ }
- @LauncherAPI
- public SocketAddress getSocketAddress() {
- return new InetSocketAddress(bindAddress, port);
- }
-
- @LauncherAPI
- public void setAddress(String address) {
- this.address.setValue(address);
- }
-
- @LauncherAPI
- public void verify() {
- VerifyHelper.verify(getAddress(), VerifyHelper.NOT_EMPTY, "LaunchServer address can't be empty");
- }
- }
+ @LauncherAPI
+ public void verify() {
+ VerifyHelper.verify(getAddress(), VerifyHelper.NOT_EMPTY, "LaunchServer address can't be empty");
+ }
+ }
}
diff --git a/LaunchServer/source/auth/AuthException.java b/LaunchServer/source/auth/AuthException.java
index 36cc84c..6e392a2 100644
--- a/LaunchServer/source/auth/AuthException.java
+++ b/LaunchServer/source/auth/AuthException.java
@@ -5,15 +5,15 @@
import launcher.LauncherAPI;
public final class AuthException extends IOException {
- private static final long serialVersionUID = -2586107832847245863L;
+ private static final long serialVersionUID = -2586107832847245863L;
- @LauncherAPI
- public AuthException(String message) {
- super(message);
- }
+ @LauncherAPI
+ public AuthException(String message) {
+ super(message);
+ }
- @Override
- public String toString() {
- return getMessage();
- }
+ @Override
+ public String toString() {
+ return getMessage();
+ }
}
diff --git a/LaunchServer/source/auth/MySQLSourceConfig.java b/LaunchServer/source/auth/MySQLSourceConfig.java
index af0b732..8d18554 100644
--- a/LaunchServer/source/auth/MySQLSourceConfig.java
+++ b/LaunchServer/source/auth/MySQLSourceConfig.java
@@ -1,8 +1,8 @@
package launchserver.auth;
-import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
+import javax.sql.DataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import com.zaxxer.hikari.HikariDataSource;
@@ -15,97 +15,97 @@
import launcher.serialize.config.entry.StringConfigEntry;
public final class MySQLSourceConfig extends ConfigObject implements AutoCloseable {
- @LauncherAPI public static final int TIMEOUT = VerifyHelper.verifyInt(
- Integer.parseUnsignedInt(System.getProperty("launcher.mysql.timeout", Integer.toString(5))),
- VerifyHelper.POSITIVE, "launcher.mysql.timeout can't be <= 0");
- private static final int MAX_POOL_SIZE = VerifyHelper.verifyInt(
- Integer.parseUnsignedInt(System.getProperty("launcher.mysql.maxPoolSize", Integer.toString(25))),
- VerifyHelper.POSITIVE, "launcher.mysql.maxPoolSize can't be <= 0");
- private static final int STMT_CACHE_SIZE = VerifyHelper.verifyInt(
- Integer.parseUnsignedInt(System.getProperty("launcher.mysql.stmtCacheSize", Integer.toString(250))),
- VerifyHelper.NOT_NEGATIVE, "launcher.mysql.stmtCacheSize can't be < 0");
+ @LauncherAPI public static final int TIMEOUT = VerifyHelper.verifyInt(
+ Integer.parseUnsignedInt(System.getProperty("launcher.mysql.timeout", Integer.toString(5))),
+ VerifyHelper.POSITIVE, "launcher.mysql.timeout can't be <= 0");
+ private static final int MAX_POOL_SIZE = VerifyHelper.verifyInt(
+ Integer.parseUnsignedInt(System.getProperty("launcher.mysql.maxPoolSize", Integer.toString(25))),
+ VerifyHelper.POSITIVE, "launcher.mysql.maxPoolSize can't be <= 0");
+ private static final int STMT_CACHE_SIZE = VerifyHelper.verifyInt(
+ Integer.parseUnsignedInt(System.getProperty("launcher.mysql.stmtCacheSize", Integer.toString(250))),
+ VerifyHelper.NOT_NEGATIVE, "launcher.mysql.stmtCacheSize can't be < 0");
- // Instance
- private final String poolName;
+ // Instance
+ private final String poolName;
- // Config
- private final String address;
- private final int port;
- private final String username;
- private final String password;
- private final String database;
+ // Config
+ private final String address;
+ private final int port;
+ private final String username;
+ private final String password;
+ private final String database;
- // Cache
- private DataSource source;
- private boolean hikari;
+ // Cache
+ private DataSource source;
+ private boolean hikari;
- @LauncherAPI
- public MySQLSourceConfig(String poolName, BlockConfigEntry block) {
- super(block);
- this.poolName = poolName;
- address = VerifyHelper.verify(block.getEntryValue("address", StringConfigEntry.class),
- VerifyHelper.NOT_EMPTY, "MySQL address can't be empty");
- port = VerifyHelper.verifyInt(block.getEntryValue("port", IntegerConfigEntry.class),
- VerifyHelper.range(0, 65535), "Illegal MySQL port");
- username = VerifyHelper.verify(block.getEntryValue("username", StringConfigEntry.class),
- VerifyHelper.NOT_EMPTY, "MySQL username can't be empty");
- password = block.getEntryValue("password", StringConfigEntry.class);
- database = VerifyHelper.verify(block.getEntryValue("database", StringConfigEntry.class),
- VerifyHelper.NOT_EMPTY, "MySQL database can't be empty");
+ @LauncherAPI
+ public MySQLSourceConfig(String poolName, BlockConfigEntry block) {
+ super(block);
+ this.poolName = poolName;
+ address = VerifyHelper.verify(block.getEntryValue("address", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL address can't be empty");
+ port = VerifyHelper.verifyInt(block.getEntryValue("port", IntegerConfigEntry.class),
+ VerifyHelper.range(0, 65535), "Illegal MySQL port");
+ username = VerifyHelper.verify(block.getEntryValue("username", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL username can't be empty");
+ password = block.getEntryValue("password", StringConfigEntry.class);
+ database = VerifyHelper.verify(block.getEntryValue("database", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL database can't be empty");
- // Password shouldn't be verified
- }
+ // Password shouldn't be verified
+ }
- @Override
- public synchronized void close() {
- if (hikari) { // Shutdown hikari pool
- ((HikariDataSource) source).close();
- }
- }
+ @Override
+ public synchronized void close() {
+ if (hikari) { // Shutdown hikari pool
+ ((HikariDataSource) source).close();
+ }
+ }
- @LauncherAPI
- public synchronized Connection getConnection() throws SQLException {
- if (source == null) { // New data source
- MysqlDataSource mysqlSource = new MysqlDataSource();
- mysqlSource.setUseUnicode(true);
- mysqlSource.setCachePrepStmts(true);
+ @LauncherAPI
+ public synchronized Connection getConnection() throws SQLException {
+ if (source == null) { // New data source
+ MysqlDataSource mysqlSource = new MysqlDataSource();
+ mysqlSource.setUseUnicode(true);
+ mysqlSource.setCachePrepStmts(true);
- // Set timeouts and cache
- mysqlSource.setEnableQueryTimeouts(true);
- mysqlSource.setLoginTimeout(TIMEOUT);
- mysqlSource.setConnectTimeout(TIMEOUT * 1000);
- mysqlSource.setPrepStmtCacheSize(STMT_CACHE_SIZE);
- mysqlSource.setPrepStmtCacheSqlLimit(2048);
+ // Set timeouts and cache
+ mysqlSource.setEnableQueryTimeouts(true);
+ mysqlSource.setLoginTimeout(TIMEOUT);
+ mysqlSource.setConnectTimeout(TIMEOUT * 1000);
+ mysqlSource.setPrepStmtCacheSize(STMT_CACHE_SIZE);
+ mysqlSource.setPrepStmtCacheSqlLimit(2048);
- // Set credentials
- mysqlSource.setServerName(address);
- mysqlSource.setPortNumber(port);
- mysqlSource.setUser(username);
- mysqlSource.setPassword(password);
- mysqlSource.setDatabaseName(database);
+ // Set credentials
+ mysqlSource.setServerName(address);
+ mysqlSource.setPortNumber(port);
+ mysqlSource.setUser(username);
+ mysqlSource.setPassword(password);
+ mysqlSource.setDatabaseName(database);
- // Try using HikariCP
- source = mysqlSource;
- try {
- Class.forName("com.zaxxer.hikari.HikariDataSource");
- hikari = true; // Used for shutdown. Not instanceof because of possible classpath error
+ // Try using HikariCP
+ source = mysqlSource;
+ try {
+ Class.forName("com.zaxxer.hikari.HikariDataSource");
+ hikari = true; // Used for shutdown. Not instanceof because of possible classpath error
- // Set HikariCP pool
- HikariDataSource hikariSource = new HikariDataSource();
- hikariSource.setDataSource(source);
+ // Set HikariCP pool
+ HikariDataSource hikariSource = new HikariDataSource();
+ hikariSource.setDataSource(source);
- // Set pool settings
- hikariSource.setPoolName(poolName);
- hikariSource.setMaximumPoolSize(MAX_POOL_SIZE);
- hikariSource.setValidationTimeout(TIMEOUT * 1000L);
+ // Set pool settings
+ hikariSource.setPoolName(poolName);
+ hikariSource.setMaximumPoolSize(MAX_POOL_SIZE);
+ hikariSource.setValidationTimeout(TIMEOUT * 1000L);
- // Replace source with hds
- source = hikariSource;
- LogHelper.info("HikariCP pooling enabled for '%s'", poolName);
- } catch (ClassNotFoundException ignored) {
- LogHelper.warning("HikariCP isn't in classpath for '%s'", poolName);
- }
- }
- return source.getConnection();
- }
+ // Replace source with hds
+ source = hikariSource;
+ LogHelper.info("HikariCP pooling enabled for '%s'", poolName);
+ } catch (ClassNotFoundException ignored) {
+ LogHelper.warning("HikariCP isn't in classpath for '%s'", poolName);
+ }
+ }
+ return source.getConnection();
+ }
}
diff --git a/LaunchServer/source/auth/handler/AuthHandler.java b/LaunchServer/source/auth/handler/AuthHandler.java
index d04462d..61b4593 100644
--- a/LaunchServer/source/auth/handler/AuthHandler.java
+++ b/LaunchServer/source/auth/handler/AuthHandler.java
@@ -13,57 +13,57 @@
import launchserver.auth.AuthException;
public abstract class AuthHandler extends ConfigObject implements AutoCloseable {
- private static final Map> AUTH_HANDLERS = new ConcurrentHashMap<>(4);
+ private static final Map> AUTH_HANDLERS = new ConcurrentHashMap<>(4);
- @LauncherAPI
- protected AuthHandler(BlockConfigEntry block) {
- super(block);
- }
+ @LauncherAPI
+ protected AuthHandler(BlockConfigEntry block) {
+ super(block);
+ }
- @Override
- public abstract void close() throws IOException;
+ @Override
+ public abstract void close() throws IOException;
- @LauncherAPI
- public abstract UUID auth(String username, String accessToken) throws IOException;
+ @LauncherAPI
+ public abstract UUID auth(String username, String accessToken) throws IOException;
- @LauncherAPI
- public abstract UUID checkServer(String username, String serverID) throws IOException;
+ @LauncherAPI
+ public abstract UUID checkServer(String username, String serverID) throws IOException;
- @LauncherAPI
- public abstract boolean joinServer(String username, String accessToken, String serverID) throws IOException;
+ @LauncherAPI
+ public abstract boolean joinServer(String username, String accessToken, String serverID) throws IOException;
- @LauncherAPI
- public abstract UUID usernameToUUID(String username) throws IOException;
+ @LauncherAPI
+ public abstract UUID usernameToUUID(String username) throws IOException;
- @LauncherAPI
- public abstract String uuidToUsername(UUID uuid) throws IOException;
+ @LauncherAPI
+ public abstract String uuidToUsername(UUID uuid) throws IOException;
- @LauncherAPI
- public static UUID authError(String message) throws AuthException {
- throw new AuthException(message);
- }
+ @LauncherAPI
+ public static UUID authError(String message) throws AuthException {
+ throw new AuthException(message);
+ }
- @LauncherAPI
- public static AuthHandler newHandler(String name, BlockConfigEntry block) {
- Adapter authHandlerAdapter = VerifyHelper.getMapValue(AUTH_HANDLERS, name,
- String.format("Unknown auth handler: '%s'", name));
- return authHandlerAdapter.convert(block);
- }
+ @LauncherAPI
+ public static AuthHandler newHandler(String name, BlockConfigEntry block) {
+ Adapter authHandlerAdapter = VerifyHelper.getMapValue(AUTH_HANDLERS, name,
+ String.format("Unknown auth handler: '%s'", name));
+ return authHandlerAdapter.convert(block);
+ }
- @LauncherAPI
- public static void registerHandler(String name, Adapter adapter) {
- VerifyHelper.verifyIDName(name);
- VerifyHelper.putIfAbsent(AUTH_HANDLERS, name, Objects.requireNonNull(adapter, "adapter"),
- String.format("Auth handler has been already registered: '%s'", name));
- }
+ @LauncherAPI
+ public static void registerHandler(String name, Adapter adapter) {
+ VerifyHelper.verifyIDName(name);
+ VerifyHelper.putIfAbsent(AUTH_HANDLERS, name, Objects.requireNonNull(adapter, "adapter"),
+ String.format("Auth handler has been already registered: '%s'", name));
+ }
- static {
- registerHandler("null", NullAuthHandler::new);
- registerHandler("memory", MemoryAuthHandler::new);
+ static {
+ registerHandler("null", NullAuthHandler::new);
+ registerHandler("memory", MemoryAuthHandler::new);
- // Auth handler that doesn't do nothing :D
- registerHandler("binaryFile", BinaryFileAuthHandler::new);
- registerHandler("textFile", TextFileAuthHandler::new);
- registerHandler("mysql", MySQLAuthHandler::new);
- }
+ // Auth handler that doesn't do nothing :D
+ registerHandler("binaryFile", BinaryFileAuthHandler::new);
+ registerHandler("textFile", TextFileAuthHandler::new);
+ registerHandler("mysql", MySQLAuthHandler::new);
+ }
}
diff --git a/LaunchServer/source/auth/handler/BinaryFileAuthHandler.java b/LaunchServer/source/auth/handler/BinaryFileAuthHandler.java
index c6813f4..51259e5 100644
--- a/LaunchServer/source/auth/handler/BinaryFileAuthHandler.java
+++ b/LaunchServer/source/auth/handler/BinaryFileAuthHandler.java
@@ -11,31 +11,31 @@
import launcher.serialize.config.entry.BlockConfigEntry;
public final class BinaryFileAuthHandler extends FileAuthHandler {
- public BinaryFileAuthHandler(BlockConfigEntry block) {
- super(block);
- }
+ public BinaryFileAuthHandler(BlockConfigEntry block) {
+ super(block);
+ }
- @Override
- protected void readAuthFile() throws IOException {
- try (HInput input = new HInput(IOHelper.newInput(file))) {
- int count = input.readLength(0);
- for (int i = 0; i < count; i++) {
- UUID uuid = input.readUUID();
- Entry entry = new Entry(input);
- addAuth(uuid, entry);
- }
- }
- }
+ @Override
+ protected void readAuthFile() throws IOException {
+ try (HInput input = new HInput(IOHelper.newInput(file))) {
+ int count = input.readLength(0);
+ for (int i = 0; i < count; i++) {
+ UUID uuid = input.readUUID();
+ Entry entry = new Entry(input);
+ addAuth(uuid, entry);
+ }
+ }
+ }
- @Override
- protected void writeAuthFile() throws IOException {
- Set> entrySet = entrySet();
- try (HOutput output = new HOutput(IOHelper.newOutput(file))) {
- output.writeLength(entrySet.size(), 0);
- for (Map.Entry entry : entrySet) {
- output.writeUUID(entry.getKey());
- entry.getValue().write(output);
- }
- }
- }
+ @Override
+ protected void writeAuthFile() throws IOException {
+ Set> entrySet = entrySet();
+ try (HOutput output = new HOutput(IOHelper.newOutput(file))) {
+ output.writeLength(entrySet.size(), 0);
+ for (Map.Entry entry : entrySet) {
+ output.writeUUID(entry.getKey());
+ entry.getValue().write(output);
+ }
+ }
+ }
}
diff --git a/LaunchServer/source/auth/handler/CachedAuthHandler.java b/LaunchServer/source/auth/handler/CachedAuthHandler.java
index 1f77197..9050aa6 100644
--- a/LaunchServer/source/auth/handler/CachedAuthHandler.java
+++ b/LaunchServer/source/auth/handler/CachedAuthHandler.java
@@ -13,120 +13,120 @@
import launcher.serialize.config.entry.BlockConfigEntry;
public abstract class CachedAuthHandler extends AuthHandler {
- private final Map entryCache = new HashMap<>();
- private final Map usernamesCache = new HashMap<>();
+ private final Map entryCache = new HashMap<>();
+ private final Map usernamesCache = new HashMap<>();
- @LauncherAPI
- protected CachedAuthHandler(BlockConfigEntry block) {
- super(block);
- }
+ @LauncherAPI
+ protected CachedAuthHandler(BlockConfigEntry block) {
+ super(block);
+ }
- @Override
- public final synchronized UUID auth(String username, String accessToken) throws IOException {
- Entry entry = getEntry(username);
- if (entry == null || !updateAuth(entry.uuid, entry.username, accessToken)) {
- return authError(String.format("UUID is null for username '%s'", username));
- }
+ @Override
+ public final synchronized UUID auth(String username, String accessToken) throws IOException {
+ Entry entry = getEntry(username);
+ if (entry == null || !updateAuth(entry.uuid, entry.username, accessToken)) {
+ return authError(String.format("UUID is null for username '%s'", username));
+ }
- // Update cached access token (and username case)
- entry.username = username;
- entry.accessToken = accessToken;
- entry.serverID = null;
- return entry.uuid;
- }
+ // Update cached access token (and username case)
+ entry.username = username;
+ entry.accessToken = accessToken;
+ entry.serverID = null;
+ return entry.uuid;
+ }
- @Override
- public final synchronized UUID checkServer(String username, String serverID) throws IOException {
- Entry entry = getEntry(username);
- return entry != null && username.equals(entry.username) &&
- serverID.equals(entry.serverID) ? entry.uuid : null;
- }
+ @Override
+ public final synchronized UUID checkServer(String username, String serverID) throws IOException {
+ Entry entry = getEntry(username);
+ return entry != null && username.equals(entry.username) &&
+ serverID.equals(entry.serverID) ? entry.uuid : null;
+ }
- @Override
- public final synchronized boolean joinServer(String username, String accessToken, String serverID) throws IOException {
- Entry entry = getEntry(username);
- if (entry == null || !username.equals(entry.username) || !accessToken.equals(entry.accessToken) ||
- !updateServerID(entry.uuid, serverID)) {
- return false; // Account doesn't exist or invalid access token
- }
+ @Override
+ public final synchronized boolean joinServer(String username, String accessToken, String serverID) throws IOException {
+ Entry entry = getEntry(username);
+ if (entry == null || !username.equals(entry.username) || !accessToken.equals(entry.accessToken) ||
+ !updateServerID(entry.uuid, serverID)) {
+ return false; // Account doesn't exist or invalid access token
+ }
- // Update cached server ID
- entry.serverID = serverID;
- return true;
- }
+ // Update cached server ID
+ entry.serverID = serverID;
+ return true;
+ }
- @Override
- public final synchronized UUID usernameToUUID(String username) throws IOException {
- Entry entry = getEntry(username);
- return entry == null ? null : entry.uuid;
- }
+ @Override
+ public final synchronized UUID usernameToUUID(String username) throws IOException {
+ Entry entry = getEntry(username);
+ return entry == null ? null : entry.uuid;
+ }
- @Override
- public final synchronized String uuidToUsername(UUID uuid) throws IOException {
- Entry entry = getEntry(uuid);
- return entry == null ? null : entry.username;
- }
+ @Override
+ public final synchronized String uuidToUsername(UUID uuid) throws IOException {
+ Entry entry = getEntry(uuid);
+ return entry == null ? null : entry.username;
+ }
- @LauncherAPI
- protected void addEntry(Entry entry) {
- Entry previous = entryCache.put(entry.uuid, entry);
- if (previous != null) { // In case of username changing
- usernamesCache.remove(CommonHelper.low(previous.username));
- }
- usernamesCache.put(CommonHelper.low(entry.username), entry.uuid);
- }
+ @LauncherAPI
+ protected abstract Entry fetchEntry(UUID uuid) throws IOException;
- @LauncherAPI
- protected abstract Entry fetchEntry(UUID uuid) throws IOException;
+ @LauncherAPI
+ protected abstract Entry fetchEntry(String username) throws IOException;
- @LauncherAPI
- protected abstract Entry fetchEntry(String username) throws IOException;
+ @LauncherAPI
+ protected abstract boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException;
- @LauncherAPI
- protected abstract boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException;
+ @LauncherAPI
+ protected abstract boolean updateServerID(UUID uuid, String serverID) throws IOException;
- @LauncherAPI
- protected abstract boolean updateServerID(UUID uuid, String serverID) throws IOException;
+ @LauncherAPI
+ protected void addEntry(Entry entry) {
+ Entry previous = entryCache.put(entry.uuid, entry);
+ if (previous != null) { // In case of username changing
+ usernamesCache.remove(CommonHelper.low(previous.username));
+ }
+ usernamesCache.put(CommonHelper.low(entry.username), entry.uuid);
+ }
- private Entry getEntry(UUID uuid) throws IOException {
- Entry entry = entryCache.get(uuid);
- if (entry == null) {
- entry = fetchEntry(uuid);
- if (entry != null) {
- addEntry(entry);
- }
- }
- return entry;
- }
+ private Entry getEntry(UUID uuid) throws IOException {
+ Entry entry = entryCache.get(uuid);
+ if (entry == null) {
+ entry = fetchEntry(uuid);
+ if (entry != null) {
+ addEntry(entry);
+ }
+ }
+ return entry;
+ }
- private Entry getEntry(String username) throws IOException {
- UUID uuid = usernamesCache.get(CommonHelper.low(username));
- if (uuid != null) {
- return getEntry(uuid);
- }
+ private Entry getEntry(String username) throws IOException {
+ UUID uuid = usernamesCache.get(CommonHelper.low(username));
+ if (uuid != null) {
+ return getEntry(uuid);
+ }
- // Fetch entry by username
- Entry entry = fetchEntry(username);
- if (entry != null) {
- addEntry(entry);
- }
+ // Fetch entry by username
+ Entry entry = fetchEntry(username);
+ if (entry != null) {
+ addEntry(entry);
+ }
- // Return what we got
- return entry;
- }
+ // Return what we got
+ return entry;
+ }
- public final class Entry {
- @LauncherAPI public final UUID uuid;
- private String username;
- private String accessToken;
- private String serverID;
+ public final class Entry {
+ @LauncherAPI public final UUID uuid;
+ private String username;
+ private String accessToken;
+ private String serverID;
- @LauncherAPI
- public Entry(UUID uuid, String username, String accessToken, String serverID) {
- this.uuid = Objects.requireNonNull(uuid, "uuid");
- this.username = Objects.requireNonNull(username, "username");
- this.accessToken = accessToken == null ? null : SecurityHelper.verifyToken(accessToken);
- this.serverID = serverID == null ? null : JoinServerRequest.verifyServerID(serverID);
- }
- }
+ @LauncherAPI
+ public Entry(UUID uuid, String username, String accessToken, String serverID) {
+ this.uuid = Objects.requireNonNull(uuid, "uuid");
+ this.username = Objects.requireNonNull(username, "username");
+ this.accessToken = accessToken == null ? null : SecurityHelper.verifyToken(accessToken);
+ this.serverID = serverID == null ? null : JoinServerRequest.verifyServerID(serverID);
+ }
+ }
}
diff --git a/LaunchServer/source/auth/handler/FileAuthHandler.java b/LaunchServer/source/auth/handler/FileAuthHandler.java
index a937876..0e0b46c 100644
--- a/LaunchServer/source/auth/handler/FileAuthHandler.java
+++ b/LaunchServer/source/auth/handler/FileAuthHandler.java
@@ -26,237 +26,237 @@
import launcher.serialize.stream.StreamObject;
public abstract class FileAuthHandler extends AuthHandler {
- @LauncherAPI public final Path file;
- @LauncherAPI public final boolean offlineUUIDs;
+ @LauncherAPI public final Path file;
+ @LauncherAPI public final boolean offlineUUIDs;
- // Instance
- private final SecureRandom random = SecurityHelper.newRandom();
- private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+ // Instance
+ private final SecureRandom random = SecurityHelper.newRandom();
+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
- // Storage
- private final Map entryMap = new HashMap<>();
- private final Map usernamesMap = new HashMap<>();
+ // Storage
+ private final Map entryMap = new HashMap<>();
+ private final Map usernamesMap = new HashMap<>();
- @LauncherAPI
- protected FileAuthHandler(BlockConfigEntry block) {
- super(block);
- file = IOHelper.toPath(block.getEntryValue("file", StringConfigEntry.class));
- offlineUUIDs = block.getEntryValue("offlineUUIDs", BooleanConfigEntry.class);
+ @LauncherAPI
+ protected FileAuthHandler(BlockConfigEntry block) {
+ super(block);
+ file = IOHelper.toPath(block.getEntryValue("file", StringConfigEntry.class));
+ offlineUUIDs = block.getEntryValue("offlineUUIDs", BooleanConfigEntry.class);
- // Read auth handler file
- if (IOHelper.isFile(file)) {
- LogHelper.info("Reading auth handler file: '%s'", file);
- try {
- readAuthFile();
- } catch (IOException e) {
- LogHelper.error(e);
- }
- }
- }
+ // Read auth handler file
+ if (IOHelper.isFile(file)) {
+ LogHelper.info("Reading auth handler file: '%s'", file);
+ try {
+ readAuthFile();
+ } catch (IOException e) {
+ LogHelper.error(e);
+ }
+ }
+ }
- @Override
- public final UUID auth(String username, String accessToken) {
- lock.writeLock().lock();
- try {
- UUID uuid = usernameToUUID(username);
- Entry entry = entryMap.get(uuid);
+ @Override
+ public final UUID auth(String username, String accessToken) {
+ lock.writeLock().lock();
+ try {
+ UUID uuid = usernameToUUID(username);
+ Entry entry = entryMap.get(uuid);
- // Not registered? Fix it!
- if (entry == null) {
- entry = new Entry(username);
+ // Not registered? Fix it!
+ if (entry == null) {
+ entry = new Entry(username);
- // Generate UUID
- uuid = genUUIDFor(username);
- entryMap.put(uuid, entry);
- usernamesMap.put(CommonHelper.low(username), uuid);
- }
+ // Generate UUID
+ uuid = genUUIDFor(username);
+ entryMap.put(uuid, entry);
+ usernamesMap.put(CommonHelper.low(username), uuid);
+ }
- // Authenticate
- entry.auth(username, accessToken);
- return uuid;
- } finally {
- lock.writeLock().unlock();
- }
- }
+ // Authenticate
+ entry.auth(username, accessToken);
+ return uuid;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
- @Override
- public final UUID checkServer(String username, String serverID) {
- lock.readLock().lock();
- try {
- UUID uuid = usernameToUUID(username);
- Entry entry = entryMap.get(uuid);
+ @Override
+ public final UUID checkServer(String username, String serverID) {
+ lock.readLock().lock();
+ try {
+ UUID uuid = usernameToUUID(username);
+ Entry entry = entryMap.get(uuid);
- // Check server (if has such account of course)
- return entry != null && entry.checkServer(username, serverID) ? uuid : null;
- } finally {
- lock.readLock().unlock();
- }
- }
+ // Check server (if has such account of course)
+ return entry != null && entry.checkServer(username, serverID) ? uuid : null;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
- @Override
- public final void close() throws IOException {
- lock.readLock().lock();
- try {
- LogHelper.info("Writing auth handler file (%d entries)", entryMap.size());
- writeAuthFile();
- } finally {
- lock.readLock().unlock();
- }
- }
+ @Override
+ public final void close() throws IOException {
+ lock.readLock().lock();
+ try {
+ LogHelper.info("Writing auth handler file (%d entries)", entryMap.size());
+ writeAuthFile();
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
- @Override
- public final boolean joinServer(String username, String accessToken, String serverID) {
- lock.writeLock().lock();
- try {
- Entry entry = entryMap.get(usernameToUUID(username));
- return entry != null && entry.joinServer(username, accessToken, serverID);
- } finally {
- lock.writeLock().unlock();
- }
- }
+ @Override
+ public final boolean joinServer(String username, String accessToken, String serverID) {
+ lock.writeLock().lock();
+ try {
+ Entry entry = entryMap.get(usernameToUUID(username));
+ return entry != null && entry.joinServer(username, accessToken, serverID);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
- @Override
- public final UUID usernameToUUID(String username) {
- lock.readLock().lock();
- try {
- return usernamesMap.get(CommonHelper.low(username));
- } finally {
- lock.readLock().unlock();
- }
- }
+ @Override
+ public final UUID usernameToUUID(String username) {
+ lock.readLock().lock();
+ try {
+ return usernamesMap.get(CommonHelper.low(username));
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
- @Override
- public final String uuidToUsername(UUID uuid) {
- lock.readLock().lock();
- try {
- Entry entry = entryMap.get(uuid);
- return entry == null ? null : entry.username;
- } finally {
- lock.readLock().unlock();
- }
- }
+ @Override
+ public final String uuidToUsername(UUID uuid) {
+ lock.readLock().lock();
+ try {
+ Entry entry = entryMap.get(uuid);
+ return entry == null ? null : entry.username;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
- @LauncherAPI
- protected final void addAuth(UUID uuid, Entry entry) throws IOException {
- lock.writeLock().lock();
- try {
- Entry previous = entryMap.put(uuid, entry);
- if (previous != null) { // In case of username changing
- usernamesMap.remove(CommonHelper.low(previous.username));
- }
- usernamesMap.put(CommonHelper.low(entry.username), uuid);
- } finally {
- lock.writeLock().unlock();
- }
- }
+ @LauncherAPI
+ protected abstract void readAuthFile() throws IOException;
- @LauncherAPI
- protected final Set> entrySet() {
- return Collections.unmodifiableMap(entryMap).entrySet();
- }
+ @LauncherAPI
+ protected abstract void writeAuthFile() throws IOException;
- @LauncherAPI
- protected abstract void readAuthFile() throws IOException;
+ @LauncherAPI
+ protected final void addAuth(UUID uuid, Entry entry) {
+ lock.writeLock().lock();
+ try {
+ Entry previous = entryMap.put(uuid, entry);
+ if (previous != null) { // In case of username changing
+ usernamesMap.remove(CommonHelper.low(previous.username));
+ }
+ usernamesMap.put(CommonHelper.low(entry.username), uuid);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
- @LauncherAPI
- protected abstract void writeAuthFile() throws IOException;
+ @LauncherAPI
+ protected final Set> entrySet() {
+ return Collections.unmodifiableMap(entryMap).entrySet();
+ }
- private UUID genUUIDFor(String username) {
- if (offlineUUIDs) {
- UUID md5UUID = PlayerProfile.offlineUUID(username);
- if (!entryMap.containsKey(md5UUID)) {
- return md5UUID;
- }
- LogHelper.warning("Offline UUID collision, using random: '%s'", username);
- }
+ private UUID genUUIDFor(String username) {
+ if (offlineUUIDs) {
+ UUID md5UUID = PlayerProfile.offlineUUID(username);
+ if (!entryMap.containsKey(md5UUID)) {
+ return md5UUID;
+ }
+ LogHelper.warning("Offline UUID collision, using random: '%s'", username);
+ }
- // Pick random UUID
- UUID uuid;
- do {
- uuid = new UUID(random.nextLong(), random.nextLong());
- } while (entryMap.containsKey(uuid));
- return uuid;
- }
+ // Pick random UUID
+ UUID uuid;
+ do {
+ uuid = new UUID(random.nextLong(), random.nextLong());
+ } while (entryMap.containsKey(uuid));
+ return uuid;
+ }
- public static final class Entry extends StreamObject {
- private String username;
- private String accessToken;
- private String serverID;
+ public static final class Entry extends StreamObject {
+ private String username;
+ private String accessToken;
+ private String serverID;
- @LauncherAPI
- public Entry(String username) {
- this.username = VerifyHelper.verifyUsername(username);
- }
+ @LauncherAPI
+ public Entry(String username) {
+ this.username = VerifyHelper.verifyUsername(username);
+ }
- @LauncherAPI
- public Entry(String username, String accessToken, String serverID) {
- this(username);
- if (accessToken == null && serverID != null) {
- throw new IllegalArgumentException("Can't set access token while server ID is null");
- }
+ @LauncherAPI
+ public Entry(String username, String accessToken, String serverID) {
+ this(username);
+ if (accessToken == null && serverID != null) {
+ throw new IllegalArgumentException("Can't set access token while server ID is null");
+ }
- // Set and verify access token
- this.accessToken = accessToken == null ? null : SecurityHelper.verifyToken(accessToken);
- this.serverID = serverID == null ? null : JoinServerRequest.verifyServerID(serverID);
- }
+ // Set and verify access token
+ this.accessToken = accessToken == null ? null : SecurityHelper.verifyToken(accessToken);
+ this.serverID = serverID == null ? null : JoinServerRequest.verifyServerID(serverID);
+ }
- @LauncherAPI
- public Entry(HInput input) throws IOException {
- username = VerifyHelper.verifyUsername(input.readASCII(16));
- if (input.readBoolean()) {
- accessToken = SecurityHelper.verifyToken(input.readASCII(-SecurityHelper.TOKEN_STRING_LENGTH));
- if (input.readBoolean()) {
- serverID = JoinServerRequest.verifyServerID(input.readASCII(41));
- }
- }
- }
+ @LauncherAPI
+ public Entry(HInput input) throws IOException {
+ username = VerifyHelper.verifyUsername(input.readASCII(16));
+ if (input.readBoolean()) {
+ accessToken = SecurityHelper.verifyToken(input.readASCII(-SecurityHelper.TOKEN_STRING_LENGTH));
+ if (input.readBoolean()) {
+ serverID = JoinServerRequest.verifyServerID(input.readASCII(41));
+ }
+ }
+ }
- @Override
- public void write(HOutput output) throws IOException {
- output.writeASCII(username, 16);
- output.writeBoolean(accessToken != null);
- if (accessToken != null) {
- output.writeASCII(accessToken, -SecurityHelper.TOKEN_STRING_LENGTH);
- output.writeBoolean(serverID != null);
- if (serverID != null) {
- output.writeASCII(serverID, 41);
- }
- }
- }
+ @Override
+ public void write(HOutput output) throws IOException {
+ output.writeASCII(username, 16);
+ output.writeBoolean(accessToken != null);
+ if (accessToken != null) {
+ output.writeASCII(accessToken, -SecurityHelper.TOKEN_STRING_LENGTH);
+ output.writeBoolean(serverID != null);
+ if (serverID != null) {
+ output.writeASCII(serverID, 41);
+ }
+ }
+ }
- @LauncherAPI
- public String getAccessToken() {
- return accessToken;
- }
+ @LauncherAPI
+ public String getAccessToken() {
+ return accessToken;
+ }
- @LauncherAPI
- public String getServerID() {
- return serverID;
- }
+ @LauncherAPI
+ public String getServerID() {
+ return serverID;
+ }
- @LauncherAPI
- public String getUsername() {
- return username;
- }
+ @LauncherAPI
+ public String getUsername() {
+ return username;
+ }
- private void auth(String username, String accessToken) {
- this.username = username; // Update username case
- this.accessToken = accessToken;
- serverID = null;
- }
+ private void auth(String username, String accessToken) {
+ this.username = username; // Update username case
+ this.accessToken = accessToken;
+ serverID = null;
+ }
- private boolean checkServer(String username, String serverID) {
- return username.equals(this.username) && serverID.equals(this.serverID);
- }
+ private boolean checkServer(String username, String serverID) {
+ return username.equals(this.username) && serverID.equals(this.serverID);
+ }
- private boolean joinServer(String username, String accessToken, String serverID) {
- if (!username.equals(this.username) || !accessToken.equals(this.accessToken)) {
- return false; // Username or access token mismatch
- }
+ private boolean joinServer(String username, String accessToken, String serverID) {
+ if (!username.equals(this.username) || !accessToken.equals(this.accessToken)) {
+ return false; // Username or access token mismatch
+ }
- // Update server ID
- this.serverID = serverID;
- return true;
- }
- }
+ // Update server ID
+ this.serverID = serverID;
+ return true;
+ }
+ }
}
diff --git a/LaunchServer/source/auth/handler/MemoryAuthHandler.java b/LaunchServer/source/auth/handler/MemoryAuthHandler.java
index 7d9e8ed..9ccadde 100644
--- a/LaunchServer/source/auth/handler/MemoryAuthHandler.java
+++ b/LaunchServer/source/auth/handler/MemoryAuthHandler.java
@@ -11,53 +11,53 @@
import launcher.serialize.config.entry.BlockConfigEntry;
public final class MemoryAuthHandler extends CachedAuthHandler {
- public MemoryAuthHandler(BlockConfigEntry block) {
- super(block);
- LogHelper.warning("Usage of MemoryAuthHandler isn't recommended!");
- }
+ public MemoryAuthHandler(BlockConfigEntry block) {
+ super(block);
+ LogHelper.warning("Usage of MemoryAuthHandler isn't recommended!");
+ }
- @Override
- public void close() {
- // Do nothing
- }
+ @Override
+ public void close() {
+ // Do nothing
+ }
- @Override
- protected Entry fetchEntry(UUID uuid) throws IOException {
- return new Entry(uuid, toUsername(uuid), null, null);
- }
+ @Override
+ protected Entry fetchEntry(UUID uuid) {
+ return new Entry(uuid, toUsername(uuid), null, null);
+ }
- @Override
- protected Entry fetchEntry(String username) throws IOException {
- return new Entry(toUUID(username), username, null, null);
- }
+ @Override
+ protected Entry fetchEntry(String username) {
+ return new Entry(toUUID(username), username, null, null);
+ }
- @Override
- protected boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException {
- return true; // Do nothing
- }
+ @Override
+ protected boolean updateAuth(UUID uuid, String username, String accessToken) {
+ return true; // Do nothing
+ }
- @Override
- protected boolean updateServerID(UUID uuid, String serverID) throws IOException {
- return true; // Do nothing
- }
+ @Override
+ protected boolean updateServerID(UUID uuid, String serverID) {
+ return true; // Do nothing
+ }
- private static UUID toUUID(String username) {
- ByteBuffer buffer = ByteBuffer.wrap(Arrays.copyOf(IOHelper.encodeASCII(username), 16));
- return new UUID(buffer.getLong(), buffer.getLong()); // MOST, LEAST
- }
+ private static UUID toUUID(String username) {
+ ByteBuffer buffer = ByteBuffer.wrap(Arrays.copyOf(IOHelper.encodeASCII(username), 16));
+ return new UUID(buffer.getLong(), buffer.getLong()); // MOST, LEAST
+ }
- private static String toUsername(UUID uuid) {
- byte[] bytes = ByteBuffer.allocate(16).
- putLong(uuid.getMostSignificantBits()).
- putLong(uuid.getLeastSignificantBits()).array();
+ private static String toUsername(UUID uuid) {
+ byte[] bytes = ByteBuffer.allocate(16).
+ putLong(uuid.getMostSignificantBits()).
+ putLong(uuid.getLeastSignificantBits()).array();
- // Find username end
- int length = 0;
- while (length < bytes.length && bytes[length] != 0) {
- length++;
- }
+ // Find username end
+ int length = 0;
+ while (length < bytes.length && bytes[length] != 0) {
+ length++;
+ }
- // Decode and verify
- return VerifyHelper.verifyUsername(new String(bytes, 0, length, IOHelper.ASCII_CHARSET));
- }
+ // Decode and verify
+ return VerifyHelper.verifyUsername(new String(bytes, 0, length, IOHelper.ASCII_CHARSET));
+ }
}
diff --git a/LaunchServer/source/auth/handler/MySQLAuthHandler.java b/LaunchServer/source/auth/handler/MySQLAuthHandler.java
index 1c41ab2..6a29d75 100644
--- a/LaunchServer/source/auth/handler/MySQLAuthHandler.java
+++ b/LaunchServer/source/auth/handler/MySQLAuthHandler.java
@@ -16,121 +16,121 @@
import launchserver.auth.MySQLSourceConfig;
public final class MySQLAuthHandler extends CachedAuthHandler {
- private final MySQLSourceConfig mySQLHolder;
- private final String table;
- private final String uuidColumn;
- private final String usernameColumn;
- private final String accessTokenColumn;
- private final String serverIDColumn;
+ private final MySQLSourceConfig mySQLHolder;
+ private final String table;
+ private final String uuidColumn;
+ private final String usernameColumn;
+ private final String accessTokenColumn;
+ private final String serverIDColumn;
- // Prepared SQL queries
- private final String queryByUUIDSQL;
- private final String queryByUsernameSQL;
- private final String updateAuthSQL;
- private final String updateServerIDSQL;
+ // Prepared SQL queries
+ private final String queryByUUIDSQL;
+ private final String queryByUsernameSQL;
+ private final String updateAuthSQL;
+ private final String updateServerIDSQL;
- public MySQLAuthHandler(BlockConfigEntry block) {
- super(block);
- mySQLHolder = new MySQLSourceConfig("authHandlerPool", block);
+ public MySQLAuthHandler(BlockConfigEntry block) {
+ super(block);
+ mySQLHolder = new MySQLSourceConfig("authHandlerPool", block);
- // Read query params
- table = VerifyHelper.verifyIDName(
- block.getEntryValue("table", StringConfigEntry.class));
- uuidColumn = VerifyHelper.verifyIDName(
- block.getEntryValue("uuidColumn", StringConfigEntry.class));
- usernameColumn = VerifyHelper.verifyIDName(
- block.getEntryValue("usernameColumn", StringConfigEntry.class));
- accessTokenColumn = VerifyHelper.verifyIDName(
- block.getEntryValue("accessTokenColumn", StringConfigEntry.class));
- serverIDColumn = VerifyHelper.verifyIDName(
- block.getEntryValue("serverIDColumn", StringConfigEntry.class));
+ // Read query params
+ table = VerifyHelper.verifyIDName(
+ block.getEntryValue("table", StringConfigEntry.class));
+ uuidColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("uuidColumn", StringConfigEntry.class));
+ usernameColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("usernameColumn", StringConfigEntry.class));
+ accessTokenColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("accessTokenColumn", StringConfigEntry.class));
+ serverIDColumn = VerifyHelper.verifyIDName(
+ block.getEntryValue("serverIDColumn", StringConfigEntry.class));
- // Prepare SQL queries
- queryByUUIDSQL = String.format("SELECT %s, %s, %s, %s FROM %s WHERE %s=? LIMIT 1",
- uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table, uuidColumn);
- queryByUsernameSQL = String.format("SELECT %s, %s, %s, %s FROM %s WHERE %s=? LIMIT 1",
- uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table, usernameColumn);
- updateAuthSQL = String.format("UPDATE %s SET %s=?, %s=?, %s=NULL WHERE %s=? LIMIT 1",
- table, usernameColumn, accessTokenColumn, serverIDColumn, uuidColumn);
- updateServerIDSQL = String.format("UPDATE %s SET %s=? WHERE %s=? LIMIT 1",
- table, serverIDColumn, uuidColumn);
+ // Prepare SQL queries
+ queryByUUIDSQL = String.format("SELECT %s, %s, %s, %s FROM %s WHERE %s=? LIMIT 1",
+ uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table, uuidColumn);
+ queryByUsernameSQL = String.format("SELECT %s, %s, %s, %s FROM %s WHERE %s=? LIMIT 1",
+ uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table, usernameColumn);
+ updateAuthSQL = String.format("UPDATE %s SET %s=?, %s=?, %s=NULL WHERE %s=? LIMIT 1",
+ table, usernameColumn, accessTokenColumn, serverIDColumn, uuidColumn);
+ updateServerIDSQL = String.format("UPDATE %s SET %s=? WHERE %s=? LIMIT 1",
+ table, serverIDColumn, uuidColumn);
- // Fetch all entries
- if (block.getEntryValue("fetchAll", BooleanConfigEntry.class)) {
- LogHelper.info("Fetching all AuthHandler entries");
- String query = String.format("SELECT %s, %s, %s, %s FROM %s",
- uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table);
- try (Connection c = mySQLHolder.getConnection(); Statement statement = c.createStatement();
- ResultSet set = statement.executeQuery(query)) {
- for (Entry entry = constructEntry(set); entry != null; entry = constructEntry(set)) {
- addEntry(entry);
- }
- } catch (SQLException e) {
- LogHelper.error(e);
- }
- }
- }
+ // Fetch all entries
+ if (block.getEntryValue("fetchAll", BooleanConfigEntry.class)) {
+ LogHelper.info("Fetching all AuthHandler entries");
+ String query = String.format("SELECT %s, %s, %s, %s FROM %s",
+ uuidColumn, usernameColumn, accessTokenColumn, serverIDColumn, table);
+ try (Connection c = mySQLHolder.getConnection(); Statement statement = c.createStatement();
+ ResultSet set = statement.executeQuery(query)) {
+ for (Entry entry = constructEntry(set); entry != null; entry = constructEntry(set)) {
+ addEntry(entry);
+ }
+ } catch (SQLException e) {
+ LogHelper.error(e);
+ }
+ }
+ }
- @Override
- public void close() {
- mySQLHolder.close();
- }
+ @Override
+ public void close() {
+ mySQLHolder.close();
+ }
- @Override
- protected Entry fetchEntry(String username) throws IOException {
- return query(queryByUsernameSQL, username);
- }
+ @Override
+ protected Entry fetchEntry(String username) throws IOException {
+ return query(queryByUsernameSQL, username);
+ }
- @Override
- protected Entry fetchEntry(UUID uuid) throws IOException {
- return query(queryByUUIDSQL, uuid.toString());
- }
+ @Override
+ protected Entry fetchEntry(UUID uuid) throws IOException {
+ return query(queryByUUIDSQL, uuid.toString());
+ }
- @Override
- protected boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException {
- try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(updateAuthSQL)) {
- s.setString(1, username); // Username case
- s.setString(2, accessToken);
- s.setString(3, uuid.toString());
+ @Override
+ protected boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException {
+ try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(updateAuthSQL)) {
+ s.setString(1, username); // Username case
+ s.setString(2, accessToken);
+ s.setString(3, uuid.toString());
- // Execute update
- s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
- return s.executeUpdate() > 0;
- } catch (SQLException e) {
- throw new IOException(e);
- }
- }
+ // Execute update
+ s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
+ return s.executeUpdate() > 0;
+ } catch (SQLException e) {
+ throw new IOException(e);
+ }
+ }
- @Override
- protected boolean updateServerID(UUID uuid, String serverID) throws IOException {
- try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(updateServerIDSQL)) {
- s.setString(1, serverID);
- s.setString(2, uuid.toString());
+ @Override
+ protected boolean updateServerID(UUID uuid, String serverID) throws IOException {
+ try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(updateServerIDSQL)) {
+ s.setString(1, serverID);
+ s.setString(2, uuid.toString());
- // Execute update
- s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
- return s.executeUpdate() > 0;
- } catch (SQLException e) {
- throw new IOException(e);
- }
- }
+ // Execute update
+ s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
+ return s.executeUpdate() > 0;
+ } catch (SQLException e) {
+ throw new IOException(e);
+ }
+ }
- private Entry constructEntry(ResultSet set) throws SQLException {
- return set.next() ? new Entry(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
- set.getString(accessTokenColumn), set.getString(serverIDColumn)) : null;
- }
+ private Entry constructEntry(ResultSet set) throws SQLException {
+ return set.next() ? new Entry(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
+ set.getString(accessTokenColumn), set.getString(serverIDColumn)) : null;
+ }
- private Entry query(String sql, String value) throws IOException {
- try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(sql)) {
- s.setString(1, value);
+ private Entry query(String sql, String value) throws IOException {
+ try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(sql)) {
+ s.setString(1, value);
- // Execute query
- s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
- try (ResultSet set = s.executeQuery()) {
- return constructEntry(set);
- }
- } catch (SQLException e) {
- throw new IOException(e);
- }
- }
+ // Execute query
+ s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
+ try (ResultSet set = s.executeQuery()) {
+ return constructEntry(set);
+ }
+ } catch (SQLException e) {
+ throw new IOException(e);
+ }
+ }
}
diff --git a/LaunchServer/source/auth/handler/NullAuthHandler.java b/LaunchServer/source/auth/handler/NullAuthHandler.java
index e748171..95fc6e7 100644
--- a/LaunchServer/source/auth/handler/NullAuthHandler.java
+++ b/LaunchServer/source/auth/handler/NullAuthHandler.java
@@ -8,51 +8,51 @@
import launcher.serialize.config.entry.BlockConfigEntry;
public final class NullAuthHandler extends AuthHandler {
- private volatile AuthHandler handler;
+ private volatile AuthHandler handler;
- public NullAuthHandler(BlockConfigEntry block) {
- super(block);
- }
+ public NullAuthHandler(BlockConfigEntry block) {
+ super(block);
+ }
- @Override
- public UUID auth(String username, String accessToken) throws IOException {
- return getHandler().auth(username, accessToken);
- }
+ @Override
+ public UUID auth(String username, String accessToken) throws IOException {
+ return getHandler().auth(username, accessToken);
+ }
- @Override
- public UUID checkServer(String username, String serverID) throws IOException {
- return getHandler().checkServer(username, serverID);
- }
+ @Override
+ public UUID checkServer(String username, String serverID) throws IOException {
+ return getHandler().checkServer(username, serverID);
+ }
- @Override
- public void close() throws IOException {
- AuthHandler handler = this.handler;
- if (handler != null) {
- handler.close();
- }
- }
+ @Override
+ public void close() throws IOException {
+ AuthHandler handler = this.handler;
+ if (handler != null) {
+ handler.close();
+ }
+ }
- @Override
- public boolean joinServer(String username, String accessToken, String serverID) throws IOException {
- return getHandler().joinServer(username, accessToken, serverID);
- }
+ @Override
+ public boolean joinServer(String username, String accessToken, String serverID) throws IOException {
+ return getHandler().joinServer(username, accessToken, serverID);
+ }
- @Override
- public UUID usernameToUUID(String username) throws IOException {
- return getHandler().usernameToUUID(username);
- }
+ @Override
+ public UUID usernameToUUID(String username) throws IOException {
+ return getHandler().usernameToUUID(username);
+ }
- @Override
- public String uuidToUsername(UUID uuid) throws IOException {
- return getHandler().uuidToUsername(uuid);
- }
+ @Override
+ public String uuidToUsername(UUID uuid) throws IOException {
+ return getHandler().uuidToUsername(uuid);
+ }
- @LauncherAPI
- public void setBackend(AuthHandler handler) {
- this.handler = handler;
- }
+ @LauncherAPI
+ public void setBackend(AuthHandler handler) {
+ this.handler = handler;
+ }
- private AuthHandler getHandler() {
- return VerifyHelper.verify(handler, a -> a != null, "Backend auth handler wasn't set");
- }
+ private AuthHandler getHandler() {
+ return VerifyHelper.verify(handler, a -> a != null, "Backend auth handler wasn't set");
+ }
}
diff --git a/LaunchServer/source/auth/handler/TextFileAuthHandler.java b/LaunchServer/source/auth/handler/TextFileAuthHandler.java
index 191bd43..d5ee7f3 100644
--- a/LaunchServer/source/auth/handler/TextFileAuthHandler.java
+++ b/LaunchServer/source/auth/handler/TextFileAuthHandler.java
@@ -14,87 +14,88 @@
import launcher.serialize.config.TextConfigWriter;
import launcher.serialize.config.entry.BlockConfigEntry;
import launcher.serialize.config.entry.ConfigEntry;
+import launcher.serialize.config.entry.ConfigEntry.Type;
import launcher.serialize.config.entry.StringConfigEntry;
public final class TextFileAuthHandler extends FileAuthHandler {
- public TextFileAuthHandler(BlockConfigEntry block) {
- super(block);
- }
+ public TextFileAuthHandler(BlockConfigEntry block) {
+ super(block);
+ }
- @Override
- protected void readAuthFile() throws IOException {
- BlockConfigEntry authFile;
- try (BufferedReader reader = IOHelper.newReader(file)) {
- authFile = TextConfigReader.read(reader, false);
- }
+ @Override
+ protected void readAuthFile() throws IOException {
+ BlockConfigEntry authFile;
+ try (BufferedReader reader = IOHelper.newReader(file)) {
+ authFile = TextConfigReader.read(reader, false);
+ }
- // Read auths from config block
- Set>> entrySet = authFile.getValue().entrySet();
- for (Map.Entry> entry : entrySet) {
- UUID uuid = UUID.fromString(entry.getKey());
- ConfigEntry> value = VerifyHelper.verify(entry.getValue(),
- v -> v.getType() == ConfigEntry.Type.BLOCK, "Illegal config entry type: " + uuid);
+ // Read auths from config block
+ Set>> entrySet = authFile.getValue().entrySet();
+ for (Map.Entry> entry : entrySet) {
+ UUID uuid = UUID.fromString(entry.getKey());
+ ConfigEntry> value = VerifyHelper.verify(entry.getValue(),
+ v -> v.getType() == Type.BLOCK, "Illegal config entry type: " + uuid);
- // Get auth entry data
- BlockConfigEntry authBlock = (BlockConfigEntry) value;
- String username = authBlock.getEntryValue("username", StringConfigEntry.class);
- String accessToken = authBlock.hasEntry("accessToken") ?
- authBlock.getEntryValue("accessToken", StringConfigEntry.class) : null;
- String serverID = authBlock.hasEntry("serverID") ?
- authBlock.getEntryValue("serverID", StringConfigEntry.class) : null;
+ // Get auth entry data
+ BlockConfigEntry authBlock = (BlockConfigEntry) value;
+ String username = authBlock.getEntryValue("username", StringConfigEntry.class);
+ String accessToken = authBlock.hasEntry("accessToken") ?
+ authBlock.getEntryValue("accessToken", StringConfigEntry.class) : null;
+ String serverID = authBlock.hasEntry("serverID") ?
+ authBlock.getEntryValue("serverID", StringConfigEntry.class) : null;
- // Add auth entry
- addAuth(uuid, new Entry(username, accessToken, serverID));
- }
- }
+ // Add auth entry
+ addAuth(uuid, new Entry(username, accessToken, serverID));
+ }
+ }
- @Override
- protected void writeAuthFile() throws IOException {
- boolean next = false;
+ @Override
+ protected void writeAuthFile() throws IOException {
+ boolean next = false;
- // Write auth blocks to map
- Set> entrySet = entrySet();
- Map> map = new LinkedHashMap<>(entrySet.size());
- for (Map.Entry entry : entrySet) {
- UUID uuid = entry.getKey();
- Entry auth = entry.getValue();
+ // Write auth blocks to map
+ Set> entrySet = entrySet();
+ Map> map = new LinkedHashMap<>(entrySet.size());
+ for (Map.Entry entry : entrySet) {
+ UUID uuid = entry.getKey();
+ Entry auth = entry.getValue();
- // Set auth entry data
- Map> authMap = new LinkedHashMap<>(entrySet.size());
- authMap.put("username", cc(auth.getUsername()));
- String accessToken = auth.getAccessToken();
- if (accessToken != null) {
- authMap.put("accessToken", cc(accessToken));
- }
- String serverID = auth.getServerID();
- if (serverID != null) {
- authMap.put("serverID", cc(serverID));
- }
+ // Set auth entry data
+ Map> authMap = new LinkedHashMap<>(entrySet.size());
+ authMap.put("username", cc(auth.getUsername()));
+ String accessToken = auth.getAccessToken();
+ if (accessToken != null) {
+ authMap.put("accessToken", cc(accessToken));
+ }
+ String serverID = auth.getServerID();
+ if (serverID != null) {
+ authMap.put("serverID", cc(serverID));
+ }
- // Create and add auth block
- BlockConfigEntry authBlock = new BlockConfigEntry(authMap, true, 5);
- if (next) {
- authBlock.setComment(0, "\n"); // Pre-name
- } else {
- next = true;
- }
- authBlock.setComment(2, " "); // Pre-value
- authBlock.setComment(4, "\n"); // Post-comment
- map.put(uuid.toString(), authBlock);
- }
+ // Create and add auth block
+ BlockConfigEntry authBlock = new BlockConfigEntry(authMap, true, 5);
+ if (next) {
+ authBlock.setComment(0, "\n"); // Pre-name
+ } else {
+ next = true;
+ }
+ authBlock.setComment(2, " "); // Pre-value
+ authBlock.setComment(4, "\n"); // Post-comment
+ map.put(uuid.toString(), authBlock);
+ }
- // Write auth handler file
- try (BufferedWriter writer = IOHelper.newWriter(file)) {
- BlockConfigEntry authFile = new BlockConfigEntry(map, true, 1);
- authFile.setComment(0, "\n");
- TextConfigWriter.write(authFile, writer, true);
- }
- }
+ // Write auth handler file
+ try (BufferedWriter writer = IOHelper.newWriter(file)) {
+ BlockConfigEntry authFile = new BlockConfigEntry(map, true, 1);
+ authFile.setComment(0, "\n");
+ TextConfigWriter.write(authFile, writer, true);
+ }
+ }
- private static StringConfigEntry cc(String value) {
- StringConfigEntry entry = new StringConfigEntry(value, true, 4);
- entry.setComment(0, "\n\t"); // Pre-name
- entry.setComment(2, " "); // Pre-value
- return entry;
- }
+ private static StringConfigEntry cc(String value) {
+ StringConfigEntry entry = new StringConfigEntry(value, true, 4);
+ entry.setComment(0, "\n\t"); // Pre-name
+ entry.setComment(2, " "); // Pre-value
+ return entry;
+ }
}
diff --git a/LaunchServer/source/auth/provider/AcceptAuthProvider.java b/LaunchServer/source/auth/provider/AcceptAuthProvider.java
index 660bb8c..65c40f1 100644
--- a/LaunchServer/source/auth/provider/AcceptAuthProvider.java
+++ b/LaunchServer/source/auth/provider/AcceptAuthProvider.java
@@ -3,17 +3,17 @@
import launcher.serialize.config.entry.BlockConfigEntry;
public final class AcceptAuthProvider extends AuthProvider {
- public AcceptAuthProvider(BlockConfigEntry block) {
- super(block);
- }
+ public AcceptAuthProvider(BlockConfigEntry block) {
+ super(block);
+ }
- @Override
- public String auth(String login, String password) {
- return login; // Same as login
- }
+ @Override
+ public String auth(String login, String password) {
+ return login; // Same as login
+ }
- @Override
- public void close() {
- // Do nothing
- }
+ @Override
+ public void close() {
+ // Do nothing
+ }
}
diff --git a/LaunchServer/source/auth/provider/AuthProvider.java b/LaunchServer/source/auth/provider/AuthProvider.java
index 714a9b2..76837af 100644
--- a/LaunchServer/source/auth/provider/AuthProvider.java
+++ b/LaunchServer/source/auth/provider/AuthProvider.java
@@ -12,46 +12,46 @@
import launchserver.auth.AuthException;
public abstract class AuthProvider extends ConfigObject implements AutoCloseable {
- private static final Map> AUTH_PROVIDERS = new ConcurrentHashMap<>(8);
+ private static final Map> AUTH_PROVIDERS = new ConcurrentHashMap<>(8);
- @LauncherAPI
- protected AuthProvider(BlockConfigEntry block) {
- super(block);
- }
+ @LauncherAPI
+ protected AuthProvider(BlockConfigEntry block) {
+ super(block);
+ }
- @Override
- public abstract void close() throws IOException;
+ @Override
+ public abstract void close() throws IOException;
- @LauncherAPI
- public abstract String auth(String login, String password) throws Exception;
+ @LauncherAPI
+ public abstract String auth(String login, String password) throws Exception;
- @LauncherAPI
- public static String authError(String message) throws AuthException {
- throw new AuthException(message);
- }
+ @LauncherAPI
+ public static String authError(String message) throws AuthException {
+ throw new AuthException(message);
+ }
- @LauncherAPI
- public static AuthProvider newProvider(String name, BlockConfigEntry block) {
- VerifyHelper.verifyIDName(name);
- Adapter authHandlerAdapter = VerifyHelper.getMapValue(AUTH_PROVIDERS, name,
- String.format("Unknown auth provider: '%s'", name));
- return authHandlerAdapter.convert(block);
- }
+ @LauncherAPI
+ public static AuthProvider newProvider(String name, BlockConfigEntry block) {
+ VerifyHelper.verifyIDName(name);
+ Adapter authHandlerAdapter = VerifyHelper.getMapValue(AUTH_PROVIDERS, name,
+ String.format("Unknown auth provider: '%s'", name));
+ return authHandlerAdapter.convert(block);
+ }
- @LauncherAPI
- public static void registerProvider(String name, Adapter adapter) {
- VerifyHelper.putIfAbsent(AUTH_PROVIDERS, name, Objects.requireNonNull(adapter, "adapter"),
- String.format("Auth provider has been already registered: '%s'", name));
- }
+ @LauncherAPI
+ public static void registerProvider(String name, Adapter adapter) {
+ VerifyHelper.putIfAbsent(AUTH_PROVIDERS, name, Objects.requireNonNull(adapter, "adapter"),
+ String.format("Auth provider has been already registered: '%s'", name));
+ }
- static {
- registerProvider("null", NullAuthProvider::new);
- registerProvider("accept", AcceptAuthProvider::new);
- registerProvider("reject", RejectAuthProvider::new);
+ static {
+ registerProvider("null", NullAuthProvider::new);
+ registerProvider("accept", AcceptAuthProvider::new);
+ registerProvider("reject", RejectAuthProvider::new);
- // Auth providers that doesn't do nothing :D
- registerProvider("mysql", MySQLAuthProvider::new);
- registerProvider("file", FileAuthProvider::new);
- registerProvider("request", RequestAuthProvider::new);
- }
+ // Auth providers that doesn't do nothing :D
+ registerProvider("mysql", MySQLAuthProvider::new);
+ registerProvider("file", FileAuthProvider::new);
+ registerProvider("request", RequestAuthProvider::new);
+ }
}
diff --git a/LaunchServer/source/auth/provider/DigestAuthProvider.java b/LaunchServer/source/auth/provider/DigestAuthProvider.java
index af6e777..a43698c 100644
--- a/LaunchServer/source/auth/provider/DigestAuthProvider.java
+++ b/LaunchServer/source/auth/provider/DigestAuthProvider.java
@@ -2,34 +2,35 @@
import launcher.LauncherAPI;
import launcher.helper.SecurityHelper;
+import launcher.helper.SecurityHelper.DigestAlgorithm;
import launcher.serialize.config.entry.BlockConfigEntry;
import launcher.serialize.config.entry.StringConfigEntry;
import launchserver.auth.AuthException;
public abstract class DigestAuthProvider extends AuthProvider {
- private final SecurityHelper.DigestAlgorithm digest;
+ private final DigestAlgorithm digest;
- @LauncherAPI
- protected DigestAuthProvider(BlockConfigEntry block) {
- super(block);
- digest = SecurityHelper.DigestAlgorithm.byName(block.getEntryValue("digest", StringConfigEntry.class));
- }
+ @LauncherAPI
+ protected DigestAuthProvider(BlockConfigEntry block) {
+ super(block);
+ digest = DigestAlgorithm.byName(block.getEntryValue("digest", StringConfigEntry.class));
+ }
- @LauncherAPI
- protected final void verifyDigest(String validDigest, String password) throws AuthException {
- boolean valid;
- if (digest == SecurityHelper.DigestAlgorithm.PLAIN) {
- valid = password.equals(validDigest);
- } else if (validDigest == null) {
- valid = false;
- } else {
- byte[] actualDigest = SecurityHelper.digest(digest, password);
- valid = SecurityHelper.toHex(actualDigest).equals(validDigest);
- }
+ @LauncherAPI
+ protected final void verifyDigest(String validDigest, String password) throws AuthException {
+ boolean valid;
+ if (digest == DigestAlgorithm.PLAIN) {
+ valid = password.equals(validDigest);
+ } else if (validDigest == null) {
+ valid = false;
+ } else {
+ byte[] actualDigest = SecurityHelper.digest(digest, password);
+ valid = SecurityHelper.toHex(actualDigest).equals(validDigest);
+ }
- // Verify is valid
- if (!valid) {
- authError("Incorrect username or password");
- }
- }
+ // Verify is valid
+ if (!valid) {
+ authError("Incorrect username or password");
+ }
+ }
}
diff --git a/LaunchServer/source/auth/provider/FileAuthProvider.java b/LaunchServer/source/auth/provider/FileAuthProvider.java
index ff99975..1910638 100644
--- a/LaunchServer/source/auth/provider/FileAuthProvider.java
+++ b/LaunchServer/source/auth/provider/FileAuthProvider.java
@@ -16,86 +16,87 @@
import launcher.serialize.config.TextConfigReader;
import launcher.serialize.config.entry.BlockConfigEntry;
import launcher.serialize.config.entry.ConfigEntry;
+import launcher.serialize.config.entry.ConfigEntry.Type;
import launcher.serialize.config.entry.StringConfigEntry;
public final class FileAuthProvider extends DigestAuthProvider {
- private final Path file;
+ private final Path file;
- // Cache
- private final Map entries = new HashMap<>();
- private final Object cacheLock = new Object();
- private FileTime cacheLastModified;
+ // Cache
+ private final Map entries = new HashMap<>();
+ private final Object cacheLock = new Object();
+ private FileTime cacheLastModified;
- public FileAuthProvider(BlockConfigEntry block) {
- super(block);
- file = IOHelper.toPath(block.getEntryValue("file", StringConfigEntry.class));
+ public FileAuthProvider(BlockConfigEntry block) {
+ super(block);
+ file = IOHelper.toPath(block.getEntryValue("file", StringConfigEntry.class));
- // Try to update cache
- try {
- updateCache();
- } catch (IOException e) {
- LogHelper.error(e);
- }
- }
+ // Try to update cache
+ try {
+ updateCache();
+ } catch (IOException e) {
+ LogHelper.error(e);
+ }
+ }
- @Override
- public String auth(String login, String password) throws IOException {
- Entry entry;
- synchronized (cacheLock) {
- updateCache();
- entry = entries.get(CommonHelper.low(login));
- }
+ @Override
+ public String auth(String login, String password) throws IOException {
+ Entry entry;
+ synchronized (cacheLock) {
+ updateCache();
+ entry = entries.get(CommonHelper.low(login));
+ }
- // Verify digest and return true username
- verifyDigest(entry == null ? null : entry.password, password);
- return entry.username;
- }
+ // Verify digest and return true username
+ verifyDigest(entry == null ? null : entry.password, password);
+ return entry.username;
+ }
- @Override
- public void close() {
- // Do nothing
- }
+ @Override
+ public void close() {
+ // Do nothing
+ }
- private void updateCache() throws IOException {
- FileTime lastModified = IOHelper.readAttributes(file).lastModifiedTime();
- if (lastModified.equals(cacheLastModified)) {
- return; // Not modified, so cache is up-to-date
- }
+ private void updateCache() throws IOException {
+ FileTime lastModified = IOHelper.readAttributes(file).lastModifiedTime();
+ if (lastModified.equals(cacheLastModified)) {
+ return; // Not modified, so cache is up-to-date
+ }
- // Read file
- LogHelper.info("Recaching auth provider file: '%s'", file);
- BlockConfigEntry authFile;
- try (BufferedReader reader = IOHelper.newReader(file)) {
- authFile = TextConfigReader.read(reader, false);
- }
+ // Read file
+ LogHelper.info("Recaching auth provider file: '%s'", file);
+ BlockConfigEntry authFile;
+ try (BufferedReader reader = IOHelper.newReader(file)) {
+ authFile = TextConfigReader.read(reader, false);
+ }
- // Read entries from config block
- entries.clear();
- Set>> entrySet = authFile.getValue().entrySet();
- for (Map.Entry> entry : entrySet) {
- String login = entry.getKey();
- ConfigEntry> value = VerifyHelper.verify(entry.getValue(), v -> v.getType() == ConfigEntry.Type.BLOCK,
- String.format("Illegal config entry type: '%s'", login));
+ // Read entries from config block
+ entries.clear();
+ Set>> entrySet = authFile.getValue().entrySet();
+ for (Map.Entry> entry : entrySet) {
+ String login = entry.getKey();
+ ConfigEntry> value = VerifyHelper.verify(entry.getValue(), v -> v.getType() == Type.BLOCK,
+ String.format("Illegal config entry type: '%s'", login));
- // Add auth entry
- Entry auth = new Entry((BlockConfigEntry) value);
- VerifyHelper.putIfAbsent(entries, CommonHelper.low(login), auth,
- String.format("Duplicate login: '%s'", login));
- }
+ // Add auth entry
+ Entry auth = new Entry((BlockConfigEntry) value);
+ VerifyHelper.putIfAbsent(entries, CommonHelper.low(login), auth,
+ String.format("Duplicate login: '%s'", login));
+ }
- // Update last modified time
- cacheLastModified = lastModified;
- }
+ // Update last modified time
+ cacheLastModified = lastModified;
+ }
- private static final class Entry extends ConfigObject {
- private final String username;
- private final String password;
+ private static final class Entry extends ConfigObject {
+ private final String username;
+ private final String password;
- private Entry(BlockConfigEntry block) {
- super(block);
- this.username = VerifyHelper.verifyUsername(block.getEntryValue("username", StringConfigEntry.class));
- this.password = VerifyHelper.verify(block.getEntryValue("password", StringConfigEntry.class),
- VerifyHelper.NOT_EMPTY, String.format("Password can't be empty: '%s'", username));
- }
- }
+ private Entry(BlockConfigEntry block) {
+ super(block);
+ username = VerifyHelper.verifyUsername(block.getEntryValue("username", StringConfigEntry.class));
+ password = VerifyHelper.verify(block.getEntryValue("password", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, String.format("Password can't be empty: '%s'", username));
+ }
+ }
}
diff --git a/LaunchServer/source/auth/provider/MySQLAuthProvider.java b/LaunchServer/source/auth/provider/MySQLAuthProvider.java
index a3cf2b3..63dfbf5 100644
--- a/LaunchServer/source/auth/provider/MySQLAuthProvider.java
+++ b/LaunchServer/source/auth/provider/MySQLAuthProvider.java
@@ -14,39 +14,39 @@
import launchserver.auth.MySQLSourceConfig;
public final class MySQLAuthProvider extends AuthProvider {
- private final MySQLSourceConfig mySQLHolder;
- private final String query;
- private final String[] queryParams;
+ private final MySQLSourceConfig mySQLHolder;
+ private final String query;
+ private final String[] queryParams;
- public MySQLAuthProvider(BlockConfigEntry block) {
- super(block);
- mySQLHolder = new MySQLSourceConfig("authProviderPool", block);
+ public MySQLAuthProvider(BlockConfigEntry block) {
+ super(block);
+ mySQLHolder = new MySQLSourceConfig("authProviderPool", block);
- // Read query
- query = VerifyHelper.verify(block.getEntryValue("query", StringConfigEntry.class),
- VerifyHelper.NOT_EMPTY, "MySQL query can't be empty");
- queryParams = block.getEntry("queryParams", ListConfigEntry.class).
- stream(StringConfigEntry.class).toArray(String[]::new);
- }
+ // Read query
+ query = VerifyHelper.verify(block.getEntryValue("query", StringConfigEntry.class),
+ VerifyHelper.NOT_EMPTY, "MySQL query can't be empty");
+ queryParams = block.getEntry("queryParams", ListConfigEntry.class).
+ stream(StringConfigEntry.class).toArray(String[]::new);
+ }
- @Override
- public String auth(String login, String password) throws SQLException, AuthException {
- try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(query)) {
- String[] replaceParams = { "login", login, "password", password };
- for (int i = 0; i < queryParams.length; i++) {
- s.setString(i + 1, CommonHelper.replace(queryParams[i], replaceParams));
- }
+ @Override
+ public String auth(String login, String password) throws SQLException, AuthException {
+ try (Connection c = mySQLHolder.getConnection(); PreparedStatement s = c.prepareStatement(query)) {
+ String[] replaceParams = { "login", login, "password", password };
+ for (int i = 0; i < queryParams.length; i++) {
+ s.setString(i + 1, CommonHelper.replace(queryParams[i], replaceParams));
+ }
- // Execute SQL query
- s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
- try (ResultSet set = s.executeQuery()) {
- return set.next() ? set.getString(1) : authError("Incorrect username or password");
- }
- }
- }
+ // Execute SQL query
+ s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
+ try (ResultSet set = s.executeQuery()) {
+ return set.next() ? set.getString(1) : authError("Incorrect username or password");
+ }
+ }
+ }
- @Override
- public void close() {
- // Do nothing
- }
+ @Override
+ public void close() {
+ // Do nothing
+ }
}
diff --git a/LaunchServer/source/auth/provider/NullAuthProvider.java b/LaunchServer/source/auth/provider/NullAuthProvider.java
index 0e24277..83ec3ef 100644
--- a/LaunchServer/source/auth/provider/NullAuthProvider.java
+++ b/LaunchServer/source/auth/provider/NullAuthProvider.java
@@ -7,31 +7,31 @@
import launcher.serialize.config.entry.BlockConfigEntry;
public final class NullAuthProvider extends AuthProvider {
- private volatile AuthProvider provider;
+ private volatile AuthProvider provider;
- public NullAuthProvider(BlockConfigEntry block) {
- super(block);
- }
+ public NullAuthProvider(BlockConfigEntry block) {
+ super(block);
+ }
- @Override
- public String auth(String login, String password) throws Exception {
- return getProvider().auth(login, password);
- }
+ @Override
+ public String auth(String login, String password) throws Exception {
+ return getProvider().auth(login, password);
+ }
- @Override
- public void close() throws IOException {
- AuthProvider provider = this.provider;
- if (provider != null) {
- provider.close();
- }
- }
+ @Override
+ public void close() throws IOException {
+ AuthProvider provider = this.provider;
+ if (provider != null) {
+ provider.close();
+ }
+ }
- @LauncherAPI
- public void setBackend(AuthProvider provider) {
- this.provider = provider;
- }
+ @LauncherAPI
+ public void setBackend(AuthProvider provider) {
+ this.provider = provider;
+ }
- private AuthProvider getProvider() {
- return VerifyHelper.verify(provider, a -> a != null, "Backend auth provider wasn't set");
- }
+ private AuthProvider getProvider() {
+ return VerifyHelper.verify(provider, a -> a != null, "Backend auth provider wasn't set");
+ }
}
diff --git a/LaunchServer/source/auth/provider/RejectAuthProvider.java b/LaunchServer/source/auth/provider/RejectAuthProvider.java
index 30fbe34..74eced1 100644
--- a/LaunchServer/source/auth/provider/RejectAuthProvider.java
+++ b/LaunchServer/source/auth/provider/RejectAuthProvider.java
@@ -6,21 +6,21 @@
import launchserver.auth.AuthException;
public final class RejectAuthProvider extends AuthProvider {
- private final String message;
+ private final String message;
- public RejectAuthProvider(BlockConfigEntry block) {
- super(block);
- message = VerifyHelper.verify(block.getEntryValue("message", StringConfigEntry.class), VerifyHelper.NOT_EMPTY,
- "Auth error message can't be empty");
- }
+ public RejectAuthProvider(BlockConfigEntry block) {
+ super(block);
+ message = VerifyHelper.verify(block.getEntryValue("message", StringConfigEntry.class), VerifyHelper.NOT_EMPTY,
+ "Auth error message can't be empty");
+ }
- @Override
- public String auth(String login, String password) throws AuthException {
- return authError(message);
- }
+ @Override
+ public String auth(String login, String password) throws AuthException {
+ return authError(message);
+ }
- @Override
- public void close() {
- // Do nothing
- }
+ @Override
+ public void close() {
+ // Do nothing
+ }
}
diff --git a/LaunchServer/source/auth/provider/RequestAuthProvider.java b/LaunchServer/source/auth/provider/RequestAuthProvider.java
index c56bd8c..88539fb 100644
--- a/LaunchServer/source/auth/provider/RequestAuthProvider.java
+++ b/LaunchServer/source/auth/provider/RequestAuthProvider.java
@@ -11,34 +11,34 @@
import launcher.serialize.config.entry.StringConfigEntry;
public final class RequestAuthProvider extends AuthProvider {
- private final String url;
- private final Pattern response;
+ private final String url;
+ private final Pattern response;
- public RequestAuthProvider(BlockConfigEntry block) {
- super(block);
- url = block.getEntryValue("url", StringConfigEntry.class);
- response = Pattern.compile(block.getEntryValue("response", StringConfigEntry.class));
+ public RequestAuthProvider(BlockConfigEntry block) {
+ super(block);
+ url = block.getEntryValue("url", StringConfigEntry.class);
+ response = Pattern.compile(block.getEntryValue("response", StringConfigEntry.class));
- // Verify is valid URL
- IOHelper.verifyURL(getFormattedURL("urlAuthLogin", "urlAuthPassword"));
- }
+ // Verify is valid URL
+ IOHelper.verifyURL(getFormattedURL("urlAuthLogin", "urlAuthPassword"));
+ }
- @Override
- public String auth(String login, String password) throws IOException {
- String currentResponse = IOHelper.request(new URL(getFormattedURL(login, password)));
+ @Override
+ public String auth(String login, String password) throws IOException {
+ String currentResponse = IOHelper.request(new URL(getFormattedURL(login, password)));
- // Match username
- Matcher matcher = response.matcher(currentResponse);
- return matcher.matches() && matcher.groupCount() >= 1 ?
- matcher.group("username") : authError(currentResponse);
- }
+ // Match username
+ Matcher matcher = response.matcher(currentResponse);
+ return matcher.matches() && matcher.groupCount() >= 1 ?
+ matcher.group("username") : authError(currentResponse);
+ }
- @Override
- public void close() {
- // Do nothing
- }
+ @Override
+ public void close() {
+ // Do nothing
+ }
- private String getFormattedURL(String login, String password) {
- return CommonHelper.replace(url, "login", IOHelper.urlEncode(login), "password", IOHelper.urlEncode(password));
- }
+ private String getFormattedURL(String login, String password) {
+ return CommonHelper.replace(url, "login", IOHelper.urlEncode(login), "password", IOHelper.urlEncode(password));
+ }
}
diff --git a/LaunchServer/source/binary/EXEL4JLauncherBinary.java b/LaunchServer/source/binary/EXEL4JLauncherBinary.java
index 10fd1a6..00a2df5 100644
--- a/LaunchServer/source/binary/EXEL4JLauncherBinary.java
+++ b/LaunchServer/source/binary/EXEL4JLauncherBinary.java
@@ -15,81 +15,81 @@
import net.sf.launch4j.config.Jre;
public final class EXEL4JLauncherBinary extends LauncherBinary {
- // URL constants
- private static final String DOWNLOAD_URL = "http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html"; // Oracle JRE 8
+ // URL constants
+ private static final String DOWNLOAD_URL = "http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html"; // Oracle JRE 8
- // File constants
- private static final Path EXE_BINARY_FILE = IOHelper.WORKING_DIR.resolve(EXELauncherBinary.EXE_BINARY_FILE);
- private static final Path FAVICON_FILE = IOHelper.WORKING_DIR.resolve("favicon.ico");
+ // File constants
+ private static final Path EXE_BINARY_FILE = IOHelper.WORKING_DIR.resolve(EXELauncherBinary.EXE_BINARY_FILE);
+ private static final Path FAVICON_FILE = IOHelper.WORKING_DIR.resolve("favicon.ico");
- @LauncherAPI
- public EXEL4JLauncherBinary(LaunchServer server) {
- super(server, EXE_BINARY_FILE);
- }
+ @LauncherAPI
+ public EXEL4JLauncherBinary(LaunchServer server) {
+ super(server, EXE_BINARY_FILE);
+ }
- @Override
- public void build() throws IOException {
- LogHelper.info("Building launcher EXE binary file (Using Launch4J)");
+ @Override
+ public void build() throws IOException {
+ LogHelper.info("Building launcher EXE binary file (Using Launch4J)");
- // Set favicon path
- Config config = ConfigPersister.getInstance().getConfig();
- if (IOHelper.isFile(FAVICON_FILE)) {
- config.setIcon(new File("favicon.ico"));
- } else {
- config.setIcon(null);
- LogHelper.warning("Missing favicon.ico file");
- }
+ // Set favicon path
+ Config config = ConfigPersister.getInstance().getConfig();
+ if (IOHelper.isFile(FAVICON_FILE)) {
+ config.setIcon(new File("favicon.ico"));
+ } else {
+ config.setIcon(null);
+ LogHelper.warning("Missing favicon.ico file");
+ }
- // Start building
- Builder builder = new Builder(Launch4JLog.INSTANCE);
- try {
- builder.build();
- } catch (Throwable e) {
- throw new IOException(e);
- }
- }
+ // Start building
+ Builder builder = new Builder(Launch4JLog.INSTANCE);
+ try {
+ builder.build();
+ } catch (Throwable e) {
+ throw new IOException(e);
+ }
+ }
- static {
- Config config = new Config();
+ static {
+ Config config = new Config();
- // Set string options
- config.setChdir(".");
- config.setErrTitle("JVM Error");
- config.setDownloadUrl(DOWNLOAD_URL);
+ // Set string options
+ config.setChdir(".");
+ config.setErrTitle("JVM Error");
+ config.setDownloadUrl(DOWNLOAD_URL);
- // Set boolean options
- config.setPriorityIndex(0);
- config.setHeaderTypeIndex(0);
- config.setStayAlive(false);
- config.setRestartOnCrash(false);
+ // Set boolean options
+ config.setPriorityIndex(0);
+ config.setHeaderTypeIndex(0);
+ config.setStayAlive(false);
+ config.setRestartOnCrash(false);
- // Prepare JRE
- Jre jre = new Jre();
- jre.setMinVersion("1.8.0");
- jre.setRuntimeBits(Jre.RUNTIME_BITS_64_AND_32);
- jre.setJdkPreference(Jre.JDK_PREFERENCE_PREFER_JRE);
- config.setJre(jre);
+ // Prepare JRE
+ Jre jre = new Jre();
+ jre.setMinVersion("1.8.0");
+ jre.setRuntimeBits(Jre.RUNTIME_BITS_64_AND_32);
+ jre.setJdkPreference(Jre.JDK_PREFERENCE_PREFER_JRE);
+ config.setJre(jre);
- // Set JAR wrapping options
- config.setDontWrapJar(false);
- config.setJar(JARLauncherBinary.JAR_BINARY_FILE.toFile());
- config.setOutfile(EXE_BINARY_FILE.toFile());
+ // Set JAR wrapping options
+ config.setDontWrapJar(false);
+ config.setJar(JARLauncherBinary.JAR_BINARY_FILE.toFile());
+ config.setOutfile(EXE_BINARY_FILE.toFile());
- // Return prepared config
- ConfigPersister.getInstance().setAntConfig(config, null);
- }
+ // Return prepared config
+ ConfigPersister.getInstance().setAntConfig(config, null);
+ }
- private static final class Launch4JLog extends Log {
- private static final Launch4JLog INSTANCE = new Launch4JLog();
+ private static final class Launch4JLog extends Log {
+ private static final Launch4JLog INSTANCE = new Launch4JLog();
- @Override
- public void append(String s) {
- LogHelper.subInfo(s);
- }
+ @Override
+ public void append(String s) {
+ LogHelper.subInfo(s);
+ }
- @Override
- public void clear() {
- // Do nothing
- }
- }
+ @Override
+ public void clear() {
+ // Do nothing
+ }
+ }
}
diff --git a/LaunchServer/source/binary/EXELauncherBinary.java b/LaunchServer/source/binary/EXELauncherBinary.java
index 15bc9c8..7e5818a 100644
--- a/LaunchServer/source/binary/EXELauncherBinary.java
+++ b/LaunchServer/source/binary/EXELauncherBinary.java
@@ -10,18 +10,18 @@
import launchserver.LaunchServer;
public final class EXELauncherBinary extends LauncherBinary {
- @LauncherAPI public static final Path EXE_BINARY_FILE = IOHelper.toPath("Launcher.exe");
+ @LauncherAPI public static final Path EXE_BINARY_FILE = IOHelper.toPath("Launcher.exe");
- @LauncherAPI
- public EXELauncherBinary(LaunchServer server) {
- super(server, IOHelper.WORKING_DIR.resolve(EXE_BINARY_FILE));
- }
+ @LauncherAPI
+ public EXELauncherBinary(LaunchServer server) {
+ super(server, IOHelper.WORKING_DIR.resolve(EXE_BINARY_FILE));
+ }
- @Override
- public void build() throws IOException {
- if (IOHelper.isFile(binaryFile)) {
- LogHelper.subWarning("Deleting obsolete launcher EXE binary file");
- Files.delete(binaryFile);
- }
- }
+ @Override
+ public void build() throws IOException {
+ if (IOHelper.isFile(binaryFile)) {
+ LogHelper.subWarning("Deleting obsolete launcher EXE binary file");
+ Files.delete(binaryFile);
+ }
+ }
}
diff --git a/LaunchServer/source/binary/JARLauncherBinary.java b/LaunchServer/source/binary/JARLauncherBinary.java
index 9f56c6a..06923f0 100644
--- a/LaunchServer/source/binary/JARLauncherBinary.java
+++ b/LaunchServer/source/binary/JARLauncherBinary.java
@@ -19,112 +19,114 @@
import java.util.zip.ZipOutputStream;
import launcher.Launcher;
+import launcher.Launcher.Config;
import launcher.LauncherAPI;
import launcher.helper.IOHelper;
import launcher.helper.LogHelper;
import launcher.helper.SecurityHelper;
+import launcher.helper.SecurityHelper.DigestAlgorithm;
import launcher.serialize.HOutput;
import launchserver.LaunchServer;
public final class JARLauncherBinary extends LauncherBinary {
- @LauncherAPI public static final Path RUNTIME_DIR = IOHelper.WORKING_DIR.resolve(Launcher.RUNTIME_DIR);
- @LauncherAPI public static final Path INIT_SCRIPT_FILE = RUNTIME_DIR.resolve(Launcher.INIT_SCRIPT_FILE);
- @LauncherAPI public static final Path JAR_BINARY_FILE = IOHelper.WORKING_DIR.resolve("Launcher.jar");
+ @LauncherAPI public static final Path RUNTIME_DIR = IOHelper.WORKING_DIR.resolve(Launcher.RUNTIME_DIR);
+ @LauncherAPI public static final Path INIT_SCRIPT_FILE = RUNTIME_DIR.resolve(Launcher.INIT_SCRIPT_FILE);
+ @LauncherAPI public static final Path JAR_BINARY_FILE = IOHelper.WORKING_DIR.resolve("Launcher.jar");
- @LauncherAPI
- public JARLauncherBinary(LaunchServer server) throws IOException {
- super(server, JAR_BINARY_FILE);
- tryUnpackRuntime();
- }
+ @LauncherAPI
+ public JARLauncherBinary(LaunchServer server) throws IOException {
+ super(server, JAR_BINARY_FILE);
+ tryUnpackRuntime();
+ }
- @Override
- public void build() throws IOException {
- LogHelper.info("Building launcher binary file");
- try (JarOutputStream output = new JarOutputStream(IOHelper.newOutput(JAR_BINARY_FILE))) {
- output.setMethod(ZipOutputStream.DEFLATED);
- output.setLevel(Deflater.BEST_COMPRESSION);
- try (InputStream input = new GZIPInputStream(IOHelper.newInput(IOHelper.getResourceURL("Launcher.pack.gz")))) {
- Pack200.newUnpacker().unpack(input, output);
- }
+ @Override
+ public void build() throws IOException {
+ LogHelper.info("Building launcher binary file");
+ try (JarOutputStream output = new JarOutputStream(IOHelper.newOutput(JAR_BINARY_FILE))) {
+ output.setMethod(ZipOutputStream.DEFLATED);
+ output.setLevel(Deflater.BEST_COMPRESSION);
+ try (InputStream input = new GZIPInputStream(IOHelper.newInput(IOHelper.getResourceURL("Launcher.pack.gz")))) {
+ Pack200.newUnpacker().unpack(input, output);
+ }
- // Verify has init script file
- if (!IOHelper.isFile(INIT_SCRIPT_FILE)) {
- throw new IOException(String.format("Missing init script file ('%s')", Launcher.INIT_SCRIPT_FILE));
- }
+ // Verify has init script file
+ if (!IOHelper.isFile(INIT_SCRIPT_FILE)) {
+ throw new IOException(String.format("Missing init script file ('%s')", Launcher.INIT_SCRIPT_FILE));
+ }
- // Write launcher runtime dir
- Map runtime = new HashMap<>();
- IOHelper.walk(RUNTIME_DIR, new RuntimeDirVisitor(output, runtime), false);
+ // Write launcher runtime dir
+ Map runtime = new HashMap<>();
+ IOHelper.walk(RUNTIME_DIR, new RuntimeDirVisitor(output, runtime), false);
- // Create launcher config file
- byte[] launcherConfigBytes;
- try (ByteArrayOutputStream configArray = IOHelper.newByteArrayOutput()) {
- try (HOutput configOutput = new HOutput(configArray)) {
- new Launcher.Config(server.config.getAddress(), server.config.port,
- server.publicKey, runtime).write(configOutput);
- }
- launcherConfigBytes = configArray.toByteArray();
- }
+ // Create launcher config file
+ byte[] launcherConfigBytes;
+ try (ByteArrayOutputStream configArray = IOHelper.newByteArrayOutput()) {
+ try (HOutput configOutput = new HOutput(configArray)) {
+ new Config(server.config.getAddress(), server.config.port,
+ server.publicKey, runtime).write(configOutput);
+ }
+ launcherConfigBytes = configArray.toByteArray();
+ }
- // Write launcher config file
- output.putNextEntry(IOHelper.newZipEntry(Launcher.CONFIG_FILE));
- output.write(launcherConfigBytes);
- }
- }
+ // Write launcher config file
+ output.putNextEntry(IOHelper.newZipEntry(Launcher.CONFIG_FILE));
+ output.write(launcherConfigBytes);
+ }
+ }
- @LauncherAPI
- public void tryUnpackRuntime() throws IOException {
- // Verify is runtime dir unpacked
- if (IOHelper.isDir(RUNTIME_DIR)) {
- return; // Already unpacked
- }
+ @LauncherAPI
+ public void tryUnpackRuntime() throws IOException {
+ // Verify is runtime dir unpacked
+ if (IOHelper.isDir(RUNTIME_DIR)) {
+ return; // Already unpacked
+ }
- // Unpack launcher runtime files
- Files.createDirectory(RUNTIME_DIR);
- LogHelper.info("Unpacking launcher runtime files");
- try (ZipInputStream input = IOHelper.newZipInput(IOHelper.getResourceURL("launchserver/defaults/runtime.zip"))) {
- for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) {
- if (entry.isDirectory()) {
- continue; // Skip dirs
- }
+ // Unpack launcher runtime files
+ Files.createDirectory(RUNTIME_DIR);
+ LogHelper.info("Unpacking launcher runtime files");
+ try (ZipInputStream input = IOHelper.newZipInput(IOHelper.getResourceURL("launchserver/defaults/runtime.zip"))) {
+ for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) {
+ if (entry.isDirectory()) {
+ continue; // Skip dirs
+ }
- // Unpack runtime file
- IOHelper.transfer(input, RUNTIME_DIR.resolve(IOHelper.toPath(entry.getName())));
- }
- }
- }
+ // Unpack runtime file
+ IOHelper.transfer(input, RUNTIME_DIR.resolve(IOHelper.toPath(entry.getName())));
+ }
+ }
+ }
- private static final class RuntimeDirVisitor extends SimpleFileVisitor {
- private final ZipOutputStream output;
- private final Map runtime;
+ private static final class RuntimeDirVisitor extends SimpleFileVisitor {
+ private final ZipOutputStream output;
+ private final Map runtime;
- private RuntimeDirVisitor(ZipOutputStream output, Map runtime) {
- this.output = output;
- this.runtime = runtime;
- }
+ private RuntimeDirVisitor(ZipOutputStream output, Map runtime) {
+ this.output = output;
+ this.runtime = runtime;
+ }
- @Override
- public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
- String dirName = IOHelper.toString(RUNTIME_DIR.relativize(dir));
- output.putNextEntry(newEntry(dirName + '/'));
- return super.preVisitDirectory(dir, attrs);
- }
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ String dirName = IOHelper.toString(RUNTIME_DIR.relativize(dir));
+ output.putNextEntry(newEntry(dirName + '/'));
+ return super.preVisitDirectory(dir, attrs);
+ }
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- String fileName = IOHelper.toString(RUNTIME_DIR.relativize(file));
- runtime.put(fileName, SecurityHelper.digest(SecurityHelper.DigestAlgorithm.MD5, file));
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ String fileName = IOHelper.toString(RUNTIME_DIR.relativize(file));
+ runtime.put(fileName, SecurityHelper.digest(DigestAlgorithm.MD5, file));
- // Create zip entry and transfer contents
- output.putNextEntry(newEntry(fileName));
- IOHelper.transfer(file, output);
+ // Create zip entry and transfer contents
+ output.putNextEntry(newEntry(fileName));
+ IOHelper.transfer(file, output);
- // Return result
- return super.visitFile(file, attrs);
- }
+ // Return result
+ return super.visitFile(file, attrs);
+ }
- private static ZipEntry newEntry(String fileName) {
- return IOHelper.newZipEntry(Launcher.RUNTIME_DIR + IOHelper.CROSS_SEPARATOR + fileName);
- }
- }
+ private static ZipEntry newEntry(String fileName) {
+ return IOHelper.newZipEntry(Launcher.RUNTIME_DIR + IOHelper.CROSS_SEPARATOR + fileName);
+ }
+ }
}
diff --git a/LaunchServer/source/binary/LauncherBinary.java b/LaunchServer/source/binary/LauncherBinary.java
index 0db3b47..86c712c 100644
--- a/LaunchServer/source/binary/LauncherBinary.java
+++ b/LaunchServer/source/binary/LauncherBinary.java
@@ -9,33 +9,33 @@
import launchserver.LaunchServer;
public abstract class LauncherBinary {
- @LauncherAPI protected final LaunchServer server;
- @LauncherAPI protected final Path binaryFile;
- private volatile SignedBytesHolder binary;
+ @LauncherAPI protected final LaunchServer server;
+ @LauncherAPI protected final Path binaryFile;
+ private volatile SignedBytesHolder binary;
- @LauncherAPI
- protected LauncherBinary(LaunchServer server, Path binaryFile) {
- this.server = server;
- this.binaryFile = binaryFile;
- }
+ @LauncherAPI
+ protected LauncherBinary(LaunchServer server, Path binaryFile) {
+ this.server = server;
+ this.binaryFile = binaryFile;
+ }
- @LauncherAPI
- public abstract void build() throws IOException;
+ @LauncherAPI
+ public abstract void build() throws IOException;
- @LauncherAPI
- public final boolean exists() {
- return IOHelper.isFile(binaryFile);
- }
+ @LauncherAPI
+ public final boolean exists() {
+ return IOHelper.isFile(binaryFile);
+ }
- @LauncherAPI
- public final SignedBytesHolder getBytes() {
- return binary;
- }
+ @LauncherAPI
+ public final SignedBytesHolder getBytes() {
+ return binary;
+ }
- @LauncherAPI
- public final boolean sync() throws IOException {
- boolean exists = exists();
- binary = exists ? new SignedBytesHolder(IOHelper.read(binaryFile), server.privateKey) : null;
- return exists;
- }
+ @LauncherAPI
+ public final boolean sync() throws IOException {
+ boolean exists = exists();
+ binary = exists ? new SignedBytesHolder(IOHelper.read(binaryFile), server.privateKey) : null;
+ return exists;
+ }
}
diff --git a/LaunchServer/source/command/Command.java b/LaunchServer/source/command/Command.java
index 6559811..d2bd0dd 100644
--- a/LaunchServer/source/command/Command.java
+++ b/LaunchServer/source/command/Command.java
@@ -7,44 +7,44 @@
import launchserver.LaunchServer;
public abstract class Command {
- @LauncherAPI protected final LaunchServer server;
+ @LauncherAPI protected final LaunchServer server;
- @LauncherAPI
- protected Command(LaunchServer server) {
- this.server = server;
- }
+ @LauncherAPI
+ protected Command(LaunchServer server) {
+ this.server = server;
+ }
- @LauncherAPI
- public abstract String getArgsDescription(); // " [optional]"
+ @LauncherAPI
+ public abstract String getArgsDescription(); // " [optional]"
- @LauncherAPI
- public abstract String getUsageDescription();
+ @LauncherAPI
+ public abstract String getUsageDescription();
- @LauncherAPI
- public abstract void invoke(String... args) throws Exception;
+ @LauncherAPI
+ public abstract void invoke(String... args) throws Exception;
- @LauncherAPI
- protected final void verifyArgs(String[] args, int min) throws CommandException {
- if (args.length < min) {
- throw new CommandException("Command usage: " + getArgsDescription());
- }
- }
+ @LauncherAPI
+ protected final void verifyArgs(String[] args, int min) throws CommandException {
+ if (args.length < min) {
+ throw new CommandException("Command usage: " + getArgsDescription());
+ }
+ }
- @LauncherAPI
- protected static UUID parseUUID(String s) throws CommandException {
- try {
- return UUID.fromString(s);
- } catch (IllegalArgumentException ignored) {
- throw new CommandException(String.format("Invalid UUID: '%s'", s));
- }
- }
+ @LauncherAPI
+ protected static UUID parseUUID(String s) throws CommandException {
+ try {
+ return UUID.fromString(s);
+ } catch (IllegalArgumentException ignored) {
+ throw new CommandException(String.format("Invalid UUID: '%s'", s));
+ }
+ }
- @LauncherAPI
- protected static String parseUsername(String username) throws CommandException {
- try {
- return VerifyHelper.verifyUsername(username);
- } catch (IllegalArgumentException e) {
- throw new CommandException(e.getMessage());
- }
- }
+ @LauncherAPI
+ protected static String parseUsername(String username) throws CommandException {
+ try {
+ return VerifyHelper.verifyUsername(username);
+ } catch (IllegalArgumentException e) {
+ throw new CommandException(e.getMessage());
+ }
+ }
}
diff --git a/LaunchServer/source/command/CommandException.java b/LaunchServer/source/command/CommandException.java
index 2de0f2e..d9858e6 100644
--- a/LaunchServer/source/command/CommandException.java
+++ b/LaunchServer/source/command/CommandException.java
@@ -3,20 +3,20 @@
import launcher.LauncherAPI;
public final class CommandException extends Exception {
- private static final long serialVersionUID = -6588814993972117772L;
+ private static final long serialVersionUID = -6588814993972117772L;
- @LauncherAPI
- public CommandException(String message) {
- super(message);
- }
+ @LauncherAPI
+ public CommandException(String message) {
+ super(message);
+ }
- @LauncherAPI
- public CommandException(Throwable exc) {
- super(exc);
- }
+ @LauncherAPI
+ public CommandException(Throwable exc) {
+ super(exc);
+ }
- @Override
- public String toString() {
- return getMessage();
- }
-}
\ No newline at end of file
+ @Override
+ public String toString() {
+ return getMessage();
+ }
+}
diff --git a/LaunchServer/source/command/auth/AuthCommand.java b/LaunchServer/source/command/auth/AuthCommand.java
index b0b4da8..9a6bb1a 100644
--- a/LaunchServer/source/command/auth/AuthCommand.java
+++ b/LaunchServer/source/command/auth/AuthCommand.java
@@ -8,34 +8,34 @@
import launchserver.command.Command;
public final class AuthCommand extends Command {
- public AuthCommand(LaunchServer server) {
- super(server);
- }
+ public AuthCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return " ";
- }
+ @Override
+ public String getArgsDescription() {
+ return " ";
+ }
- @Override
- public String getUsageDescription() {
- return "Try to auth with specified login and password";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Try to auth with specified login and password";
+ }
- @Override
- public void invoke(String... args) throws Exception {
- verifyArgs(args, 2);
- String login = args[0];
- String password = args[1];
+ @Override
+ public void invoke(String... args) throws Exception {
+ verifyArgs(args, 2);
+ String login = args[0];
+ String password = args[1];
- // Authenticate
- String username = server.config.authProvider.auth(login, password);
+ // Authenticate
+ String username = server.config.authProvider.auth(login, password);
- // Authenticate on server (and get UUID)
- String accessToken = SecurityHelper.randomStringToken();
- UUID uuid = server.config.authHandler.auth(username, accessToken);
+ // Authenticate on server (and get UUID)
+ String accessToken = SecurityHelper.randomStringToken();
+ UUID uuid = server.config.authHandler.auth(username, accessToken);
- // Print auth successful message
- LogHelper.subInfo("UUID: %s, Username: '%s', Access Token: '%s'", uuid, username, accessToken);
- }
+ // Print auth successful message
+ LogHelper.subInfo("UUID: %s, Username: '%s', Access Token: '%s'", uuid, username, accessToken);
+ }
}
diff --git a/LaunchServer/source/command/auth/UUIDToUsernameCommand.java b/LaunchServer/source/command/auth/UUIDToUsernameCommand.java
index c8d8482..d84e206 100644
--- a/LaunchServer/source/command/auth/UUIDToUsernameCommand.java
+++ b/LaunchServer/source/command/auth/UUIDToUsernameCommand.java
@@ -9,32 +9,32 @@
import launchserver.command.CommandException;
public final class UUIDToUsernameCommand extends Command {
- public UUIDToUsernameCommand(LaunchServer server) {
- super(server);
- }
+ public UUIDToUsernameCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return "";
- }
+ @Override
+ public String getArgsDescription() {
+ return "";
+ }
- @Override
- public String getUsageDescription() {
- return "Convert player UUID to username";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Convert player UUID to username";
+ }
- @Override
- public void invoke(String... args) throws CommandException, IOException {
- verifyArgs(args, 1);
- UUID uuid = parseUUID(args[0]);
+ @Override
+ public void invoke(String... args) throws CommandException, IOException {
+ verifyArgs(args, 1);
+ UUID uuid = parseUUID(args[0]);
- // Get UUID by username
- String username = server.config.authHandler.uuidToUsername(uuid);
- if (username == null) {
- throw new CommandException("Unknown UUID: " + uuid);
- }
+ // Get UUID by username
+ String username = server.config.authHandler.uuidToUsername(uuid);
+ if (username == null) {
+ throw new CommandException("Unknown UUID: " + uuid);
+ }
- // Print username
- LogHelper.subInfo("Username of player %s: '%s'", uuid, username);
- }
+ // Print username
+ LogHelper.subInfo("Username of player %s: '%s'", uuid, username);
+ }
}
diff --git a/LaunchServer/source/command/auth/UsernameToUUIDCommand.java b/LaunchServer/source/command/auth/UsernameToUUIDCommand.java
index b441e33..76f497d 100644
--- a/LaunchServer/source/command/auth/UsernameToUUIDCommand.java
+++ b/LaunchServer/source/command/auth/UsernameToUUIDCommand.java
@@ -9,32 +9,32 @@
import launchserver.command.CommandException;
public final class UsernameToUUIDCommand extends Command {
- public UsernameToUUIDCommand(LaunchServer server) {
- super(server);
- }
+ public UsernameToUUIDCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return "";
- }
+ @Override
+ public String getArgsDescription() {
+ return "";
+ }
- @Override
- public String getUsageDescription() {
- return "Convert player username to UUID";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Convert player username to UUID";
+ }
- @Override
- public void invoke(String... args) throws CommandException, IOException {
- verifyArgs(args, 1);
- String username = parseUsername(args[0]);
+ @Override
+ public void invoke(String... args) throws CommandException, IOException {
+ verifyArgs(args, 1);
+ String username = parseUsername(args[0]);
- // Get UUID by username
- UUID uuid = server.config.authHandler.usernameToUUID(username);
- if (uuid == null) {
- throw new CommandException(String.format("Unknown username: '%s'", username));
- }
+ // Get UUID by username
+ UUID uuid = server.config.authHandler.usernameToUUID(username);
+ if (uuid == null) {
+ throw new CommandException(String.format("Unknown username: '%s'", username));
+ }
- // Print UUID
- LogHelper.subInfo("UUID of player '%s': %s", username, uuid);
- }
+ // Print UUID
+ LogHelper.subInfo("UUID of player '%s': %s", username, uuid);
+ }
}
diff --git a/LaunchServer/source/command/basic/BuildCommand.java b/LaunchServer/source/command/basic/BuildCommand.java
index 28f2e79..2ecedb8 100644
--- a/LaunchServer/source/command/basic/BuildCommand.java
+++ b/LaunchServer/source/command/basic/BuildCommand.java
@@ -4,23 +4,23 @@
import launchserver.command.Command;
public final class BuildCommand extends Command {
- public BuildCommand(LaunchServer server) {
- super(server);
- }
+ public BuildCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return null;
- }
+ @Override
+ public String getArgsDescription() {
+ return null;
+ }
- @Override
- public String getUsageDescription() {
- return "Build launcher binaries";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Build launcher binaries";
+ }
- @Override
- public void invoke(String... args) throws Exception {
- server.buildLauncherBinaries();
- server.syncLauncherBinaries();
- }
+ @Override
+ public void invoke(String... args) throws Exception {
+ server.buildLauncherBinaries();
+ server.syncLauncherBinaries();
+ }
}
diff --git a/LaunchServer/source/command/basic/ClearCommand.java b/LaunchServer/source/command/basic/ClearCommand.java
index 271c510..2ab2671 100644
--- a/LaunchServer/source/command/basic/ClearCommand.java
+++ b/LaunchServer/source/command/basic/ClearCommand.java
@@ -5,23 +5,23 @@
import launchserver.command.Command;
public final class ClearCommand extends Command {
- public ClearCommand(LaunchServer server) {
- super(server);
- }
+ public ClearCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return null;
- }
+ @Override
+ public String getArgsDescription() {
+ return null;
+ }
- @Override
- public String getUsageDescription() {
- return "Clear terminal";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Clear terminal";
+ }
- @Override
- public void invoke(String... args) throws Exception {
- server.commandHandler.clear();
- LogHelper.subInfo("Terminal cleared");
- }
+ @Override
+ public void invoke(String... args) throws Exception {
+ server.commandHandler.clear();
+ LogHelper.subInfo("Terminal cleared");
+ }
}
diff --git a/LaunchServer/source/command/basic/DebugCommand.java b/LaunchServer/source/command/basic/DebugCommand.java
index 1fd30fe..8e601d6 100644
--- a/LaunchServer/source/command/basic/DebugCommand.java
+++ b/LaunchServer/source/command/basic/DebugCommand.java
@@ -5,29 +5,29 @@
import launchserver.command.Command;
public final class DebugCommand extends Command {
- public DebugCommand(LaunchServer server) {
- super(server);
- }
+ public DebugCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return "[true/false]";
- }
+ @Override
+ public String getArgsDescription() {
+ return "[true/false]";
+ }
- @Override
- public String getUsageDescription() {
- return "Enable or disable debug logging at runtime";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Enable or disable debug logging at runtime";
+ }
- @Override
- public void invoke(String... args) {
- boolean newValue;
- if (args.length >= 1) {
- newValue = Boolean.parseBoolean(args[0]);
- LogHelper.setDebugEnabled(newValue);
- } else {
- newValue = LogHelper.isDebugEnabled();
- }
- LogHelper.subInfo("Debug enabled: " + newValue);
- }
+ @Override
+ public void invoke(String... args) {
+ boolean newValue;
+ if (args.length >= 1) {
+ newValue = Boolean.parseBoolean(args[0]);
+ LogHelper.setDebugEnabled(newValue);
+ } else {
+ newValue = LogHelper.isDebugEnabled();
+ }
+ LogHelper.subInfo("Debug enabled: " + newValue);
+ }
}
diff --git a/LaunchServer/source/command/basic/GCCommand.java b/LaunchServer/source/command/basic/GCCommand.java
index 3ba2f2a..3f2424b 100644
--- a/LaunchServer/source/command/basic/GCCommand.java
+++ b/LaunchServer/source/command/basic/GCCommand.java
@@ -6,30 +6,30 @@
import launchserver.command.Command;
public final class GCCommand extends Command {
- public GCCommand(LaunchServer server) {
- super(server);
- }
+ public GCCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return null;
- }
+ @Override
+ public String getArgsDescription() {
+ return null;
+ }
- @Override
- public String getUsageDescription() {
- return "Perform Garbage Collection and print memory usage";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Perform Garbage Collection and print memory usage";
+ }
- @Override
- public void invoke(String... args) throws Exception {
- LogHelper.subInfo("Performing full GC");
- JVMHelper.fullGC();
+ @Override
+ public void invoke(String... args) throws Exception {
+ LogHelper.subInfo("Performing full GC");
+ JVMHelper.fullGC();
- // Print memory usage
- long max = JVMHelper.RUNTIME.maxMemory() >> 20;
- long free = JVMHelper.RUNTIME.freeMemory() >> 20;
- long total = JVMHelper.RUNTIME.totalMemory() >> 20;
- long used = total - free;
- LogHelper.subInfo("Heap usage: %d / %d / %d MiB", used, total, max);
- }
+ // Print memory usage
+ long max = JVMHelper.RUNTIME.maxMemory() >> 20;
+ long free = JVMHelper.RUNTIME.freeMemory() >> 20;
+ long total = JVMHelper.RUNTIME.totalMemory() >> 20;
+ long used = total - free;
+ LogHelper.subInfo("Heap usage: %d / %d / %d MiB", used, total, max);
+ }
}
diff --git a/LaunchServer/source/command/basic/HelpCommand.java b/LaunchServer/source/command/basic/HelpCommand.java
index edacfd1..14621b2 100644
--- a/LaunchServer/source/command/basic/HelpCommand.java
+++ b/LaunchServer/source/command/basic/HelpCommand.java
@@ -1,6 +1,7 @@
package launchserver.command.basic;
import java.util.Map;
+import java.util.Map.Entry;
import launcher.helper.LogHelper;
import launchserver.LaunchServer;
@@ -8,43 +9,43 @@
import launchserver.command.CommandException;
public final class HelpCommand extends Command {
- public HelpCommand(LaunchServer server) {
- super(server);
- }
+ public HelpCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return "[command name]";
- }
+ @Override
+ public String getArgsDescription() {
+ return "[command name]";
+ }
- @Override
- public String getUsageDescription() {
- return "Print command usage";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Print command usage";
+ }
- @Override
- public void invoke(String... args) throws CommandException {
- if (args.length < 1) {
- printCommands();
- return;
- }
+ @Override
+ public void invoke(String... args) throws CommandException {
+ if (args.length < 1) {
+ printCommands();
+ return;
+ }
- // Print command help
- printCommand(args[0]);
- }
+ // Print command help
+ printCommand(args[0]);
+ }
- private void printCommand(String name) throws CommandException {
- printCommand(name, server.commandHandler.lookup(name));
- }
+ private void printCommand(String name) throws CommandException {
+ printCommand(name, server.commandHandler.lookup(name));
+ }
- private void printCommands() {
- for (Map.Entry entry : server.commandHandler.commandsMap().entrySet()) {
- printCommand(entry.getKey(), entry.getValue());
- }
- }
+ private void printCommands() {
+ for (Entry entry : server.commandHandler.commandsMap().entrySet()) {
+ printCommand(entry.getKey(), entry.getValue());
+ }
+ }
- private static void printCommand(String name, Command command) {
- String args = command.getArgsDescription();
- LogHelper.subInfo("%s %s - %s", name, args == null ? "[nothing]" : args, command.getUsageDescription());
- }
+ private static void printCommand(String name, Command command) {
+ String args = command.getArgsDescription();
+ LogHelper.subInfo("%s %s - %s", name, args == null ? "[nothing]" : args, command.getUsageDescription());
+ }
}
diff --git a/LaunchServer/source/command/basic/LogConnectionsCommand.java b/LaunchServer/source/command/basic/LogConnectionsCommand.java
index ed3fbca..29ba612 100644
--- a/LaunchServer/source/command/basic/LogConnectionsCommand.java
+++ b/LaunchServer/source/command/basic/LogConnectionsCommand.java
@@ -5,29 +5,29 @@
import launchserver.command.Command;
public final class LogConnectionsCommand extends Command {
- public LogConnectionsCommand(LaunchServer server) {
- super(server);
- }
+ public LogConnectionsCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return "[true/false]";
- }
+ @Override
+ public String getArgsDescription() {
+ return "[true/false]";
+ }
- @Override
- public String getUsageDescription() {
- return "Enable or disable logging connections";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Enable or disable logging connections";
+ }
- @Override
- public void invoke(String... args) {
- boolean newValue;
- if (args.length >= 1) {
- newValue = Boolean.parseBoolean(args[0]);
- server.serverSocketHandler.logConnections = newValue;
- } else {
- newValue = server.serverSocketHandler.logConnections;
- }
- LogHelper.subInfo("Log connections: " + newValue);
- }
+ @Override
+ public void invoke(String... args) {
+ boolean newValue;
+ if (args.length >= 1) {
+ newValue = Boolean.parseBoolean(args[0]);
+ server.serverSocketHandler.logConnections = newValue;
+ } else {
+ newValue = server.serverSocketHandler.logConnections;
+ }
+ LogHelper.subInfo("Log connections: " + newValue);
+ }
}
diff --git a/LaunchServer/source/command/basic/RebindCommand.java b/LaunchServer/source/command/basic/RebindCommand.java
index 531d2c2..03e24df 100644
--- a/LaunchServer/source/command/basic/RebindCommand.java
+++ b/LaunchServer/source/command/basic/RebindCommand.java
@@ -4,22 +4,22 @@
import launchserver.command.Command;
public final class RebindCommand extends Command {
- public RebindCommand(LaunchServer server) {
- super(server);
- }
+ public RebindCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return null;
- }
+ @Override
+ public String getArgsDescription() {
+ return null;
+ }
- @Override
- public String getUsageDescription() {
- return "Rebind server socket";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Rebind server socket";
+ }
- @Override
- public void invoke(String... args) throws Exception {
- server.rebindServerSocket();
- }
+ @Override
+ public void invoke(String... args) throws Exception {
+ server.rebindServerSocket();
+ }
}
diff --git a/LaunchServer/source/command/basic/StopCommand.java b/LaunchServer/source/command/basic/StopCommand.java
index bd27b97..8a32cab 100644
--- a/LaunchServer/source/command/basic/StopCommand.java
+++ b/LaunchServer/source/command/basic/StopCommand.java
@@ -5,23 +5,23 @@
import launchserver.command.Command;
public final class StopCommand extends Command {
- public StopCommand(LaunchServer server) {
- super(server);
- }
+ public StopCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return null;
- }
+ @Override
+ public String getArgsDescription() {
+ return null;
+ }
- @Override
- public String getUsageDescription() {
- return "Stop LaunchServer";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Stop LaunchServer";
+ }
- @Override
- @SuppressWarnings("CallToSystemExit")
- public void invoke(String... args) {
- JVMHelper.RUNTIME.exit(0);
- }
+ @Override
+ @SuppressWarnings("CallToSystemExit")
+ public void invoke(String... args) {
+ JVMHelper.RUNTIME.exit(0);
+ }
}
diff --git a/LaunchServer/source/command/basic/VersionCommand.java b/LaunchServer/source/command/basic/VersionCommand.java
index d9fc705..24302af 100644
--- a/LaunchServer/source/command/basic/VersionCommand.java
+++ b/LaunchServer/source/command/basic/VersionCommand.java
@@ -6,22 +6,22 @@
import launchserver.command.Command;
public final class VersionCommand extends Command {
- public VersionCommand(LaunchServer server) {
- super(server);
- }
+ public VersionCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return null;
- }
+ @Override
+ public String getArgsDescription() {
+ return null;
+ }
- @Override
- public String getUsageDescription() {
- return "Print LaunchServer version";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Print LaunchServer version";
+ }
- @Override
- public void invoke(String... args) throws Exception {
- LogHelper.subInfo("LaunchServer version: %s (build #%s)", Launcher.VERSION, Launcher.BUILD);
- }
+ @Override
+ public void invoke(String... args) throws Exception {
+ LogHelper.subInfo("LaunchServer version: %s (build #%s)", Launcher.VERSION, Launcher.BUILD);
+ }
}
diff --git a/LaunchServer/source/command/handler/CommandHandler.java b/LaunchServer/source/command/handler/CommandHandler.java
index 9af003c..2c96322 100644
--- a/LaunchServer/source/command/handler/CommandHandler.java
+++ b/LaunchServer/source/command/handler/CommandHandler.java
@@ -38,153 +38,153 @@
import launchserver.command.hash.UnindexAssetCommand;
public abstract class CommandHandler implements Runnable {
- private final Map commands = new ConcurrentHashMap<>(32);
+ private final Map commands = new ConcurrentHashMap<>(32);
- protected CommandHandler(LaunchServer server) {
- // Register basic commands
- registerCommand("help", new HelpCommand(server));
- registerCommand("version", new VersionCommand(server));
- registerCommand("build", new BuildCommand(server));
- registerCommand("stop", new StopCommand(server));
- registerCommand("rebind", new RebindCommand(server));
- registerCommand("debug", new DebugCommand(server));
- registerCommand("clear", new ClearCommand(server));
- registerCommand("gc", new GCCommand(server));
- registerCommand("logConnections", new LogConnectionsCommand(server));
+ protected CommandHandler(LaunchServer server) {
+ // Register basic commands
+ registerCommand("help", new HelpCommand(server));
+ registerCommand("version", new VersionCommand(server));
+ registerCommand("build", new BuildCommand(server));
+ registerCommand("stop", new StopCommand(server));
+ registerCommand("rebind", new RebindCommand(server));
+ registerCommand("debug", new DebugCommand(server));
+ registerCommand("clear", new ClearCommand(server));
+ registerCommand("gc", new GCCommand(server));
+ registerCommand("logConnections", new LogConnectionsCommand(server));
- // Register sync commands
- registerCommand("indexAsset", new IndexAssetCommand(server));
- registerCommand("unindexAsset", new UnindexAssetCommand(server));
- registerCommand("downloadAsset", new DownloadAssetCommand(server));
- registerCommand("downloadClient", new DownloadClientCommand(server));
- registerCommand("syncBinaries", new SyncBinariesCommand(server));
- registerCommand("syncUpdates", new SyncUpdatesCommand(server));
- registerCommand("syncProfiles", new SyncProfilesCommand(server));
+ // Register sync commands
+ registerCommand("indexAsset", new IndexAssetCommand(server));
+ registerCommand("unindexAsset", new UnindexAssetCommand(server));
+ registerCommand("downloadAsset", new DownloadAssetCommand(server));
+ registerCommand("downloadClient", new DownloadClientCommand(server));
+ registerCommand("syncBinaries", new SyncBinariesCommand(server));
+ registerCommand("syncUpdates", new SyncUpdatesCommand(server));
+ registerCommand("syncProfiles", new SyncProfilesCommand(server));
- // Register auth commands
- registerCommand("auth", new AuthCommand(server));
- registerCommand("usernameToUUID", new UsernameToUUIDCommand(server));
- registerCommand("uuidToUsername", new UUIDToUsernameCommand(server));
- }
+ // Register auth commands
+ registerCommand("auth", new AuthCommand(server));
+ registerCommand("usernameToUUID", new UsernameToUUIDCommand(server));
+ registerCommand("uuidToUsername", new UUIDToUsernameCommand(server));
+ }
- @Override
- public final void run() {
- try {
- readLoop();
- } catch (IOException e) {
- LogHelper.error(e);
- }
- }
+ @Override
+ public final void run() {
+ try {
+ readLoop();
+ } catch (IOException e) {
+ LogHelper.error(e);
+ }
+ }
- @LauncherAPI
- public abstract void bell() throws IOException;
+ @LauncherAPI
+ public abstract void bell() throws IOException;
- @LauncherAPI
- public abstract void clear() throws IOException;
+ @LauncherAPI
+ public abstract void clear() throws IOException;
- @LauncherAPI
- public final Map commandsMap() {
- return Collections.unmodifiableMap(commands);
- }
+ @LauncherAPI
+ public abstract String readLine() throws IOException;
- @LauncherAPI
- public final void eval(String line, boolean bell) {
- Instant startTime = Instant.now();
- try {
- String[] args = parse(line);
- if (args.length == 0) {
- return;
- }
+ @LauncherAPI
+ public final Map commandsMap() {
+ return Collections.unmodifiableMap(commands);
+ }
- // Invoke command
- LogHelper.info("Command '%s'", line);
- lookup(args[0]).invoke(Arrays.copyOfRange(args, 1, args.length));
- } catch (Exception e) {
- LogHelper.error(e);
- }
+ @LauncherAPI
+ public final void eval(String line, boolean bell) {
+ Instant startTime = Instant.now();
+ try {
+ String[] args = parse(line);
+ if (args.length == 0) {
+ return;
+ }
- // Bell if invocation took > 1s
- Instant endTime = Instant.now();
- if (bell && Duration.between(startTime, endTime).getSeconds() >= 5) {
- try {
- bell();
- } catch (IOException e) {
- LogHelper.error(e);
- }
- }
- }
+ // Invoke command
+ LogHelper.info("Command '%s'", line);
+ lookup(args[0]).invoke(Arrays.copyOfRange(args, 1, args.length));
+ } catch (Exception e) {
+ LogHelper.error(e);
+ }
- @LauncherAPI
- public final Command lookup(String name) throws CommandException {
- Command command = commands.get(name);
- if (command == null) {
- throw new CommandException(String.format("Unknown command: '%s'", name));
- }
- return command;
- }
+ // Bell if invocation took > 1s
+ Instant endTime = Instant.now();
+ if (bell && Duration.between(startTime, endTime).getSeconds() >= 5) {
+ try {
+ bell();
+ } catch (IOException e) {
+ LogHelper.error(e);
+ }
+ }
+ }
- @LauncherAPI
- public abstract String readLine() throws IOException;
+ @LauncherAPI
+ public final Command lookup(String name) throws CommandException {
+ Command command = commands.get(name);
+ if (command == null) {
+ throw new CommandException(String.format("Unknown command: '%s'", name));
+ }
+ return command;
+ }
- @LauncherAPI
- public final void registerCommand(String name, Command command) {
- VerifyHelper.verifyIDName(name);
- VerifyHelper.putIfAbsent(commands, name, Objects.requireNonNull(command, "command"),
- String.format("Command has been already registered: '%s'", name));
- }
+ @LauncherAPI
+ public final void registerCommand(String name, Command command) {
+ VerifyHelper.verifyIDName(name);
+ VerifyHelper.putIfAbsent(commands, name, Objects.requireNonNull(command, "command"),
+ String.format("Command has been already registered: '%s'", name));
+ }
- private void readLoop() throws IOException {
- for (String line = readLine(); line != null; line = readLine()) {
- eval(line, true);
- }
- }
+ private void readLoop() throws IOException {
+ for (String line = readLine(); line != null; line = readLine()) {
+ eval(line, true);
+ }
+ }
- private static String[] parse(CharSequence line) throws CommandException {
- boolean quoted = false;
- boolean wasQuoted = false;
+ private static String[] parse(CharSequence line) throws CommandException {
+ boolean quoted = false;
+ boolean wasQuoted = false;
- // Read line char by char
- Collection result = new LinkedList<>();
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < line.length() + 1; i++) {
- boolean end = i >= line.length();
- char ch = end ? 0 : line.charAt(i);
+ // Read line char by char
+ Collection result = new LinkedList<>();
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < line.length() + 1; i++) {
+ boolean end = i >= line.length();
+ char ch = end ? 0 : line.charAt(i);
- // Maybe we should read next argument?
- if (end || !quoted && Character.isWhitespace(ch)) {
- if (end && quoted) { // Quotes should be closed
- throw new CommandException("Quotes wasn't closed");
- }
+ // Maybe we should read next argument?
+ if (end || !quoted && Character.isWhitespace(ch)) {
+ if (end && quoted) { // Quotes should be closed
+ throw new CommandException("Quotes wasn't closed");
+ }
- // Empty args are ignored (except if was quoted)
- if (wasQuoted || builder.length() > 0) {
- result.add(builder.toString());
- }
+ // Empty args are ignored (except if was quoted)
+ if (wasQuoted || builder.length() > 0) {
+ result.add(builder.toString());
+ }
- // Reset string builder
- wasQuoted = false;
- builder.setLength(0);
- continue;
- }
+ // Reset string builder
+ wasQuoted = false;
+ builder.setLength(0);
+ continue;
+ }
- // Append next char
- switch (ch) {
- case '"': // "abc"de, "abc""de" also allowed
- quoted = !quoted;
- wasQuoted = true;
- break;
- case '\\': // All escapes, including spaces etc
- char next = line.charAt(i + 1);
- builder.append(next);
- i++;
- break;
- default: // Default char, simply append
- builder.append(ch);
- break;
- }
- }
+ // Append next char
+ switch (ch) {
+ case '"': // "abc"de, "abc""de" also allowed
+ quoted = !quoted;
+ wasQuoted = true;
+ break;
+ case '\\': // All escapes, including spaces etc
+ char next = line.charAt(i + 1);
+ builder.append(next);
+ i++;
+ break;
+ default: // Default char, simply append
+ builder.append(ch);
+ break;
+ }
+ }
- // Return result as array
- return result.toArray(new String[result.size()]);
- }
+ // Return result as array
+ return result.toArray(new String[result.size()]);
+ }
}
diff --git a/LaunchServer/source/command/handler/JLineCommandHandler.java b/LaunchServer/source/command/handler/JLineCommandHandler.java
index fd6aa12..0198797 100644
--- a/LaunchServer/source/command/handler/JLineCommandHandler.java
+++ b/LaunchServer/source/command/handler/JLineCommandHandler.java
@@ -4,48 +4,49 @@
import jline.console.ConsoleReader;
import launcher.helper.LogHelper;
+import launcher.helper.LogHelper.Output;
import launchserver.LaunchServer;
public final class JLineCommandHandler extends CommandHandler {
- private final ConsoleReader reader;
+ private final ConsoleReader reader;
- public JLineCommandHandler(LaunchServer server) throws IOException {
- super(server);
+ public JLineCommandHandler(LaunchServer server) throws IOException {
+ super(server);
- // Set reader
- reader = new ConsoleReader();
- reader.setExpandEvents(false);
+ // Set reader
+ reader = new ConsoleReader();
+ reader.setExpandEvents(false);
- // Replace writer
- LogHelper.removeStdOutput();
- LogHelper.addOutput(new JLineOutput());
- }
+ // Replace writer
+ LogHelper.removeStdOutput();
+ LogHelper.addOutput(new JLineOutput());
+ }
- @Override
- public void bell() throws IOException {
- reader.beep();
- }
+ @Override
+ public void bell() throws IOException {
+ reader.beep();
+ }
- @Override
- public void clear() throws IOException {
- reader.clearScreen();
- }
+ @Override
+ public void clear() throws IOException {
+ reader.clearScreen();
+ }
- @Override
- public String readLine() throws IOException {
- return reader.readLine();
- }
+ @Override
+ public String readLine() throws IOException {
+ return reader.readLine();
+ }
- private final class JLineOutput implements LogHelper.Output {
- @Override
- public void println(String message) {
- try {
- reader.println(ConsoleReader.RESET_LINE + message);
- reader.drawLine();
- reader.flush();
- } catch (IOException ignored) {
- // Ignored
- }
- }
- }
+ private final class JLineOutput implements Output {
+ @Override
+ public void println(String message) {
+ try {
+ reader.println(ConsoleReader.RESET_LINE + message);
+ reader.drawLine();
+ reader.flush();
+ } catch (IOException ignored) {
+ // Ignored
+ }
+ }
+ }
}
diff --git a/LaunchServer/source/command/handler/StdCommandHandler.java b/LaunchServer/source/command/handler/StdCommandHandler.java
index c073c92..7d175b0 100644
--- a/LaunchServer/source/command/handler/StdCommandHandler.java
+++ b/LaunchServer/source/command/handler/StdCommandHandler.java
@@ -7,25 +7,25 @@
import launchserver.LaunchServer;
public final class StdCommandHandler extends CommandHandler {
- private final BufferedReader reader;
+ private final BufferedReader reader;
- public StdCommandHandler(LaunchServer server) {
- super(server);
- reader = IOHelper.newReader(System.in);
- }
+ public StdCommandHandler(LaunchServer server) {
+ super(server);
+ reader = IOHelper.newReader(System.in);
+ }
- @Override
- public void bell() {
- // Do nothing, unsupported
- }
+ @Override
+ public void bell() {
+ // Do nothing, unsupported
+ }
- @Override
- public void clear() {
- throw new UnsupportedOperationException("clear terminal");
- }
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException("clear terminal");
+ }
- @Override
- public String readLine() throws IOException {
- return reader.readLine();
- }
+ @Override
+ public String readLine() throws IOException {
+ return reader.readLine();
+ }
}
diff --git a/LaunchServer/source/command/hash/DownloadAssetCommand.java b/LaunchServer/source/command/hash/DownloadAssetCommand.java
index 5242820..a1dc8bb 100644
--- a/LaunchServer/source/command/hash/DownloadAssetCommand.java
+++ b/LaunchServer/source/command/hash/DownloadAssetCommand.java
@@ -9,60 +9,61 @@
import java.util.zip.ZipInputStream;
import launcher.client.ClientProfile;
+import launcher.client.ClientProfile.Version;
import launcher.helper.IOHelper;
import launcher.helper.LogHelper;
import launchserver.LaunchServer;
import launchserver.command.Command;
public final class DownloadAssetCommand extends Command {
- private static final String ASSET_URL_MASK = "http://launcher.sashok724.net/download/assets/%s.zip";
+ private static final String ASSET_URL_MASK = "http://launcher.sashok724.net/download/assets/%s.zip";
- public DownloadAssetCommand(LaunchServer server) {
- super(server);
- }
+ public DownloadAssetCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return " ";
- }
+ @Override
+ public String getArgsDescription() {
+ return " ";
+ }
- @Override
- public String getUsageDescription() {
- return "Download asset dir";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Download asset dir";
+ }
- @Override
- public void invoke(String... args) throws Exception {
- verifyArgs(args, 2);
- ClientProfile.Version version = ClientProfile.Version.byName(args[0]);
- String dirName = IOHelper.verifyFileName(args[1]);
- Path assetDir = LaunchServer.UPDATES_DIR.resolve(dirName);
+ @Override
+ public void invoke(String... args) throws Exception {
+ verifyArgs(args, 2);
+ Version version = Version.byName(args[0]);
+ String dirName = IOHelper.verifyFileName(args[1]);
+ Path assetDir = LaunchServer.UPDATES_DIR.resolve(dirName);
- // Create asset dir
- LogHelper.subInfo("Creating asset dir: '%s'", dirName);
- Files.createDirectory(assetDir);
+ // Create asset dir
+ LogHelper.subInfo("Creating asset dir: '%s'", dirName);
+ Files.createDirectory(assetDir);
- // Download required asset
- LogHelper.subInfo("Downloading asset, it may take some time");
- unpack(new URL(String.format(ASSET_URL_MASK, IOHelper.urlEncode(version.name))), assetDir);
+ // Download required asset
+ LogHelper.subInfo("Downloading asset, it may take some time");
+ unpack(new URL(String.format(ASSET_URL_MASK, IOHelper.urlEncode(version.name))), assetDir);
- // Finished
- server.syncUpdatesDir(Collections.singleton(dirName));
- LogHelper.subInfo("Asset successfully downloaded: '%s'", dirName);
- }
+ // Finished
+ server.syncUpdatesDir(Collections.singleton(dirName));
+ LogHelper.subInfo("Asset successfully downloaded: '%s'", dirName);
+ }
- public static void unpack(URL url, Path dir) throws IOException {
- try (ZipInputStream input = IOHelper.newZipInput(url)) {
- for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) {
- if (entry.isDirectory()) {
- continue; // Skip directories
- }
+ public static void unpack(URL url, Path dir) throws IOException {
+ try (ZipInputStream input = IOHelper.newZipInput(url)) {
+ for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) {
+ if (entry.isDirectory()) {
+ continue; // Skip directories
+ }
- // Unpack entry
- String name = entry.getName();
- LogHelper.subInfo("Downloading file: '%s'", name);
- IOHelper.transfer(input, dir.resolve(IOHelper.toPath(name)));
- }
- }
- }
+ // Unpack entry
+ String name = entry.getName();
+ LogHelper.subInfo("Downloading file: '%s'", name);
+ IOHelper.transfer(input, dir.resolve(IOHelper.toPath(name)));
+ }
+ }
+ }
}
diff --git a/LaunchServer/source/command/hash/DownloadClientCommand.java b/LaunchServer/source/command/hash/DownloadClientCommand.java
index 5f792c1..656b5a5 100644
--- a/LaunchServer/source/command/hash/DownloadClientCommand.java
+++ b/LaunchServer/source/command/hash/DownloadClientCommand.java
@@ -9,6 +9,7 @@
import java.util.Collections;
import launcher.client.ClientProfile;
+import launcher.client.ClientProfile.Version;
import launcher.helper.IOHelper;
import launcher.helper.LogHelper;
import launcher.serialize.config.TextConfigReader;
@@ -19,55 +20,55 @@
import launchserver.command.CommandException;
public final class DownloadClientCommand extends Command {
- private static final String CLIENT_URL_MASK = "http://launcher.sashok724.net/download/clients/%s.zip";
+ private static final String CLIENT_URL_MASK = "http://launcher.sashok724.net/download/clients/%s.zip";
- public DownloadClientCommand(LaunchServer server) {
- super(server);
- }
+ public DownloadClientCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return " ";
- }
+ @Override
+ public String getArgsDescription() {
+ return " ";
+ }
- @Override
- public String getUsageDescription() {
- return "Download client dir";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Download client dir";
+ }
- @Override
- public void invoke(String... args) throws IOException, CommandException {
- verifyArgs(args, 2);
- ClientProfile.Version version = ClientProfile.Version.byName(args[0]);
- String dirName = IOHelper.verifyFileName(args[1]);
- Path clientDir = LaunchServer.UPDATES_DIR.resolve(args[1]);
+ @Override
+ public void invoke(String... args) throws IOException, CommandException {
+ verifyArgs(args, 2);
+ Version version = Version.byName(args[0]);
+ String dirName = IOHelper.verifyFileName(args[1]);
+ Path clientDir = LaunchServer.UPDATES_DIR.resolve(args[1]);
- // Create client dir
- LogHelper.subInfo("Creating client dir: '%s'", dirName);
- Files.createDirectory(clientDir);
+ // Create client dir
+ LogHelper.subInfo("Creating client dir: '%s'", dirName);
+ Files.createDirectory(clientDir);
- // Download required client
- LogHelper.subInfo("Downloading client, it may take some time");
- DownloadAssetCommand.unpack(new URL(String.format(CLIENT_URL_MASK,
- IOHelper.urlEncode(version.name))), clientDir);
+ // Download required client
+ LogHelper.subInfo("Downloading client, it may take some time");
+ DownloadAssetCommand.unpack(new URL(String.format(CLIENT_URL_MASK,
+ IOHelper.urlEncode(version.name))), clientDir);
- // Create profile file
- LogHelper.subInfo("Creaing profile file: '%s'", dirName);
- ClientProfile client;
- String profilePath = String.format("launchserver/defaults/profile%s.cfg", version.name);
- try (BufferedReader reader = IOHelper.newReader(IOHelper.getResourceURL(profilePath))) {
- client = new ClientProfile(TextConfigReader.read(reader, false));
- }
- client.setTitle(dirName);
- client.block.getEntry("dir", StringConfigEntry.class).setValue(dirName);
- try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(LaunchServer.PROFILES_DIR,
- dirName, "cfg"))) {
- TextConfigWriter.write(client.block, writer, true);
- }
+ // Create profile file
+ LogHelper.subInfo("Creaing profile file: '%s'", dirName);
+ ClientProfile client;
+ String profilePath = String.format("launchserver/defaults/profile%s.cfg", version.name);
+ try (BufferedReader reader = IOHelper.newReader(IOHelper.getResourceURL(profilePath))) {
+ client = new ClientProfile(TextConfigReader.read(reader, false));
+ }
+ client.setTitle(dirName);
+ client.block.getEntry("dir", StringConfigEntry.class).setValue(dirName);
+ try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(LaunchServer.PROFILES_DIR,
+ dirName, "cfg"))) {
+ TextConfigWriter.write(client.block, writer, true);
+ }
- // Finished
- server.syncProfilesDir();
- server.syncUpdatesDir(Collections.singleton(dirName));
- LogHelper.subInfo("Client successfully downloaded: '%s'", dirName);
- }
+ // Finished
+ server.syncProfilesDir();
+ server.syncUpdatesDir(Collections.singleton(dirName));
+ LogHelper.subInfo("Client successfully downloaded: '%s'", dirName);
+ }
}
diff --git a/LaunchServer/source/command/hash/IndexAssetCommand.java b/LaunchServer/source/command/hash/IndexAssetCommand.java
index 9fe49a4..201cf68 100644
--- a/LaunchServer/source/command/hash/IndexAssetCommand.java
+++ b/LaunchServer/source/command/hash/IndexAssetCommand.java
@@ -16,94 +16,95 @@
import launcher.helper.IOHelper;
import launcher.helper.LogHelper;
import launcher.helper.SecurityHelper;
+import launcher.helper.SecurityHelper.DigestAlgorithm;
import launchserver.LaunchServer;
import launchserver.command.Command;
import launchserver.command.CommandException;
public final class IndexAssetCommand extends Command {
- public static final String INDEXES_DIR = "indexes";
- public static final String OBJECTS_DIR = "objects";
- private static final String JSON_EXTENSION = ".json";
+ public static final String INDEXES_DIR = "indexes";
+ public static final String OBJECTS_DIR = "objects";
+ private static final String JSON_EXTENSION = ".json";
- public IndexAssetCommand(LaunchServer server) {
- super(server);
- }
+ public IndexAssetCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return " ";
- }
+ @Override
+ public String getArgsDescription() {
+ return " ";
+ }
- @Override
- public String getUsageDescription() {
- return "Index asset dir (1.7.10+)";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Index asset dir (1.7.10+)";
+ }
- @Override
- public void invoke(String... args) throws Exception {
- verifyArgs(args, 3);
- String inputAssetDirName = IOHelper.verifyFileName(args[0]);
- String indexFileName = IOHelper.verifyFileName(args[1]);
- String outputAssetDirName = IOHelper.verifyFileName(args[2]);
- Path inputAssetDir = LaunchServer.UPDATES_DIR.resolve(inputAssetDirName);
- Path outputAssetDir = LaunchServer.UPDATES_DIR.resolve(outputAssetDirName);
- if (outputAssetDir.equals(inputAssetDir)) {
- throw new CommandException("Unindexed and indexed asset dirs can't be same");
- }
+ @Override
+ public void invoke(String... args) throws Exception {
+ verifyArgs(args, 3);
+ String inputAssetDirName = IOHelper.verifyFileName(args[0]);
+ String indexFileName = IOHelper.verifyFileName(args[1]);
+ String outputAssetDirName = IOHelper.verifyFileName(args[2]);
+ Path inputAssetDir = LaunchServer.UPDATES_DIR.resolve(inputAssetDirName);
+ Path outputAssetDir = LaunchServer.UPDATES_DIR.resolve(outputAssetDirName);
+ if (outputAssetDir.equals(inputAssetDir)) {
+ throw new CommandException("Unindexed and indexed asset dirs can't be same");
+ }
- // Create new asset dir
- LogHelper.subInfo("Creating indexed asset dir: '%s'", outputAssetDirName);
- Files.createDirectory(outputAssetDir);
+ // Create new asset dir
+ LogHelper.subInfo("Creating indexed asset dir: '%s'", outputAssetDirName);
+ Files.createDirectory(outputAssetDir);
- // Index objects
- JsonObject objects = Json.object();
- LogHelper.subInfo("Indexing objects");
- IOHelper.walk(inputAssetDir, new IndexAssetVisitor(objects, inputAssetDir, outputAssetDir), false);
+ // Index objects
+ JsonObject objects = Json.object();
+ LogHelper.subInfo("Indexing objects");
+ IOHelper.walk(inputAssetDir, new IndexAssetVisitor(objects, inputAssetDir, outputAssetDir), false);
- // Write index file
- LogHelper.subInfo("Writing asset index file: '%s'", indexFileName);
- try (BufferedWriter writer = IOHelper.newWriter(resolveIndexFile(outputAssetDir, indexFileName))) {
- Json.object().add(OBJECTS_DIR, objects).writeTo(writer, WriterConfig.MINIMAL);
- }
+ // Write index file
+ LogHelper.subInfo("Writing asset index file: '%s'", indexFileName);
+ try (BufferedWriter writer = IOHelper.newWriter(resolveIndexFile(outputAssetDir, indexFileName))) {
+ Json.object().add(OBJECTS_DIR, objects).writeTo(writer, WriterConfig.MINIMAL);
+ }
- // Finished
- server.syncUpdatesDir(Collections.singleton(outputAssetDirName));
- LogHelper.subInfo("Asset successfully indexed: '%s'", inputAssetDirName);
- }
+ // Finished
+ server.syncUpdatesDir(Collections.singleton(outputAssetDirName));
+ LogHelper.subInfo("Asset successfully indexed: '%s'", inputAssetDirName);
+ }
- @LauncherAPI
- public static Path resolveIndexFile(Path assetDir, String name) {
- return assetDir.resolve(INDEXES_DIR).resolve(name + JSON_EXTENSION);
- }
+ @LauncherAPI
+ public static Path resolveIndexFile(Path assetDir, String name) {
+ return assetDir.resolve(INDEXES_DIR).resolve(name + JSON_EXTENSION);
+ }
- @LauncherAPI
- public static Path resolveObjectFile(Path assetDir, String hash) {
- return assetDir.resolve(OBJECTS_DIR).resolve(hash.substring(0, 2)).resolve(hash);
- }
+ @LauncherAPI
+ public static Path resolveObjectFile(Path assetDir, String hash) {
+ return assetDir.resolve(OBJECTS_DIR).resolve(hash.substring(0, 2)).resolve(hash);
+ }
- private static final class IndexAssetVisitor extends SimpleFileVisitor {
- private final JsonObject objects;
- private final Path inputAssetDir;
- private final Path outputAssetDir;
+ private static final class IndexAssetVisitor extends SimpleFileVisitor {
+ private final JsonObject objects;
+ private final Path inputAssetDir;
+ private final Path outputAssetDir;
- private IndexAssetVisitor(JsonObject objects, Path inputAssetDir, Path outputAssetDir) {
- this.objects = objects;
- this.inputAssetDir = inputAssetDir;
- this.outputAssetDir = outputAssetDir;
- }
+ private IndexAssetVisitor(JsonObject objects, Path inputAssetDir, Path outputAssetDir) {
+ this.objects = objects;
+ this.inputAssetDir = inputAssetDir;
+ this.outputAssetDir = outputAssetDir;
+ }
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- String name = IOHelper.toString(inputAssetDir.relativize(file));
- LogHelper.subInfo("Indexing: '%s'", name);
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ String name = IOHelper.toString(inputAssetDir.relativize(file));
+ LogHelper.subInfo("Indexing: '%s'", name);
- // Add to index and copy file
- String digest = SecurityHelper.toHex(SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA1, file));
- objects.add(name, Json.object().add("size", attrs.size()).add("hash", digest));
- IOHelper.copy(file, resolveObjectFile(outputAssetDir, digest));
+ // Add to index and copy file
+ String digest = SecurityHelper.toHex(SecurityHelper.digest(DigestAlgorithm.SHA1, file));
+ objects.add(name, Json.object().add("size", attrs.size()).add("hash", digest));
+ IOHelper.copy(file, resolveObjectFile(outputAssetDir, digest));
- // Continue visiting
- return super.visitFile(file, attrs);
- }
- }
+ // Continue visiting
+ return super.visitFile(file, attrs);
+ }
+ }
}
diff --git a/LaunchServer/source/command/hash/SyncBinariesCommand.java b/LaunchServer/source/command/hash/SyncBinariesCommand.java
index 62c3089..9879fe3 100644
--- a/LaunchServer/source/command/hash/SyncBinariesCommand.java
+++ b/LaunchServer/source/command/hash/SyncBinariesCommand.java
@@ -7,23 +7,23 @@
import launchserver.command.Command;
public final class SyncBinariesCommand extends Command {
- public SyncBinariesCommand(LaunchServer server) {
- super(server);
- }
+ public SyncBinariesCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return null;
- }
+ @Override
+ public String getArgsDescription() {
+ return null;
+ }
- @Override
- public String getUsageDescription() {
- return "Resync launcher binaries";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Resync launcher binaries";
+ }
- @Override
- public void invoke(String... args) throws IOException {
- server.syncLauncherBinaries();
- LogHelper.subInfo("Binaries successfully resynced");
- }
+ @Override
+ public void invoke(String... args) throws IOException {
+ server.syncLauncherBinaries();
+ LogHelper.subInfo("Binaries successfully resynced");
+ }
}
diff --git a/LaunchServer/source/command/hash/SyncProfilesCommand.java b/LaunchServer/source/command/hash/SyncProfilesCommand.java
index 25de620..3de7477 100644
--- a/LaunchServer/source/command/hash/SyncProfilesCommand.java
+++ b/LaunchServer/source/command/hash/SyncProfilesCommand.java
@@ -7,23 +7,23 @@
import launchserver.command.Command;
public final class SyncProfilesCommand extends Command {
- public SyncProfilesCommand(LaunchServer server) {
- super(server);
- }
+ public SyncProfilesCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return null;
- }
+ @Override
+ public String getArgsDescription() {
+ return null;
+ }
- @Override
- public String getUsageDescription() {
- return "Resync profiles dir";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Resync profiles dir";
+ }
- @Override
- public void invoke(String... args) throws IOException {
- server.syncProfilesDir();
- LogHelper.subInfo("Profiles successfully resynced");
- }
+ @Override
+ public void invoke(String... args) throws IOException {
+ server.syncProfilesDir();
+ LogHelper.subInfo("Profiles successfully resynced");
+ }
}
diff --git a/LaunchServer/source/command/hash/SyncUpdatesCommand.java b/LaunchServer/source/command/hash/SyncUpdatesCommand.java
index ff2ebdc..da90456 100644
--- a/LaunchServer/source/command/hash/SyncUpdatesCommand.java
+++ b/LaunchServer/source/command/hash/SyncUpdatesCommand.java
@@ -10,30 +10,30 @@
import launchserver.command.Command;
public final class SyncUpdatesCommand extends Command {
- public SyncUpdatesCommand(LaunchServer server) {
- super(server);
- }
+ public SyncUpdatesCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return "[subdirs...]";
- }
+ @Override
+ public String getArgsDescription() {
+ return "[subdirs...]";
+ }
- @Override
- public String getUsageDescription() {
- return "Resync updates dir";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Resync updates dir";
+ }
- @Override
- public void invoke(String... args) throws IOException {
- Set dirs = null;
- if (args.length > 0) { // Hash all updates dirs
- dirs = new HashSet<>(args.length);
- Collections.addAll(dirs, args);
- }
+ @Override
+ public void invoke(String... args) throws IOException {
+ Set dirs = null;
+ if (args.length > 0) { // Hash all updates dirs
+ dirs = new HashSet<>(args.length);
+ Collections.addAll(dirs, args);
+ }
- // Hash updates dir
- server.syncUpdatesDir(dirs);
- LogHelper.subInfo("Updates dir successfully resynced");
- }
+ // Hash updates dir
+ server.syncUpdatesDir(dirs);
+ LogHelper.subInfo("Updates dir successfully resynced");
+ }
}
diff --git a/LaunchServer/source/command/hash/UnindexAssetCommand.java b/LaunchServer/source/command/hash/UnindexAssetCommand.java
index 6362598..8cc2bbf 100644
--- a/LaunchServer/source/command/hash/UnindexAssetCommand.java
+++ b/LaunchServer/source/command/hash/UnindexAssetCommand.java
@@ -7,6 +7,7 @@
import com.eclipsesource.json.Json;
import com.eclipsesource.json.JsonObject;
+import com.eclipsesource.json.JsonObject.Member;
import launcher.helper.IOHelper;
import launcher.helper.LogHelper;
import launchserver.LaunchServer;
@@ -14,57 +15,57 @@
import launchserver.command.CommandException;
public final class UnindexAssetCommand extends Command {
- public UnindexAssetCommand(LaunchServer server) {
- super(server);
- }
+ public UnindexAssetCommand(LaunchServer server) {
+ super(server);
+ }
- @Override
- public String getArgsDescription() {
- return " ";
- }
+ @Override
+ public String getArgsDescription() {
+ return " ";
+ }
- @Override
- public String getUsageDescription() {
- return "Unindex asset dir (1.7.10+)";
- }
+ @Override
+ public String getUsageDescription() {
+ return "Unindex asset dir (1.7.10+)";
+ }
- @Override
- public void invoke(String... args) throws Exception {
- verifyArgs(args, 3);
- String inputAssetDirName = IOHelper.verifyFileName(args[0]);
- String indexFileName = IOHelper.verifyFileName(args[1]);
- String outputAssetDirName = IOHelper.verifyFileName(args[2]);
- Path inputAssetDir = LaunchServer.UPDATES_DIR.resolve(inputAssetDirName);
- Path outputAssetDir = LaunchServer.UPDATES_DIR.resolve(outputAssetDirName);
- if (outputAssetDir.equals(inputAssetDir)) {
- throw new CommandException("Indexed and unindexed asset dirs can't be same");
- }
+ @Override
+ public void invoke(String... args) throws Exception {
+ verifyArgs(args, 3);
+ String inputAssetDirName = IOHelper.verifyFileName(args[0]);
+ String indexFileName = IOHelper.verifyFileName(args[1]);
+ String outputAssetDirName = IOHelper.verifyFileName(args[2]);
+ Path inputAssetDir = LaunchServer.UPDATES_DIR.resolve(inputAssetDirName);
+ Path outputAssetDir = LaunchServer.UPDATES_DIR.resolve(outputAssetDirName);
+ if (outputAssetDir.equals(inputAssetDir)) {
+ throw new CommandException("Indexed and unindexed asset dirs can't be same");
+ }
- // Create new asset dir
- LogHelper.subInfo("Creating unindexed asset dir: '%s'", outputAssetDirName);
- Files.createDirectory(outputAssetDir);
+ // Create new asset dir
+ LogHelper.subInfo("Creating unindexed asset dir: '%s'", outputAssetDirName);
+ Files.createDirectory(outputAssetDir);
- // Read JSON file
- JsonObject objects;
- LogHelper.subInfo("Reading asset index file: '%s'", indexFileName);
- try (BufferedReader reader = IOHelper.newReader(IndexAssetCommand.resolveIndexFile(inputAssetDir, indexFileName))) {
- objects = Json.parse(reader).asObject().get(IndexAssetCommand.OBJECTS_DIR).asObject();
- }
+ // Read JSON file
+ JsonObject objects;
+ LogHelper.subInfo("Reading asset index file: '%s'", indexFileName);
+ try (BufferedReader reader = IOHelper.newReader(IndexAssetCommand.resolveIndexFile(inputAssetDir, indexFileName))) {
+ objects = Json.parse(reader).asObject().get(IndexAssetCommand.OBJECTS_DIR).asObject();
+ }
- // Restore objects
- LogHelper.subInfo("Unindexing %d objects", objects.size());
- for (JsonObject.Member member : objects) {
- String name = member.getName();
- LogHelper.subInfo("Unindexing: '%s'", name);
+ // Restore objects
+ LogHelper.subInfo("Unindexing %d objects", objects.size());
+ for (Member member : objects) {
+ String name = member.getName();
+ LogHelper.subInfo("Unindexing: '%s'", name);
- // Copy hashed file to target
- String hash = member.getValue().asObject().get("hash").asString();
- Path source = IndexAssetCommand.resolveObjectFile(inputAssetDir, hash);
- IOHelper.copy(source, outputAssetDir.resolve(name));
- }
+ // Copy hashed file to target
+ String hash = member.getValue().asObject().get("hash").asString();
+ Path source = IndexAssetCommand.resolveObjectFile(inputAssetDir, hash);
+ IOHelper.copy(source, outputAssetDir.resolve(name));
+ }
- // Finished
- server.syncUpdatesDir(Collections.singleton(outputAssetDirName));
- LogHelper.subInfo("Asset successfully unindexed: '%s'", inputAssetDirName);
- }
+ // Finished
+ server.syncUpdatesDir(Collections.singleton(outputAssetDirName));
+ LogHelper.subInfo("Asset successfully unindexed: '%s'", inputAssetDirName);
+ }
}
diff --git a/LaunchServer/source/response/PingResponse.java b/LaunchServer/source/response/PingResponse.java
index ceca9d5..9b94ce2 100644
--- a/LaunchServer/source/response/PingResponse.java
+++ b/LaunchServer/source/response/PingResponse.java
@@ -8,12 +8,12 @@
import launchserver.LaunchServer;
public final class PingResponse extends Response {
- public PingResponse(LaunchServer server, long id, HInput input, HOutput output) {
- super(server, id, input, output);
- }
+ public PingResponse(LaunchServer server, long id, HInput input, HOutput output) {
+ super(server, id, input, output);
+ }
- @Override
- public void reply() throws IOException {
- output.writeUnsignedByte(PingRequest.EXPECTED_BYTE);
- }
+ @Override
+ public void reply() throws IOException {
+ output.writeUnsignedByte(PingRequest.EXPECTED_BYTE);
+ }
}
diff --git a/LaunchServer/source/response/Response.java b/LaunchServer/source/response/Response.java
index a493590..b058823 100644
--- a/LaunchServer/source/response/Response.java
+++ b/LaunchServer/source/response/Response.java
@@ -10,45 +10,45 @@
import launchserver.LaunchServer;
public abstract class Response {
- @LauncherAPI protected final LaunchServer server;
- @LauncherAPI protected final long id;
- @LauncherAPI protected final HInput input;
- @LauncherAPI protected final HOutput output;
+ @LauncherAPI protected final LaunchServer server;
+ @LauncherAPI protected final long id;
+ @LauncherAPI protected final HInput input;
+ @LauncherAPI protected final HOutput output;
- @LauncherAPI
- protected Response(LaunchServer server, long id, HInput input, HOutput output) {
- this.server = server;
- this.id = id;
- this.input = input;
- this.output = output;
- }
+ @LauncherAPI
+ protected Response(LaunchServer server, long id, HInput input, HOutput output) {
+ this.server = server;
+ this.id = id;
+ this.input = input;
+ this.output = output;
+ }
- @LauncherAPI
- public abstract void reply() throws Exception;
+ @LauncherAPI
+ public abstract void reply() throws Exception;
- @LauncherAPI
- protected final void debug(String message) {
- LogHelper.subDebug("#%d %s", id, message);
- }
+ @LauncherAPI
+ protected final void debug(String message) {
+ LogHelper.subDebug("#%d %s", id, message);
+ }
- @LauncherAPI
- protected final void debug(String message, Object... args) {
- debug(String.format(message, args));
- }
+ @LauncherAPI
+ protected final void debug(String message, Object... args) {
+ debug(String.format(message, args));
+ }
- @LauncherAPI
- protected final void writeNoError(HOutput output) throws IOException {
- output.writeString("", 0);
- }
+ @LauncherAPI
+ protected final void writeNoError(HOutput output) throws IOException {
+ output.writeString("", 0);
+ }
- @LauncherAPI
- public static void requestError(String message) throws RequestException {
- throw new RequestException(message);
- }
+ @LauncherAPI
+ public static void requestError(String message) throws RequestException {
+ throw new RequestException(message);
+ }
- @FunctionalInterface
- public interface Factory {
- @LauncherAPI
- Response newResponse(LaunchServer server, long id, HInput input, HOutput output);
- }
+ @FunctionalInterface
+ public interface Factory {
+ @LauncherAPI
+ Response newResponse(LaunchServer server, long id, HInput input, HOutput output);
+ }
}
diff --git a/LaunchServer/source/response/ResponseThread.java b/LaunchServer/source/response/ResponseThread.java
index 0196a22..032cd71 100644
--- a/LaunchServer/source/response/ResponseThread.java
+++ b/LaunchServer/source/response/ResponseThread.java
@@ -11,6 +11,7 @@
import launcher.helper.SecurityHelper;
import launcher.helper.VerifyHelper;
import launcher.request.Request;
+import launcher.request.Request.Type;
import launcher.request.RequestException;
import launcher.serialize.HInput;
import launcher.serialize.HOutput;
@@ -26,132 +27,132 @@
import launchserver.response.update.UpdateResponse;
public final class ResponseThread implements Runnable {
- private final LaunchServer server;
- private final long id;
- private final Socket socket;
+ private final LaunchServer server;
+ private final long id;
+ private final Socket socket;
- public ResponseThread(LaunchServer server, long id, Socket socket) throws SocketException {
- this.server = server;
- this.id = id;
- this.socket = socket;
+ public ResponseThread(LaunchServer server, long id, Socket socket) throws SocketException {
+ this.server = server;
+ this.id = id;
+ this.socket = socket;
- // Fix socket flags
- IOHelper.setSocketFlags(socket);
- }
+ // Fix socket flags
+ IOHelper.setSocketFlags(socket);
+ }
- @Override
- public void run() {
- boolean cancelled = false;
- Exception savedError = null;
- if (!server.serverSocketHandler.logConnections) {
- LogHelper.debug("Connection #%d from %s", id, IOHelper.getIP(socket.getRemoteSocketAddress()));
- }
+ @Override
+ public void run() {
+ boolean cancelled = false;
+ Exception savedError = null;
+ if (!server.serverSocketHandler.logConnections) {
+ LogHelper.debug("Connection #%d from %s", id, IOHelper.getIP(socket.getRemoteSocketAddress()));
+ }
- // Process connection
- try (HInput input = new HInput(socket.getInputStream());
- HOutput output = new HOutput(socket.getOutputStream())) {
- Request.Type type = readHandshake(input, output);
- if (type == null) { // Not accepted
- cancelled = true;
- return;
- }
+ // Process connection
+ try (HInput input = new HInput(socket.getInputStream());
+ HOutput output = new HOutput(socket.getOutputStream())) {
+ Type type = readHandshake(input, output);
+ if (type == null) { // Not accepted
+ cancelled = true;
+ return;
+ }
- // Start response
- try {
- respond(type, input, output);
- } catch (RequestException e) {
- LogHelper.subDebug(String.format("#%d Request error: %s", id, e.getMessage()));
- output.writeString(e.getMessage(), 0);
- }
- } catch (Exception e) {
- savedError = e;
- LogHelper.error(e);
- } finally {
- IOHelper.close(socket);
- if (!cancelled) {
- server.serverSocketHandler.onDisconnect(id, savedError);
- }
- }
- }
+ // Start response
+ try {
+ respond(type, input, output);
+ } catch (RequestException e) {
+ LogHelper.subDebug(String.format("#%d Request error: %s", id, e.getMessage()));
+ output.writeString(e.getMessage(), 0);
+ }
+ } catch (Exception e) {
+ savedError = e;
+ LogHelper.error(e);
+ } finally {
+ IOHelper.close(socket);
+ if (!cancelled) {
+ server.serverSocketHandler.onDisconnect(id, savedError);
+ }
+ }
+ }
- private Request.Type readHandshake(HInput input, HOutput output) throws IOException {
- // Verify magic number
- int magicNumber = input.readInt();
- if (magicNumber != Launcher.PROTOCOL_MAGIC) {
- output.writeBoolean(false);
- throw new IOException(String.format("#%d Protocol magic mismatch", id));
- }
+ private Type readHandshake(HInput input, HOutput output) throws IOException {
+ // Verify magic number
+ int magicNumber = input.readInt();
+ if (magicNumber != Launcher.PROTOCOL_MAGIC) {
+ output.writeBoolean(false);
+ throw new IOException(String.format("#%d Protocol magic mismatch", id));
+ }
- // Verify key modulus
- BigInteger keyModulus = input.readBigInteger(SecurityHelper.RSA_KEY_LENGTH + 1);
- if (!keyModulus.equals(server.privateKey.getModulus())) {
- output.writeBoolean(false);
- throw new IOException(String.format("#%d Key modulus mismatch", id));
- }
+ // Verify key modulus
+ BigInteger keyModulus = input.readBigInteger(SecurityHelper.RSA_KEY_LENGTH + 1);
+ if (!keyModulus.equals(server.privateKey.getModulus())) {
+ output.writeBoolean(false);
+ throw new IOException(String.format("#%d Key modulus mismatch", id));
+ }
- // Read request type
- Request.Type type = Request.Type.read(input);
- if (!server.serverSocketHandler.onHandshake(id, type)) {
- output.writeBoolean(false);
- return null;
- }
+ // Read request type
+ Type type = Type.read(input);
+ if (!server.serverSocketHandler.onHandshake(id, type)) {
+ output.writeBoolean(false);
+ return null;
+ }
- // Protocol successfully verified
- output.writeBoolean(true);
- output.flush();
- return type;
- }
+ // Protocol successfully verified
+ output.writeBoolean(true);
+ output.flush();
+ return type;
+ }
- private void respond(Request.Type type, HInput input, HOutput output) throws Exception {
- if (server.serverSocketHandler.logConnections) {
- LogHelper.info("Connection #%d from %s: %s", id, IOHelper.getIP(socket.getRemoteSocketAddress()), type.name());
- } else {
- LogHelper.subDebug("#%d Type: %s", id, type.name());
- }
+ private void respond(Type type, HInput input, HOutput output) throws Exception {
+ if (server.serverSocketHandler.logConnections) {
+ LogHelper.info("Connection #%d from %s: %s", id, IOHelper.getIP(socket.getRemoteSocketAddress()), type.name());
+ } else {
+ LogHelper.subDebug("#%d Type: %s", id, type.name());
+ }
- // Choose response based on type
- Response response;
- switch (type) {
- case PING:
- response = new PingResponse(server, id, input, output);
- break;
- case AUTH:
- response = new AuthResponse(server, id, input, output);
- break;
- case JOIN_SERVER:
- response = new JoinServerResponse(server, id, input, output);
- break;
- case CHECK_SERVER:
- response = new CheckServerResponse(server, id, input, output);
- break;
- case LAUNCHER:
- response = new LauncherResponse(server, id, input, output);
- break;
- case UPDATE:
- response = new UpdateResponse(server, id, input, output);
- break;
- case UPDATE_LIST:
- response = new UpdateListResponse(server, id, input, output);
- break;
- case PROFILE_BY_USERNAME:
- response = new ProfileByUsernameResponse(server, id, input, output);
- break;
- case PROFILE_BY_UUID:
- response = new ProfileByUUIDResponse(server, id, input, output);
- break;
- case BATCH_PROFILE_BY_USERNAME:
- response = new BatchProfileByUsernameResponse(server, id, input, output);
- break;
- case CUSTOM:
- String name = VerifyHelper.verifyIDName(input.readASCII(255));
- response = server.serverSocketHandler.newCustomResponse(name, id, input, output);
- break;
- default:
- throw new AssertionError("Unsupported request type: " + type.name());
- }
+ // Choose response based on type
+ Response response;
+ switch (type) {
+ case PING:
+ response = new PingResponse(server, id, input, output);
+ break;
+ case AUTH:
+ response = new AuthResponse(server, id, input, output);
+ break;
+ case JOIN_SERVER:
+ response = new JoinServerResponse(server, id, input, output);
+ break;
+ case CHECK_SERVER:
+ response = new CheckServerResponse(server, id, input, output);
+ break;
+ case LAUNCHER:
+ response = new LauncherResponse(server, id, input, output);
+ break;
+ case UPDATE:
+ response = new UpdateResponse(server, id, input, output);
+ break;
+ case UPDATE_LIST:
+ response = new UpdateListResponse(server, id, input, output);
+ break;
+ case PROFILE_BY_USERNAME:
+ response = new ProfileByUsernameResponse(server, id, input, output);
+ break;
+ case PROFILE_BY_UUID:
+ response = new ProfileByUUIDResponse(server, id, input, output);
+ break;
+ case BATCH_PROFILE_BY_USERNAME:
+ response = new BatchProfileByUsernameResponse(server, id, input, output);
+ break;
+ case CUSTOM:
+ String name = VerifyHelper.verifyIDName(input.readASCII(255));
+ response = server.serverSocketHandler.newCustomResponse(name, id, input, output);
+ break;
+ default:
+ throw new AssertionError("Unsupported request type: " + type.name());
+ }
- // Reply
- response.reply();
- LogHelper.subDebug("#%d Replied", id);
- }
+ // Reply
+ response.reply();
+ LogHelper.subDebug("#%d Replied", id);
+ }
}
diff --git a/LaunchServer/source/response/ServerSocketHandler.java b/LaunchServer/source/response/ServerSocketHandler.java
index 60cdf87..9a67c68 100644
--- a/LaunchServer/source/response/ServerSocketHandler.java
+++ b/LaunchServer/source/response/ServerSocketHandler.java
@@ -18,114 +18,114 @@
import launcher.helper.LogHelper;
import launcher.helper.VerifyHelper;
import launcher.request.Request;
+import launcher.request.Request.Type;
import launcher.serialize.HInput;
import launcher.serialize.HOutput;
import launchserver.LaunchServer;
+import launchserver.response.Response.Factory;
public final class ServerSocketHandler implements Runnable, AutoCloseable {
- private static final ThreadFactory THREAD_FACTORY = r -> CommonHelper.newThread("Network Thread", true, r);
+ private static final ThreadFactory THREAD_FACTORY = r -> CommonHelper.newThread("Network Thread", true, r);
+ @LauncherAPI public volatile boolean logConnections = Boolean.getBoolean("launcher.logConnections");
+ // Instance
+ private final LaunchServer server;
+ private final AtomicReference serverSocket = new AtomicReference<>();
+ private final ExecutorService threadPool = Executors.newCachedThreadPool(THREAD_FACTORY);
+ // API
+ private final Map customResponses = new ConcurrentHashMap<>(2);
+ private final AtomicLong idCounter = new AtomicLong(0L);
+ private volatile Listener listener;
- // Instance
- private final LaunchServer server;
- private final AtomicReference serverSocket = new AtomicReference<>();
- private final ExecutorService threadPool = Executors.newCachedThreadPool(THREAD_FACTORY);
- @LauncherAPI public volatile boolean logConnections = Boolean.getBoolean("launcher.logConnections");
+ public ServerSocketHandler(LaunchServer server) {
+ this.server = server;
+ }
- // API
- private final Map customResponses = new ConcurrentHashMap<>(2);
- private final AtomicLong idCounter = new AtomicLong(0L);
- private volatile Listener listener;
+ @Override
+ public void close() {
+ ServerSocket socket = serverSocket.getAndSet(null);
+ if (socket != null) {
+ LogHelper.info("Closing server socket listener");
+ try {
+ socket.close();
+ } catch (IOException e) {
+ LogHelper.error(e);
+ }
+ }
+ }
- public ServerSocketHandler(LaunchServer server) {
- this.server = server;
- }
+ @Override
+ public void run() {
+ LogHelper.info("Starting server socket thread");
+ try (ServerSocket serverSocket = new ServerSocket()) {
+ if (!this.serverSocket.compareAndSet(null, serverSocket)) {
+ throw new IllegalStateException("Previous socket wasn't closed");
+ }
- @Override
- public void close() {
- ServerSocket socket = serverSocket.getAndSet(null);
- if (socket != null) {
- LogHelper.info("Closing server socket listener");
- try {
- socket.close();
- } catch (IOException e) {
- LogHelper.error(e);
- }
- }
- }
+ // Set socket params
+ serverSocket.setReuseAddress(true);
+ serverSocket.setPerformancePreferences(1, 0, 2);
+ //serverSocket.setReceiveBufferSize(0x10000);
+ serverSocket.bind(server.config.getSocketAddress());
+ LogHelper.info("Server socket thread successfully started");
- @Override
- public void run() {
- LogHelper.info("Starting server socket thread");
- try (ServerSocket serverSocket = new ServerSocket()) {
- if (!this.serverSocket.compareAndSet(null, serverSocket)) {
- throw new IllegalStateException("Previous socket wasn't closed");
- }
+ // Listen for incoming connections
+ while (serverSocket.isBound()) {
+ Socket socket = serverSocket.accept();
- // Set socket params
- serverSocket.setReuseAddress(true);
- serverSocket.setPerformancePreferences(1, 0, 2);
- //serverSocket.setReceiveBufferSize(0x10000);
- serverSocket.bind(server.config.getSocketAddress());
- LogHelper.info("Server socket thread successfully started");
+ // Invoke pre-connect listener
+ long id = idCounter.incrementAndGet();
+ if (listener != null && !listener.onConnect(id, socket.getInetAddress())) {
+ continue; // Listener didn't accepted this connection
+ }
- // Listen for incoming connections
- while (serverSocket.isBound()) {
- Socket socket = serverSocket.accept();
+ // Reply in separate thread
+ threadPool.execute(new ResponseThread(server, id, socket));
+ }
+ } catch (IOException e) {
+ // Ignore error after close/rebind
+ if (serverSocket.get() != null) {
+ LogHelper.error(e);
+ }
+ }
+ }
- // Invoke pre-connect listener
- long id = idCounter.incrementAndGet();
- if (listener != null && !listener.onConnect(id, socket.getInetAddress())) {
- continue; // Listener didn't accepted this connection
- }
+ @LauncherAPI
+ public Response newCustomResponse(String name, long id, HInput input, HOutput output) {
+ Factory factory = VerifyHelper.getMapValue(customResponses, name,
+ String.format("Unknown custom response: '%s'", name));
+ return factory.newResponse(server, id, input, output);
+ }
- // Reply in separate thread
- threadPool.execute(new ResponseThread(server, id, socket));
- }
- } catch (IOException e) {
- // Ignore error after close/rebind
- if (serverSocket.get() != null) {
- LogHelper.error(e);
- }
- }
- }
+ @LauncherAPI
+ public void registerCustomResponse(String name, Factory factory) {
+ VerifyHelper.verifyIDName(name);
+ VerifyHelper.putIfAbsent(customResponses, name, Objects.requireNonNull(factory, "factory"),
+ String.format("Custom response has been already registered: '%s'", name));
+ }
- @LauncherAPI
- public Response newCustomResponse(String name, long id, HInput input, HOutput output) throws IOException {
- Response.Factory factory = VerifyHelper.getMapValue(customResponses, name,
- String.format("Unknown custom response: '%s'", name));
- return factory.newResponse(server, id, input, output);
- }
+ @LauncherAPI
+ public void setListener(Listener listener) {
+ this.listener = listener;
+ }
- @LauncherAPI
- public void registerCustomResponse(String name, Response.Factory factory) {
- VerifyHelper.verifyIDName(name);
- VerifyHelper.putIfAbsent(customResponses, name, Objects.requireNonNull(factory, "factory"),
- String.format("Custom response has been already registered: '%s'", name));
- }
+ /*package*/ void onDisconnect(long id, Exception e) {
+ if (listener != null) {
+ listener.onDisconnect(id, e);
+ }
+ }
- @LauncherAPI
- public void setListener(Listener listener) {
- this.listener = listener;
- }
+ /*package*/ boolean onHandshake(long id, Type type) {
+ return listener == null || listener.onHandshake(id, type);
+ }
- /*package*/ void onDisconnect(long id, Exception e) {
- if (listener != null) {
- listener.onDisconnect(id, e);
- }
- }
+ public interface Listener {
+ @LauncherAPI
+ boolean onConnect(long id, InetAddress address);
- /*package*/ boolean onHandshake(long id, Request.Type type) {
- return listener == null || listener.onHandshake(id, type);
- }
+ @LauncherAPI
+ void onDisconnect(long id, Exception e);
- public interface Listener {
- @LauncherAPI
- boolean onConnect(long id, InetAddress address);
-
- @LauncherAPI
- void onDisconnect(long id, Exception e);
-
- @LauncherAPI
- boolean onHandshake(long id, Request.Type type);
- }
+ @LauncherAPI
+ boolean onHandshake(long id, Type type);
+ }
}
diff --git a/LaunchServer/source/response/auth/AuthResponse.java b/LaunchServer/source/response/auth/AuthResponse.java
index a5c2e8b..06fcc35 100644
--- a/LaunchServer/source/response/auth/AuthResponse.java
+++ b/LaunchServer/source/response/auth/AuthResponse.java
@@ -1,9 +1,9 @@
package launchserver.response.auth;
-import javax.crypto.BadPaddingException;
-import javax.crypto.IllegalBlockSizeException;
import java.util.Arrays;
import java.util.UUID;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
import launcher.helper.IOHelper;
import launcher.helper.LogHelper;
@@ -18,67 +18,67 @@
import launchserver.response.profile.ProfileByUUIDResponse;
public final class AuthResponse extends Response {
- public AuthResponse(LaunchServer server, long id, HInput input, HOutput output) {
- super(server, id, input, output);
- }
+ public AuthResponse(LaunchServer server, long id, HInput input, HOutput output) {
+ super(server, id, input, output);
+ }
- @Override
- public void reply() throws Exception {
- String login = input.readString(255);
- byte[] encryptedPassword = input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH);
+ @Override
+ public void reply() throws Exception {
+ String login = input.readString(255);
+ byte[] encryptedPassword = input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH);
- // Decrypt password
- String password;
- try {
- password = IOHelper.decode(SecurityHelper.newRSADecryptCipher(server.privateKey).
- doFinal(encryptedPassword));
- } catch (IllegalBlockSizeException | BadPaddingException ignored) {
- requestError("Password decryption error");
- return;
- }
+ // Decrypt password
+ String password;
+ try {
+ password = IOHelper.decode(SecurityHelper.newRSADecryptCipher(server.privateKey).
+ doFinal(encryptedPassword));
+ } catch (IllegalBlockSizeException | BadPaddingException ignored) {
+ requestError("Password decryption error");
+ return;
+ }
- // Authenticate
- debug("Login: '%s', Password: '%s'", login, echo(password.length()));
- String username;
- try {
- username = server.config.authProvider.auth(login, password);
- if (!VerifyHelper.isValidUsername(username)) {
- AuthProvider.authError(String.format("Illegal username: '%s'", username));
- return;
- }
- } catch (AuthException e) {
- requestError(e.getMessage());
- return;
- } catch (Exception e) {
- LogHelper.error(e);
- requestError("Internal auth provider error");
- return;
- }
- debug("Auth: '%s' -> '%s'", login, username);
+ // Authenticate
+ debug("Login: '%s', Password: '%s'", login, echo(password.length()));
+ String username;
+ try {
+ username = server.config.authProvider.auth(login, password);
+ if (!VerifyHelper.isValidUsername(username)) {
+ AuthProvider.authError(String.format("Illegal username: '%s'", username));
+ return;
+ }
+ } catch (AuthException e) {
+ requestError(e.getMessage());
+ return;
+ } catch (Exception e) {
+ LogHelper.error(e);
+ requestError("Internal auth provider error");
+ return;
+ }
+ debug("Auth: '%s' -> '%s'", login, username);
- // Authenticate on server (and get UUID)
- String accessToken = SecurityHelper.randomStringToken();
- UUID uuid;
- try {
- uuid = server.config.authHandler.auth(username, accessToken);
- } catch (AuthException e) {
- requestError(e.getMessage());
- return;
- } catch (Exception e) {
- LogHelper.error(e);
- requestError("Internal auth handler error");
- return;
- }
- writeNoError(output);
+ // Authenticate on server (and get UUID)
+ String accessToken = SecurityHelper.randomStringToken();
+ UUID uuid;
+ try {
+ uuid = server.config.authHandler.auth(username, accessToken);
+ } catch (AuthException e) {
+ requestError(e.getMessage());
+ return;
+ } catch (Exception e) {
+ LogHelper.error(e);
+ requestError("Internal auth handler error");
+ return;
+ }
+ writeNoError(output);
- // Write profile and UUID
- ProfileByUUIDResponse.getProfile(server, uuid, username).write(output);
- output.writeASCII(accessToken, -SecurityHelper.TOKEN_STRING_LENGTH);
- }
+ // Write profile and UUID
+ ProfileByUUIDResponse.getProfile(server, uuid, username).write(output);
+ output.writeASCII(accessToken, -SecurityHelper.TOKEN_STRING_LENGTH);
+ }
- private static String echo(int length) {
- char[] chars = new char[length];
- Arrays.fill(chars, '*');
- return new String(chars);
- }
+ private static String echo(int length) {
+ char[] chars = new char[length];
+ Arrays.fill(chars, '*');
+ return new String(chars);
+ }
}
diff --git a/LaunchServer/source/response/auth/CheckServerResponse.java b/LaunchServer/source/response/auth/CheckServerResponse.java
index 319a9b8..fb7a647 100644
--- a/LaunchServer/source/response/auth/CheckServerResponse.java
+++ b/LaunchServer/source/response/auth/CheckServerResponse.java
@@ -14,34 +14,34 @@
import launchserver.response.profile.ProfileByUUIDResponse;
public final class CheckServerResponse extends Response {
- public CheckServerResponse(LaunchServer server, long id, HInput input, HOutput output) {
- super(server, id, input, output);
- }
+ public CheckServerResponse(LaunchServer server, long id, HInput input, HOutput output) {
+ super(server, id, input, output);
+ }
- @Override
- public void reply() throws IOException {
- String username = VerifyHelper.verifyUsername(input.readASCII(16));
- String serverID = JoinServerRequest.verifyServerID(input.readASCII(41)); // With minus sign
- debug("Username: %s, Server ID: %s", username, serverID);
+ @Override
+ public void reply() throws IOException {
+ String username = VerifyHelper.verifyUsername(input.readASCII(16));
+ String serverID = JoinServerRequest.verifyServerID(input.readASCII(41)); // With minus sign
+ debug("Username: %s, Server ID: %s", username, serverID);
- // Try check server with auth handler
- UUID uuid;
- try {
- uuid = server.config.authHandler.checkServer(username, serverID);
- } catch (AuthException e) {
- requestError(e.getMessage());
- return;
- } catch (Exception e) {
- LogHelper.error(e);
- requestError("Internal auth handler error");
- return;
- }
- writeNoError(output);
+ // Try check server with auth handler
+ UUID uuid;
+ try {
+ uuid = server.config.authHandler.checkServer(username, serverID);
+ } catch (AuthException e) {
+ requestError(e.getMessage());
+ return;
+ } catch (Exception e) {
+ LogHelper.error(e);
+ requestError("Internal auth handler error");
+ return;
+ }
+ writeNoError(output);
- // Write profile and UUID
- output.writeBoolean(uuid != null);
- if (uuid != null) {
- ProfileByUUIDResponse.getProfile(server, uuid, username).write(output);
- }
- }
+ // Write profile and UUID
+ output.writeBoolean(uuid != null);
+ if (uuid != null) {
+ ProfileByUUIDResponse.getProfile(server, uuid, username).write(output);
+ }
+ }
}
diff --git a/LaunchServer/source/response/auth/JoinServerResponse.java b/LaunchServer/source/response/auth/JoinServerResponse.java
index 0469c0e..7dd4200 100644
--- a/LaunchServer/source/response/auth/JoinServerResponse.java
+++ b/LaunchServer/source/response/auth/JoinServerResponse.java
@@ -13,32 +13,32 @@
import launchserver.response.Response;
public final class JoinServerResponse extends Response {
- public JoinServerResponse(LaunchServer server, long id, HInput input, HOutput output) {
- super(server, id, input, output);
- }
+ public JoinServerResponse(LaunchServer server, long id, HInput input, HOutput output) {
+ super(server, id, input, output);
+ }
- @Override
- public void reply() throws IOException {
- String username = VerifyHelper.verifyUsername(input.readASCII(16));
- String accessToken = SecurityHelper.verifyToken(input.readASCII(-SecurityHelper.TOKEN_STRING_LENGTH));
- String serverID = JoinServerRequest.verifyServerID(input.readASCII(41)); // With minus sign
+ @Override
+ public void reply() throws IOException {
+ String username = VerifyHelper.verifyUsername(input.readASCII(16));
+ String accessToken = SecurityHelper.verifyToken(input.readASCII(-SecurityHelper.TOKEN_STRING_LENGTH));
+ String serverID = JoinServerRequest.verifyServerID(input.readASCII(41)); // With minus sign
- // Try join server with auth handler
- debug("Username: '%s', Access token: %s, Server ID: %s", username, accessToken, serverID);
- boolean success;
- try {
- success = server.config.authHandler.joinServer(username, accessToken, serverID);
- } catch (AuthException e) {
- requestError(e.getMessage());
- return;
- } catch (Exception e) {
- LogHelper.error(e);
- requestError("Internal auth handler error");
- return;
- }
- writeNoError(output);
+ // Try join server with auth handler
+ debug("Username: '%s', Access token: %s, Server ID: %s", username, accessToken, serverID);
+ boolean success;
+ try {
+ success = server.config.authHandler.joinServer(username, accessToken, serverID);
+ } catch (AuthException e) {
+ requestError(e.getMessage());
+ return;
+ } catch (Exception e) {
+ LogHelper.error(e);
+ requestError("Internal auth handler error");
+ return;
+ }
+ writeNoError(output);
- // Write response
- output.writeBoolean(success);
- }
+ // Write response
+ output.writeBoolean(success);
+ }
}
diff --git a/LaunchServer/source/response/profile/BatchProfileByUsernameResponse.java b/LaunchServer/source/response/profile/BatchProfileByUsernameResponse.java
index 3dfb589..758fa98 100644
--- a/LaunchServer/source/response/profile/BatchProfileByUsernameResponse.java
+++ b/LaunchServer/source/response/profile/BatchProfileByUsernameResponse.java
@@ -11,21 +11,21 @@
import launchserver.response.Response;
public final class BatchProfileByUsernameResponse extends Response {
- public BatchProfileByUsernameResponse(LaunchServer server, long id, HInput input, HOutput output) {
- super(server, id, input, output);
- }
+ public BatchProfileByUsernameResponse(LaunchServer server, long id, HInput input, HOutput output) {
+ super(server, id, input, output);
+ }
- @Override
- public void reply() throws IOException {
- String[] usernames = new String[input.readLength(BatchProfileByUsernameRequest.MAX_BATCH_SIZE)];
- for (int i = 0; i < usernames.length; i++) {
- usernames[i] = VerifyHelper.verifyUsername(input.readASCII(16));
- }
- debug("Usernames: " + Arrays.toString(usernames));
+ @Override
+ public void reply() throws IOException {
+ String[] usernames = new String[input.readLength(BatchProfileByUsernameRequest.MAX_BATCH_SIZE)];
+ for (int i = 0; i < usernames.length; i++) {
+ usernames[i] = VerifyHelper.verifyUsername(input.readASCII(16));
+ }
+ debug("Usernames: " + Arrays.toString(usernames));
- // Respond with profiles array
- for (String username : usernames) {
- ProfileByUsernameResponse.writeProfile(server, output, username);
- }
- }
+ // Respond with profiles array
+ for (String username : usernames) {
+ ProfileByUsernameResponse.writeProfile(server, output, username);
+ }
+ }
}
diff --git a/LaunchServer/source/response/profile/ProfileByUUIDResponse.java b/LaunchServer/source/response/profile/ProfileByUUIDResponse.java
index 77b97c1..e955341 100644
--- a/LaunchServer/source/response/profile/ProfileByUUIDResponse.java
+++ b/LaunchServer/source/response/profile/ProfileByUUIDResponse.java
@@ -4,6 +4,7 @@
import java.util.UUID;
import launcher.client.PlayerProfile;
+import launcher.client.PlayerProfile.Texture;
import launcher.helper.LogHelper;
import launcher.serialize.HInput;
import launcher.serialize.HOutput;
@@ -11,47 +12,47 @@
import launchserver.response.Response;
public final class ProfileByUUIDResponse extends Response {
- public ProfileByUUIDResponse(LaunchServer server, long id, HInput input, HOutput output) {
- super(server, id, input, output);
- }
+ public ProfileByUUIDResponse(LaunchServer server, long id, HInput input, HOutput output) {
+ super(server, id, input, output);
+ }
- @Override
- public void reply() throws IOException {
- UUID uuid = input.readUUID();
- debug("UUID: " + uuid);
+ @Override
+ public void reply() throws IOException {
+ UUID uuid = input.readUUID();
+ debug("UUID: " + uuid);
- // Verify has such profile
- String username = server.config.authHandler.uuidToUsername(uuid);
- if (username == null) {
- output.writeBoolean(false);
- return;
- }
+ // Verify has such profile
+ String username = server.config.authHandler.uuidToUsername(uuid);
+ if (username == null) {
+ output.writeBoolean(false);
+ return;
+ }
- // Write profile
- output.writeBoolean(true);
- getProfile(server, uuid, username).write(output);
- }
+ // Write profile
+ output.writeBoolean(true);
+ getProfile(server, uuid, username).write(output);
+ }
- public static PlayerProfile getProfile(LaunchServer server, UUID uuid, String username) {
- // Get skin texture
- PlayerProfile.Texture skin;
- try {
- skin = server.config.textureProvider.getSkinTexture(uuid, username);
- } catch (IOException e) {
- LogHelper.error(new IOException(String.format("Can't get skin texture: '%s'", username), e));
- skin = null;
- }
+ public static PlayerProfile getProfile(LaunchServer server, UUID uuid, String username) {
+ // Get skin texture
+ Texture skin;
+ try {
+ skin = server.config.textureProvider.getSkinTexture(uuid, username);
+ } catch (IOException e) {
+ LogHelper.error(new IOException(String.format("Can't get skin texture: '%s'", username), e));
+ skin = null;
+ }
- // Get cloak texture
- PlayerProfile.Texture cloak;
- try {
- cloak = server.config.textureProvider.getCloakTexture(uuid, username);
- } catch (IOException e) {
- LogHelper.error(new IOException(String.format("Can't get cloak texture: '%s'", username), e));
- cloak = null;
- }
+ // Get cloak texture
+ Texture cloak;
+ try {
+ cloak = server.config.textureProvider.getCloakTexture(uuid, username);
+ } catch (IOException e) {
+ LogHelper.error(new IOException(String.format("Can't get cloak texture: '%s'", username), e));
+ cloak = null;
+ }
- // Return combined profile
- return new PlayerProfile(uuid, username, skin, cloak);
- }
+ // Return combined profile
+ return new PlayerProfile(uuid, username, skin, cloak);
+ }
}
diff --git a/LaunchServer/source/response/profile/ProfileByUsernameResponse.java b/LaunchServer/source/response/profile/ProfileByUsernameResponse.java
index 8fef87b..04f5040 100644
--- a/LaunchServer/source/response/profile/ProfileByUsernameResponse.java
+++ b/LaunchServer/source/response/profile/ProfileByUsernameResponse.java
@@ -10,28 +10,28 @@
import launchserver.response.Response;
public final class ProfileByUsernameResponse extends Response {
- public ProfileByUsernameResponse(LaunchServer server, long id, HInput input, HOutput output) {
- super(server, id, input, output);
- }
+ public ProfileByUsernameResponse(LaunchServer server, long id, HInput input, HOutput output) {
+ super(server, id, input, output);
+ }
- @Override
- public void reply() throws IOException {
- String username = VerifyHelper.verifyUsername(input.readASCII(16));
- debug("Username: " + username);
+ @Override
+ public void reply() throws IOException {
+ String username = VerifyHelper.verifyUsername(input.readASCII(16));
+ debug("Username: " + username);
- // Write response
- writeProfile(server, output, username);
- }
+ // Write response
+ writeProfile(server, output, username);
+ }
- public static void writeProfile(LaunchServer server, HOutput output, String username) throws IOException {
- UUID uuid = server.config.authHandler.usernameToUUID(username);
- if (uuid == null) {
- output.writeBoolean(false);
- return;
- }
+ public static void writeProfile(LaunchServer server, HOutput output, String username) throws IOException {
+ UUID uuid = server.config.authHandler.usernameToUUID(username);
+ if (uuid == null) {
+ output.writeBoolean(false);
+ return;
+ }
- // Write profile
- output.writeBoolean(true);
- ProfileByUUIDResponse.getProfile(server, uuid, username).write(output);
- }
+ // Write profile
+ output.writeBoolean(true);
+ ProfileByUUIDResponse.getProfile(server, uuid, username).write(output);
+ }
}
diff --git a/LaunchServer/source/response/update/LauncherResponse.java b/LaunchServer/source/response/update/LauncherResponse.java
index 13a2be0..b24d524 100644
--- a/LaunchServer/source/response/update/LauncherResponse.java
+++ b/LaunchServer/source/response/update/LauncherResponse.java
@@ -13,33 +13,33 @@
import launchserver.response.Response;
public final class LauncherResponse extends Response {
- public LauncherResponse(LaunchServer server, long id, HInput input, HOutput output) {
- super(server, id, input, output);
- }
+ public LauncherResponse(LaunchServer server, long id, HInput input, HOutput output) {
+ super(server, id, input, output);
+ }
- @Override
- public void reply() throws IOException {
- // Resolve launcher binary
- SignedBytesHolder bytes = (input.readBoolean() ? server.launcherEXEBinary : server.launcherBinary).getBytes();
- if (bytes == null) {
- requestError("Missing launcher binary");
- return;
- }
- writeNoError(output);
+ @Override
+ public void reply() throws IOException {
+ // Resolve launcher binary
+ SignedBytesHolder bytes = (input.readBoolean() ? server.launcherEXEBinary : server.launcherBinary).getBytes();
+ if (bytes == null) {
+ requestError("Missing launcher binary");
+ return;
+ }
+ writeNoError(output);
- // Update launcher binary
- output.writeByteArray(bytes.getSign(), -SecurityHelper.RSA_KEY_LENGTH);
- output.flush();
- if (input.readBoolean()) {
- output.writeByteArray(bytes.getBytes(), 0);
- return; // Launcher will be restarted
- }
+ // Update launcher binary
+ output.writeByteArray(bytes.getSign(), -SecurityHelper.RSA_KEY_LENGTH);
+ output.flush();
+ if (input.readBoolean()) {
+ output.writeByteArray(bytes.getBytes(), 0);
+ return; // Launcher will be restarted
+ }
- // Write clients profiles list
- Collection> profiles = server.getProfiles();
- output.writeLength(profiles.size(), 0);
- for (SignedObjectHolder profile : profiles) {
- profile.write(output);
- }
- }
+ // Write clients profiles list
+ Collection> profiles = server.getProfiles();
+ output.writeLength(profiles.size(), 0);
+ for (SignedObjectHolder profile : profiles) {
+ profile.write(output);
+ }
+ }
}
diff --git a/LaunchServer/source/response/update/UpdateListResponse.java b/LaunchServer/source/response/update/UpdateListResponse.java
index e670055..08e38d6 100644
--- a/LaunchServer/source/response/update/UpdateListResponse.java
+++ b/LaunchServer/source/response/update/UpdateListResponse.java
@@ -1,6 +1,7 @@
package launchserver.response.update;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import launcher.hasher.HashedDir;
@@ -11,18 +12,18 @@
import launchserver.response.Response;
public final class UpdateListResponse extends Response {
- public UpdateListResponse(LaunchServer server, long id, HInput input, HOutput output) {
- super(server, id, input, output);
- }
+ public UpdateListResponse(LaunchServer server, long id, HInput input, HOutput output) {
+ super(server, id, input, output);
+ }
- @Override
- public void reply() throws Exception {
- Set>> updateDirs = server.getUpdateDirs();
+ @Override
+ public void reply() throws Exception {
+ Set>> updateDirs = server.getUpdateDirs();
- // Write all update dirs names
- output.writeLength(updateDirs.size(), 0);
- for (Map.Entry> entry : updateDirs) {
- output.writeString(entry.getKey(), 255);
- }
- }
+ // Write all update dirs names
+ output.writeLength(updateDirs.size(), 0);
+ for (Entry> entry : updateDirs) {
+ output.writeString(entry.getKey(), 255);
+ }
+ }
}
diff --git a/LaunchServer/source/response/update/UpdateResponse.java b/LaunchServer/source/response/update/UpdateResponse.java
index cebf47a..33bc6ae 100644
--- a/LaunchServer/source/response/update/UpdateResponse.java
+++ b/LaunchServer/source/response/update/UpdateResponse.java
@@ -8,8 +8,10 @@
import launcher.hasher.HashedDir;
import launcher.hasher.HashedEntry;
+import launcher.hasher.HashedEntry.Type;
import launcher.helper.IOHelper;
import launcher.request.update.UpdateRequest;
+import launcher.request.update.UpdateRequest.Action;
import launcher.serialize.HInput;
import launcher.serialize.HOutput;
import launcher.serialize.signed.SignedObjectHolder;
@@ -17,96 +19,96 @@
import launchserver.response.Response;
public final class UpdateResponse extends Response {
- public UpdateResponse(LaunchServer server, long id, HInput input, HOutput output) {
- super(server, id, input, output);
- }
+ public UpdateResponse(LaunchServer server, long id, HInput input, HOutput output) {
+ super(server, id, input, output);
+ }
- @Override
- public void reply() throws IOException {
- // Read update dir name
- String updateDirName = IOHelper.verifyFileName(input.readString(255));
- SignedObjectHolder hdir = server.getUpdateDir(updateDirName);
- if (hdir == null) {
- requestError(String.format("Unknown update dir: %s", updateDirName));
- return;
- }
- writeNoError(output);
+ @Override
+ public void reply() throws IOException {
+ // Read update dir name
+ String updateDirName = IOHelper.verifyFileName(input.readString(255));
+ SignedObjectHolder hdir = server.getUpdateDir(updateDirName);
+ if (hdir == null) {
+ requestError(String.format("Unknown update dir: %s", updateDirName));
+ return;
+ }
+ writeNoError(output);
- // Write update hdir
- debug("Update dir: '%s'", updateDirName);
- hdir.write(output);
- output.flush();
+ // Write update hdir
+ debug("Update dir: '%s'", updateDirName);
+ hdir.write(output);
+ output.flush();
- // Prepare variables for actions queue
- Path dir = LaunchServer.UPDATES_DIR.resolve(updateDirName);
- Deque dirStack = new LinkedList<>();
- dirStack.add(hdir.object);
+ // Prepare variables for actions queue
+ Path dir = LaunchServer.UPDATES_DIR.resolve(updateDirName);
+ Deque dirStack = new LinkedList<>();
+ dirStack.add(hdir.object);
- // Perform update
- UpdateRequest.Action[] actionsSlice = new UpdateRequest.Action[UpdateRequest.MAX_QUEUE_SIZE];
- loop:
- while (true) {
- // Read actions slice
- int length = input.readLength(actionsSlice.length);
- for (int i = 0; i < length; i++) {
- actionsSlice[i] = new UpdateRequest.Action(input);
- }
+ // Perform update
+ Action[] actionsSlice = new Action[UpdateRequest.MAX_QUEUE_SIZE];
+ loop:
+ while (true) {
+ // Read actions slice
+ int length = input.readLength(actionsSlice.length);
+ for (int i = 0; i < length; i++) {
+ actionsSlice[i] = new Action(input);
+ }
- // Perform actions
- for (int i = 0; i < length; i++) {
- UpdateRequest.Action action = actionsSlice[i];
- switch (action.type) {
- case CD:
- debug("CD '%s'", action.name);
+ // Perform actions
+ for (int i = 0; i < length; i++) {
+ Action action = actionsSlice[i];
+ switch (action.type) {
+ case CD:
+ debug("CD '%s'", action.name);
- // Get hashed dir (for validation)
- HashedEntry hSubdir = dirStack.getLast().getEntry(action.name);
- if (hSubdir == null || hSubdir.getType() != HashedEntry.Type.DIR) {
- throw new IOException("Unknown hashed dir: " + action.name);
- }
- dirStack.add((HashedDir) hSubdir);
+ // Get hashed dir (for validation)
+ HashedEntry hSubdir = dirStack.getLast().getEntry(action.name);
+ if (hSubdir == null || hSubdir.getType() != Type.DIR) {
+ throw new IOException("Unknown hashed dir: " + action.name);
+ }
+ dirStack.add((HashedDir) hSubdir);
- // Resolve dir
- dir = dir.resolve(action.name);
- break;
- case GET:
- debug("GET '%s'", action.name);
+ // Resolve dir
+ dir = dir.resolve(action.name);
+ break;
+ case GET:
+ debug("GET '%s'", action.name);
- // Get hashed file (for validation)
- HashedEntry hFile = dirStack.getLast().getEntry(action.name);
- if (hFile == null || hFile.getType() != HashedEntry.Type.FILE) {
- throw new IOException("Unknown hashed file: " + action.name);
- }
+ // Get hashed file (for validation)
+ HashedEntry hFile = dirStack.getLast().getEntry(action.name);
+ if (hFile == null || hFile.getType() != Type.FILE) {
+ throw new IOException("Unknown hashed file: " + action.name);
+ }
- // Resolve and write file
- Path file = dir.resolve(action.name);
- try (InputStream fileInput = IOHelper.newInput(file)) {
- IOHelper.transfer(fileInput, output.stream);
- }
- break;
- case CD_BACK:
- debug("CD ..");
+ // Resolve and write file
+ Path file = dir.resolve(action.name);
+ try (InputStream fileInput = IOHelper.newInput(file)) {
+ IOHelper.transfer(fileInput, output.stream);
+ }
+ break;
+ case CD_BACK:
+ debug("CD ..");
- // Remove from hashed dir stack
- dirStack.removeLast();
- if (dirStack.isEmpty()) {
- throw new IOException("Empty hDir stack");
- }
+ // Remove from hashed dir stack
+ dirStack.removeLast();
+ if (dirStack.isEmpty()) {
+ throw new IOException("Empty hDir stack");
+ }
- // Get parent
- dir = dir.getParent();
- break;
- case FINISH:
- break loop;
- default:
- throw new AssertionError(String.format("Unsupported action type: '%s'", action.type.name()));
- }
- }
+ // Get parent
+ dir = dir.getParent();
+ break;
+ case FINISH:
+ break loop;
+ default:
+ throw new AssertionError(String.format("Unsupported action type: '%s'", action.type.name()));
+ }
+ }
- // Flush all actions
- output.flush();
- }
+ // Flush all actions
+ output.flush();
+ }
- // So we've updated :)
- }
+ // So we've updated :)
+ }
}
diff --git a/LaunchServer/source/texture/NullTextureProvider.java b/LaunchServer/source/texture/NullTextureProvider.java
index 98937af..4f762de 100644
--- a/LaunchServer/source/texture/NullTextureProvider.java
+++ b/LaunchServer/source/texture/NullTextureProvider.java
@@ -5,40 +5,41 @@
import launcher.LauncherAPI;
import launcher.client.PlayerProfile;
+import launcher.client.PlayerProfile.Texture;
import launcher.helper.VerifyHelper;
import launcher.serialize.config.entry.BlockConfigEntry;
public final class NullTextureProvider extends TextureProvider {
- private volatile TextureProvider provider;
+ private volatile TextureProvider provider;
- public NullTextureProvider(BlockConfigEntry block) {
- super(block);
- }
+ public NullTextureProvider(BlockConfigEntry block) {
+ super(block);
+ }
- @Override
- public void close() throws IOException {
- TextureProvider provider = this.provider;
- if (provider != null) {
- provider.close();
- }
- }
+ @Override
+ public void close() throws IOException {
+ TextureProvider provider = this.provider;
+ if (provider != null) {
+ provider.close();
+ }
+ }
- @Override
- public PlayerProfile.Texture getCloakTexture(UUID uuid, String username) throws IOException {
- return getProvider().getCloakTexture(uuid, username);
- }
+ @Override
+ public Texture getCloakTexture(UUID uuid, String username) throws IOException {
+ return getProvider().getCloakTexture(uuid, username);
+ }
- @Override
- public PlayerProfile.Texture getSkinTexture(UUID uuid, String username) throws IOException {
- return getProvider().getSkinTexture(uuid, username);
- }
+ @Override
+ public Texture getSkinTexture(UUID uuid, String username) throws IOException {
+ return getProvider().getSkinTexture(uuid, username);
+ }
- @LauncherAPI
- public void setBackend(TextureProvider provider) {
- this.provider = provider;
- }
+ @LauncherAPI
+ public void setBackend(TextureProvider provider) {
+ this.provider = provider;
+ }
- private TextureProvider getProvider() {
- return VerifyHelper.verify(provider, a -> a != null, "Backend texture provider wasn't set");
- }
+ private TextureProvider getProvider() {
+ return VerifyHelper.verify(provider, a -> a != null, "Backend texture provider wasn't set");
+ }
}
diff --git a/LaunchServer/source/texture/RequestTextureProvider.java b/LaunchServer/source/texture/RequestTextureProvider.java
index 7dd3d24..2fad417 100644
--- a/LaunchServer/source/texture/RequestTextureProvider.java
+++ b/LaunchServer/source/texture/RequestTextureProvider.java
@@ -6,6 +6,7 @@
import launcher.client.ClientLauncher;
import launcher.client.PlayerProfile;
+import launcher.client.PlayerProfile.Texture;
import launcher.helper.CommonHelper;
import launcher.helper.IOHelper;
import launcher.helper.LogHelper;
@@ -13,49 +14,49 @@
import launcher.serialize.config.entry.StringConfigEntry;
public final class RequestTextureProvider extends TextureProvider {
- private static final UUID ZERO_UUID = new UUID(0, 0);
+ private static final UUID ZERO_UUID = new UUID(0, 0);
- // Instance
- private final String skinURL;
- private final String cloakURL;
+ // Instance
+ private final String skinURL;
+ private final String cloakURL;
- public RequestTextureProvider(BlockConfigEntry block) {
- super(block);
- skinURL = block.getEntryValue("skinsURL", StringConfigEntry.class);
- cloakURL = block.getEntryValue("cloaksURL", StringConfigEntry.class);
+ public RequestTextureProvider(BlockConfigEntry block) {
+ super(block);
+ skinURL = block.getEntryValue("skinsURL", StringConfigEntry.class);
+ cloakURL = block.getEntryValue("cloaksURL", StringConfigEntry.class);
- // Verify
- IOHelper.verifyURL(getTextureURL(skinURL, ZERO_UUID, "skinUsername"));
- IOHelper.verifyURL(getTextureURL(cloakURL, ZERO_UUID, "cloakUsername"));
- }
+ // Verify
+ IOHelper.verifyURL(getTextureURL(skinURL, ZERO_UUID, "skinUsername"));
+ IOHelper.verifyURL(getTextureURL(cloakURL, ZERO_UUID, "cloakUsername"));
+ }
- @Override
- public void close() {
- // Do nothing
- }
+ @Override
+ public void close() {
+ // Do nothing
+ }
- @Override
- public PlayerProfile.Texture getCloakTexture(UUID uuid, String username) throws IOException {
- return getTexture(getTextureURL(cloakURL, uuid, username));
- }
+ @Override
+ public Texture getCloakTexture(UUID uuid, String username) throws IOException {
+ return getTexture(getTextureURL(cloakURL, uuid, username));
+ }
- @Override
- public PlayerProfile.Texture getSkinTexture(UUID uuid, String username) throws IOException {
- return getTexture(getTextureURL(skinURL, uuid, username));
- }
+ @Override
+ public Texture getSkinTexture(UUID uuid, String username) throws IOException {
+ return getTexture(getTextureURL(skinURL, uuid, username));
+ }
- private static PlayerProfile.Texture getTexture(String url) throws IOException {
- LogHelper.debug("Getting texture: '%s'", url);
- try {
- return new PlayerProfile.Texture(url);
- } catch (FileNotFoundException e) {
- LogHelper.subDebug("Texture not found :(");
- return null; // Simply not found
- }
- }
+ private static Texture getTexture(String url) throws IOException {
+ LogHelper.debug("Getting texture: '%s'", url);
+ try {
+ return new Texture(url);
+ } catch (FileNotFoundException e) {
+ LogHelper.subDebug("Texture not found :(");
+ return null; // Simply not found
+ }
+ }
- private static String getTextureURL(String url, UUID uuid, String username) {
- return CommonHelper.replace(url, "username", IOHelper.urlEncode(username),
- "uuid", IOHelper.urlEncode(uuid.toString()), "hash", IOHelper.urlEncode(ClientLauncher.toHash(uuid)));
- }
+ private static String getTextureURL(String url, UUID uuid, String username) {
+ return CommonHelper.replace(url, "username", IOHelper.urlEncode(username),
+ "uuid", IOHelper.urlEncode(uuid.toString()), "hash", IOHelper.urlEncode(ClientLauncher.toHash(uuid)));
+ }
}
diff --git a/LaunchServer/source/texture/TextureProvider.java b/LaunchServer/source/texture/TextureProvider.java
index e172127..c64cf2c 100644
--- a/LaunchServer/source/texture/TextureProvider.java
+++ b/LaunchServer/source/texture/TextureProvider.java
@@ -8,46 +8,47 @@
import launcher.LauncherAPI;
import launcher.client.PlayerProfile;
+import launcher.client.PlayerProfile.Texture;
import launcher.helper.VerifyHelper;
import launcher.serialize.config.ConfigObject;
import launcher.serialize.config.entry.BlockConfigEntry;
public abstract class TextureProvider extends ConfigObject implements AutoCloseable {
- private static final Map> TEXTURE_PROVIDERS = new ConcurrentHashMap<>(2);
+ private static final Map> TEXTURE_PROVIDERS = new ConcurrentHashMap<>(2);
- @LauncherAPI
- protected TextureProvider(BlockConfigEntry block) {
- super(block);
- }
+ @LauncherAPI
+ protected TextureProvider(BlockConfigEntry block) {
+ super(block);
+ }
- @LauncherAPI
- public abstract PlayerProfile.Texture getCloakTexture(UUID uuid, String username) throws IOException;
+ @Override
+ public abstract void close() throws IOException;
- @LauncherAPI
- public abstract PlayerProfile.Texture getSkinTexture(UUID uuid, String username) throws IOException;
+ @LauncherAPI
+ public abstract Texture getCloakTexture(UUID uuid, String username) throws IOException;
- @LauncherAPI
- public static TextureProvider newProvider(String name, BlockConfigEntry block) {
- VerifyHelper.verifyIDName(name);
- Adapter authHandlerAdapter = VerifyHelper.getMapValue(TEXTURE_PROVIDERS, name,
- String.format("Unknown texture provider: '%s'", name));
- return authHandlerAdapter.convert(block);
- }
+ @LauncherAPI
+ public abstract Texture getSkinTexture(UUID uuid, String username) throws IOException;
- @Override
- public abstract void close() throws IOException;
+ @LauncherAPI
+ public static TextureProvider newProvider(String name, BlockConfigEntry block) {
+ VerifyHelper.verifyIDName(name);
+ Adapter authHandlerAdapter = VerifyHelper.getMapValue(TEXTURE_PROVIDERS, name,
+ String.format("Unknown texture provider: '%s'", name));
+ return authHandlerAdapter.convert(block);
+ }
- @LauncherAPI
- public static void registerProvider(String name, Adapter adapter) {
- VerifyHelper.putIfAbsent(TEXTURE_PROVIDERS, name, Objects.requireNonNull(adapter, "adapter"),
- String.format("Texture provider has been already registered: '%s'", name));
- }
+ @LauncherAPI
+ public static void registerProvider(String name, Adapter adapter) {
+ VerifyHelper.putIfAbsent(TEXTURE_PROVIDERS, name, Objects.requireNonNull(adapter, "adapter"),
+ String.format("Texture provider has been already registered: '%s'", name));
+ }
- static {
- registerProvider("null", NullTextureProvider::new);
- registerProvider("void", VoidTextureProvider::new);
+ static {
+ registerProvider("null", NullTextureProvider::new);
+ registerProvider("void", VoidTextureProvider::new);
- // Auth providers that doesn't do nothing :D
- registerProvider("request", RequestTextureProvider::new);
- }
+ // Auth providers that doesn't do nothing :D
+ registerProvider("request", RequestTextureProvider::new);
+ }
}
diff --git a/LaunchServer/source/texture/VoidTextureProvider.java b/LaunchServer/source/texture/VoidTextureProvider.java
index 6e31f32..b525f33 100644
--- a/LaunchServer/source/texture/VoidTextureProvider.java
+++ b/LaunchServer/source/texture/VoidTextureProvider.java
@@ -3,25 +3,26 @@
import java.util.UUID;
import launcher.client.PlayerProfile;
+import launcher.client.PlayerProfile.Texture;
import launcher.serialize.config.entry.BlockConfigEntry;
public final class VoidTextureProvider extends TextureProvider {
- public VoidTextureProvider(BlockConfigEntry block) {
- super(block);
- }
+ public VoidTextureProvider(BlockConfigEntry block) {
+ super(block);
+ }
- @Override
- public void close() {
- // Do nothing
- }
+ @Override
+ public void close() {
+ // Do nothing
+ }
- @Override
- public PlayerProfile.Texture getCloakTexture(UUID uuid, String username) {
- return null; // Always nothing
- }
+ @Override
+ public Texture getCloakTexture(UUID uuid, String username) {
+ return null; // Always nothing
+ }
- @Override
- public PlayerProfile.Texture getSkinTexture(UUID uuid, String username) {
- return null; // Always nothing
- }
+ @Override
+ public Texture getSkinTexture(UUID uuid, String username) {
+ return null; // Always nothing
+ }
}
diff --git a/Launcher/source-testing/LauncherWrap.java b/Launcher/source-testing/LauncherWrap.java
index 5fa27c0..d63b905 100644
--- a/Launcher/source-testing/LauncherWrap.java
+++ b/Launcher/source-testing/LauncherWrap.java
@@ -1,10 +1,10 @@
package launcher;
public final class LauncherWrap {
- private LauncherWrap() {
- }
+ private LauncherWrap() {
+ }
- public static void main(String... args) throws Throwable {
- Launcher.main(args); // Just for test runtime
- }
-}
\ No newline at end of file
+ public static void main(String... args) throws Throwable {
+ Launcher.main(args); // Just for test runtime
+ }
+}
diff --git a/Launcher/source/Launcher.java b/Launcher/source/Launcher.java
index 8a712ca..375b756 100644
--- a/Launcher/source/Launcher.java
+++ b/Launcher/source/Launcher.java
@@ -1,10 +1,5 @@
package launcher;
-import javax.script.Bindings;
-import javax.script.Invocable;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.InetSocketAddress;
@@ -18,14 +13,23 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
+import javax.script.Bindings;
+import javax.script.Invocable;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
import launcher.client.ClientLauncher;
+import launcher.client.ClientLauncher.Params;
import launcher.client.ClientProfile;
+import launcher.client.ClientProfile.Version;
import launcher.client.PlayerProfile;
+import launcher.client.PlayerProfile.Texture;
import launcher.client.ServerPinger;
import launcher.hasher.FileNameMatcher;
import launcher.hasher.HashedDir;
@@ -34,8 +38,11 @@
import launcher.helper.CommonHelper;
import launcher.helper.IOHelper;
import launcher.helper.JVMHelper;
+import launcher.helper.JVMHelper.OS;
import launcher.helper.LogHelper;
+import launcher.helper.LogHelper.Output;
import launcher.helper.SecurityHelper;
+import launcher.helper.SecurityHelper.DigestAlgorithm;
import launcher.helper.VerifyHelper;
import launcher.helper.js.JSApplication;
import launcher.request.CustomRequest;
@@ -53,11 +60,13 @@
import launcher.serialize.HInput;
import launcher.serialize.HOutput;
import launcher.serialize.config.ConfigObject;
+import launcher.serialize.config.ConfigObject.Adapter;
import launcher.serialize.config.TextConfigReader;
import launcher.serialize.config.TextConfigWriter;
import launcher.serialize.config.entry.BlockConfigEntry;
import launcher.serialize.config.entry.BooleanConfigEntry;
import launcher.serialize.config.entry.ConfigEntry;
+import launcher.serialize.config.entry.ConfigEntry.Type;
import launcher.serialize.config.entry.IntegerConfigEntry;
import launcher.serialize.config.entry.ListConfigEntry;
import launcher.serialize.config.entry.StringConfigEntry;
@@ -67,247 +76,247 @@
import launcher.serialize.stream.StreamObject;
public final class Launcher {
- private static final AtomicReference CONFIG = new AtomicReference<>();
+ private static final AtomicReference CONFIG = new AtomicReference<>();
- // Version info
- @LauncherAPI public static final String VERSION = "15.2.1";
- @LauncherAPI public static final String BUILD = readBuildNumber();
- @LauncherAPI public static final int PROTOCOL_MAGIC = 0x724724_16;
+ // Version info
+ @LauncherAPI public static final String VERSION = "15.2.1";
+ @LauncherAPI public static final String BUILD = readBuildNumber();
+ @LauncherAPI public static final int PROTOCOL_MAGIC = 0x724724_16;
- // Constants
- @LauncherAPI public static final String RUNTIME_DIR = "runtime";
- @LauncherAPI public static final String CONFIG_FILE = "config.bin";
- @LauncherAPI public static final String INIT_SCRIPT_FILE = "init.js";
+ // Constants
+ @LauncherAPI public static final String RUNTIME_DIR = "runtime";
+ @LauncherAPI public static final String CONFIG_FILE = "config.bin";
+ @LauncherAPI public static final String INIT_SCRIPT_FILE = "init.js";
- // Instance
- private final AtomicBoolean started = new AtomicBoolean(false);
- private final ScriptEngine engine = CommonHelper.newScriptEngine();
+ // Instance
+ private final AtomicBoolean started = new AtomicBoolean(false);
+ private final ScriptEngine engine = CommonHelper.newScriptEngine();
- private Launcher() {
- setScriptBindings();
- }
+ private Launcher() {
+ setScriptBindings();
+ }
- @LauncherAPI
- public Object loadScript(URL url) throws IOException, ScriptException {
- LogHelper.debug("Loading script: '%s'", url);
- try (BufferedReader reader = IOHelper.newReader(url)) {
- return engine.eval(reader);
- }
- }
+ @LauncherAPI
+ public Object loadScript(URL url) throws IOException, ScriptException {
+ LogHelper.debug("Loading script: '%s'", url);
+ try (BufferedReader reader = IOHelper.newReader(url)) {
+ return engine.eval(reader);
+ }
+ }
- @LauncherAPI
- public void start(String... args) throws Throwable {
- Objects.requireNonNull(args, "args");
- if (started.getAndSet(true)) {
- throw new IllegalStateException("Launcher has been already started");
- }
+ @LauncherAPI
+ public void start(String... args) throws Throwable {
+ Objects.requireNonNull(args, "args");
+ if (started.getAndSet(true)) {
+ throw new IllegalStateException("Launcher has been already started");
+ }
- // Load init.js script
- loadScript(getResourceURL(INIT_SCRIPT_FILE));
- LogHelper.info("Invoking start() function");
- ((Invocable) engine).invokeFunction("start", (Object) args);
- }
+ // Load init.js script
+ loadScript(getResourceURL(INIT_SCRIPT_FILE));
+ LogHelper.info("Invoking start() function");
+ ((Invocable) engine).invokeFunction("start", (Object) args);
+ }
- private void setScriptBindings() {
- LogHelper.info("Setting up script engine bindings");
- Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
- bindings.put("launcher", this);
+ private void setScriptBindings() {
+ LogHelper.info("Setting up script engine bindings");
+ Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
+ bindings.put("launcher", this);
- // Add launcher class bindings
- addLauncherClassBindings(bindings);
- }
+ // Add launcher class bindings
+ addLauncherClassBindings(bindings);
+ }
- @LauncherAPI
- public static void addLauncherClassBindings(Map bindings) {
- bindings.put("LauncherClass", Launcher.class);
+ @LauncherAPI
+ public static void addLauncherClassBindings(Map bindings) {
+ bindings.put("LauncherClass", Launcher.class);
- // Set client class bindings
- bindings.put("PlayerProfileClass", PlayerProfile.class);
- bindings.put("PlayerProfileTextureClass", PlayerProfile.Texture.class);
- bindings.put("ClientProfileClass", ClientProfile.class);
- bindings.put("ClientProfileVersionClass", ClientProfile.Version.class);
- bindings.put("ClientLauncherClass", ClientLauncher.class);
- bindings.put("ClientLauncherParamsClass", ClientLauncher.Params.class);
- bindings.put("ServerPingerClass", ServerPinger.class);
+ // Set client class bindings
+ bindings.put("PlayerProfileClass", PlayerProfile.class);
+ bindings.put("PlayerProfileTextureClass", Texture.class);
+ bindings.put("ClientProfileClass", ClientProfile.class);
+ bindings.put("ClientProfileVersionClass", Version.class);
+ bindings.put("ClientLauncherClass", ClientLauncher.class);
+ bindings.put("ClientLauncherParamsClass", Params.class);
+ bindings.put("ServerPingerClass", ServerPinger.class);
- // Set request class bindings
- bindings.put("RequestClass", Request.class);
- bindings.put("RequestTypeClass", Request.Type.class);
- bindings.put("RequestExceptionClass", RequestException.class);
- bindings.put("CustomRequestClass", CustomRequest.class);
- bindings.put("PingRequestClass", PingRequest.class);
- bindings.put("AuthRequestClass", AuthRequest.class);
- bindings.put("JoinServerRequestClass", JoinServerRequest.class);
- bindings.put("CheckServerRequestClass", CheckServerRequest.class);
- bindings.put("UpdateRequestClass", UpdateRequest.class);
- bindings.put("LauncherRequestClass", LauncherRequest.class);
- bindings.put("ProfileByUsernameRequestClass", ProfileByUsernameRequest.class);
- bindings.put("ProfileByUUIDRequestClass", ProfileByUUIDRequest.class);
- bindings.put("BatchProfileByUsernameRequestClass", BatchProfileByUsernameRequest.class);
+ // Set request class bindings
+ bindings.put("RequestClass", Request.class);
+ bindings.put("RequestTypeClass", Request.Type.class);
+ bindings.put("RequestExceptionClass", RequestException.class);
+ bindings.put("CustomRequestClass", CustomRequest.class);
+ bindings.put("PingRequestClass", PingRequest.class);
+ bindings.put("AuthRequestClass", AuthRequest.class);
+ bindings.put("JoinServerRequestClass", JoinServerRequest.class);
+ bindings.put("CheckServerRequestClass", CheckServerRequest.class);
+ bindings.put("UpdateRequestClass", UpdateRequest.class);
+ bindings.put("LauncherRequestClass", LauncherRequest.class);
+ bindings.put("ProfileByUsernameRequestClass", ProfileByUsernameRequest.class);
+ bindings.put("ProfileByUUIDRequestClass", ProfileByUUIDRequest.class);
+ bindings.put("BatchProfileByUsernameRequestClass", BatchProfileByUsernameRequest.class);
- // Set hasher class bindings
- bindings.put("FileNameMatcherClass", FileNameMatcher.class);
- bindings.put("HashedDirClass", HashedDir.class);
- bindings.put("HashedFileClass", HashedFile.class);
- bindings.put("HashedEntryTypeClass", HashedEntry.Type.class);
+ // Set hasher class bindings
+ bindings.put("FileNameMatcherClass", FileNameMatcher.class);
+ bindings.put("HashedDirClass", HashedDir.class);
+ bindings.put("HashedFileClass", HashedFile.class);
+ bindings.put("HashedEntryTypeClass", HashedEntry.Type.class);
- // Set serialization class bindings
- bindings.put("HInputClass", HInput.class);
- bindings.put("HOutputClass", HOutput.class);
- bindings.put("StreamObjectClass", StreamObject.class);
- bindings.put("StreamObjectAdapterClass", StreamObject.Adapter.class);
- bindings.put("SignedBytesHolderClass", SignedBytesHolder.class);
- bindings.put("SignedObjectHolderClass", SignedObjectHolder.class);
- bindings.put("EnumSerializerClass", EnumSerializer.class);
+ // Set serialization class bindings
+ bindings.put("HInputClass", HInput.class);
+ bindings.put("HOutputClass", HOutput.class);
+ bindings.put("StreamObjectClass", StreamObject.class);
+ bindings.put("StreamObjectAdapterClass", StreamObject.Adapter.class);
+ bindings.put("SignedBytesHolderClass", SignedBytesHolder.class);
+ bindings.put("SignedObjectHolderClass", SignedObjectHolder.class);
+ bindings.put("EnumSerializerClass", EnumSerializer.class);
- // Set config serialization class bindings
- bindings.put("ConfigObjectClass", ConfigObject.class);
- bindings.put("ConfigObjectAdapterClass", ConfigObject.Adapter.class);
- bindings.put("BlockConfigEntryClass", BlockConfigEntry.class);
- bindings.put("BooleanConfigEntryClass", BooleanConfigEntry.class);
- bindings.put("IntegerConfigEntryClass", IntegerConfigEntry.class);
- bindings.put("ListConfigEntryClass", ListConfigEntry.class);
- bindings.put("StringConfigEntryClass", StringConfigEntry.class);
- bindings.put("ConfigEntryTypeClass", ConfigEntry.Type.class);
- bindings.put("TextConfigReaderClass", TextConfigReader.class);
- bindings.put("TextConfigWriterClass", TextConfigWriter.class);
+ // Set config serialization class bindings
+ bindings.put("ConfigObjectClass", ConfigObject.class);
+ bindings.put("ConfigObjectAdapterClass", Adapter.class);
+ bindings.put("BlockConfigEntryClass", BlockConfigEntry.class);
+ bindings.put("BooleanConfigEntryClass", BooleanConfigEntry.class);
+ bindings.put("IntegerConfigEntryClass", IntegerConfigEntry.class);
+ bindings.put("ListConfigEntryClass", ListConfigEntry.class);
+ bindings.put("StringConfigEntryClass", StringConfigEntry.class);
+ bindings.put("ConfigEntryTypeClass", Type.class);
+ bindings.put("TextConfigReaderClass", TextConfigReader.class);
+ bindings.put("TextConfigWriterClass", TextConfigWriter.class);
- // Set helper class bindings
- bindings.put("CommonHelperClass", CommonHelper.class);
- bindings.put("IOHelperClass", IOHelper.class);
- bindings.put("JVMHelperClass", JVMHelper.class);
- bindings.put("JVMHelperOSClass", JVMHelper.OS.class);
- bindings.put("LogHelperClass", LogHelper.class);
- bindings.put("LogHelperOutputClass", LogHelper.Output.class);
- bindings.put("SecurityHelperClass", SecurityHelper.class);
- bindings.put("DigestAlgorithmClass", SecurityHelper.DigestAlgorithm.class);
- bindings.put("VerifyHelperClass", VerifyHelper.class);
+ // Set helper class bindings
+ bindings.put("CommonHelperClass", CommonHelper.class);
+ bindings.put("IOHelperClass", IOHelper.class);
+ bindings.put("JVMHelperClass", JVMHelper.class);
+ bindings.put("JVMHelperOSClass", OS.class);
+ bindings.put("LogHelperClass", LogHelper.class);
+ bindings.put("LogHelperOutputClass", Output.class);
+ bindings.put("SecurityHelperClass", SecurityHelper.class);
+ bindings.put("DigestAlgorithmClass", DigestAlgorithm.class);
+ bindings.put("VerifyHelperClass", VerifyHelper.class);
- // Load JS API if available
- try {
- Class.forName("javafx.application.Application");
- bindings.put("JSApplicationClass", JSApplication.class);
- } catch (ClassNotFoundException e) {
- LogHelper.warning("JavaFX API isn't available");
- }
- }
+ // Load JS API if available
+ try {
+ Class.forName("javafx.application.Application");
+ bindings.put("JSApplicationClass", JSApplication.class);
+ } catch (ClassNotFoundException e) {
+ LogHelper.warning("JavaFX API isn't available");
+ }
+ }
- @LauncherAPI
- public static Config getConfig() {
- Config config = CONFIG.get();
- if (config == null) {
- try (HInput input = new HInput(IOHelper.newInput(IOHelper.getResourceURL(CONFIG_FILE)))) {
- config = new Config(input);
- } catch (IOException | InvalidKeySpecException e) {
- throw new SecurityException(e);
- }
- CONFIG.set(config);
- }
- return config;
- }
+ @LauncherAPI
+ public static Config getConfig() {
+ Config config = CONFIG.get();
+ if (config == null) {
+ try (HInput input = new HInput(IOHelper.newInput(IOHelper.getResourceURL(CONFIG_FILE)))) {
+ config = new Config(input);
+ } catch (IOException | InvalidKeySpecException e) {
+ throw new SecurityException(e);
+ }
+ CONFIG.set(config);
+ }
+ return config;
+ }
- @LauncherAPI
- public static URL getResourceURL(String name) throws IOException {
- Config config = getConfig();
- byte[] validDigest = config.runtime.get(name);
- if (validDigest == null) { // No such resource digest
- throw new NoSuchFileException(name);
- }
+ @LauncherAPI
+ public static URL getResourceURL(String name) throws IOException {
+ Config config = getConfig();
+ byte[] validDigest = config.runtime.get(name);
+ if (validDigest == null) { // No such resource digest
+ throw new NoSuchFileException(name);
+ }
- // Resolve URL and verify digest
- URL url = IOHelper.getResourceURL(RUNTIME_DIR + '/' + name);
- if (!Arrays.equals(validDigest, SecurityHelper.digest(SecurityHelper.DigestAlgorithm.MD5, url))) {
- throw new NoSuchFileException(name); // Digest mismatch
- }
+ // Resolve URL and verify digest
+ URL url = IOHelper.getResourceURL(RUNTIME_DIR + '/' + name);
+ if (!Arrays.equals(validDigest, SecurityHelper.digest(DigestAlgorithm.MD5, url))) {
+ throw new NoSuchFileException(name); // Digest mismatch
+ }
- // Return verified URL
- return url;
- }
+ // Return verified URL
+ return url;
+ }
- @LauncherAPI
- @SuppressWarnings({ "SameReturnValue", "MethodReturnAlwaysConstant" })
- public static String getVersion() {
- return VERSION; // Because Java constants are known at compile-time
- }
+ @LauncherAPI
+ @SuppressWarnings({ "SameReturnValue", "MethodReturnAlwaysConstant" })
+ public static String getVersion() {
+ return VERSION; // Because Java constants are known at compile-time
+ }
- public static void main(String... args) throws Throwable {
- JVMHelper.verifySystemProperties(Launcher.class);
- SecurityHelper.verifyCertificates(Launcher.class);
- LogHelper.printVersion("Launcher");
+ public static void main(String... args) throws Throwable {
+ JVMHelper.verifySystemProperties(Launcher.class);
+ SecurityHelper.verifyCertificates(Launcher.class);
+ LogHelper.printVersion("Launcher");
- // Start Launcher
- Instant start = Instant.now();
- try {
- new Launcher().start(args);
- } catch (Exception e) {
- LogHelper.error(e);
- return;
- }
- Instant end = Instant.now();
- LogHelper.debug("Launcher started in %dms", Duration.between(start, end).toMillis());
- }
+ // Start Launcher
+ Instant start = Instant.now();
+ try {
+ new Launcher().start(args);
+ } catch (Exception e) {
+ LogHelper.error(e);
+ return;
+ }
+ Instant end = Instant.now();
+ LogHelper.debug("Launcher started in %dms", Duration.between(start, end).toMillis());
+ }
- private static String readBuildNumber() {
- try {
- return IOHelper.request(IOHelper.getResourceURL("buildnumber"));
- } catch (IOException ignored) {
- return "dev"; // Maybe dev env?
- }
- }
+ private static String readBuildNumber() {
+ try {
+ return IOHelper.request(IOHelper.getResourceURL("buildnumber"));
+ } catch (IOException ignored) {
+ return "dev"; // Maybe dev env?
+ }
+ }
- public static final class Config extends StreamObject {
- private static final String ADDRESS_OVERRIDE = System.getProperty("launcher.addressOverride", null);
+ public static final class Config extends StreamObject {
+ private static final String ADDRESS_OVERRIDE = System.getProperty("launcher.addressOverride", null);
- // Instance
- @LauncherAPI public final InetSocketAddress address;
- @LauncherAPI public final RSAPublicKey publicKey;
- @LauncherAPI public final Map runtime;
+ // Instance
+ @LauncherAPI public final InetSocketAddress address;
+ @LauncherAPI public final RSAPublicKey publicKey;
+ @LauncherAPI public final Map runtime;
- @LauncherAPI
- @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
- public Config(String address, int port, RSAPublicKey publicKey, Map runtime) {
- this.address = InetSocketAddress.createUnresolved(address, port);
- this.publicKey = Objects.requireNonNull(publicKey, "publicKey");
- this.runtime = Collections.unmodifiableMap(new HashMap<>(runtime));
- }
+ @LauncherAPI
+ @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
+ public Config(String address, int port, RSAPublicKey publicKey, Map runtime) {
+ this.address = InetSocketAddress.createUnresolved(address, port);
+ this.publicKey = Objects.requireNonNull(publicKey, "publicKey");
+ this.runtime = Collections.unmodifiableMap(new HashMap<>(runtime));
+ }
- @LauncherAPI
- public Config(HInput input) throws IOException, InvalidKeySpecException {
- String localAddress = input.readASCII(255);
- address = InetSocketAddress.createUnresolved(
- ADDRESS_OVERRIDE == null ? localAddress : ADDRESS_OVERRIDE, input.readLength(65535));
- publicKey = SecurityHelper.toPublicRSAKey(input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH));
+ @LauncherAPI
+ public Config(HInput input) throws IOException, InvalidKeySpecException {
+ String localAddress = input.readASCII(255);
+ address = InetSocketAddress.createUnresolved(
+ ADDRESS_OVERRIDE == null ? localAddress : ADDRESS_OVERRIDE, input.readLength(65535));
+ publicKey = SecurityHelper.toPublicRSAKey(input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH));
- // Read signed runtime
- int count = input.readLength(0);
- Map localResources = new HashMap<>(count);
- for (int i = 0; i < count; i++) {
- String name = input.readString(255);
- VerifyHelper.putIfAbsent(localResources, name,
- input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH),
- String.format("Duplicate runtime resource: '%s'", name));
- }
- runtime = Collections.unmodifiableMap(localResources);
+ // Read signed runtime
+ int count = input.readLength(0);
+ Map localResources = new HashMap<>(count);
+ for (int i = 0; i < count; i++) {
+ String name = input.readString(255);
+ VerifyHelper.putIfAbsent(localResources, name,
+ input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH),
+ String.format("Duplicate runtime resource: '%s'", name));
+ }
+ runtime = Collections.unmodifiableMap(localResources);
- // Print warning if address override is enabled
- if (ADDRESS_OVERRIDE != null) {
- LogHelper.warning("Address override is enabled: '%s'", ADDRESS_OVERRIDE);
- }
- }
+ // Print warning if address override is enabled
+ if (ADDRESS_OVERRIDE != null) {
+ LogHelper.warning("Address override is enabled: '%s'", ADDRESS_OVERRIDE);
+ }
+ }
- @Override
- public void write(HOutput output) throws IOException {
- output.writeASCII(address.getHostString(), 255);
- output.writeLength(address.getPort(), 65535);
- output.writeByteArray(publicKey.getEncoded(), SecurityHelper.CRYPTO_MAX_LENGTH);
+ @Override
+ public void write(HOutput output) throws IOException {
+ output.writeASCII(address.getHostString(), 255);
+ output.writeLength(address.getPort(), 65535);
+ output.writeByteArray(publicKey.getEncoded(), SecurityHelper.CRYPTO_MAX_LENGTH);
- // Write signed runtime
- Set> entrySet = runtime.entrySet();
- output.writeLength(entrySet.size(), 0);
- for (Map.Entry entry : runtime.entrySet()) {
- output.writeString(entry.getKey(), 255);
- output.writeByteArray(entry.getValue(), SecurityHelper.CRYPTO_MAX_LENGTH);
- }
- }
- }
+ // Write signed runtime
+ Set> entrySet = runtime.entrySet();
+ output.writeLength(entrySet.size(), 0);
+ for (Entry entry : runtime.entrySet()) {
+ output.writeString(entry.getKey(), 255);
+ output.writeByteArray(entry.getValue(), SecurityHelper.CRYPTO_MAX_LENGTH);
+ }
+ }
+ }
}
diff --git a/Launcher/source/LauncherAPI.java b/Launcher/source/LauncherAPI.java
index c526922..6978944 100644
--- a/Launcher/source/LauncherAPI.java
+++ b/Launcher/source/LauncherAPI.java
@@ -8,5 +8,5 @@
@Retention(RetentionPolicy.CLASS)
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD })
public @interface LauncherAPI {
- /* This annotation implies that method/field/class should not be renamed or obfuscated */
+ /* This annotation implies that method/field/class should not be renamed or obfuscated */
}
diff --git a/Launcher/source/client/ClientLauncher.java b/Launcher/source/client/ClientLauncher.java
index ac13d68..86cc5f5 100644
--- a/Launcher/source/client/ClientLauncher.java
+++ b/Launcher/source/client/ClientLauncher.java
@@ -1,6 +1,7 @@
package launcher.client;
import java.io.IOException;
+import java.lang.ProcessBuilder.Redirect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
@@ -28,12 +29,14 @@
import com.eclipsesource.json.WriterConfig;
import launcher.Launcher;
import launcher.LauncherAPI;
+import launcher.client.ClientProfile.Version;
import launcher.hasher.DirWatcher;
import launcher.hasher.FileNameMatcher;
import launcher.hasher.HashedDir;
import launcher.helper.CommonHelper;
import launcher.helper.IOHelper;
import launcher.helper.JVMHelper;
+import launcher.helper.JVMHelper.OS;
import launcher.helper.LogHelper;
import launcher.helper.SecurityHelper;
import launcher.helper.VerifyHelper;
@@ -44,362 +47,360 @@
import launcher.serialize.stream.StreamObject;
public final class ClientLauncher {
- private static final String MAGICAL_INTEL_OPTION = "-XX:HeapDumpPath=ThisTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump";
- private static final Set BIN_POSIX_PERMISSIONS = Collections.unmodifiableSet(EnumSet.of(
- PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE, // Owner
- PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_EXECUTE, // Group
- PosixFilePermission.OTHERS_READ, PosixFilePermission.OTHERS_EXECUTE // Others
- ));
+ private static final String MAGICAL_INTEL_OPTION = "-XX:HeapDumpPath=ThisTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump";
+ private static final Set BIN_POSIX_PERMISSIONS = Collections.unmodifiableSet(EnumSet.of(
+ PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE, // Owner
+ PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_EXECUTE, // Group
+ PosixFilePermission.OTHERS_READ, PosixFilePermission.OTHERS_EXECUTE // Others
+ ));
- // Constants
- private static final Path NATIVES_DIR = IOHelper.toPath("natives");
- private static final Path RESOURCEPACKS_DIR = IOHelper.toPath("resourcepacks");
- private static final Pattern UUID_PATTERN = Pattern.compile("-", Pattern.LITERAL);
+ // Constants
+ private static final Path NATIVES_DIR = IOHelper.toPath("natives");
+ private static final Path RESOURCEPACKS_DIR = IOHelper.toPath("resourcepacks");
+ private static final Pattern UUID_PATTERN = Pattern.compile("-", Pattern.LITERAL);
- // Authlib constants
- @LauncherAPI public static final String SKIN_URL_PROPERTY = "skinURL";
- @LauncherAPI public static final String SKIN_DIGEST_PROPERTY = "skinDigest";
- @LauncherAPI public static final String CLOAK_URL_PROPERTY = "cloakURL";
- @LauncherAPI public static final String CLOAK_DIGEST_PROPERTY = "cloakDigest";
+ // Authlib constants
+ @LauncherAPI public static final String SKIN_URL_PROPERTY = "skinURL";
+ @LauncherAPI public static final String SKIN_DIGEST_PROPERTY = "skinDigest";
+ @LauncherAPI public static final String CLOAK_URL_PROPERTY = "cloakURL";
+ @LauncherAPI public static final String CLOAK_DIGEST_PROPERTY = "cloakDigest";
- // Used to determine from clientside is launched from launcher
- private static final AtomicBoolean LAUNCHED = new AtomicBoolean(false);
+ // Used to determine from clientside is launched from launcher
+ private static final AtomicBoolean LAUNCHED = new AtomicBoolean(false);
- private ClientLauncher() {
- }
+ private ClientLauncher() {
+ }
- @LauncherAPI
- public static boolean isLaunched() {
- return LAUNCHED.get();
- }
+ @LauncherAPI
+ public static boolean isLaunched() {
+ return LAUNCHED.get();
+ }
- public static String jvmProperty(String name, String value) {
- return String.format("-D%s=%s", name, value);
- }
+ public static String jvmProperty(String name, String value) {
+ return String.format("-D%s=%s", name, value);
+ }
- @LauncherAPI
- public static Process launch(Path jvmDir, SignedObjectHolder jvmHDir,
- SignedObjectHolder assetHDir, SignedObjectHolder clientHDir,
- SignedObjectHolder profile, Params params, boolean pipeOutput) throws Throwable {
- // Write params file (instead of CLI; Mustdie32 API can't handle command line > 32767 chars)
- LogHelper.debug("Writing ClientLauncher params file");
- Path paramsFile = Files.createTempFile("ClientLauncherParams", ".bin");
- try (HOutput output = new HOutput(IOHelper.newOutput(paramsFile))) {
- params.write(output);
- profile.write(output);
+ @LauncherAPI
+ public static Process launch(Path jvmDir, SignedObjectHolder jvmHDir,
+ SignedObjectHolder assetHDir, SignedObjectHolder clientHDir,
+ SignedObjectHolder profile, Params params, boolean pipeOutput) throws Throwable {
+ // Write params file (instead of CLI; Mustdie32 API can't handle command line > 32767 chars)
+ LogHelper.debug("Writing ClientLauncher params file");
+ Path paramsFile = Files.createTempFile("ClientLauncherParams", ".bin");
+ try (HOutput output = new HOutput(IOHelper.newOutput(paramsFile))) {
+ params.write(output);
+ profile.write(output);
- // Write hdirs
- jvmHDir.write(output);
- assetHDir.write(output);
- clientHDir.write(output);
- }
+ // Write hdirs
+ jvmHDir.write(output);
+ assetHDir.write(output);
+ clientHDir.write(output);
+ }
- // Resolve java bin and set permissions
- LogHelper.debug("Resolving JVM binary");
- Path javaBin = IOHelper.resolveJavaBin(jvmDir);
- if (IOHelper.POSIX) {
- Files.setPosixFilePermissions(javaBin, BIN_POSIX_PERMISSIONS);
- }
+ // Resolve java bin and set permissions
+ LogHelper.debug("Resolving JVM binary");
+ Path javaBin = IOHelper.resolveJavaBin(jvmDir);
+ if (IOHelper.POSIX) {
+ Files.setPosixFilePermissions(javaBin, BIN_POSIX_PERMISSIONS);
+ }
- // Fill CLI arguments
- List args = new LinkedList<>();
- args.add(javaBin.toString());
- args.add(MAGICAL_INTEL_OPTION);
- if (params.ram > 0 && params.ram <= JVMHelper.RAM) {
- args.add("-Xmx" + params.ram + 'M');
- }
- args.add(jvmProperty(LogHelper.DEBUG_PROPERTY, Boolean.toString(LogHelper.isDebugEnabled())));
- if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE && JVMHelper.OS_VERSION.startsWith("10.")) {
- LogHelper.debug("MustDie 10 fix is applied");
- args.add(jvmProperty("os.name", "Windows 10"));
- args.add(jvmProperty("os.version", "10.0"));
- }
+ // Fill CLI arguments
+ List args = new LinkedList<>();
+ args.add(javaBin.toString());
+ args.add(MAGICAL_INTEL_OPTION);
+ if (params.ram > 0 && params.ram <= JVMHelper.RAM) {
+ args.add("-Xmx" + params.ram + 'M');
+ }
+ args.add(jvmProperty(LogHelper.DEBUG_PROPERTY, Boolean.toString(LogHelper.isDebugEnabled())));
+ if (JVMHelper.OS_TYPE == OS.MUSTDIE && JVMHelper.OS_VERSION.startsWith("10.")) {
+ LogHelper.debug("MustDie 10 fix is applied");
+ args.add(jvmProperty("os.name", "Windows 10"));
+ args.add(jvmProperty("os.version", "10.0"));
+ }
- // Add classpath and main class
- Collections.addAll(args, profile.object.getJvmArgs());
- Collections.addAll(args, "-classpath", IOHelper.getCodeSource(ClientLauncher.class).toString(),
- ClientLauncher.class.getName());
- args.add(paramsFile.toString()); // Add params file path to args
+ // Add classpath and main class
+ Collections.addAll(args, profile.object.getJvmArgs());
+ Collections.addAll(args, "-classpath", IOHelper.getCodeSource(ClientLauncher.class).toString(),
+ ClientLauncher.class.getName());
+ args.add(paramsFile.toString()); // Add params file path to args
- // Build client process
- LogHelper.debug("Launching client instance");
- ProcessBuilder builder = new ProcessBuilder(args);
- builder.directory(params.clientDir.toFile());
- builder.inheritIO();
- if (pipeOutput) {
- builder.redirectErrorStream(true);
- builder.redirectOutput(ProcessBuilder.Redirect.PIPE);
- }
+ // Build client process
+ LogHelper.debug("Launching client instance");
+ ProcessBuilder builder = new ProcessBuilder(args);
+ builder.directory(params.clientDir.toFile());
+ builder.inheritIO();
+ if (pipeOutput) {
+ builder.redirectErrorStream(true);
+ builder.redirectOutput(Redirect.PIPE);
+ }
- // Let's rock!
- return builder.start();
- }
+ // Let's rock!
+ return builder.start();
+ }
- @LauncherAPI
- public static void main(String... args) throws Throwable {
- JVMHelper.verifySystemProperties(ClientLauncher.class);
- SecurityHelper.verifyCertificates(ClientLauncher.class);
- LogHelper.printVersion("Client Launcher");
+ @LauncherAPI
+ public static void main(String... args) throws Throwable {
+ JVMHelper.verifySystemProperties(ClientLauncher.class);
+ SecurityHelper.verifyCertificates(ClientLauncher.class);
+ LogHelper.printVersion("Client Launcher");
- // Resolve params file
- VerifyHelper.verifyInt(args.length, l -> l >= 1, "Missing args: ");
- Path paramsFile = IOHelper.toPath(args[0]);
+ // Resolve params file
+ VerifyHelper.verifyInt(args.length, l -> l >= 1, "Missing args: ");
+ Path paramsFile = IOHelper.toPath(args[0]);
- // Read and delete params file
- LogHelper.debug("Reading ClientLauncher params file");
- Params params;
- SignedObjectHolder profile;
- SignedObjectHolder jvmHDir, assetHDir, clientHDir;
- RSAPublicKey publicKey = Launcher.getConfig().publicKey;
- try (HInput input = new HInput(IOHelper.newInput(paramsFile))) {
- params = new Params(input);
- profile = new SignedObjectHolder<>(input, publicKey, ClientProfile.RO_ADAPTER);
+ // Read and delete params file
+ LogHelper.debug("Reading ClientLauncher params file");
+ Params params;
+ SignedObjectHolder profile;
+ SignedObjectHolder jvmHDir, assetHDir, clientHDir;
+ RSAPublicKey publicKey = Launcher.getConfig().publicKey;
+ try (HInput input = new HInput(IOHelper.newInput(paramsFile))) {
+ params = new Params(input);
+ profile = new SignedObjectHolder<>(input, publicKey, ClientProfile.RO_ADAPTER);
- // Read hdirs
- jvmHDir = new SignedObjectHolder<>(input, publicKey, HashedDir::new);
- assetHDir = new SignedObjectHolder<>(input, publicKey, HashedDir::new);
- clientHDir = new SignedObjectHolder<>(input, publicKey, HashedDir::new);
- } finally {
- Files.delete(paramsFile);
- }
+ // Read hdirs
+ jvmHDir = new SignedObjectHolder<>(input, publicKey, HashedDir::new);
+ assetHDir = new SignedObjectHolder<>(input, publicKey, HashedDir::new);
+ clientHDir = new SignedObjectHolder<>(input, publicKey, HashedDir::new);
+ } finally {
+ Files.delete(paramsFile);
+ }
- // Verify ClientLauncher sign and classpath
- LogHelper.debug("Verifying ClientLauncher sign and classpath");
- SecurityHelper.verifySign(LauncherRequest.BINARY_PATH, params.launcherSign, publicKey);
- URL[] classpath = JVMHelper.LOADER.getURLs();
- for (URL classpathURL : classpath) {
- Path file = Paths.get(classpathURL.toURI());
- if (!file.startsWith(IOHelper.JVM_DIR) && !file.equals(LauncherRequest.BINARY_PATH)) {
- throw new SecurityException(String.format("Forbidden classpath entry: '%s'", file));
- }
- }
+ // Verify ClientLauncher sign and classpath
+ LogHelper.debug("Verifying ClientLauncher sign and classpath");
+ SecurityHelper.verifySign(LauncherRequest.BINARY_PATH, params.launcherSign, publicKey);
+ URL[] classpath = JVMHelper.LOADER.getURLs();
+ for (URL classpathURL : classpath) {
+ Path file = Paths.get(classpathURL.toURI());
+ if (!file.startsWith(IOHelper.JVM_DIR) && !file.equals(LauncherRequest.BINARY_PATH)) {
+ throw new SecurityException(String.format("Forbidden classpath entry: '%s'", file));
+ }
+ }
- // Start client with WatchService monitoring
- LogHelper.debug("Starting JVM and client WatchService");
- FileNameMatcher assetMatcher = profile.object.getAssetUpdateMatcher();
- FileNameMatcher clientMatcher = profile.object.getClientUpdateMatcher();
- try (DirWatcher jvmWatcher = new DirWatcher(IOHelper.JVM_DIR, jvmHDir.object, null); // JVM Watcher
- DirWatcher assetWatcher = new DirWatcher(params.assetDir, assetHDir.object, assetMatcher);
- DirWatcher clientWatcher = new DirWatcher(params.clientDir, clientHDir.object, clientMatcher)) {
- // Verify current state of all dirs
- verifyHDir(IOHelper.JVM_DIR, jvmHDir.object, null);
- verifyHDir(params.assetDir, assetHDir.object, assetMatcher);
- verifyHDir(params.clientDir, clientHDir.object, clientMatcher);
+ // Start client with WatchService monitoring
+ LogHelper.debug("Starting JVM and client WatchService");
+ FileNameMatcher assetMatcher = profile.object.getAssetUpdateMatcher();
+ FileNameMatcher clientMatcher = profile.object.getClientUpdateMatcher();
+ try (DirWatcher jvmWatcher = new DirWatcher(IOHelper.JVM_DIR, jvmHDir.object, null); // JVM Watcher
+ DirWatcher assetWatcher = new DirWatcher(params.assetDir, assetHDir.object, assetMatcher);
+ DirWatcher clientWatcher = new DirWatcher(params.clientDir, clientHDir.object, clientMatcher)) {
+ // Verify current state of all dirs
+ verifyHDir(IOHelper.JVM_DIR, jvmHDir.object, null);
+ verifyHDir(params.assetDir, assetHDir.object, assetMatcher);
+ verifyHDir(params.clientDir, clientHDir.object, clientMatcher);
- // Start WatchService, and only then client
- CommonHelper.newThread("JVM Directory Watcher", true, jvmWatcher).start();
- CommonHelper.newThread("Asset Directory Watcher", true, assetWatcher).start();
- CommonHelper.newThread("Client Directory Watcher", true, clientWatcher).start();
- launch(profile.object, params);
- }
- }
+ // Start WatchService, and only then client
+ CommonHelper.newThread("JVM Directory Watcher", true, jvmWatcher).start();
+ CommonHelper.newThread("Asset Directory Watcher", true, assetWatcher).start();
+ CommonHelper.newThread("Client Directory Watcher", true, clientWatcher).start();
+ launch(profile.object, params);
+ }
+ }
- @LauncherAPI
- public static String toHash(UUID uuid) {
- return UUID_PATTERN.matcher(uuid.toString()).replaceAll("");
- }
+ @LauncherAPI
+ public static String toHash(UUID uuid) {
+ return UUID_PATTERN.matcher(uuid.toString()).replaceAll("");
+ }
- @LauncherAPI
- public static void verifyHDir(Path dir, HashedDir hdir, FileNameMatcher matcher) throws IOException {
- if (matcher != null) {
- matcher = matcher.verifyOnly();
- }
+ @LauncherAPI
+ public static void verifyHDir(Path dir, HashedDir hdir, FileNameMatcher matcher) throws IOException {
+ if (matcher != null) {
+ matcher = matcher.verifyOnly();
+ }
- // Hash directory and compare (ignore update-only matcher entries, it will break offline-mode)
- HashedDir currentHDir = new HashedDir(dir, matcher, false);
- if (!hdir.diff(currentHDir, matcher).isSame()) {
- throw new SecurityException(String.format("Forbidden modification: '%s'", IOHelper.getFileName(dir)));
- }
- }
+ // Hash directory and compare (ignore update-only matcher entries, it will break offline-mode)
+ HashedDir currentHDir = new HashedDir(dir, matcher, false);
+ if (!hdir.diff(currentHDir, matcher).isSame()) {
+ throw new SecurityException(String.format("Forbidden modification: '%s'", IOHelper.getFileName(dir)));
+ }
+ }
- private static void addClientArgs(Collection args, ClientProfile profile, Params params) {
- PlayerProfile pp = params.pp;
+ private static void addClientArgs(Collection args, ClientProfile profile, Params params) {
+ PlayerProfile pp = params.pp;
- // Add version-dependent args
- ClientProfile.Version version = profile.getVersion();
- Collections.addAll(args, "--username", pp.username);
- if (version.compareTo(ClientProfile.Version.MC172) >= 0) {
- Collections.addAll(args, "--uuid", toHash(pp.uuid));
- Collections.addAll(args, "--accessToken", params.accessToken);
+ // Add version-dependent args
+ Version version = profile.getVersion();
+ Collections.addAll(args, "--username", pp.username);
+ if (version.compareTo(Version.MC172) >= 0) {
+ Collections.addAll(args, "--uuid", toHash(pp.uuid));
+ Collections.addAll(args, "--accessToken", params.accessToken);
- // Add 1.7.10+ args (user properties, asset index)
- if (version.compareTo(ClientProfile.Version.MC1710) >= 0) {
- // Add user properties
- Collections.addAll(args, "--userType", "mojang");
- JsonObject properties = Json.object();
- if (pp.skin != null) {
- properties.add(SKIN_URL_PROPERTY, Json.array(pp.skin.url));
- properties.add(SKIN_DIGEST_PROPERTY, Json.array(SecurityHelper.toHex(pp.skin.digest)));
- }
- if (pp.cloak != null) {
- properties.add(CLOAK_URL_PROPERTY, Json.array(pp.cloak.url));
- properties.add(CLOAK_DIGEST_PROPERTY, Json.array(SecurityHelper.toHex(pp.cloak.digest)));
- }
- Collections.addAll(args, "--userProperties", properties.toString(WriterConfig.MINIMAL));
+ // Add 1.7.10+ args (user properties, asset index)
+ if (version.compareTo(Version.MC1710) >= 0) {
+ // Add user properties
+ Collections.addAll(args, "--userType", "mojang");
+ JsonObject properties = Json.object();
+ if (pp.skin != null) {
+ properties.add(SKIN_URL_PROPERTY, Json.array(pp.skin.url));
+ properties.add(SKIN_DIGEST_PROPERTY, Json.array(SecurityHelper.toHex(pp.skin.digest)));
+ }
+ if (pp.cloak != null) {
+ properties.add(CLOAK_URL_PROPERTY, Json.array(pp.cloak.url));
+ properties.add(CLOAK_DIGEST_PROPERTY, Json.array(SecurityHelper.toHex(pp.cloak.digest)));
+ }
+ Collections.addAll(args, "--userProperties", properties.toString(WriterConfig.MINIMAL));
- // Add asset index
- Collections.addAll(args, "--assetIndex", profile.getAssetIndex());
- }
- } else {
- Collections.addAll(args, "--session", params.accessToken);
- }
+ // Add asset index
+ Collections.addAll(args, "--assetIndex", profile.getAssetIndex());
+ }
+ } else {
+ Collections.addAll(args, "--session", params.accessToken);
+ }
- // Add version and dirs args
- Collections.addAll(args, "--version", profile.getVersion().name);
- Collections.addAll(args, "--gameDir", params.clientDir.toString());
- Collections.addAll(args, "--assetsDir", params.assetDir.toString());
- Collections.addAll(args, "--resourcePackDir", params.clientDir.resolve(RESOURCEPACKS_DIR).toString());
- if (version.compareTo(ClientProfile.Version.MC194) >= 0) { // Just to show it in debug screen
- Collections.addAll(args, "--versionType", "Launcher v" + Launcher.VERSION);
- }
+ // Add version and dirs args
+ Collections.addAll(args, "--version", profile.getVersion().name);
+ Collections.addAll(args, "--gameDir", params.clientDir.toString());
+ Collections.addAll(args, "--assetsDir", params.assetDir.toString());
+ Collections.addAll(args, "--resourcePackDir", params.clientDir.resolve(RESOURCEPACKS_DIR).toString());
+ if (version.compareTo(Version.MC194) >= 0) { // Just to show it in debug screen
+ Collections.addAll(args, "--versionType", "Launcher v" + Launcher.VERSION);
+ }
- // Add server args
- if (params.autoEnter) {
- Collections.addAll(args, "--server", profile.getServerAddress());
- Collections.addAll(args, "--port", Integer.toString(profile.getServerPort()));
- }
+ // Add server args
+ if (params.autoEnter) {
+ Collections.addAll(args, "--server", profile.getServerAddress());
+ Collections.addAll(args, "--port", Integer.toString(profile.getServerPort()));
+ }
- // Add window size args
- if (params.fullScreen) {
- Collections.addAll(args, "--fullscreen", Boolean.toString(true));
- }
- if (params.width > 0 && params.height > 0) {
- Collections.addAll(args, "--width", Integer.toString(params.width));
- Collections.addAll(args, "--height", Integer.toString(params.height));
- }
- }
+ // Add window size args
+ if (params.fullScreen) {
+ Collections.addAll(args, "--fullscreen", Boolean.toString(true));
+ }
+ if (params.width > 0 && params.height > 0) {
+ Collections.addAll(args, "--width", Integer.toString(params.width));
+ Collections.addAll(args, "--height", Integer.toString(params.height));
+ }
+ }
- private static void launch(ClientProfile profile, Params params) throws Throwable {
- // Add natives path
- JVMHelper.addNativePath(params.clientDir.resolve(NATIVES_DIR));
+ private static void launch(ClientProfile profile, Params params) throws Throwable {
+ // Add natives path
+ JVMHelper.addNativePath(params.clientDir.resolve(NATIVES_DIR));
- // Add client args
- Collection args = new LinkedList<>();
- addClientArgs(args, profile, params);
- Collections.addAll(args, profile.getClientArgs());
+ // Add client args
+ Collection args = new LinkedList<>();
+ addClientArgs(args, profile, params);
+ Collections.addAll(args, profile.getClientArgs());
- // Add client classpath
- URL[] classPath = resolveClassPath(params.clientDir, profile.getClassPath());
- for (URL url : classPath) {
- JVMHelper.UCP.addURL(url);
- }
+ // Add client classpath
+ URL[] classPath = resolveClassPath(params.clientDir, profile.getClassPath());
+ for (URL url : classPath) {
+ JVMHelper.UCP.addURL(url);
+ }
- // Resolve main class and method
- Class> mainClass = Class.forName(profile.getMainClass());
- Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
+ // Resolve main class and method
+ Class> mainClass = Class.forName(profile.getMainClass());
+ Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
- // Invoke main method with exception wrapping
- LAUNCHED.set(true);
- JVMHelper.fullGC();
- try {
- mainMethod.invoke(null, (Object) args.toArray(new String[args.size()]));
- } catch (InvocationTargetException e) {
- throw e.getTargetException();
- } finally {
- LAUNCHED.set(false);
- }
- }
+ // Invoke main method with exception wrapping
+ LAUNCHED.set(true);
+ JVMHelper.fullGC();
+ try {
+ mainMethod.invoke(null, (Object) args.toArray(new String[args.size()]));
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ } finally {
+ LAUNCHED.set(false);
+ }
+ }
- private static URL[] resolveClassPath(Path clientDir, String... classPath) throws IOException {
- Collection result = new LinkedList<>();
- for (String classPathEntry : classPath) {
- Path path = clientDir.resolve(IOHelper.toPath(classPathEntry));
- if (IOHelper.isDir(path)) { // Recursive walking and adding
- IOHelper.walk(path, new ClassPathFileVisitor(result), false);
- continue;
- }
- result.add(path);
- }
- return result.stream().map(IOHelper::toURL).toArray(URL[]::new);
- }
+ private static URL[] resolveClassPath(Path clientDir, String... classPath) throws IOException {
+ Collection result = new LinkedList<>();
+ for (String classPathEntry : classPath) {
+ Path path = clientDir.resolve(IOHelper.toPath(classPathEntry));
+ if (IOHelper.isDir(path)) { // Recursive walking and adding
+ IOHelper.walk(path, new ClassPathFileVisitor(result), false);
+ continue;
+ }
+ result.add(path);
+ }
+ return result.stream().map(IOHelper::toURL).toArray(URL[]::new);
+ }
- public static final class Params extends StreamObject {
- private final byte[] launcherSign;
+ public static final class Params extends StreamObject {
+ // Client paths
+ @LauncherAPI public final Path assetDir;
+ @LauncherAPI public final Path clientDir;
+ // Client params
+ @LauncherAPI public final PlayerProfile pp;
+ @LauncherAPI public final String accessToken;
+ @LauncherAPI public final boolean autoEnter;
+ @LauncherAPI public final boolean fullScreen;
+ @LauncherAPI public final int ram;
+ @LauncherAPI public final int width;
+ @LauncherAPI public final int height;
+ private final byte[] launcherSign;
- // Client paths
- @LauncherAPI public final Path assetDir;
- @LauncherAPI public final Path clientDir;
+ @LauncherAPI
+ public Params(byte[] launcherSign, Path assetDir, Path clientDir, PlayerProfile pp, String accessToken,
+ boolean autoEnter, boolean fullScreen, int ram, int width, int height) {
+ this.launcherSign = Arrays.copyOf(launcherSign, launcherSign.length);
- // Client params
- @LauncherAPI public final PlayerProfile pp;
- @LauncherAPI public final String accessToken;
- @LauncherAPI public final boolean autoEnter;
- @LauncherAPI public final boolean fullScreen;
- @LauncherAPI public final int ram;
- @LauncherAPI public final int width;
- @LauncherAPI public final int height;
+ // Client paths
+ this.assetDir = assetDir;
+ this.clientDir = clientDir;
- @LauncherAPI
- public Params(byte[] launcherSign, Path assetDir, Path clientDir, PlayerProfile pp, String accessToken,
- boolean autoEnter, boolean fullScreen, int ram, int width, int height) {
- this.launcherSign = Arrays.copyOf(launcherSign, launcherSign.length);
+ // Client params
+ this.pp = pp;
+ this.accessToken = SecurityHelper.verifyToken(accessToken);
+ this.autoEnter = autoEnter;
+ this.fullScreen = fullScreen;
+ this.ram = ram;
+ this.width = width;
+ this.height = height;
+ }
- // Client paths
- this.assetDir = assetDir;
- this.clientDir = clientDir;
+ @LauncherAPI
+ public Params(HInput input) throws IOException {
+ launcherSign = input.readByteArray(-SecurityHelper.RSA_KEY_LENGTH);
- // Client params
- this.pp = pp;
- this.accessToken = SecurityHelper.verifyToken(accessToken);
- this.autoEnter = autoEnter;
- this.fullScreen = fullScreen;
- this.ram = ram;
- this.width = width;
- this.height = height;
- }
+ // Client paths
+ assetDir = IOHelper.toPath(input.readString(0));
+ clientDir = IOHelper.toPath(input.readString(0));
- @LauncherAPI
- public Params(HInput input) throws IOException {
- launcherSign = input.readByteArray(-SecurityHelper.RSA_KEY_LENGTH);
+ // Client params
+ pp = new PlayerProfile(input);
+ accessToken = SecurityHelper.verifyToken(input.readASCII(-SecurityHelper.TOKEN_STRING_LENGTH));
+ autoEnter = input.readBoolean();
+ fullScreen = input.readBoolean();
+ ram = input.readVarInt();
+ width = input.readVarInt();
+ height = input.readVarInt();
+ }
- // Client paths
- assetDir = IOHelper.toPath(input.readString(0));
- clientDir = IOHelper.toPath(input.readString(0));
+ @Override
+ public void write(HOutput output) throws IOException {
+ output.writeByteArray(launcherSign, -SecurityHelper.RSA_KEY_LENGTH);
- // Client params
- pp = new PlayerProfile(input);
- accessToken = SecurityHelper.verifyToken(input.readASCII(-SecurityHelper.TOKEN_STRING_LENGTH));
- autoEnter = input.readBoolean();
- fullScreen = input.readBoolean();
- ram = input.readVarInt();
- width = input.readVarInt();
- height = input.readVarInt();
- }
+ // Client paths
+ output.writeString(assetDir.toString(), 0);
+ output.writeString(clientDir.toString(), 0);
- @Override
- public void write(HOutput output) throws IOException {
- output.writeByteArray(launcherSign, -SecurityHelper.RSA_KEY_LENGTH);
+ // Client params
+ pp.write(output);
+ output.writeASCII(accessToken, -SecurityHelper.TOKEN_STRING_LENGTH);
+ output.writeBoolean(autoEnter);
+ output.writeBoolean(fullScreen);
+ output.writeVarInt(ram);
+ output.writeVarInt(width);
+ output.writeVarInt(height);
+ }
+ }
- // Client paths
- output.writeString(assetDir.toString(), 0);
- output.writeString(clientDir.toString(), 0);
+ private static final class ClassPathFileVisitor extends SimpleFileVisitor {
+ private final Collection result;
- // Client params
- pp.write(output);
- output.writeASCII(accessToken, -SecurityHelper.TOKEN_STRING_LENGTH);
- output.writeBoolean(autoEnter);
- output.writeBoolean(fullScreen);
- output.writeVarInt(ram);
- output.writeVarInt(width);
- output.writeVarInt(height);
- }
- }
+ private ClassPathFileVisitor(Collection result) {
+ this.result = result;
+ }
- private static final class ClassPathFileVisitor extends SimpleFileVisitor {
- private final Collection result;
-
- private ClassPathFileVisitor(Collection result) {
- this.result = result;
- }
-
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- if (IOHelper.hasExtension(file, "jar") || IOHelper.hasExtension(file, "zip")) {
- result.add(file);
- }
- return super.visitFile(file, attrs);
- }
- }
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ if (IOHelper.hasExtension(file, "jar") || IOHelper.hasExtension(file, "zip")) {
+ result.add(file);
+ }
+ return super.visitFile(file, attrs);
+ }
+ }
}
// It's here since first commit, there's no any reasons to remove :D
diff --git a/Launcher/source/client/ClientProfile.java b/Launcher/source/client/ClientProfile.java
index 7c30f38..2e91351 100644
--- a/Launcher/source/client/ClientProfile.java
+++ b/Launcher/source/client/ClientProfile.java
@@ -12,7 +12,7 @@
import launcher.serialize.HInput;
import launcher.serialize.config.ConfigObject;
import launcher.serialize.config.entry.BlockConfigEntry;
-import launcher.serialize.config.entry.ConfigEntry;
+import launcher.serialize.config.entry.ConfigEntry.Type;
import launcher.serialize.config.entry.IntegerConfigEntry;
import launcher.serialize.config.entry.ListConfigEntry;
import launcher.serialize.config.entry.StringConfigEntry;
@@ -20,200 +20,200 @@
@SuppressWarnings("ComparableImplementedButEqualsNotOverridden")
public final class ClientProfile extends ConfigObject implements Comparable {
- @LauncherAPI public static final StreamObject.Adapter RO_ADAPTER = input -> new ClientProfile(input, true);
- private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher(
- new String[0], new String[] { "indexes", "objects" }, new String[0]);
+ @LauncherAPI public static final StreamObject.Adapter RO_ADAPTER = input -> new ClientProfile(input, true);
+ private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher(
+ new String[0], new String[] { "indexes", "objects" }, new String[0]);
- // Version
- private final StringConfigEntry version;
- private final StringConfigEntry assetIndex;
+ // Version
+ private final StringConfigEntry version;
+ private final StringConfigEntry assetIndex;
- // Client
- private final IntegerConfigEntry sortIndex;
- private final StringConfigEntry title;
- private final StringConfigEntry serverAddress;
- private final IntegerConfigEntry serverPort;
+ // Client
+ private final IntegerConfigEntry sortIndex;
+ private final StringConfigEntry title;
+ private final StringConfigEntry serverAddress;
+ private final IntegerConfigEntry serverPort;
- // Updater and client watch service
- private final ListConfigEntry update;
- private final ListConfigEntry updateExclusions;
- private final ListConfigEntry updateVerify;
+ // Updater and client watch service
+ private final ListConfigEntry update;
+ private final ListConfigEntry updateExclusions;
+ private final ListConfigEntry updateVerify;
- // Client launcher
- private final StringConfigEntry mainClass;
- private final ListConfigEntry jvmArgs;
- private final ListConfigEntry classPath;
- private final ListConfigEntry clientArgs;
+ // Client launcher
+ private final StringConfigEntry mainClass;
+ private final ListConfigEntry jvmArgs;
+ private final ListConfigEntry classPath;
+ private final ListConfigEntry clientArgs;
- @LauncherAPI
- public ClientProfile(BlockConfigEntry block) {
- super(block);
+ @LauncherAPI
+ public ClientProfile(BlockConfigEntry block) {
+ super(block);
- // Version
- version = block.getEntry("version", StringConfigEntry.class);
- assetIndex = block.getEntry("assetIndex", StringConfigEntry.class);
+ // Version
+ version = block.getEntry("version", StringConfigEntry.class);
+ assetIndex = block.getEntry("assetIndex", StringConfigEntry.class);
- // Client
- sortIndex = block.getEntry("sortIndex", IntegerConfigEntry.class);
- title = block.getEntry("title", StringConfigEntry.class);
- serverAddress = block.getEntry("serverAddress", StringConfigEntry.class);
- serverPort = block.getEntry("serverPort", IntegerConfigEntry.class);
+ // Client
+ sortIndex = block.getEntry("sortIndex", IntegerConfigEntry.class);
+ title = block.getEntry("title", StringConfigEntry.class);
+ serverAddress = block.getEntry("serverAddress", StringConfigEntry.class);
+ serverPort = block.getEntry("serverPort", IntegerConfigEntry.class);
- // Updater and client watch service
- update = block.getEntry("update", ListConfigEntry.class);
- updateVerify = block.getEntry("updateVerify", ListConfigEntry.class);
- updateExclusions = block.getEntry("updateExclusions", ListConfigEntry.class);
+ // Updater and client watch service
+ update = block.getEntry("update", ListConfigEntry.class);
+ updateVerify = block.getEntry("updateVerify", ListConfigEntry.class);
+ updateExclusions = block.getEntry("updateExclusions", ListConfigEntry.class);
- // Client launcher
- mainClass = block.getEntry("mainClass", StringConfigEntry.class);
- classPath = block.getEntry("classPath", ListConfigEntry.class);
- jvmArgs = block.getEntry("jvmArgs", ListConfigEntry.class);
- clientArgs = block.getEntry("clientArgs", ListConfigEntry.class);
- }
+ // Client launcher
+ mainClass = block.getEntry("mainClass", StringConfigEntry.class);
+ classPath = block.getEntry("classPath", ListConfigEntry.class);
+ jvmArgs = block.getEntry("jvmArgs", ListConfigEntry.class);
+ clientArgs = block.getEntry("clientArgs", ListConfigEntry.class);
+ }
- @LauncherAPI
- public ClientProfile(HInput input, boolean ro) throws IOException {
- this(new BlockConfigEntry(input, ro));
- }
+ @LauncherAPI
+ public ClientProfile(HInput input, boolean ro) throws IOException {
+ this(new BlockConfigEntry(input, ro));
+ }
- @LauncherAPI
- public String getAssetIndex() {
- return assetIndex.getValue();
- }
+ @Override
+ public int compareTo(ClientProfile o) {
+ return Integer.compare(getSortIndex(), o.getSortIndex());
+ }
- @LauncherAPI
- public FileNameMatcher getAssetUpdateMatcher() {
- return getVersion().compareTo(Version.MC1710) >= 0 ? ASSET_MATCHER : null;
- }
+ @Override
+ public String toString() {
+ return title.getValue();
+ }
- @LauncherAPI
- public String[] getClassPath() {
- return classPath.stream(StringConfigEntry.class).toArray(String[]::new);
- }
+ @LauncherAPI
+ public String getAssetIndex() {
+ return assetIndex.getValue();
+ }
- @LauncherAPI
- public String[] getClientArgs() {
- return clientArgs.stream(StringConfigEntry.class).toArray(String[]::new);
- }
+ @LauncherAPI
+ public FileNameMatcher getAssetUpdateMatcher() {
+ return getVersion().compareTo(Version.MC1710) >= 0 ? ASSET_MATCHER : null;
+ }
- @LauncherAPI
- public String[] getJvmArgs() {
- return jvmArgs.stream(StringConfigEntry.class).toArray(String[]::new);
- }
+ @LauncherAPI
+ public String[] getClassPath() {
+ return classPath.stream(StringConfigEntry.class).toArray(String[]::new);
+ }
- @LauncherAPI
- public String getMainClass() {
- return mainClass.getValue();
- }
+ @LauncherAPI
+ public String[] getClientArgs() {
+ return clientArgs.stream(StringConfigEntry.class).toArray(String[]::new);
+ }
- @LauncherAPI
- public String getServerAddress() {
- return serverAddress.getValue();
- }
+ @LauncherAPI
+ public FileNameMatcher getClientUpdateMatcher() {
+ String[] updateArray = update.stream(StringConfigEntry.class).toArray(String[]::new);
+ String[] verifyArray = updateVerify.stream(StringConfigEntry.class).toArray(String[]::new);
+ String[] exclusionsArray = updateExclusions.stream(StringConfigEntry.class).toArray(String[]::new);
+ return new FileNameMatcher(updateArray, verifyArray, exclusionsArray);
+ }
- @LauncherAPI
- public int getServerPort() {
- return serverPort.getValue();
- }
+ @LauncherAPI
+ public String[] getJvmArgs() {
+ return jvmArgs.stream(StringConfigEntry.class).toArray(String[]::new);
+ }
- @LauncherAPI
- public InetSocketAddress getServerSocketAddress() {
- return InetSocketAddress.createUnresolved(getServerAddress(), getServerPort());
- }
+ @LauncherAPI
+ public String getMainClass() {
+ return mainClass.getValue();
+ }
- @LauncherAPI
- public int getSortIndex() {
- return sortIndex.getValue();
- }
+ @LauncherAPI
+ public String getServerAddress() {
+ return serverAddress.getValue();
+ }
- @LauncherAPI
- public String getTitle() {
- return title.getValue();
- }
+ @LauncherAPI
+ public int getServerPort() {
+ return serverPort.getValue();
+ }
- @LauncherAPI
- public FileNameMatcher getClientUpdateMatcher() {
- String[] updateArray = update.stream(StringConfigEntry.class).toArray(String[]::new);
- String[] verifyArray = updateVerify.stream(StringConfigEntry.class).toArray(String[]::new);
- String[] exclusionsArray = updateExclusions.stream(StringConfigEntry.class).toArray(String[]::new);
- return new FileNameMatcher(updateArray, verifyArray, exclusionsArray);
- }
+ @LauncherAPI
+ public InetSocketAddress getServerSocketAddress() {
+ return InetSocketAddress.createUnresolved(getServerAddress(), getServerPort());
+ }
- @LauncherAPI
- public Version getVersion() {
- return Version.byName(version.getValue());
- }
+ @LauncherAPI
+ public int getSortIndex() {
+ return sortIndex.getValue();
+ }
- @LauncherAPI
- public void setTitle(String title) {
- this.title.setValue(title);
- }
+ @LauncherAPI
+ public String getTitle() {
+ return title.getValue();
+ }
- @LauncherAPI
- public void setVersion(Version version) {
- this.version.setValue(version.name);
- }
+ @LauncherAPI
+ public void setTitle(String title) {
+ this.title.setValue(title);
+ }
- @LauncherAPI
- public void verify() {
- // Version
- getVersion();
- IOHelper.verifyFileName(getAssetIndex());
+ @LauncherAPI
+ public Version getVersion() {
+ return Version.byName(version.getValue());
+ }
- // Client
- VerifyHelper.verify(getTitle(), VerifyHelper.NOT_EMPTY, "Profile title can't be empty");
- VerifyHelper.verify(getServerAddress(), VerifyHelper.NOT_EMPTY, "Server address can't be empty");
- VerifyHelper.verifyInt(getServerPort(), VerifyHelper.range(0, 65535), "Illegal server port: " + getServerPort());
+ @LauncherAPI
+ public void setVersion(Version version) {
+ this.version.setValue(version.name);
+ }
- // Updater and client watch service
- update.verifyOfType(ConfigEntry.Type.STRING);
- updateVerify.verifyOfType(ConfigEntry.Type.STRING);
- updateExclusions.verifyOfType(ConfigEntry.Type.STRING);
+ @LauncherAPI
+ public void verify() {
+ // Version
+ getVersion();
+ IOHelper.verifyFileName(getAssetIndex());
- // Client launcher
- jvmArgs.verifyOfType(ConfigEntry.Type.STRING);
- classPath.verifyOfType(ConfigEntry.Type.STRING);
- clientArgs.verifyOfType(ConfigEntry.Type.STRING);
- VerifyHelper.verify(getTitle(), VerifyHelper.NOT_EMPTY, "Main class can't be empty");
- }
+ // Client
+ VerifyHelper.verify(getTitle(), VerifyHelper.NOT_EMPTY, "Profile title can't be empty");
+ VerifyHelper.verify(getServerAddress(), VerifyHelper.NOT_EMPTY, "Server address can't be empty");
+ VerifyHelper.verifyInt(getServerPort(), VerifyHelper.range(0, 65535), "Illegal server port: " + getServerPort());
- @Override
- public int compareTo(ClientProfile o) {
- return Integer.compare(getSortIndex(), o.getSortIndex());
- }
+ // Updater and client watch service
+ update.verifyOfType(Type.STRING);
+ updateVerify.verifyOfType(Type.STRING);
+ updateExclusions.verifyOfType(Type.STRING);
- @Override
- public String toString() {
- return title.getValue();
- }
+ // Client launcher
+ jvmArgs.verifyOfType(Type.STRING);
+ classPath.verifyOfType(Type.STRING);
+ clientArgs.verifyOfType(Type.STRING);
+ VerifyHelper.verify(getTitle(), VerifyHelper.NOT_EMPTY, "Main class can't be empty");
+ }
- @LauncherAPI
- public enum Version {
- MC164("1.6.4", 78), MC172("1.7.2", 4), MC1710("1.7.10", 5), MC189("1.8.9", 47), MC194("1.9.4", 110), MC1102("1.10.2", 210);
- private static final Map VERSIONS;
- public final String name;
- public final int protocol;
+ @LauncherAPI
+ public enum Version {
+ MC164("1.6.4", 78), MC172("1.7.2", 4), MC1710("1.7.10", 5), MC189("1.8.9", 47), MC194("1.9.4", 110), MC1102("1.10.2", 210);
+ private static final Map VERSIONS;
+ public final String name;
+ public final int protocol;
- Version(String name, int protocol) {
- this.name = name;
- this.protocol = protocol;
- }
+ Version(String name, int protocol) {
+ this.name = name;
+ this.protocol = protocol;
+ }
- @Override
- public String toString() {
- return "Minecraft " + name;
- }
+ @Override
+ public String toString() {
+ return "Minecraft " + name;
+ }
- public static Version byName(String name) {
- return VerifyHelper.getMapValue(VERSIONS, name, String.format("Unknown client version: '%s'", name));
- }
+ public static Version byName(String name) {
+ return VerifyHelper.getMapValue(VERSIONS, name, String.format("Unknown client version: '%s'", name));
+ }
- static {
- Version[] versionsValues = values();
- VERSIONS = new HashMap<>(versionsValues.length);
- for (Version version : versionsValues) {
- VERSIONS.put(version.name, version);
- }
- }
- }
+ static {
+ Version[] versionsValues = values();
+ VERSIONS = new HashMap<>(versionsValues.length);
+ for (Version version : versionsValues) {
+ VERSIONS.put(version.name, version);
+ }
+ }
+ }
}
diff --git a/Launcher/source/client/PlayerProfile.java b/Launcher/source/client/PlayerProfile.java
index 89dea4f..1916b98 100644
--- a/Launcher/source/client/PlayerProfile.java
+++ b/Launcher/source/client/PlayerProfile.java
@@ -8,84 +8,85 @@
import launcher.LauncherAPI;
import launcher.helper.IOHelper;
import launcher.helper.SecurityHelper;
+import launcher.helper.SecurityHelper.DigestAlgorithm;
import launcher.helper.VerifyHelper;
import launcher.serialize.HInput;
import launcher.serialize.HOutput;
import launcher.serialize.stream.StreamObject;
public final class PlayerProfile extends StreamObject {
- @LauncherAPI public final UUID uuid;
- @LauncherAPI public final String username;
- @LauncherAPI public final Texture skin, cloak;
+ @LauncherAPI public final UUID uuid;
+ @LauncherAPI public final String username;
+ @LauncherAPI public final Texture skin, cloak;
- @LauncherAPI
- public PlayerProfile(HInput input) throws IOException {
- uuid = input.readUUID();
- username = VerifyHelper.verifyUsername(input.readASCII(16));
- skin = input.readBoolean() ? new Texture(input) : null;
- cloak = input.readBoolean() ? new Texture(input) : null;
- }
+ @LauncherAPI
+ public PlayerProfile(HInput input) throws IOException {
+ uuid = input.readUUID();
+ username = VerifyHelper.verifyUsername(input.readASCII(16));
+ skin = input.readBoolean() ? new Texture(input) : null;
+ cloak = input.readBoolean() ? new Texture(input) : null;
+ }
- @LauncherAPI
- public PlayerProfile(UUID uuid, String username, Texture skin, Texture cloak) {
- this.uuid = Objects.requireNonNull(uuid, "uuid");
- this.username = VerifyHelper.verifyUsername(username);
- this.skin = skin;
- this.cloak = cloak;
- }
+ @LauncherAPI
+ public PlayerProfile(UUID uuid, String username, Texture skin, Texture cloak) {
+ this.uuid = Objects.requireNonNull(uuid, "uuid");
+ this.username = VerifyHelper.verifyUsername(username);
+ this.skin = skin;
+ this.cloak = cloak;
+ }
- @Override
- public void write(HOutput output) throws IOException {
- output.writeUUID(uuid);
- output.writeASCII(username, 16);
+ @Override
+ public void write(HOutput output) throws IOException {
+ output.writeUUID(uuid);
+ output.writeASCII(username, 16);
- // Write textures
- output.writeBoolean(skin != null);
- if (skin != null) {
- skin.write(output);
- }
- output.writeBoolean(cloak != null);
- if (cloak != null) {
- cloak.write(output);
- }
- }
+ // Write textures
+ output.writeBoolean(skin != null);
+ if (skin != null) {
+ skin.write(output);
+ }
+ output.writeBoolean(cloak != null);
+ if (cloak != null) {
+ cloak.write(output);
+ }
+ }
- @LauncherAPI
- public static PlayerProfile newOfflineProfile(String username) {
- return new PlayerProfile(offlineUUID(username), username, null, null);
- }
+ @LauncherAPI
+ public static PlayerProfile newOfflineProfile(String username) {
+ return new PlayerProfile(offlineUUID(username), username, null, null);
+ }
- @LauncherAPI
- public static UUID offlineUUID(String username) {
- return UUID.nameUUIDFromBytes(IOHelper.encodeASCII("OfflinePlayer:" + username));
- }
+ @LauncherAPI
+ public static UUID offlineUUID(String username) {
+ return UUID.nameUUIDFromBytes(IOHelper.encodeASCII("OfflinePlayer:" + username));
+ }
- public static final class Texture extends StreamObject {
- @LauncherAPI public final String url;
- @LauncherAPI public final byte[] digest;
+ public static final class Texture extends StreamObject {
+ @LauncherAPI public final String url;
+ @LauncherAPI public final byte[] digest;
- @LauncherAPI
- public Texture(String url, byte[] digest) {
- this.url = IOHelper.verifyURL(url);
- this.digest = Objects.requireNonNull(digest, "digest");
- }
+ @LauncherAPI
+ public Texture(String url, byte[] digest) {
+ this.url = IOHelper.verifyURL(url);
+ this.digest = Objects.requireNonNull(digest, "digest");
+ }
- @LauncherAPI
- public Texture(String url) throws IOException {
- this.url = IOHelper.verifyURL(url);
- digest = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256, new URL(url));
- }
+ @LauncherAPI
+ public Texture(String url) throws IOException {
+ this.url = IOHelper.verifyURL(url);
+ digest = SecurityHelper.digest(DigestAlgorithm.SHA256, new URL(url));
+ }
- @LauncherAPI
- public Texture(HInput input) throws IOException {
- this.url = IOHelper.verifyURL(input.readASCII(2048));
- this.digest = input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH);
- }
+ @LauncherAPI
+ public Texture(HInput input) throws IOException {
+ url = IOHelper.verifyURL(input.readASCII(2048));
+ digest = input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH);
+ }
- @Override
- public void write(HOutput output) throws IOException {
- output.writeASCII(url, 2048);
- output.writeByteArray(digest, SecurityHelper.CRYPTO_MAX_LENGTH);
- }
- }
+ @Override
+ public void write(HOutput output) throws IOException {
+ output.writeASCII(url, 2048);
+ output.writeByteArray(digest, SecurityHelper.CRYPTO_MAX_LENGTH);
+ }
+ }
}
diff --git a/Launcher/source/client/ServerPinger.java b/Launcher/source/client/ServerPinger.java
index eb5ce23..c5ccdb3 100644
--- a/Launcher/source/client/ServerPinger.java
+++ b/Launcher/source/client/ServerPinger.java
@@ -1,14 +1,5 @@
package launcher.client;
-import com.eclipsesource.json.Json;
-import com.eclipsesource.json.JsonObject;
-import launcher.LauncherAPI;
-import launcher.helper.IOHelper;
-import launcher.helper.LogHelper;
-import launcher.helper.VerifyHelper;
-import launcher.serialize.HInput;
-import launcher.serialize.HOutput;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
@@ -18,185 +9,195 @@
import java.time.Instant;
import java.util.regex.Pattern;
+import com.eclipsesource.json.Json;
+import com.eclipsesource.json.JsonObject;
+import launcher.LauncherAPI;
+import launcher.client.ClientProfile.Version;
+import launcher.helper.IOHelper;
+import launcher.helper.LogHelper;
+import launcher.helper.VerifyHelper;
+import launcher.serialize.HInput;
+import launcher.serialize.HOutput;
+
public final class ServerPinger {
- // Constants
- private static final String LEGACY_PING_HOST_MAGIC = "§1";
- private static final String LEGACY_PING_HOST_CHANNEL = "MC|PingHost";
- private static final Pattern LEGACY_PING_HOST_DELIMETER = Pattern.compile("\0", Pattern.LITERAL);
- private static final int PACKET_LENGTH = 65535;
+ // Constants
+ private static final String LEGACY_PING_HOST_MAGIC = "§1";
+ private static final String LEGACY_PING_HOST_CHANNEL = "MC|PingHost";
+ private static final Pattern LEGACY_PING_HOST_DELIMETER = Pattern.compile("\0", Pattern.LITERAL);
+ private static final int PACKET_LENGTH = 65535;
- // Instance
- private final InetSocketAddress address;
- private final ClientProfile.Version version;
+ // Instance
+ private final InetSocketAddress address;
+ private final Version version;
- // Cache
- private final Object cacheLock = new Object();
- private Result cache;
- private Instant cacheTime;
+ // Cache
+ private final Object cacheLock = new Object();
+ private Result cache;
+ private Instant cacheTime;
- @LauncherAPI
- public ServerPinger(InetSocketAddress address, ClientProfile.Version version) {
- this.address = address;
- this.version = version;
- }
+ @LauncherAPI
+ public ServerPinger(InetSocketAddress address, Version version) {
+ this.address = address;
+ this.version = version;
+ }
- @LauncherAPI
- public Result ping() throws IOException {
- Instant now = Instant.now();
- synchronized (cacheLock) {
- if (cache == null || cacheTime == null || Duration.between(now, cacheTime).getSeconds() >= 30) {
- cache = doPing();
- cacheTime = now;
- }
- return cache;
- }
- }
+ @LauncherAPI
+ public Result ping() throws IOException {
+ Instant now = Instant.now();
+ synchronized (cacheLock) {
+ if (cache == null || cacheTime == null || Duration.between(now, cacheTime).getSeconds() >= 30) {
+ cache = doPing();
+ cacheTime = now;
+ }
+ return cache;
+ }
+ }
- private Result doPing() throws IOException {
- try (Socket socket = IOHelper.newSocket()) {
- socket.connect(IOHelper.resolve(address), IOHelper.SOCKET_TIMEOUT);
- try (HInput input = new HInput(socket.getInputStream());
- HOutput output = new HOutput(socket.getOutputStream())) {
- return version.compareTo(ClientProfile.Version.MC172) >= 0 ?
- modernPing(input, output) : legacyPing(input, output);
- }
- }
- }
+ private Result doPing() throws IOException {
+ try (Socket socket = IOHelper.newSocket()) {
+ socket.connect(IOHelper.resolve(address), IOHelper.SOCKET_TIMEOUT);
+ try (HInput input = new HInput(socket.getInputStream());
+ HOutput output = new HOutput(socket.getOutputStream())) {
+ return version.compareTo(Version.MC172) >= 0 ?
+ modernPing(input, output) : legacyPing(input, output);
+ }
+ }
+ }
- private Result legacyPing(HInput input, HOutput output) throws IOException {
- output.writeUnsignedByte(0xFE); // 254 packet ID, Server list ping
- output.writeUnsignedByte(0x01); // Server ping payload
- output.writeUnsignedByte(0xFA); // 250 packet ID, Custom payload
- writeUTF16String(output, LEGACY_PING_HOST_CHANNEL); // Custom payload name
+ private Result legacyPing(HInput input, HOutput output) throws IOException {
+ output.writeUnsignedByte(0xFE); // 254 packet ID, Server list ping
+ output.writeUnsignedByte(0x01); // Server ping payload
+ output.writeUnsignedByte(0xFA); // 250 packet ID, Custom payload
+ writeUTF16String(output, LEGACY_PING_HOST_CHANNEL); // Custom payload name
- // Prepare custom payload packet
- byte[] customPayloadPacket;
- try (ByteArrayOutputStream packetArray = IOHelper.newByteArrayOutput()) {
- try (HOutput packetOutput = new HOutput(packetArray)) {
- packetOutput.writeUnsignedByte(version.protocol); // Protocol version
- writeUTF16String(packetOutput, address.getHostString()); // Server address
- packetOutput.writeInt(address.getPort()); // Server port
- }
- customPayloadPacket = packetArray.toByteArray();
- }
+ // Prepare custom payload packet
+ byte[] customPayloadPacket;
+ try (ByteArrayOutputStream packetArray = IOHelper.newByteArrayOutput()) {
+ try (HOutput packetOutput = new HOutput(packetArray)) {
+ packetOutput.writeUnsignedByte(version.protocol); // Protocol version
+ writeUTF16String(packetOutput, address.getHostString()); // Server address
+ packetOutput.writeInt(address.getPort()); // Server port
+ }
+ customPayloadPacket = packetArray.toByteArray();
+ }
- // Write custom payload packet
- output.writeShort((short) customPayloadPacket.length);
- output.stream.write(customPayloadPacket);
- output.flush();
+ // Write custom payload packet
+ output.writeShort((short) customPayloadPacket.length);
+ output.stream.write(customPayloadPacket);
+ output.flush();
- // Raed kick (response) packet
- int kickPacketID = input.readUnsignedByte();
- if (kickPacketID != 0xFF) {
- throw new IOException("Illegal kick packet ID: " + kickPacketID);
- }
+ // Raed kick (response) packet
+ int kickPacketID = input.readUnsignedByte();
+ if (kickPacketID != 0xFF) {
+ throw new IOException("Illegal kick packet ID: " + kickPacketID);
+ }
- // Read and parse response
- String response = readUTF16String(input);
- LogHelper.debug("Ping response (legacy): '%s'", response);
- String[] splitted = LEGACY_PING_HOST_DELIMETER.split(response);
- if (splitted.length != 6) {
- throw new IOException("Tokens count mismatch");
- }
+ // Read and parse response
+ String response = readUTF16String(input);
+ LogHelper.debug("Ping response (legacy): '%s'", response);
+ String[] splitted = LEGACY_PING_HOST_DELIMETER.split(response);
+ if (splitted.length != 6) {
+ throw new IOException("Tokens count mismatch");
+ }
- // Verify all parts
- String magic = splitted[0];
- if (!magic.equals(LEGACY_PING_HOST_MAGIC)) {
- throw new IOException("Magic string mismatch: " + magic);
- }
- int protocol = Integer.parseInt(splitted[1]);
- if (protocol != version.protocol) {
- throw new IOException("Protocol mismatch: " + protocol);
- }
- String clientVersion = splitted[2];
- if (!clientVersion.equals(version.name)) {
- throw new IOException(String.format("Version mismatch: '%s'", clientVersion));
- }
- int onlinePlayers = VerifyHelper.verifyInt(Integer.parseInt(splitted[4]),
- VerifyHelper.NOT_NEGATIVE, "onlinePlayers can't be < 0");
- int maxPlayers = VerifyHelper.verifyInt(Integer.parseInt(splitted[5]),
- VerifyHelper.NOT_NEGATIVE, "maxPlayers can't be < 0");
+ // Verify all parts
+ String magic = splitted[0];
+ if (!magic.equals(LEGACY_PING_HOST_MAGIC)) {
+ throw new IOException("Magic string mismatch: " + magic);
+ }
+ int protocol = Integer.parseInt(splitted[1]);
+ if (protocol != version.protocol) {
+ throw new IOException("Protocol mismatch: " + protocol);
+ }
+ String clientVersion = splitted[2];
+ if (!clientVersion.equals(version.name)) {
+ throw new IOException(String.format("Version mismatch: '%s'", clientVersion));
+ }
+ int onlinePlayers = VerifyHelper.verifyInt(Integer.parseInt(splitted[4]),
+ VerifyHelper.NOT_NEGATIVE, "onlinePlayers can't be < 0");
+ int maxPlayers = VerifyHelper.verifyInt(Integer.parseInt(splitted[5]),
+ VerifyHelper.NOT_NEGATIVE, "maxPlayers can't be < 0");
- // Return ping status
- return new Result(onlinePlayers, maxPlayers, response);
- }
+ // Return ping status
+ return new Result(onlinePlayers, maxPlayers, response);
+ }
- private Result modernPing(HInput input, HOutput output) throws IOException {
- // Prepare handshake packet
- byte[] handshakePacket;
- try (ByteArrayOutputStream packetArray = IOHelper.newByteArrayOutput()) {
- try (HOutput packetOutput = new HOutput(packetArray)) {
- packetOutput.writeVarInt(0x0); // Handshake packet ID
- packetOutput.writeVarInt(version.protocol); // Protocol version
- packetOutput.writeString(address.getHostString(), 0); // Server address
- packetOutput.writeShort((short) address.getPort()); // Server port
- packetOutput.writeVarInt(0x1); // Next state - status
- }
- handshakePacket = packetArray.toByteArray();
- }
+ private Result modernPing(HInput input, HOutput output) throws IOException {
+ // Prepare handshake packet
+ byte[] handshakePacket;
+ try (ByteArrayOutputStream packetArray = IOHelper.newByteArrayOutput()) {
+ try (HOutput packetOutput = new HOutput(packetArray)) {
+ packetOutput.writeVarInt(0x0); // Handshake packet ID
+ packetOutput.writeVarInt(version.protocol); // Protocol version
+ packetOutput.writeString(address.getHostString(), 0); // Server address
+ packetOutput.writeShort((short) address.getPort()); // Server port
+ packetOutput.writeVarInt(0x1); // Next state - status
+ }
+ handshakePacket = packetArray.toByteArray();
+ }
- // Write handshake packet
- output.writeByteArray(handshakePacket, PACKET_LENGTH);
+ // Write handshake packet
+ output.writeByteArray(handshakePacket, PACKET_LENGTH);
- // Request status packet
- output.writeVarInt(1); // Status packet size (single byte)
- output.writeVarInt(0x0); // Status packet ID
- output.flush();
+ // Request status packet
+ output.writeVarInt(1); // Status packet size (single byte)
+ output.writeVarInt(0x0); // Status packet ID
+ output.flush();
- // Read outer status response packet ID
- // ab is a dirty fix for some servers (noticed KCauldron 1.7.10)
- String response;
- int ab = IOHelper.verifyLength(input.readVarInt(), PACKET_LENGTH);
- byte[] statusPacket = ab == 0x0 ? input.readByteArray(PACKET_LENGTH) : input.readByteArray(-ab);
- try (HInput packetInput = new HInput(statusPacket)) {
- int statusPacketID = packetInput.readVarInt();
- if (statusPacketID != 0x0) {
- throw new IOException("Illegal status packet ID: " + statusPacketID);
- }
- response = packetInput.readString(PACKET_LENGTH);
- LogHelper.debug("Ping response (modern): '%s'", response);
- }
+ // Read outer status response packet ID
+ // ab is a dirty fix for some servers (noticed KCauldron 1.7.10)
+ String response;
+ int ab = IOHelper.verifyLength(input.readVarInt(), PACKET_LENGTH);
+ byte[] statusPacket = input.readByteArray(ab == 0x0 ? PACKET_LENGTH : -ab);
+ try (HInput packetInput = new HInput(statusPacket)) {
+ int statusPacketID = packetInput.readVarInt();
+ if (statusPacketID != 0x0) {
+ throw new IOException("Illegal status packet ID: " + statusPacketID);
+ }
+ response = packetInput.readString(PACKET_LENGTH);
+ LogHelper.debug("Ping response (modern): '%s'", response);
+ }
- // Parse JSON response
- JsonObject object = Json.parse(response).asObject();
- JsonObject playersObject = object.get("players").asObject();
- int online = playersObject.get("online").asInt();
- int max = playersObject.get("max").asInt();
+ // Parse JSON response
+ JsonObject object = Json.parse(response).asObject();
+ JsonObject playersObject = object.get("players").asObject();
+ int online = playersObject.get("online").asInt();
+ int max = playersObject.get("max").asInt();
- // Return ping status
- return new Result(online, max, response);
- }
+ // Return ping status
+ return new Result(online, max, response);
+ }
- private static String readUTF16String(HInput input) throws IOException {
- int length = input.readUnsignedShort() << 1;
- byte[] encoded = input.readByteArray(-length);
- return new String(encoded, StandardCharsets.UTF_16BE);
- }
+ private static String readUTF16String(HInput input) throws IOException {
+ int length = input.readUnsignedShort() << 1;
+ byte[] encoded = input.readByteArray(-length);
+ return new String(encoded, StandardCharsets.UTF_16BE);
+ }
- private static void writeUTF16String(HOutput output, String s) throws IOException {
- output.writeShort((short) s.length());
- output.stream.write(s.getBytes(StandardCharsets.UTF_16BE));
- }
+ private static void writeUTF16String(HOutput output, String s) throws IOException {
+ output.writeShort((short) s.length());
+ output.stream.write(s.getBytes(StandardCharsets.UTF_16BE));
+ }
- public static final class Result {
- private static final Pattern CODES_PATTERN = Pattern.compile("§[0-9a-fkmnor]", Pattern.CASE_INSENSITIVE);
+ public static final class Result {
+ private static final Pattern CODES_PATTERN = Pattern.compile("§[0-9a-fkmnor]", Pattern.CASE_INSENSITIVE);
- // Instance
- @LauncherAPI public final int onlinePlayers;
- @LauncherAPI public final int maxPlayers;
- @LauncherAPI public final String raw;
+ // Instance
+ @LauncherAPI public final int onlinePlayers;
+ @LauncherAPI public final int maxPlayers;
+ @LauncherAPI public final String raw;
- public Result(int onlinePlayers, int maxPlayers, String raw) {
- this.onlinePlayers = VerifyHelper.verifyInt(onlinePlayers,
- VerifyHelper.NOT_NEGATIVE, "onlinePlayers can't be < 0");
- this.maxPlayers = VerifyHelper.verifyInt(maxPlayers,
- VerifyHelper.NOT_NEGATIVE, "maxPlayers can't be < 0");
- this.raw = raw;
- }
+ public Result(int onlinePlayers, int maxPlayers, String raw) {
+ this.onlinePlayers = VerifyHelper.verifyInt(onlinePlayers,
+ VerifyHelper.NOT_NEGATIVE, "onlinePlayers can't be < 0");
+ this.maxPlayers = VerifyHelper.verifyInt(maxPlayers,
+ VerifyHelper.NOT_NEGATIVE, "maxPlayers can't be < 0");
+ this.raw = raw;
+ }
- @LauncherAPI
- public boolean isOverfilled() {
- return onlinePlayers >= maxPlayers;
- }
- }
+ @LauncherAPI
+ public boolean isOverfilled() {
+ return onlinePlayers >= maxPlayers;
+ }
+ }
}
diff --git a/Launcher/source/hasher/DirWatcher.java b/Launcher/source/hasher/DirWatcher.java
index d165135..282267f 100644
--- a/Launcher/source/hasher/DirWatcher.java
+++ b/Launcher/source/hasher/DirWatcher.java
@@ -7,6 +7,8 @@
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchEvent.Modifier;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.attribute.BasicFileAttributes;
@@ -18,142 +20,144 @@
import com.sun.nio.file.ExtendedWatchEventModifier;
import com.sun.nio.file.SensitivityWatchEventModifier;
import launcher.LauncherAPI;
+import launcher.hasher.HashedEntry.Type;
import launcher.helper.IOHelper;
import launcher.helper.JVMHelper;
+import launcher.helper.JVMHelper.OS;
import launcher.helper.LogHelper;
public final class DirWatcher implements Runnable, AutoCloseable {
- private static final boolean FILE_TREE_SUPPORTED = JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE;
+ private static final boolean FILE_TREE_SUPPORTED = JVMHelper.OS_TYPE == OS.MUSTDIE;
- // Constants
- private static final WatchEvent.Modifier[] MODIFIERS = { SensitivityWatchEventModifier.HIGH };
- private static final WatchEvent.Modifier[] FILE_TREE_MODIFIERS = {
- ExtendedWatchEventModifier.FILE_TREE, SensitivityWatchEventModifier.HIGH
- };
- private static final WatchEvent.Kind>[] KINDS = {
- StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE
- };
+ // Constants
+ private static final Modifier[] MODIFIERS = { SensitivityWatchEventModifier.HIGH };
+ private static final Modifier[] FILE_TREE_MODIFIERS = {
+ ExtendedWatchEventModifier.FILE_TREE, SensitivityWatchEventModifier.HIGH
+ };
+ private static final Kind>[] KINDS = {
+ StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE
+ };
- // Instance
- private final Path dir;
- private final HashedDir hdir;
- private final FileNameMatcher matcher;
- private final WatchService service;
+ // Instance
+ private final Path dir;
+ private final HashedDir hdir;
+ private final FileNameMatcher matcher;
+ private final WatchService service;
- @LauncherAPI
- public DirWatcher(Path dir, HashedDir hdir, FileNameMatcher matcher) throws IOException {
- this.dir = Objects.requireNonNull(dir, "dir");
- this.hdir = Objects.requireNonNull(hdir, "hdir");
- this.matcher = matcher;
- service = dir.getFileSystem().newWatchService();
+ @LauncherAPI
+ public DirWatcher(Path dir, HashedDir hdir, FileNameMatcher matcher) throws IOException {
+ this.dir = Objects.requireNonNull(dir, "dir");
+ this.hdir = Objects.requireNonNull(hdir, "hdir");
+ this.matcher = matcher;
+ service = dir.getFileSystem().newWatchService();
- // Use FILE_TREE if supported
- if (FILE_TREE_SUPPORTED) {
- dir.register(service, KINDS, FILE_TREE_MODIFIERS);
- return;
- }
+ // Use FILE_TREE if supported
+ if (FILE_TREE_SUPPORTED) {
+ dir.register(service, KINDS, FILE_TREE_MODIFIERS);
+ return;
+ }
- // Register dirs recursively
- IOHelper.walk(dir, new RegisterFileVisitor(), true);
- }
+ // Register dirs recursively
+ IOHelper.walk(dir, new RegisterFileVisitor(), true);
+ }
- @Override
- @LauncherAPI
- public void close() throws IOException {
- service.close();
- }
+ @Override
+ @LauncherAPI
+ public void close() throws IOException {
+ service.close();
+ }
- @Override
- @LauncherAPI
- public void run() {
- try {
- processLoop();
- } catch (InterruptedException | ClosedWatchServiceException ignored) {
- // Do nothing (closed etc)
- } catch (Throwable exc) {
- handleError(exc);
- }
- }
+ @Override
+ @LauncherAPI
+ public void run() {
+ try {
+ processLoop();
+ } catch (InterruptedException | ClosedWatchServiceException ignored) {
+ // Do nothing (closed etc)
+ } catch (Throwable exc) {
+ handleError(exc);
+ }
+ }
- private void processKey(WatchKey key) throws IOException {
- Path watchDir = (Path) key.watchable();
- Collection> events = key.pollEvents();
- for (WatchEvent> event : events) {
- WatchEvent.Kind> kind = event.kind();
- if (kind.equals(StandardWatchEventKinds.OVERFLOW)) {
- throw new IOException("Overflow");
- }
+ private void processKey(WatchKey key) throws IOException {
+ Path watchDir = (Path) key.watchable();
+ Collection> events = key.pollEvents();
+ for (WatchEvent> event : events) {
+ Kind> kind = event.kind();
+ if (kind.equals(StandardWatchEventKinds.OVERFLOW)) {
+ throw new IOException("Overflow");
+ }
- // Resolve paths and verify is not exclusion
- Path path = watchDir.resolve((Path) event.context());
- Deque stringPath = toPath(dir.relativize(path));
- if (matcher != null && !matcher.shouldVerify(stringPath)) {
- continue; // Exclusion; should not be verified
- }
+ // Resolve paths and verify is not exclusion
+ Path path = watchDir.resolve((Path) event.context());
+ Deque stringPath = toPath(dir.relativize(path));
+ if (matcher != null && !matcher.shouldVerify(stringPath)) {
+ continue; // Exclusion; should not be verified
+ }
- // Verify is REALLY modified (not just attributes)
- if (kind.equals(StandardWatchEventKinds.ENTRY_MODIFY)) {
- HashedEntry entry = hdir.resolve(stringPath);
- if (entry != null && (entry.getType() != HashedEntry.Type.FILE || ((HashedFile) entry).isSame(path))) {
- continue; // Modified attributes, not need to worry :D
- }
- }
+ // Verify is REALLY modified (not just attributes)
+ if (kind.equals(StandardWatchEventKinds.ENTRY_MODIFY)) {
+ HashedEntry entry = hdir.resolve(stringPath);
+ if (entry != null && (entry.getType() != Type.FILE || ((HashedFile) entry).isSame(path))) {
+ continue; // Modified attributes, not need to worry :D
+ }
+ }
- // Forbidden modification!
- throw new SecurityException(String.format("Forbidden modification (%s, %d times): '%s'",
- kind, event.count(), path));
- }
- key.reset();
- }
+ // Forbidden modification!
+ throw new SecurityException(String.format("Forbidden modification (%s, %d times): '%s'",
+ kind, event.count(), path));
+ }
+ key.reset();
+ }
- private void processLoop() throws IOException, InterruptedException {
- while (!Thread.interrupted()) {
- processKey(service.take());
- }
- }
+ private void processLoop() throws IOException, InterruptedException {
+ while (!Thread.interrupted()) {
+ processKey(service.take());
+ }
+ }
- private static void handleError(Throwable e) {
- LogHelper.error(e);
- JVMHelper.halt0(0x0BADFEE1);
- }
+ private static void handleError(Throwable e) {
+ LogHelper.error(e);
+ JVMHelper.halt0(0x0BADFEE1);
+ }
- private static Deque toPath(Iterable path) {
- Deque result = new LinkedList<>();
- for (Path pe : path) {
- result.add(pe.toString());
- }
- return result;
- }
+ private static Deque toPath(Iterable path) {
+ Deque result = new LinkedList<>();
+ for (Path pe : path) {
+ result.add(pe.toString());
+ }
+ return result;
+ }
- private final class RegisterFileVisitor extends SimpleFileVisitor {
- private final Deque path = new LinkedList<>();
+ private final class RegisterFileVisitor extends SimpleFileVisitor {
+ private final Deque path = new LinkedList<>();
- @Override
- public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
- FileVisitResult result = super.postVisitDirectory(dir, exc);
- if (!DirWatcher.this.dir.equals(dir)) {
- path.removeLast();
- }
- return result;
- }
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ FileVisitResult result = super.postVisitDirectory(dir, exc);
+ if (!DirWatcher.this.dir.equals(dir)) {
+ path.removeLast();
+ }
+ return result;
+ }
- @Override
- public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
- FileVisitResult result = super.preVisitDirectory(dir, attrs);
- if (DirWatcher.this.dir.equals(dir)) {
- dir.register(service, KINDS, MODIFIERS);
- return result;
- }
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ FileVisitResult result = super.preVisitDirectory(dir, attrs);
+ if (DirWatcher.this.dir.equals(dir)) {
+ dir.register(service, KINDS, MODIFIERS);
+ return result;
+ }
- // Maybe it's unnecessary to go deeper
- path.add(IOHelper.getFileName(dir));
- if (matcher != null && !matcher.shouldVerify(path)) {
- return FileVisitResult.SKIP_SUBTREE;
- }
+ // Maybe it's unnecessary to go deeper
+ path.add(IOHelper.getFileName(dir));
+ if (matcher != null && !matcher.shouldVerify(path)) {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
- // Register
- dir.register(service, KINDS, MODIFIERS);
- return result;
- }
- }
+ // Register
+ dir.register(service, KINDS, MODIFIERS);
+ return result;
+ }
+ }
}
diff --git a/Launcher/source/hasher/FileNameMatcher.java b/Launcher/source/hasher/FileNameMatcher.java
index 3b0bdb0..f0a2db4 100644
--- a/Launcher/source/hasher/FileNameMatcher.java
+++ b/Launcher/source/hasher/FileNameMatcher.java
@@ -9,73 +9,73 @@
import launcher.helper.IOHelper;
public final class FileNameMatcher {
- private static final Entry[] NO_ENTRIES = new Entry[0];
+ private static final Entry[] NO_ENTRIES = new Entry[0];
- // Instance
- private final Entry[] update;
- private final Entry[] verify;
- private final Entry[] exclusions;
+ // Instance
+ private final Entry[] update;
+ private final Entry[] verify;
+ private final Entry[] exclusions;
- @LauncherAPI
- public FileNameMatcher(String[] update, String[] verify, String[] exclusions) {
- this.update = toEntries(update);
- this.verify = toEntries(verify);
- this.exclusions = toEntries(exclusions);
- }
+ @LauncherAPI
+ public FileNameMatcher(String[] update, String[] verify, String[] exclusions) {
+ this.update = toEntries(update);
+ this.verify = toEntries(verify);
+ this.exclusions = toEntries(exclusions);
+ }
- private FileNameMatcher(Entry[] update, Entry[] verify, Entry[] exclusions) {
- this.update = update;
- this.verify = verify;
- this.exclusions = exclusions;
- }
+ private FileNameMatcher(Entry[] update, Entry[] verify, Entry[] exclusions) {
+ this.update = update;
+ this.verify = verify;
+ this.exclusions = exclusions;
+ }
- @LauncherAPI
- public boolean shouldUpdate(Collection path) {
- return (anyMatch(update, path) || anyMatch(verify, path)) && !anyMatch(exclusions, path);
- }
+ @LauncherAPI
+ public boolean shouldUpdate(Collection path) {
+ return (anyMatch(update, path) || anyMatch(verify, path)) && !anyMatch(exclusions, path);
+ }
- @LauncherAPI
- public boolean shouldVerify(Collection path) {
- return anyMatch(verify, path) && !anyMatch(exclusions, path);
- }
+ @LauncherAPI
+ public boolean shouldVerify(Collection path) {
+ return anyMatch(verify, path) && !anyMatch(exclusions, path);
+ }
- @LauncherAPI
- public FileNameMatcher verifyOnly() {
- return new FileNameMatcher(NO_ENTRIES, verify, exclusions);
- }
+ @LauncherAPI
+ public FileNameMatcher verifyOnly() {
+ return new FileNameMatcher(NO_ENTRIES, verify, exclusions);
+ }
- private static boolean anyMatch(Entry[] entries, Collection path) {
- return Arrays.stream(entries).anyMatch(e -> e.matches(path));
- }
+ private static boolean anyMatch(Entry[] entries, Collection path) {
+ return Arrays.stream(entries).anyMatch(e -> e.matches(path));
+ }
- private static Entry[] toEntries(String... entries) {
- return Arrays.stream(entries).map(Entry::new).toArray(Entry[]::new);
- }
+ private static Entry[] toEntries(String... entries) {
+ return Arrays.stream(entries).map(Entry::new).toArray(Entry[]::new);
+ }
- private static final class Entry {
- private static final Pattern SPLITTER = Pattern.compile(Pattern.quote(IOHelper.CROSS_SEPARATOR) + '+');
- private final Pattern[] parts;
+ private static final class Entry {
+ private static final Pattern SPLITTER = Pattern.compile(Pattern.quote(IOHelper.CROSS_SEPARATOR) + '+');
+ private final Pattern[] parts;
- private Entry(CharSequence exclusion) {
- parts = SPLITTER.splitAsStream(exclusion).map(Pattern::compile).toArray(Pattern[]::new);
- }
+ private Entry(CharSequence exclusion) {
+ parts = SPLITTER.splitAsStream(exclusion).map(Pattern::compile).toArray(Pattern[]::new);
+ }
- private boolean matches(Collection path) {
- if (parts.length > path.size()) {
- return false;
- }
+ private boolean matches(Collection path) {
+ if (parts.length > path.size()) {
+ return false;
+ }
- // Verify path parts
- Iterator iterator = path.iterator();
- for (Pattern patternPart : parts) {
- String pathPart = iterator.next();
- if (!patternPart.matcher(pathPart).matches()) {
- return false;
- }
- }
+ // Verify path parts
+ Iterator iterator = path.iterator();
+ for (Pattern patternPart : parts) {
+ String pathPart = iterator.next();
+ if (!patternPart.matcher(pathPart).matches()) {
+ return false;
+ }
+ }
- // All matches
- return true;
- }
- }
+ // All matches
+ return true;
+ }
+ }
}
diff --git a/Launcher/source/hasher/HashedDir.java b/Launcher/source/hasher/HashedDir.java
index ec6c3d9..6c989af 100644
--- a/Launcher/source/hasher/HashedDir.java
+++ b/Launcher/source/hasher/HashedDir.java
@@ -10,6 +10,7 @@
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import launcher.LauncherAPI;
@@ -20,237 +21,237 @@
import launcher.serialize.stream.EnumSerializer;
public final class HashedDir extends HashedEntry {
- private final Map map = new HashMap<>(32);
+ private final Map map = new HashMap<>(32);
- @LauncherAPI
- public HashedDir() {
- }
+ @LauncherAPI
+ public HashedDir() {
+ }
- @LauncherAPI
- public HashedDir(Path dir, FileNameMatcher matcher, boolean allowSymlinks) throws IOException {
- IOHelper.walk(dir, new HashFileVisitor(dir, matcher, allowSymlinks), true);
- }
+ @LauncherAPI
+ public HashedDir(Path dir, FileNameMatcher matcher, boolean allowSymlinks) throws IOException {
+ IOHelper.walk(dir, new HashFileVisitor(dir, matcher, allowSymlinks), true);
+ }
- @LauncherAPI
- public HashedDir(HInput input) throws IOException {
- int entriesCount = input.readLength(0);
- for (int i = 0; i < entriesCount; i++) {
- String name = IOHelper.verifyFileName(input.readString(255));
+ @LauncherAPI
+ public HashedDir(HInput input) throws IOException {
+ int entriesCount = input.readLength(0);
+ for (int i = 0; i < entriesCount; i++) {
+ String name = IOHelper.verifyFileName(input.readString(255));
- // Read entry
- HashedEntry entry;
- Type type = Type.read(input);
- switch (type) {
- case FILE:
- entry = new HashedFile(input);
- break;
- case DIR:
- entry = new HashedDir(input);
- break;
- default:
- throw new AssertionError("Unsupported hashed entry type: " + type.name());
- }
+ // Read entry
+ HashedEntry entry;
+ Type type = Type.read(input);
+ switch (type) {
+ case FILE:
+ entry = new HashedFile(input);
+ break;
+ case DIR:
+ entry = new HashedDir(input);
+ break;
+ default:
+ throw new AssertionError("Unsupported hashed entry type: " + type.name());
+ }
- // Try add entry to map
- VerifyHelper.putIfAbsent(map, name, entry, String.format("Duplicate dir entry: '%s'", name));
- }
- }
+ // Try add entry to map
+ VerifyHelper.putIfAbsent(map, name, entry, String.format("Duplicate dir entry: '%s'", name));
+ }
+ }
- @Override
- public Type getType() {
- return Type.DIR;
- }
+ @Override
+ public Type getType() {
+ return Type.DIR;
+ }
- @Override
- public long size() {
- return map.values().stream().mapToLong(HashedEntry::size).sum();
- }
+ @Override
+ public long size() {
+ return map.values().stream().mapToLong(HashedEntry::size).sum();
+ }
- @Override
- public void write(HOutput output) throws IOException {
- Set> entries = map.entrySet();
- output.writeLength(entries.size(), 0);
- for (Map.Entry mapEntry : entries) {
- output.writeString(mapEntry.getKey(), 255);
+ @Override
+ public void write(HOutput output) throws IOException {
+ Set> entries = map.entrySet();
+ output.writeLength(entries.size(), 0);
+ for (Entry mapEntry : entries) {
+ output.writeString(mapEntry.getKey(), 255);
- // Write hashed entry
- HashedEntry entry = mapEntry.getValue();
- EnumSerializer.write(output, entry.getType());
- entry.write(output);
- }
- }
+ // Write hashed entry
+ HashedEntry entry = mapEntry.getValue();
+ EnumSerializer.write(output, entry.getType());
+ entry.write(output);
+ }
+ }
- @LauncherAPI
- public Diff diff(HashedDir other, FileNameMatcher matcher) {
- HashedDir mismatch = sideDiff(other, matcher, new LinkedList<>(), true);
- HashedDir extra = other.sideDiff(this, matcher, new LinkedList<>(), false);
- return new Diff(mismatch, extra);
- }
+ @LauncherAPI
+ public Diff diff(HashedDir other, FileNameMatcher matcher) {
+ HashedDir mismatch = sideDiff(other, matcher, new LinkedList<>(), true);
+ HashedDir extra = other.sideDiff(this, matcher, new LinkedList<>(), false);
+ return new Diff(mismatch, extra);
+ }
- @LauncherAPI
- public HashedEntry getEntry(String name) {
- return map.get(name);
- }
+ @LauncherAPI
+ public HashedEntry getEntry(String name) {
+ return map.get(name);
+ }
- @LauncherAPI
- public boolean isEmpty() {
- return map.isEmpty();
- }
+ @LauncherAPI
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
- @LauncherAPI
- public Map map() {
- return Collections.unmodifiableMap(map);
- }
+ @LauncherAPI
+ public Map map() {
+ return Collections.unmodifiableMap(map);
+ }
- @LauncherAPI
- public HashedEntry resolve(Iterable path) {
- HashedEntry current = this;
- for (String pathEntry : path) {
- if (current instanceof HashedDir) {
- current = ((HashedDir) current).map.get(pathEntry);
- continue;
- }
- return null;
- }
- return current;
- }
+ @LauncherAPI
+ public HashedEntry resolve(Iterable path) {
+ HashedEntry current = this;
+ for (String pathEntry : path) {
+ if (current instanceof HashedDir) {
+ current = ((HashedDir) current).map.get(pathEntry);
+ continue;
+ }
+ return null;
+ }
+ return current;
+ }
- private HashedDir sideDiff(HashedDir other, FileNameMatcher matcher, Deque path, boolean mismatchList) {
- HashedDir diff = new HashedDir();
- for (Map.Entry mapEntry : map.entrySet()) {
- String name = mapEntry.getKey();
- HashedEntry entry = mapEntry.getValue();
- path.add(name);
+ private HashedDir sideDiff(HashedDir other, FileNameMatcher matcher, Deque path, boolean mismatchList) {
+ HashedDir diff = new HashedDir();
+ for (Entry mapEntry : map.entrySet()) {
+ String name = mapEntry.getKey();
+ HashedEntry entry = mapEntry.getValue();
+ path.add(name);
- // Should update?
- boolean shouldUpdate = matcher == null || matcher.shouldUpdate(path);
+ // Should update?
+ boolean shouldUpdate = matcher == null || matcher.shouldUpdate(path);
- // Not found or of different type
- Type type = entry.getType();
- HashedEntry otherEntry = other.map.get(name);
- if (otherEntry == null || otherEntry.getType() != type) {
- if (shouldUpdate || mismatchList && otherEntry == null) {
- diff.map.put(name, entry);
+ // Not found or of different type
+ Type type = entry.getType();
+ HashedEntry otherEntry = other.map.get(name);
+ if (otherEntry == null || otherEntry.getType() != type) {
+ if (shouldUpdate || mismatchList && otherEntry == null) {
+ diff.map.put(name, entry);
- // Should be deleted!
- if (!mismatchList) {
- entry.flag = true;
- }
- }
- path.removeLast();
- continue;
- }
+ // Should be deleted!
+ if (!mismatchList) {
+ entry.flag = true;
+ }
+ }
+ path.removeLast();
+ continue;
+ }
- // Compare entries based on type
- switch (type) {
- case FILE:
- HashedFile file = (HashedFile) entry;
- HashedFile otherFile = (HashedFile) otherEntry;
- if (mismatchList && shouldUpdate && !file.isSame(otherFile)) {
- diff.map.put(name, entry);
- }
- break;
- case DIR:
- HashedDir dir = (HashedDir) entry;
- HashedDir otherDir = (HashedDir) otherEntry;
- if (mismatchList || shouldUpdate) { // Maybe isn't need to go deeper?
- HashedDir mismatch = dir.sideDiff(otherDir, matcher, path, mismatchList);
- if (!mismatch.isEmpty()) {
- diff.map.put(name, mismatch);
- }
- }
- break;
- default:
- throw new AssertionError("Unsupported hashed entry type: " + type.name());
- }
+ // Compare entries based on type
+ switch (type) {
+ case FILE:
+ HashedFile file = (HashedFile) entry;
+ HashedFile otherFile = (HashedFile) otherEntry;
+ if (mismatchList && shouldUpdate && !file.isSame(otherFile)) {
+ diff.map.put(name, entry);
+ }
+ break;
+ case DIR:
+ HashedDir dir = (HashedDir) entry;
+ HashedDir otherDir = (HashedDir) otherEntry;
+ if (mismatchList || shouldUpdate) { // Maybe isn't need to go deeper?
+ HashedDir mismatch = dir.sideDiff(otherDir, matcher, path, mismatchList);
+ if (!mismatch.isEmpty()) {
+ diff.map.put(name, mismatch);
+ }
+ }
+ break;
+ default:
+ throw new AssertionError("Unsupported hashed entry type: " + type.name());
+ }
- // Remove this path entry
- path.removeLast();
- }
- return diff;
- }
+ // Remove this path entry
+ path.removeLast();
+ }
+ return diff;
+ }
- private final class HashFileVisitor extends SimpleFileVisitor {
- private final Path dir;
- private final FileNameMatcher matcher;
- private final boolean allowSymlinks;
+ private final class HashFileVisitor extends SimpleFileVisitor {
+ private final Path dir;
+ private final FileNameMatcher matcher;
+ private final boolean allowSymlinks;
- // State
- private HashedDir current = HashedDir.this;
- private final Deque path = new LinkedList<>();
- private final Deque stack = new LinkedList<>();
+ // State
+ private HashedDir current = HashedDir.this;
+ private final Deque path = new LinkedList<>();
+ private final Deque stack = new LinkedList<>();
- private HashFileVisitor(Path dir, FileNameMatcher matcher, boolean allowSymlinks) {
- this.dir = dir;
- this.matcher = matcher;
- this.allowSymlinks = allowSymlinks;
- }
+ private HashFileVisitor(Path dir, FileNameMatcher matcher, boolean allowSymlinks) {
+ this.dir = dir;
+ this.matcher = matcher;
+ this.allowSymlinks = allowSymlinks;
+ }
- @Override
- public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
- FileVisitResult result = super.postVisitDirectory(dir, exc);
- if (this.dir.equals(dir)) {
- return result;
- }
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ FileVisitResult result = super.postVisitDirectory(dir, exc);
+ if (this.dir.equals(dir)) {
+ return result;
+ }
- // Add directory to parent
- HashedDir parent = stack.removeLast();
- parent.map.put(path.removeLast(), current);
- current = parent;
+ // Add directory to parent
+ HashedDir parent = stack.removeLast();
+ parent.map.put(path.removeLast(), current);
+ current = parent;
- // We're done
- return result;
- }
+ // We're done
+ return result;
+ }
- @Override
- public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
- FileVisitResult result = super.preVisitDirectory(dir, attrs);
- if (this.dir.equals(dir)) {
- return result;
- }
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ FileVisitResult result = super.preVisitDirectory(dir, attrs);
+ if (this.dir.equals(dir)) {
+ return result;
+ }
- // Verify is not symlink
- // Symlinks was disallowed because modification of it's destination are ignored by DirWatcher
- if (!allowSymlinks && attrs.isSymbolicLink()) {
- throw new SecurityException("Symlinks are not allowed");
- }
+ // Verify is not symlink
+ // Symlinks was disallowed because modification of it's destination are ignored by DirWatcher
+ if (!allowSymlinks && attrs.isSymbolicLink()) {
+ throw new SecurityException("Symlinks are not allowed");
+ }
- // Add child
- stack.add(current);
- current = new HashedDir();
- path.add(IOHelper.getFileName(dir));
+ // Add child
+ stack.add(current);
+ current = new HashedDir();
+ path.add(IOHelper.getFileName(dir));
- // We're done
- return result;
- }
+ // We're done
+ return result;
+ }
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- // Verify is not symlink
- if (!allowSymlinks && attrs.isSymbolicLink()) {
- throw new SecurityException("Symlinks are not allowed");
- }
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ // Verify is not symlink
+ if (!allowSymlinks && attrs.isSymbolicLink()) {
+ throw new SecurityException("Symlinks are not allowed");
+ }
- // Add file (may be unhashed, if exclusion)
- path.add(IOHelper.getFileName(file));
- boolean hash = matcher == null || matcher.shouldUpdate(path);
- current.map.put(path.removeLast(), new HashedFile(file, attrs.size(), hash));
- return super.visitFile(file, attrs);
- }
- }
+ // Add file (may be unhashed, if exclusion)
+ path.add(IOHelper.getFileName(file));
+ boolean hash = matcher == null || matcher.shouldUpdate(path);
+ current.map.put(path.removeLast(), new HashedFile(file, attrs.size(), hash));
+ return super.visitFile(file, attrs);
+ }
+ }
- public static final class Diff {
- @LauncherAPI public final HashedDir mismatch;
- @LauncherAPI public final HashedDir extra;
+ public static final class Diff {
+ @LauncherAPI public final HashedDir mismatch;
+ @LauncherAPI public final HashedDir extra;
- private Diff(HashedDir mismatch, HashedDir extra) {
- this.mismatch = mismatch;
- this.extra = extra;
- }
+ private Diff(HashedDir mismatch, HashedDir extra) {
+ this.mismatch = mismatch;
+ this.extra = extra;
+ }
- @LauncherAPI
- public boolean isSame() {
- return mismatch.isEmpty() && extra.isEmpty();
- }
- }
+ @LauncherAPI
+ public boolean isSame() {
+ return mismatch.isEmpty() && extra.isEmpty();
+ }
+ }
}
diff --git a/Launcher/source/hasher/HashedEntry.java b/Launcher/source/hasher/HashedEntry.java
index 8d7835d..ddc7a88 100644
--- a/Launcher/source/hasher/HashedEntry.java
+++ b/Launcher/source/hasher/HashedEntry.java
@@ -5,34 +5,35 @@
import launcher.LauncherAPI;
import launcher.serialize.HInput;
import launcher.serialize.stream.EnumSerializer;
+import launcher.serialize.stream.EnumSerializer.Itf;
import launcher.serialize.stream.StreamObject;
public abstract class HashedEntry extends StreamObject {
- @LauncherAPI public boolean flag; // For external usage
+ @LauncherAPI public boolean flag; // For external usage
- @LauncherAPI
- public abstract Type getType();
+ @LauncherAPI
+ public abstract Type getType();
- @LauncherAPI
- public abstract long size();
+ @LauncherAPI
+ public abstract long size();
- @LauncherAPI
- public enum Type implements EnumSerializer.Itf {
- DIR(1), FILE(2);
- private static final EnumSerializer SERIALIZER = new EnumSerializer<>(Type.class);
- private final int n;
+ @LauncherAPI
+ public enum Type implements Itf {
+ DIR(1), FILE(2);
+ private static final EnumSerializer SERIALIZER = new EnumSerializer<>(Type.class);
+ private final int n;
- Type(int n) {
- this.n = n;
- }
+ Type(int n) {
+ this.n = n;
+ }
- @Override
- public int getNumber() {
- return n;
- }
+ @Override
+ public int getNumber() {
+ return n;
+ }
- public static Type read(HInput input) throws IOException {
- return SERIALIZER.read(input);
- }
- }
+ public static Type read(HInput input) throws IOException {
+ return SERIALIZER.read(input);
+ }
+ }
}
diff --git a/Launcher/source/hasher/HashedFile.java b/Launcher/source/hasher/HashedFile.java
index 808975b..d9f5b85 100644
--- a/Launcher/source/hasher/HashedFile.java
+++ b/Launcher/source/hasher/HashedFile.java
@@ -7,61 +7,62 @@
import launcher.LauncherAPI;
import launcher.helper.IOHelper;
import launcher.helper.SecurityHelper;
+import launcher.helper.SecurityHelper.DigestAlgorithm;
import launcher.helper.VerifyHelper;
import launcher.serialize.HInput;
import launcher.serialize.HOutput;
public final class HashedFile extends HashedEntry {
- private static final byte[] DUMMY_HASH = new byte[0];
+ private static final byte[] DUMMY_HASH = new byte[0];
- // Instance
- @LauncherAPI public final long size;
- private final byte[] digest;
+ // Instance
+ @LauncherAPI public final long size;
+ private final byte[] digest;
- @LauncherAPI
- public HashedFile(long size, byte[] digest) {
- this.size = VerifyHelper.verifyLong(size, VerifyHelper.L_NOT_NEGATIVE, "Illegal size: " + size);
- this.digest = Arrays.copyOf(digest, digest.length);
- }
+ @LauncherAPI
+ public HashedFile(long size, byte[] digest) {
+ this.size = VerifyHelper.verifyLong(size, VerifyHelper.L_NOT_NEGATIVE, "Illegal size: " + size);
+ this.digest = Arrays.copyOf(digest, digest.length);
+ }
- @LauncherAPI
- public HashedFile(Path file, long size, boolean hash) throws IOException {
- this(size, hash ? SecurityHelper.digest(SecurityHelper.DigestAlgorithm.MD5, file) : DUMMY_HASH);
- }
+ @LauncherAPI
+ public HashedFile(Path file, long size, boolean hash) throws IOException {
+ this(size, hash ? SecurityHelper.digest(DigestAlgorithm.MD5, file) : DUMMY_HASH);
+ }
- @LauncherAPI
- public HashedFile(HInput input) throws IOException {
- this(input.readVarLong(), input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH));
- }
+ @LauncherAPI
+ public HashedFile(HInput input) throws IOException {
+ this(input.readVarLong(), input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH));
+ }
- @Override
- public Type getType() {
- return Type.FILE;
- }
+ @Override
+ public Type getType() {
+ return Type.FILE;
+ }
- @Override
- public long size() {
- return size;
- }
+ @Override
+ public long size() {
+ return size;
+ }
- @Override
- public void write(HOutput output) throws IOException {
- output.writeVarLong(size);
- output.writeByteArray(digest, SecurityHelper.CRYPTO_MAX_LENGTH);
- }
+ @Override
+ public void write(HOutput output) throws IOException {
+ output.writeVarLong(size);
+ output.writeByteArray(digest, SecurityHelper.CRYPTO_MAX_LENGTH);
+ }
- @LauncherAPI
- public boolean isSame(HashedFile o) {
- return size == o.size && Arrays.equals(digest, o.digest);
- }
+ @LauncherAPI
+ public boolean isSame(HashedFile o) {
+ return size == o.size && Arrays.equals(digest, o.digest);
+ }
- @LauncherAPI
- public boolean isSame(Path file) throws IOException {
- return isSame(new HashedFile(file, IOHelper.readAttributes(file).size(), true));
- }
+ @LauncherAPI
+ public boolean isSame(Path file) throws IOException {
+ return isSame(new HashedFile(file, IOHelper.readAttributes(file).size(), true));
+ }
- @LauncherAPI
- public boolean isSameDigest(byte[] digest) {
- return Arrays.equals(this.digest, digest);
- }
+ @LauncherAPI
+ public boolean isSameDigest(byte[] digest) {
+ return Arrays.equals(this.digest, digest);
+ }
}
diff --git a/Launcher/source/helper/CommonHelper.java b/Launcher/source/helper/CommonHelper.java
index 866fdd6..540eb95 100644
--- a/Launcher/source/helper/CommonHelper.java
+++ b/Launcher/source/helper/CommonHelper.java
@@ -1,43 +1,43 @@
package launcher.helper;
-import javax.script.ScriptEngine;
import java.util.Locale;
+import javax.script.ScriptEngine;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import launcher.LauncherAPI;
public final class CommonHelper {
- private static final String[] SCRIPT_ENGINE_ARGS = { "-strict" };
- private static final NashornScriptEngineFactory SCRIPT_ENGINE_FACTORY = new NashornScriptEngineFactory();
+ private static final String[] SCRIPT_ENGINE_ARGS = { "-strict" };
+ private static final NashornScriptEngineFactory SCRIPT_ENGINE_FACTORY = new NashornScriptEngineFactory();
- private CommonHelper() {
- }
+ private CommonHelper() {
+ }
- @LauncherAPI
- public static String low(String s) {
- return s.toLowerCase(Locale.US);
- }
+ @LauncherAPI
+ public static String low(String s) {
+ return s.toLowerCase(Locale.US);
+ }
- @LauncherAPI
- public static ScriptEngine newScriptEngine() {
- return SCRIPT_ENGINE_FACTORY.getScriptEngine(SCRIPT_ENGINE_ARGS);
- }
+ @LauncherAPI
+ public static ScriptEngine newScriptEngine() {
+ return SCRIPT_ENGINE_FACTORY.getScriptEngine(SCRIPT_ENGINE_ARGS);
+ }
- @LauncherAPI
- public static Thread newThread(String name, boolean daemon, Runnable runnable) {
- Thread thread = new Thread(runnable);
- thread.setDaemon(daemon);
- if (name != null) {
- thread.setName(name);
- }
- return thread;
- }
+ @LauncherAPI
+ public static Thread newThread(String name, boolean daemon, Runnable runnable) {
+ Thread thread = new Thread(runnable);
+ thread.setDaemon(daemon);
+ if (name != null) {
+ thread.setName(name);
+ }
+ return thread;
+ }
- @LauncherAPI
- public static String replace(String source, String... params) {
- for (int i = 0; i < params.length; i += 2) {
- source = source.replace('%' + params[i] + '%', params[i + 1]);
- }
- return source;
- }
+ @LauncherAPI
+ public static String replace(String source, String... params) {
+ for (int i = 0; i < params.length; i += 2) {
+ source = source.replace('%' + params[i] + '%', params[i + 1]);
+ }
+ return source;
+ }
}
diff --git a/Launcher/source/helper/IOHelper.java b/Launcher/source/helper/IOHelper.java
index 3b6d718..d37ce7d 100644
--- a/Launcher/source/helper/IOHelper.java
+++ b/Launcher/source/helper/IOHelper.java
@@ -1,7 +1,5 @@
package launcher.helper;
-import javax.imageio.ImageIO;
-import javax.imageio.ImageReader;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -51,608 +49,611 @@
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
import launcher.LauncherAPI;
public final class IOHelper {
- // Charset
- @LauncherAPI public static final Charset UNICODE_CHARSET = StandardCharsets.UTF_8;
- @LauncherAPI public static final Charset ASCII_CHARSET = StandardCharsets.US_ASCII;
+ // Charset
+ @LauncherAPI public static final Charset UNICODE_CHARSET = StandardCharsets.UTF_8;
+ @LauncherAPI public static final Charset ASCII_CHARSET = StandardCharsets.US_ASCII;
- // Constants
- @LauncherAPI public static final int SOCKET_TIMEOUT = VerifyHelper.verifyInt(
- Integer.parseUnsignedInt(System.getProperty("launcher.socketTimeout", Integer.toString(30000))),
- VerifyHelper.POSITIVE, "launcher.socketTimeout can't be <= 0");
- @LauncherAPI public static final int HTTP_TIMEOUT = VerifyHelper.verifyInt(
- Integer.parseUnsignedInt(System.getProperty("launcher.httpTimeout", Integer.toString(5000))),
- VerifyHelper.POSITIVE, "launcher.httpTimeout can't be <= 0");
- @LauncherAPI public static final int BUFFER_SIZE = VerifyHelper.verifyInt(
- Integer.parseUnsignedInt(System.getProperty("launcher.bufferSize", Integer.toString(4096))),
- VerifyHelper.POSITIVE, "launcher.bufferSize can't be <= 0");
+ // Constants
+ @LauncherAPI public static final int SOCKET_TIMEOUT = VerifyHelper.verifyInt(
+ Integer.parseUnsignedInt(System.getProperty("launcher.socketTimeout", Integer.toString(30000))),
+ VerifyHelper.POSITIVE, "launcher.socketTimeout can't be <= 0");
+ @LauncherAPI public static final int HTTP_TIMEOUT = VerifyHelper.verifyInt(
+ Integer.parseUnsignedInt(System.getProperty("launcher.httpTimeout", Integer.toString(5000))),
+ VerifyHelper.POSITIVE, "launcher.httpTimeout can't be <= 0");
+ @LauncherAPI public static final int BUFFER_SIZE = VerifyHelper.verifyInt(
+ Integer.parseUnsignedInt(System.getProperty("launcher.bufferSize", Integer.toString(4096))),
+ VerifyHelper.POSITIVE, "launcher.bufferSize can't be <= 0");
- // Platform-dependent
- @LauncherAPI public static final String CROSS_SEPARATOR = "/";
- @LauncherAPI public static final FileSystem FS = FileSystems.getDefault();
- @LauncherAPI public static final String PLATFORM_SEPARATOR = FS.getSeparator();
- @LauncherAPI public static final boolean POSIX = FS.supportedFileAttributeViews().contains("posix");
+ // Platform-dependent
+ @LauncherAPI public static final String CROSS_SEPARATOR = "/";
+ @LauncherAPI public static final FileSystem FS = FileSystems.getDefault();
+ @LauncherAPI public static final String PLATFORM_SEPARATOR = FS.getSeparator();
+ @LauncherAPI public static final boolean POSIX = FS.supportedFileAttributeViews().contains("posix");
- // Paths
- @LauncherAPI public static final Path JVM_DIR = Paths.get(System.getProperty("java.home"));
- @LauncherAPI public static final Path HOME_DIR = Paths.get(System.getProperty("user.home"));
- @LauncherAPI public static final Path WORKING_DIR = Paths.get(System.getProperty("user.dir"));
+ // Paths
+ @LauncherAPI public static final Path JVM_DIR = Paths.get(System.getProperty("java.home"));
+ @LauncherAPI public static final Path HOME_DIR = Paths.get(System.getProperty("user.home"));
+ @LauncherAPI public static final Path WORKING_DIR = Paths.get(System.getProperty("user.dir"));
- // File options
- private static final LinkOption[] LINK_OPTIONS = {};
- private static final OpenOption[] READ_OPTIONS = { StandardOpenOption.READ };
- private static final CopyOption[] COPY_OPTIONS = { StandardCopyOption.REPLACE_EXISTING };
- private static final OpenOption[] APPEND_OPTIONS = { StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.APPEND };
- private static final OpenOption[] WRITE_OPTIONS = { StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING };
- private static final Set WALK_OPTIONS = Collections.singleton(FileVisitOption.FOLLOW_LINKS);
+ // File options
+ private static final LinkOption[] LINK_OPTIONS = {};
+ private static final OpenOption[] READ_OPTIONS = { StandardOpenOption.READ };
+ private static final CopyOption[] COPY_OPTIONS = { StandardCopyOption.REPLACE_EXISTING };
+ private static final OpenOption[] APPEND_OPTIONS = { StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.APPEND };
+ private static final OpenOption[] WRITE_OPTIONS = { StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING };
+ private static final Set WALK_OPTIONS = Collections.singleton(FileVisitOption.FOLLOW_LINKS);
- private IOHelper() {
- }
+ private IOHelper() {
+ }
- @LauncherAPI
- public static void close(AutoCloseable closeable) {
- try {
- closeable.close();
- } catch (Exception exc) {
- LogHelper.error(exc);
- }
- }
+ @LauncherAPI
+ public static void close(AutoCloseable closeable) {
+ try {
+ closeable.close();
+ } catch (Exception exc) {
+ LogHelper.error(exc);
+ }
+ }
- @LauncherAPI
- public static void copy(Path source, Path target) throws IOException {
- createParentDirs(target);
- Files.copy(source, target, COPY_OPTIONS);
- }
+ @LauncherAPI
+ public static void copy(Path source, Path target) throws IOException {
+ createParentDirs(target);
+ Files.copy(source, target, COPY_OPTIONS);
+ }
- @LauncherAPI
- public static void createParentDirs(Path path) throws IOException {
- Path parent = path.getParent();
- if (parent != null && !isDir(parent)) {
- Files.createDirectories(parent);
- }
- }
+ @LauncherAPI
+ public static void createParentDirs(Path path) throws IOException {
+ Path parent = path.getParent();
+ if (parent != null && !isDir(parent)) {
+ Files.createDirectories(parent);
+ }
+ }
- @LauncherAPI
- public static String decode(byte[] bytes) {
- return new String(bytes, UNICODE_CHARSET);
- }
+ @LauncherAPI
+ public static String decode(byte[] bytes) {
+ return new String(bytes, UNICODE_CHARSET);
+ }
- @LauncherAPI
- public static String decodeASCII(byte[] bytes) {
- return new String(bytes, ASCII_CHARSET);
- }
+ @LauncherAPI
+ public static String decodeASCII(byte[] bytes) {
+ return new String(bytes, ASCII_CHARSET);
+ }
- @LauncherAPI
- public static void deleteDir(Path dir, boolean self) throws IOException {
- walk(dir, new DeleteDirVisitor(dir, self), true);
- }
+ @LauncherAPI
+ public static void deleteDir(Path dir, boolean self) throws IOException {
+ walk(dir, new DeleteDirVisitor(dir, self), true);
+ }
- @LauncherAPI
- public static byte[] encode(String s) {
- return s.getBytes(UNICODE_CHARSET);
- }
+ @LauncherAPI
+ public static byte[] encode(String s) {
+ return s.getBytes(UNICODE_CHARSET);
+ }
- @LauncherAPI
- public static byte[] encodeASCII(String s) {
- return s.getBytes(ASCII_CHARSET);
- }
+ @LauncherAPI
+ public static byte[] encodeASCII(String s) {
+ return s.getBytes(ASCII_CHARSET);
+ }
- @LauncherAPI
- public static boolean exists(Path path) {
- return Files.exists(path, LINK_OPTIONS);
- }
+ @LauncherAPI
+ public static boolean exists(Path path) {
+ return Files.exists(path, LINK_OPTIONS);
+ }
- @LauncherAPI
- public static Path getCodeSource(Class> clazz) {
- return Paths.get(toURI(clazz.getProtectionDomain().getCodeSource().getLocation()));
- }
+ @LauncherAPI
+ public static Path getCodeSource(Class> clazz) {
+ return Paths.get(toURI(clazz.getProtectionDomain().getCodeSource().getLocation()));
+ }
- @LauncherAPI
- public static String getFileName(Path path) {
- return path.getFileName().toString();
- }
+ @LauncherAPI
+ public static String getFileName(Path path) {
+ return path.getFileName().toString();
+ }
- @LauncherAPI
- public static String getIP(SocketAddress address) {
- return ((InetSocketAddress) address).getAddress().getHostAddress();
- }
+ @LauncherAPI
+ public static String getIP(SocketAddress address) {
+ return ((InetSocketAddress) address).getAddress().getHostAddress();
+ }
- @LauncherAPI
- public static byte[] getResourceBytes(String name) throws IOException {
- return read(getResourceURL(name));
- }
+ @LauncherAPI
+ public static byte[] getResourceBytes(String name) throws IOException {
+ return read(getResourceURL(name));
+ }
- @LauncherAPI
- public static URL getResourceURL(String name) throws NoSuchFileException {
- URL url = ClassLoader.getSystemResource(name);
- if (url == null) {
- throw new NoSuchFileException(name);
- }
- return url;
- }
+ @LauncherAPI
+ public static URL getResourceURL(String name) throws NoSuchFileException {
+ URL url = ClassLoader.getSystemResource(name);
+ if (url == null) {
+ throw new NoSuchFileException(name);
+ }
+ return url;
+ }
- @LauncherAPI
- public static boolean hasExtension(Path file, String extension) {
- return getFileName(file).endsWith('.' + extension);
- }
+ @LauncherAPI
+ public static boolean hasExtension(Path file, String extension) {
+ return getFileName(file).endsWith('.' + extension);
+ }
- @LauncherAPI
- public static boolean isDir(Path path) {
- return Files.isDirectory(path, LINK_OPTIONS);
- }
+ @LauncherAPI
+ public static boolean isDir(Path path) {
+ return Files.isDirectory(path, LINK_OPTIONS);
+ }
- @LauncherAPI
- public static boolean isEmpty(Path dir) throws IOException {
- try (DirectoryStream stream = Files.newDirectoryStream(dir)) {
- return !stream.iterator().hasNext();
- }
- }
+ @LauncherAPI
+ public static boolean isEmpty(Path dir) throws IOException {
+ try (DirectoryStream stream = Files.newDirectoryStream(dir)) {
+ return !stream.iterator().hasNext();
+ }
+ }
- @LauncherAPI
- public static boolean isFile(Path path) {
- return Files.isRegularFile(path, LINK_OPTIONS);
- }
+ @LauncherAPI
+ public static boolean isFile(Path path) {
+ return Files.isRegularFile(path, LINK_OPTIONS);
+ }
- @LauncherAPI
- public static boolean isValidFileName(String fileName) {
- return !fileName.equals(".") && !fileName.equals("..") &&
- fileName.chars().noneMatch(ch -> ch == '/' || ch == '\\') && isValidPath(fileName);
- }
+ @LauncherAPI
+ public static boolean isValidFileName(String fileName) {
+ return !fileName.equals(".") && !fileName.equals("..") &&
+ fileName.chars().noneMatch(ch -> ch == '/' || ch == '\\') && isValidPath(fileName);
+ }
- @LauncherAPI
- public static boolean isValidPath(String path) {
- try {
- toPath(path);
- return true;
- } catch (InvalidPathException ignored) {
- return false;
- }
- }
+ @LauncherAPI
+ public static boolean isValidPath(String path) {
+ try {
+ toPath(path);
+ return true;
+ } catch (InvalidPathException ignored) {
+ return false;
+ }
+ }
- @LauncherAPI
- public static boolean isValidTextureBounds(int width, int height) {
- return width % 64 == 0 && height * 2 == width && width <= 1024;
- }
+ @LauncherAPI
+ public static boolean isValidTextureBounds(int width, int height) {
+ return width % 64 == 0 && height * 2 == width && width <= 1024;
+ }
- @LauncherAPI
- public static void move(Path source, Path target) throws IOException {
- createParentDirs(target);
- Files.move(source, target, COPY_OPTIONS);
- }
+ @LauncherAPI
+ public static void move(Path source, Path target) throws IOException {
+ createParentDirs(target);
+ Files.move(source, target, COPY_OPTIONS);
+ }
- @LauncherAPI
- public static byte[] newBuffer() {
- return new byte[4096];
- }
+ @LauncherAPI
+ public static byte[] newBuffer() {
+ return new byte[4096];
+ }
- @LauncherAPI
- public static ByteArrayOutputStream newByteArrayOutput() {
- return new ByteArrayOutputStream();
- }
+ @LauncherAPI
+ public static ByteArrayOutputStream newByteArrayOutput() {
+ return new ByteArrayOutputStream();
+ }
- @LauncherAPI
- public static char[] newCharBuffer() {
- return new char[4096];
- }
+ @LauncherAPI
+ public static char[] newCharBuffer() {
+ return new char[4096];
+ }
- @LauncherAPI
- public static InputStream newInput(URL url) throws IOException {
- URLConnection connection = url.openConnection();
- if (connection instanceof HttpURLConnection) {
- connection.setReadTimeout(HTTP_TIMEOUT);
- connection.setConnectTimeout(HTTP_TIMEOUT);
- }
- connection.setDoInput(true);
- connection.setDoOutput(false);
- return connection.getInputStream();
- }
+ @LauncherAPI
+ public static InputStream newInput(URL url) throws IOException {
+ URLConnection connection = url.openConnection();
+ if (connection instanceof HttpURLConnection) {
+ connection.setReadTimeout(HTTP_TIMEOUT);
+ connection.setConnectTimeout(HTTP_TIMEOUT);
+ connection.addRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"); // Fix for stupid servers
+ }
+ connection.setDoInput(true);
+ connection.setDoOutput(false);
+ return connection.getInputStream();
+ }
- @LauncherAPI
- public static InputStream newInput(Path file) throws IOException {
- return Files.newInputStream(file, READ_OPTIONS);
- }
+ @LauncherAPI
+ public static InputStream newInput(Path file) throws IOException {
+ return Files.newInputStream(file, READ_OPTIONS);
+ }
- @LauncherAPI
- public static OutputStream newOutput(Path file) throws IOException {
- return newOutput(file, false);
- }
+ @LauncherAPI
+ public static OutputStream newOutput(Path file) throws IOException {
+ return newOutput(file, false);
+ }
- @LauncherAPI
- public static OutputStream newOutput(Path file, boolean append) throws IOException {
- createParentDirs(file);
- return Files.newOutputStream(file, append ? APPEND_OPTIONS : WRITE_OPTIONS);
- }
+ @LauncherAPI
+ public static OutputStream newOutput(Path file, boolean append) throws IOException {
+ createParentDirs(file);
+ return Files.newOutputStream(file, append ? APPEND_OPTIONS : WRITE_OPTIONS);
+ }
- @LauncherAPI
- public static BufferedReader newReader(InputStream input) {
- return newReader(input, UNICODE_CHARSET);
- }
+ @LauncherAPI
+ public static BufferedReader newReader(InputStream input) {
+ return newReader(input, UNICODE_CHARSET);
+ }
- @LauncherAPI
- public static BufferedReader newReader(InputStream input, Charset charset) {
- return new BufferedReader(new InputStreamReader(input, charset));
- }
+ @LauncherAPI
+ public static BufferedReader newReader(InputStream input, Charset charset) {
+ return new BufferedReader(new InputStreamReader(input, charset));
+ }
- @LauncherAPI
- public static BufferedReader newReader(URL url) throws IOException {
- return newReader(newInput(url));
- }
+ @LauncherAPI
+ public static BufferedReader newReader(URL url) throws IOException {
+ return newReader(newInput(url));
+ }
- @LauncherAPI
- public static BufferedReader newReader(Path file) throws IOException {
- return Files.newBufferedReader(file, UNICODE_CHARSET);
- }
+ @LauncherAPI
+ public static BufferedReader newReader(Path file) throws IOException {
+ return Files.newBufferedReader(file, UNICODE_CHARSET);
+ }
- @LauncherAPI
- public static Socket newSocket() throws SocketException {
- Socket socket = new Socket();
- setSocketFlags(socket);
- return socket;
- }
+ @LauncherAPI
+ public static Socket newSocket() throws SocketException {
+ Socket socket = new Socket();
+ setSocketFlags(socket);
+ return socket;
+ }
- @LauncherAPI
- public static BufferedWriter newWriter(OutputStream output) {
- return new BufferedWriter(new OutputStreamWriter(output, UNICODE_CHARSET));
- }
+ @LauncherAPI
+ public static BufferedWriter newWriter(OutputStream output) {
+ return new BufferedWriter(new OutputStreamWriter(output, UNICODE_CHARSET));
+ }
- @LauncherAPI
- public static BufferedWriter newWriter(Path file) throws IOException {
- return newWriter(file, false);
- }
+ @LauncherAPI
+ public static BufferedWriter newWriter(Path file) throws IOException {
+ return newWriter(file, false);
+ }
- @LauncherAPI
- public static BufferedWriter newWriter(Path file, boolean append) throws IOException {
- createParentDirs(file);
- return Files.newBufferedWriter(file, UNICODE_CHARSET, append ? APPEND_OPTIONS : WRITE_OPTIONS);
- }
+ @LauncherAPI
+ public static BufferedWriter newWriter(Path file, boolean append) throws IOException {
+ createParentDirs(file);
+ return Files.newBufferedWriter(file, UNICODE_CHARSET, append ? APPEND_OPTIONS : WRITE_OPTIONS);
+ }
- @LauncherAPI
- public static BufferedWriter newWriter(FileDescriptor fd) {
- return newWriter(new FileOutputStream(fd));
- }
+ @LauncherAPI
+ public static BufferedWriter newWriter(FileDescriptor fd) {
+ return newWriter(new FileOutputStream(fd));
+ }
- @LauncherAPI
- public static ZipEntry newZipEntry(String name) {
- ZipEntry entry = new ZipEntry(name);
- entry.setTime(0);
- return entry;
- }
+ @LauncherAPI
+ public static ZipEntry newZipEntry(String name) {
+ ZipEntry entry = new ZipEntry(name);
+ entry.setTime(0);
+ return entry;
+ }
- @LauncherAPI
- public static ZipEntry newZipEntry(ZipEntry entry) {
- return newZipEntry(entry.getName());
- }
+ @LauncherAPI
+ public static ZipEntry newZipEntry(ZipEntry entry) {
+ return newZipEntry(entry.getName());
+ }
- @LauncherAPI
- public static ZipInputStream newZipInput(InputStream input) {
- return new ZipInputStream(input, UNICODE_CHARSET);
- }
+ @LauncherAPI
+ public static ZipInputStream newZipInput(InputStream input) {
+ return new ZipInputStream(input, UNICODE_CHARSET);
+ }
- @LauncherAPI
- public static ZipInputStream newZipInput(URL url) throws IOException {
- return newZipInput(newInput(url));
- }
+ @LauncherAPI
+ public static ZipInputStream newZipInput(URL url) throws IOException {
+ return newZipInput(newInput(url));
+ }
- @LauncherAPI
- public static ZipInputStream newZipInput(Path file) throws IOException {
- return newZipInput(newInput(file));
- }
+ @LauncherAPI
+ public static ZipInputStream newZipInput(Path file) throws IOException {
+ return newZipInput(newInput(file));
+ }
- @LauncherAPI
- public static byte[] read(Path file) throws IOException {
- long size = readAttributes(file).size();
- if (size > Integer.MAX_VALUE) {
- throw new IOException("File too big");
- }
+ @LauncherAPI
+ public static byte[] read(Path file) throws IOException {
+ long size = readAttributes(file).size();
+ if (size > Integer.MAX_VALUE) {
+ throw new IOException("File too big");
+ }
- // Read bytes from file
- byte[] bytes = new byte[(int) size];
- try (InputStream input = newInput(file)) {
- read(input, bytes);
- }
+ // Read bytes from file
+ byte[] bytes = new byte[(int) size];
+ try (InputStream input = newInput(file)) {
+ read(input, bytes);
+ }
- // Return result
- return bytes;
- }
+ // Return result
+ return bytes;
+ }
- @LauncherAPI
- public static byte[] read(URL url) throws IOException {
- try (InputStream input = newInput(url)) {
- return read(input);
- }
- }
+ @LauncherAPI
+ public static byte[] read(URL url) throws IOException {
+ try (InputStream input = newInput(url)) {
+ return read(input);
+ }
+ }
- @LauncherAPI
- public static void read(InputStream input, byte[] bytes) throws IOException {
- int offset = 0;
- while (offset < bytes.length) {
- int length = input.read(bytes, offset, bytes.length - offset);
- if (length < 0) {
- throw new EOFException(String.format("%d bytes remaining", bytes.length - offset));
- }
- offset += length;
- }
- }
+ @LauncherAPI
+ public static void read(InputStream input, byte[] bytes) throws IOException {
+ int offset = 0;
+ while (offset < bytes.length) {
+ int length = input.read(bytes, offset, bytes.length - offset);
+ if (length < 0) {
+ throw new EOFException(String.format("%d bytes remaining", bytes.length - offset));
+ }
+ offset += length;
+ }
+ }
- @LauncherAPI
- public static byte[] read(InputStream input) throws IOException {
- try (ByteArrayOutputStream output = newByteArrayOutput()) {
- transfer(input, output);
- return output.toByteArray();
- }
- }
+ @LauncherAPI
+ public static byte[] read(InputStream input) throws IOException {
+ try (ByteArrayOutputStream output = newByteArrayOutput()) {
+ transfer(input, output);
+ return output.toByteArray();
+ }
+ }
- @LauncherAPI
- public static BasicFileAttributes readAttributes(Path path) throws IOException {
- return Files.readAttributes(path, BasicFileAttributes.class, LINK_OPTIONS);
- }
+ @LauncherAPI
+ public static BasicFileAttributes readAttributes(Path path) throws IOException {
+ return Files.readAttributes(path, BasicFileAttributes.class, LINK_OPTIONS);
+ }
- @LauncherAPI
- public static BufferedImage readTexture(Object input) throws IOException {
- ImageReader reader = ImageIO.getImageReadersByMIMEType("image/png").next();
- try {
- reader.setInput(ImageIO.createImageInputStream(input), false, false);
+ @LauncherAPI
+ public static BufferedImage readTexture(Object input) throws IOException {
+ ImageReader reader = ImageIO.getImageReadersByMIMEType("image/png").next();
+ try {
+ reader.setInput(ImageIO.createImageInputStream(input), false, false);
- // Verify texture bounds
- int width = reader.getWidth(0);
- int height = reader.getHeight(0);
- if (!isValidTextureBounds(width, height)) {
- throw new IOException(String.format("Invalid texture bounds: %dx%d", width, height));
- }
+ // Verify texture bounds
+ int width = reader.getWidth(0);
+ int height = reader.getHeight(0);
+ if (!isValidTextureBounds(width, height)) {
+ throw new IOException(String.format("Invalid texture bounds: %dx%d", width, height));
+ }
- // Read image
- return reader.read(0);
- } finally {
- reader.dispose();
- }
- }
+ // Read image
+ return reader.read(0);
+ } finally {
+ reader.dispose();
+ }
+ }
- @LauncherAPI
- public static String request(URL url) throws IOException {
- return decode(read(url)).trim();
- }
+ @LauncherAPI
+ public static String request(URL url) throws IOException {
+ return decode(read(url)).trim();
+ }
- @LauncherAPI
- public static InetSocketAddress resolve(InetSocketAddress address) {
- if (address.isUnresolved()) { // Create resolved address
- return new InetSocketAddress(address.getHostString(), address.getPort());
- }
- return address;
- }
+ @LauncherAPI
+ public static InetSocketAddress resolve(InetSocketAddress address) {
+ if (address.isUnresolved()) { // Create resolved address
+ return new InetSocketAddress(address.getHostString(), address.getPort());
+ }
+ return address;
+ }
- @LauncherAPI
- public static Path resolveIncremental(Path dir, String name, String extension) {
- Path original = dir.resolve(name + '.' + extension);
- if (!exists(original)) { // Not need to increment
- return original;
- }
+ @LauncherAPI
+ public static Path resolveIncremental(Path dir, String name, String extension) {
+ Path original = dir.resolve(name + '.' + extension);
+ if (!exists(original)) { // Not need to increment
+ return original;
+ }
- // Incremental resolve
- int counter = 1;
- while (true) {
- Path path = dir.resolve(String.format("%s (%d).%s", name, counter, extension));
- if (exists(path)) {
- counter++;
- continue;
- }
- return path;
- }
- }
+ // Incremental resolve
+ int counter = 1;
+ while (true) {
+ Path path = dir.resolve(String.format("%s (%d).%s", name, counter, extension));
+ if (exists(path)) {
+ counter++;
+ continue;
+ }
+ return path;
+ }
+ }
- @LauncherAPI
- public static Path resolveJavaBin(Path javaDir) {
- // Get Java binaries path
- Path javaBinDir = (javaDir == null ? JVM_DIR : javaDir).resolve("bin");
+ @LauncherAPI
+ public static Path resolveJavaBin(Path javaDir) {
+ // Get Java binaries path
+ Path javaBinDir = (javaDir == null ? JVM_DIR : javaDir).resolve("bin");
- // Verify has "javaw.exe" file
- if (!LogHelper.isDebugEnabled()) {
- Path javawExe = javaBinDir.resolve("javaw.exe");
- if (isFile(javawExe)) {
- return javawExe;
- }
- }
+ // Verify has "javaw.exe" file
+ if (!LogHelper.isDebugEnabled()) {
+ Path javawExe = javaBinDir.resolve("javaw.exe");
+ if (isFile(javawExe)) {
+ return javawExe;
+ }
+ }
- // Verify has "java.exe" file
- Path javaExe = javaBinDir.resolve("java.exe");
- if (isFile(javaExe)) {
- return javaExe;
- }
+ // Verify has "java.exe" file
+ Path javaExe = javaBinDir.resolve("java.exe");
+ if (isFile(javaExe)) {
+ return javaExe;
+ }
- // Verify has "java" file
- Path java = javaBinDir.resolve("java");
- if (isFile(java)) {
- return java;
- }
+ // Verify has "java" file
+ Path java = javaBinDir.resolve("java");
+ if (isFile(java)) {
+ return java;
+ }
- // Throw exception as no runnable found
- throw new RuntimeException("Java binary wasn't found");
- }
+ // Throw exception as no runnable found
+ throw new RuntimeException("Java binary wasn't found");
+ }
- @LauncherAPI
- public static void setSocketFlags(Socket socket) throws SocketException {
- // Set socket flags
- socket.setKeepAlive(false); // TODO To socket channels
- socket.setTcpNoDelay(false);
- socket.setReuseAddress(true);
+ @LauncherAPI
+ public static void setSocketFlags(Socket socket) throws SocketException {
+ // Set socket flags
+ socket.setKeepAlive(false); // TODO To socket channels
+ socket.setTcpNoDelay(false);
+ socket.setReuseAddress(true);
- // Set socket options
- socket.setSoTimeout(SOCKET_TIMEOUT);
- socket.setTrafficClass(0b11100);
- // Allow OS to adjust buffer sizes
-// socket.setSendBufferSize(0x100000);
-// socket.setReceiveBufferSize(0x100000);
- socket.setPerformancePreferences(1, 0, 2);
- }
+ // Set socket options
+ socket.setSoTimeout(SOCKET_TIMEOUT);
+ socket.setTrafficClass(0b11100);
+ // Allow OS to adjust buffer sizes
+ // socket.setSendBufferSize(0x100000);
+ // socket.setReceiveBufferSize(0x100000);
+ socket.setPerformancePreferences(1, 0, 2);
+ }
- @LauncherAPI
- public static Path toPath(String path) {
- return Paths.get(path.replace(CROSS_SEPARATOR, PLATFORM_SEPARATOR));
- }
+ @LauncherAPI
+ public static Path toPath(String path) {
+ return Paths.get(path.replace(CROSS_SEPARATOR, PLATFORM_SEPARATOR));
+ }
- @LauncherAPI
- public static String toString(Path path) {
- return path.toString().replace(PLATFORM_SEPARATOR, CROSS_SEPARATOR);
- }
+ @LauncherAPI
+ public static String toString(Path path) {
+ return path.toString().replace(PLATFORM_SEPARATOR, CROSS_SEPARATOR);
+ }
- @LauncherAPI
- public static URI toURI(URL url) {
- try {
- return url.toURI();
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException(e);
- }
- }
+ @LauncherAPI
+ public static URI toURI(URL url) {
+ try {
+ return url.toURI();
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
- @LauncherAPI
- public static URL toURL(Path path) {
- try {
- return path.toUri().toURL();
- } catch (MalformedURLException e) {
- throw new InternalError(e);
- }
- }
+ @LauncherAPI
+ public static URL toURL(Path path) {
+ try {
+ return path.toUri().toURL();
+ } catch (MalformedURLException e) {
+ throw new InternalError(e);
+ }
+ }
- @LauncherAPI
- public static int transfer(InputStream input, OutputStream output) throws IOException {
- int transferred = 0;
- byte[] buffer = newBuffer();
- for (int length = input.read(buffer); length >= 0; length = input.read(buffer)) {
- output.write(buffer, 0, length);
- transferred += length;
- }
- return transferred;
- }
+ @LauncherAPI
+ public static int transfer(InputStream input, OutputStream output) throws IOException {
+ int transferred = 0;
+ byte[] buffer = newBuffer();
+ for (int length = input.read(buffer); length >= 0; length = input.read(buffer)) {
+ output.write(buffer, 0, length);
+ transferred += length;
+ }
+ return transferred;
+ }
- @LauncherAPI
- public static void transfer(Path file, OutputStream output) throws IOException {
- try (InputStream input = newInput(file)) {
- transfer(input, output);
- }
- }
+ @LauncherAPI
+ public static void transfer(Path file, OutputStream output) throws IOException {
+ try (InputStream input = newInput(file)) {
+ transfer(input, output);
+ }
+ }
- @LauncherAPI
- public static int transfer(InputStream input, Path file) throws IOException {
- return transfer(input, file, false);
- }
+ @LauncherAPI
+ public static int transfer(InputStream input, Path file) throws IOException {
+ return transfer(input, file, false);
+ }
- @LauncherAPI
- public static int transfer(InputStream input, Path file, boolean append) throws IOException {
- try (OutputStream output = newOutput(file, append)) {
- return transfer(input, output);
- }
- }
+ @LauncherAPI
+ public static int transfer(InputStream input, Path file, boolean append) throws IOException {
+ try (OutputStream output = newOutput(file, append)) {
+ return transfer(input, output);
+ }
+ }
- @LauncherAPI
- public static String urlDecode(String s) {
- try {
- return URLDecoder.decode(s, UNICODE_CHARSET.name());
- } catch (UnsupportedEncodingException e) {
- throw new InternalError(e);
- }
- }
+ @LauncherAPI
+ public static String urlDecode(String s) {
+ try {
+ return URLDecoder.decode(s, UNICODE_CHARSET.name());
+ } catch (UnsupportedEncodingException e) {
+ throw new InternalError(e);
+ }
+ }
- @LauncherAPI
- public static String urlEncode(String s) {
- try {
- return URLEncoder.encode(s, UNICODE_CHARSET.name());
- } catch (UnsupportedEncodingException e) {
- throw new InternalError(e);
- }
- }
+ @LauncherAPI
+ public static String urlEncode(String s) {
+ try {
+ return URLEncoder.encode(s, UNICODE_CHARSET.name());
+ } catch (UnsupportedEncodingException e) {
+ throw new InternalError(e);
+ }
+ }
- @LauncherAPI
- public static String verifyFileName(String fileName) {
- return VerifyHelper.verify(fileName, IOHelper::isValidFileName, String.format("Invalid file name: '%s'", fileName));
- }
+ @LauncherAPI
+ public static String verifyFileName(String fileName) {
+ return VerifyHelper.verify(fileName, IOHelper::isValidFileName, String.format("Invalid file name: '%s'", fileName));
+ }
- @LauncherAPI
- public static int verifyLength(int length, int max) throws IOException {
- if (length < 0 || max < 0 && length != -max || max > 0 && length > max) {
- throw new IOException("Illegal length: " + length);
- }
- return length;
- }
+ @LauncherAPI
+ public static int verifyLength(int length, int max) throws IOException {
+ if (length < 0 || max < 0 && length != -max || max > 0 && length > max) {
+ throw new IOException("Illegal length: " + length);
+ }
+ return length;
+ }
- @LauncherAPI
- public static BufferedImage verifyTexture(BufferedImage skin) {
- return VerifyHelper.verify(skin, i -> isValidTextureBounds(i.getWidth(), i.getHeight()),
- String.format("Invalid texture bounds: %dx%d", skin.getWidth(), skin.getHeight()));
- }
+ @LauncherAPI
+ public static BufferedImage verifyTexture(BufferedImage skin) {
+ return VerifyHelper.verify(skin, i -> isValidTextureBounds(i.getWidth(), i.getHeight()),
+ String.format("Invalid texture bounds: %dx%d", skin.getWidth(), skin.getHeight()));
+ }
- @LauncherAPI
- public static String verifyURL(String url) {
- try {
- new URL(url).toURI();
- return url;
- } catch (MalformedURLException | URISyntaxException e) {
- throw new IllegalArgumentException("Invalid URL", e);
- }
- }
+ @LauncherAPI
+ public static String verifyURL(String url) {
+ try {
+ new URL(url).toURI();
+ return url;
+ } catch (MalformedURLException | URISyntaxException e) {
+ throw new IllegalArgumentException("Invalid URL", e);
+ }
+ }
- @LauncherAPI
- public static void walk(Path dir, FileVisitor visitor, boolean hidden) throws IOException {
- Files.walkFileTree(dir, WALK_OPTIONS, Integer.MAX_VALUE, hidden ? visitor : new SkipHiddenVisitor(visitor));
- }
+ @LauncherAPI
+ public static void walk(Path dir, FileVisitor visitor, boolean hidden) throws IOException {
+ Files.walkFileTree(dir, WALK_OPTIONS, Integer.MAX_VALUE, hidden ? visitor : new SkipHiddenVisitor(visitor));
+ }
- @LauncherAPI
- public static void write(Path file, byte[] bytes) throws IOException {
- createParentDirs(file);
- Files.write(file, bytes, WRITE_OPTIONS);
- }
+ @LauncherAPI
+ public static void write(Path file, byte[] bytes) throws IOException {
+ createParentDirs(file);
+ Files.write(file, bytes, WRITE_OPTIONS);
+ }
- private static final class DeleteDirVisitor extends SimpleFileVisitor {
- private final Path dir;
- private final boolean self;
+ private static final class DeleteDirVisitor extends SimpleFileVisitor {
+ private final Path dir;
+ private final boolean self;
- private DeleteDirVisitor(Path dir, boolean self) {
- this.dir = dir;
- this.self = self;
- }
+ private DeleteDirVisitor(Path dir, boolean self) {
+ this.dir = dir;
+ this.self = self;
+ }
- @Override
- public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
- FileVisitResult result = super.postVisitDirectory(dir, exc);
- if (self || !this.dir.equals(dir)) {
- Files.delete(dir);
- }
- return result;
- }
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ FileVisitResult result = super.postVisitDirectory(dir, exc);
+ if (self || !this.dir.equals(dir)) {
+ Files.delete(dir);
+ }
+ return result;
+ }
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- Files.delete(file);
- return super.visitFile(file, attrs);
- }
- }
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Files.delete(file);
+ return super.visitFile(file, attrs);
+ }
+ }
- private static final class SkipHiddenVisitor implements FileVisitor {
- private final FileVisitor visitor;
+ private static final class SkipHiddenVisitor implements FileVisitor {
+ private final FileVisitor visitor;
- private SkipHiddenVisitor(FileVisitor visitor) {
- this.visitor = visitor;
- }
+ private SkipHiddenVisitor(FileVisitor visitor) {
+ this.visitor = visitor;
+ }
- @Override
- public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
- return Files.isHidden(dir) ? FileVisitResult.CONTINUE : visitor.postVisitDirectory(dir, exc);
- }
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ return Files.isHidden(dir) ? FileVisitResult.CONTINUE : visitor.postVisitDirectory(dir, exc);
+ }
- @Override
- public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
- return Files.isHidden(dir) ? FileVisitResult.SKIP_SUBTREE : visitor.preVisitDirectory(dir, attrs);
- }
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ return Files.isHidden(dir) ? FileVisitResult.SKIP_SUBTREE : visitor.preVisitDirectory(dir, attrs);
+ }
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- return Files.isHidden(file) ? FileVisitResult.CONTINUE : visitor.visitFile(file, attrs);
- }
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ return Files.isHidden(file) ? FileVisitResult.CONTINUE : visitor.visitFile(file, attrs);
+ }
- @Override
- public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
- return visitor.visitFileFailed(file, exc);
- }
- }
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+ return visitor.visitFileFailed(file, exc);
+ }
+ }
}
diff --git a/Launcher/source/helper/JVMHelper.java b/Launcher/source/helper/JVMHelper.java
index f304c88..8bbccbe 100644
--- a/Launcher/source/helper/JVMHelper.java
+++ b/Launcher/source/helper/JVMHelper.java
@@ -14,164 +14,164 @@
import sun.misc.URLClassPath;
public final class JVMHelper {
- // System properties
- @LauncherAPI public static final OS OS_TYPE = OS.byName(System.getProperty("os.name"));
- @LauncherAPI public static final String OS_VERSION = System.getProperty("os.version");
- @LauncherAPI public static final int OS_BITS = getCorrectOSArch();
- @LauncherAPI public static final int JVM_BITS = Integer.parseInt(System.getProperty("sun.arch.data.model"));
- @LauncherAPI public static final int RAM = getRAMAmount();
+ // System properties
+ @LauncherAPI public static final OS OS_TYPE = OS.byName(System.getProperty("os.name"));
+ @LauncherAPI public static final String OS_VERSION = System.getProperty("os.version");
+ @LauncherAPI public static final int OS_BITS = getCorrectOSArch();
+ @LauncherAPI public static final int JVM_BITS = Integer.parseInt(System.getProperty("sun.arch.data.model"));
+ @LauncherAPI public static final int RAM = getRAMAmount();
- // Public static fields
- @LauncherAPI public static final Runtime RUNTIME = Runtime.getRuntime();
- @LauncherAPI public static final URLClassLoader LOADER = (URLClassLoader) ClassLoader.getSystemClassLoader();
- @LauncherAPI public static final URLClassPath UCP = getURLClassPath();
+ // Public static fields
+ @LauncherAPI public static final Runtime RUNTIME = Runtime.getRuntime();
+ @LauncherAPI public static final URLClassLoader LOADER = (URLClassLoader) ClassLoader.getSystemClassLoader();
+ @LauncherAPI public static final URLClassPath UCP = getURLClassPath();
- // Useful internal fields and constants
- private static final String JAVA_LIBRARY_PATH = "java.library.path";
- private static final Field USR_PATHS_FIELD = getUsrPathsField();
- private static final Field SYS_PATHS_FIELD = getSysPathsField();
+ // Useful internal fields and constants
+ private static final String JAVA_LIBRARY_PATH = "java.library.path";
+ private static final Field USR_PATHS_FIELD = getUsrPathsField();
+ private static final Field SYS_PATHS_FIELD = getSysPathsField();
- private JVMHelper() {
- }
+ private JVMHelper() {
+ }
- @LauncherAPI
- public static void addNativePath(Path path) {
- String stringPath = path.toString();
+ @LauncherAPI
+ public static void addNativePath(Path path) {
+ String stringPath = path.toString();
- // Add to library path
- String libraryPath = System.getProperty(JAVA_LIBRARY_PATH);
- if (libraryPath == null || libraryPath.isEmpty()) {
- libraryPath = stringPath;
- } else {
- libraryPath += File.pathSeparatorChar + stringPath;
- }
- System.setProperty(JAVA_LIBRARY_PATH, libraryPath);
+ // Add to library path
+ String libraryPath = System.getProperty(JAVA_LIBRARY_PATH);
+ if (libraryPath == null || libraryPath.isEmpty()) {
+ libraryPath = stringPath;
+ } else {
+ libraryPath += File.pathSeparatorChar + stringPath;
+ }
+ System.setProperty(JAVA_LIBRARY_PATH, libraryPath);
- // Reset usrPaths and sysPaths cache
- try {
- USR_PATHS_FIELD.set(null, null);
- SYS_PATHS_FIELD.set(null, null);
- } catch (IllegalAccessException e) {
- throw new InternalError(e);
- }
- }
+ // Reset usrPaths and sysPaths cache
+ try {
+ USR_PATHS_FIELD.set(null, null);
+ SYS_PATHS_FIELD.set(null, null);
+ } catch (IllegalAccessException e) {
+ throw new InternalError(e);
+ }
+ }
- @LauncherAPI
- @SuppressWarnings("CallToSystemGC")
- public static void fullGC() {
- RUNTIME.gc();
- RUNTIME.runFinalization();
- LogHelper.debug("Used heap: %d MiB", RUNTIME.totalMemory() - RUNTIME.freeMemory() >> 20);
- }
+ @LauncherAPI
+ @SuppressWarnings("CallToSystemGC")
+ public static void fullGC() {
+ RUNTIME.gc();
+ RUNTIME.runFinalization();
+ LogHelper.debug("Used heap: %d MiB", RUNTIME.totalMemory() - RUNTIME.freeMemory() >> 20);
+ }
- @LauncherAPI
- public static void halt0(int status) {
- try {
- getMethod(Class.forName("java.lang.Shutdown"), "halt0", int.class).invoke(null, status);
- } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
- throw new InternalError(e);
- }
- }
+ @LauncherAPI
+ public static void halt0(int status) {
+ try {
+ getMethod(Class.forName("java.lang.Shutdown"), "halt0", int.class).invoke(null, status);
+ } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+ throw new InternalError(e);
+ }
+ }
- @LauncherAPI
- public static boolean isJVMMatchesSystemArch() {
- return JVM_BITS == OS_BITS;
- }
+ @LauncherAPI
+ public static boolean isJVMMatchesSystemArch() {
+ return JVM_BITS == OS_BITS;
+ }
- @LauncherAPI
- public static void verifySystemProperties(Class> mainClass) {
- Locale.setDefault(Locale.US);
+ @LauncherAPI
+ public static void verifySystemProperties(Class> mainClass) {
+ Locale.setDefault(Locale.US);
- // Verify class loader
- LogHelper.debug("Verifying class loader");
- if (!mainClass.getClassLoader().equals(LOADER)) {
- throw new SecurityException("ClassLoader should be system");
- }
+ // Verify class loader
+ LogHelper.debug("Verifying class loader");
+ if (!mainClass.getClassLoader().equals(LOADER)) {
+ throw new SecurityException("ClassLoader should be system");
+ }
- // Verify system and java architecture
- LogHelper.debug("Verifying JVM architecture");
- if (!isJVMMatchesSystemArch()) {
- LogHelper.warning("Java and OS architecture mismatch");
- LogHelper.warning("It's recommended to download %d-bit JRE", OS_BITS);
- }
+ // Verify system and java architecture
+ LogHelper.debug("Verifying JVM architecture");
+ if (!isJVMMatchesSystemArch()) {
+ LogHelper.warning("Java and OS architecture mismatch");
+ LogHelper.warning("It's recommended to download %d-bit JRE", OS_BITS);
+ }
- // Disable SNI extensions (fixes some sites SSL unrecognized_name)
- LogHelper.debug("Disabling SNI extensions (SSL fix)");
- System.setProperty("jsse.enableSNIExtension", Boolean.toString(false));
- }
+ // Disable SNI extensions (fixes some sites SSL unrecognized_name)
+ LogHelper.debug("Disabling SNI extensions (SSL fix)");
+ System.setProperty("jsse.enableSNIExtension", Boolean.toString(false));
+ }
- @SuppressWarnings("CallToSystemGetenv")
- private static int getCorrectOSArch() {
- // As always, mustdie must die
- if (OS_TYPE == OS.MUSTDIE) {
- return System.getenv("ProgramFiles(x86)") == null ? 32 : 64;
- }
+ @SuppressWarnings("CallToSystemGetenv")
+ private static int getCorrectOSArch() {
+ // As always, mustdie must die
+ if (OS_TYPE == OS.MUSTDIE) {
+ return System.getenv("ProgramFiles(x86)") == null ? 32 : 64;
+ }
- // Or trust system property (maybe incorrect)
- return System.getProperty("os.arch").contains("64") ? 64 : 32;
- }
+ // Or trust system property (maybe incorrect)
+ return System.getProperty("os.arch").contains("64") ? 64 : 32;
+ }
- private static Field getField(Class> clazz, String name) throws NoSuchFieldException {
- Field field = clazz.getDeclaredField(name);
- field.setAccessible(true);
- return field;
- }
+ private static Field getField(Class> clazz, String name) throws NoSuchFieldException {
+ Field field = clazz.getDeclaredField(name);
+ field.setAccessible(true);
+ return field;
+ }
- private static Method getMethod(Class> clazz, String name, Class>... params) throws NoSuchMethodException {
- Method method = clazz.getDeclaredMethod(name, params);
- method.setAccessible(true);
- return method;
- }
+ private static Method getMethod(Class> clazz, String name, Class>... params) throws NoSuchMethodException {
+ Method method = clazz.getDeclaredMethod(name, params);
+ method.setAccessible(true);
+ return method;
+ }
- private static int getRAMAmount() {
- int physicalRam = (int) (((OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean()).getTotalPhysicalMemorySize() >> 20);
- return Math.min(physicalRam, OS_BITS == 32 ? 1536 : 4096); // Limit 32-bit OS to 1536 MiB, and 64-bit OS to 4096 MiB (because it's enough)
- }
+ private static int getRAMAmount() {
+ int physicalRam = (int) (((OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean()).getTotalPhysicalMemorySize() >> 20);
+ return Math.min(physicalRam, OS_BITS == 32 ? 1536 : 4096); // Limit 32-bit OS to 1536 MiB, and 64-bit OS to 4096 MiB (because it's enough)
+ }
- private static Field getSysPathsField() {
- try {
- return getField(ClassLoader.class, "sys_paths");
- } catch (NoSuchFieldException e) {
- throw new InternalError(e);
- }
- }
+ private static Field getSysPathsField() {
+ try {
+ return getField(ClassLoader.class, "sys_paths");
+ } catch (NoSuchFieldException e) {
+ throw new InternalError(e);
+ }
+ }
- private static URLClassPath getURLClassPath() {
- try {
- return (URLClassPath) getField(URLClassLoader.class, "ucp").get(LOADER);
- } catch (NoSuchFieldException | IllegalAccessException e) {
- throw new InternalError(e);
- }
- }
+ private static URLClassPath getURLClassPath() {
+ try {
+ return (URLClassPath) getField(URLClassLoader.class, "ucp").get(LOADER);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ throw new InternalError(e);
+ }
+ }
- private static Field getUsrPathsField() {
- try {
- return getField(ClassLoader.class, "usr_paths");
- } catch (NoSuchFieldException e) {
- throw new InternalError(e);
- }
- }
+ private static Field getUsrPathsField() {
+ try {
+ return getField(ClassLoader.class, "usr_paths");
+ } catch (NoSuchFieldException e) {
+ throw new InternalError(e);
+ }
+ }
- @LauncherAPI
- public enum OS {
- MUSTDIE("mustdie"), LINUX("linux"), MACOSX("macosx");
- public final String name;
+ @LauncherAPI
+ public enum OS {
+ MUSTDIE("mustdie"), LINUX("linux"), MACOSX("macosx");
+ public final String name;
- OS(String name) {
- this.name = name;
- }
+ OS(String name) {
+ this.name = name;
+ }
- public static OS byName(String name) {
- if (name.startsWith("Windows")) {
- return MUSTDIE;
- }
- if (name.startsWith("Linux")) {
- return LINUX;
- }
- if (name.startsWith("Mac OS X")) {
- return MACOSX;
- }
- throw new RuntimeException(String.format("This shit is not yet supported: '%s'", name));
- }
- }
+ public static OS byName(String name) {
+ if (name.startsWith("Windows")) {
+ return MUSTDIE;
+ }
+ if (name.startsWith("Linux")) {
+ return LINUX;
+ }
+ if (name.startsWith("Mac OS X")) {
+ return MACOSX;
+ }
+ throw new RuntimeException(String.format("This shit is not yet supported: '%s'", name));
+ }
+ }
}
diff --git a/Launcher/source/helper/LogHelper.java b/Launcher/source/helper/LogHelper.java
index de123d7..00fc37d 100644
--- a/Launcher/source/helper/LogHelper.java
+++ b/Launcher/source/helper/LogHelper.java
@@ -18,313 +18,315 @@
import launcher.Launcher;
import launcher.LauncherAPI;
import org.fusesource.jansi.Ansi;
+import org.fusesource.jansi.Ansi.Attribute;
+import org.fusesource.jansi.Ansi.Color;
import org.fusesource.jansi.AnsiConsole;
import org.fusesource.jansi.AnsiOutputStream;
public final class LogHelper {
- @LauncherAPI public static final String DEBUG_PROPERTY = "launcher.debug";
- @LauncherAPI public static final String NO_JANSI_PROPERTY = "launcher.noJAnsi";
- @LauncherAPI public static final boolean JANSI;
+ @LauncherAPI public static final String DEBUG_PROPERTY = "launcher.debug";
+ @LauncherAPI public static final String NO_JANSI_PROPERTY = "launcher.noJAnsi";
+ @LauncherAPI public static final boolean JANSI;
- // Output settings
- private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss", Locale.US);
- private static final AtomicBoolean DEBUG_ENABLED = new AtomicBoolean(Boolean.getBoolean(DEBUG_PROPERTY));
- private static final Set