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 OUTPUTS = Collections.newSetFromMap(new ConcurrentHashMap<>(2)); - private static final Output STD_OUTPUT; + // 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 OUTPUTS = Collections.newSetFromMap(new ConcurrentHashMap<>(2)); + private static final Output STD_OUTPUT; - private LogHelper() { - } + private LogHelper() { + } - @LauncherAPI - public static void addOutput(Output output) { - OUTPUTS.add(Objects.requireNonNull(output, "output")); - } + @LauncherAPI + public static void addOutput(Output output) { + OUTPUTS.add(Objects.requireNonNull(output, "output")); + } - @LauncherAPI - public static void addOutput(Path file) throws IOException { - if (JANSI) { - addOutput(new JAnsiOutput(IOHelper.newOutput(file, true))); - } else { - addOutput(IOHelper.newWriter(file, true)); - } - } + @LauncherAPI + public static void addOutput(Path file) throws IOException { + if (JANSI) { + addOutput(new JAnsiOutput(IOHelper.newOutput(file, true))); + } else { + addOutput(IOHelper.newWriter(file, true)); + } + } - @LauncherAPI - public static void addOutput(Writer writer) throws IOException { - addOutput(new WriterOutput(writer)); - } + @LauncherAPI + public static void addOutput(Writer writer) throws IOException { + addOutput(new WriterOutput(writer)); + } - @LauncherAPI - public static void debug(String message) { - if (isDebugEnabled()) { - log(Level.DEBUG, message, false); - } - } + @LauncherAPI + public static void debug(String message) { + if (isDebugEnabled()) { + log(Level.DEBUG, message, false); + } + } - @LauncherAPI - public static void debug(String format, Object... args) { - debug(String.format(format, args)); - } + @LauncherAPI + public static void debug(String format, Object... args) { + debug(String.format(format, args)); + } - @LauncherAPI - public static void error(Throwable exc) { - error(isDebugEnabled() ? toString(exc) : exc.toString()); - } + @LauncherAPI + public static void error(Throwable exc) { + error(isDebugEnabled() ? toString(exc) : exc.toString()); + } - @LauncherAPI - public static void error(String message) { - log(Level.ERROR, message, false); - } + @LauncherAPI + public static void error(String message) { + log(Level.ERROR, message, false); + } - @LauncherAPI - public static void error(String format, Object... args) { - error(String.format(format, args)); - } + @LauncherAPI + public static void error(String format, Object... args) { + error(String.format(format, args)); + } - @LauncherAPI - public static void info(String message) { - log(Level.INFO, message, false); - } + @LauncherAPI + public static void info(String message) { + log(Level.INFO, message, false); + } - @LauncherAPI - public static void info(String format, Object... args) { - info(String.format(format, args)); - } + @LauncherAPI + public static void info(String format, Object... args) { + info(String.format(format, args)); + } - @LauncherAPI - public static boolean isDebugEnabled() { - return DEBUG_ENABLED.get(); - } + @LauncherAPI + public static boolean isDebugEnabled() { + return DEBUG_ENABLED.get(); + } - @LauncherAPI - public static void log(Level level, String message, boolean sub) { - String dateTime = DATE_TIME_FORMATTER.format(LocalDateTime.now()); - println(JANSI ? ansiFormatLog(level, dateTime, message, sub) : - formatLog(level, message, dateTime, sub)); - } + @LauncherAPI + public static void setDebugEnabled(boolean debugEnabled) { + DEBUG_ENABLED.set(debugEnabled); + } - @LauncherAPI - public static void printVersion(String product) { - println(JANSI ? ansiFormatVersion(product) : formatVersion(product)); - } + @LauncherAPI + public static void log(Level level, String message, boolean sub) { + String dateTime = DATE_TIME_FORMATTER.format(LocalDateTime.now()); + println(JANSI ? ansiFormatLog(level, dateTime, message, sub) : + formatLog(level, message, dateTime, sub)); + } - @LauncherAPI - public static synchronized void println(String message) { - for (Output output : OUTPUTS) { - output.println(message); - } - } + @LauncherAPI + public static void printVersion(String product) { + println(JANSI ? ansiFormatVersion(product) : formatVersion(product)); + } - @LauncherAPI - public static boolean removeOutput(Output output) { - return OUTPUTS.remove(output); - } + @LauncherAPI + public static synchronized void println(String message) { + for (Output output : OUTPUTS) { + output.println(message); + } + } - @LauncherAPI - public static boolean removeStdOutput() { - return removeOutput(STD_OUTPUT); - } + @LauncherAPI + public static boolean removeOutput(Output output) { + return OUTPUTS.remove(output); + } - @LauncherAPI - public static void setDebugEnabled(boolean debugEnabled) { - DEBUG_ENABLED.set(debugEnabled); - } + @LauncherAPI + public static boolean removeStdOutput() { + return removeOutput(STD_OUTPUT); + } - @LauncherAPI - public static void subDebug(String message) { - if (isDebugEnabled()) { - log(Level.DEBUG, message, true); - } - } + @LauncherAPI + public static void subDebug(String message) { + if (isDebugEnabled()) { + log(Level.DEBUG, message, true); + } + } - @LauncherAPI - public static void subDebug(String format, Object... args) { - subDebug(String.format(format, args)); - } + @LauncherAPI + public static void subDebug(String format, Object... args) { + subDebug(String.format(format, args)); + } - @LauncherAPI - public static void subInfo(String message) { - log(Level.INFO, message, true); - } + @LauncherAPI + public static void subInfo(String message) { + log(Level.INFO, message, true); + } - @LauncherAPI - public static void subInfo(String format, Object... args) { - subInfo(String.format(format, args)); - } + @LauncherAPI + public static void subInfo(String format, Object... args) { + subInfo(String.format(format, args)); + } - @LauncherAPI - public static void subWarning(String message) { - log(Level.WARNING, message, true); - } + @LauncherAPI + public static void subWarning(String message) { + log(Level.WARNING, message, true); + } - @LauncherAPI - public static void subWarning(String format, Object... args) { - subWarning(String.format(format, args)); - } + @LauncherAPI + public static void subWarning(String format, Object... args) { + subWarning(String.format(format, args)); + } - @LauncherAPI - public static String toString(Throwable exc) { - try (StringWriter sw = new StringWriter()) { - try (PrintWriter pw = new PrintWriter(sw)) { - exc.printStackTrace(pw); - } - return sw.toString(); - } catch (IOException e) { - throw new InternalError(e); - } - } + @LauncherAPI + public static String toString(Throwable exc) { + try (StringWriter sw = new StringWriter()) { + try (PrintWriter pw = new PrintWriter(sw)) { + exc.printStackTrace(pw); + } + return sw.toString(); + } catch (IOException e) { + throw new InternalError(e); + } + } - @LauncherAPI - public static void warning(String message) { - log(Level.WARNING, message, false); - } + @LauncherAPI + public static void warning(String message) { + log(Level.WARNING, message, false); + } - @LauncherAPI - public static void warning(String format, Object... args) { - warning(String.format(format, args)); - } + @LauncherAPI + public static void warning(String format, Object... args) { + warning(String.format(format, args)); + } - private static String ansiFormatLog(Level level, String dateTime, String message, boolean sub) { - Ansi.Color levelColor; - boolean bright = level != Level.DEBUG; - switch (level) { - case WARNING: - levelColor = Ansi.Color.YELLOW; - break; - case ERROR: - levelColor = Ansi.Color.RED; - break; - default: // INFO, DEBUG, Unknown - levelColor = Ansi.Color.WHITE; - break; - } + private static String ansiFormatLog(Level level, String dateTime, String message, boolean sub) { + Color levelColor; + boolean bright = level != Level.DEBUG; + switch (level) { + case WARNING: + levelColor = Color.YELLOW; + break; + case ERROR: + levelColor = Color.RED; + break; + default: // INFO, DEBUG, Unknown + levelColor = Color.WHITE; + break; + } - // Date-time - Ansi ansi = new Ansi(); - ansi.fg(Ansi.Color.WHITE).a(dateTime); + // Date-time + Ansi ansi = new Ansi(); + ansi.fg(Color.WHITE).a(dateTime); - // Level - ansi.fgBright(Ansi.Color.WHITE).a(" [").bold(); - if (bright) { - ansi.fgBright(levelColor); - } else { - ansi.fg(levelColor); - } - ansi.a(level).boldOff().fgBright(Ansi.Color.WHITE).a("] "); + // Level + ansi.fgBright(Color.WHITE).a(" [").bold(); + if (bright) { + ansi.fgBright(levelColor); + } else { + ansi.fg(levelColor); + } + ansi.a(level).boldOff().fgBright(Color.WHITE).a("] "); - // Message - if (bright) { - ansi.fgBright(levelColor); - } else { - ansi.fg(levelColor); - } - if (sub) { - ansi.a(' ').a(Ansi.Attribute.ITALIC); - } - ansi.a(message); + // Message + if (bright) { + ansi.fgBright(levelColor); + } else { + ansi.fg(levelColor); + } + if (sub) { + ansi.a(' ').a(Attribute.ITALIC); + } + ansi.a(message); - // Finish with reset code - return ansi.reset().toString(); - } + // Finish with reset code + return ansi.reset().toString(); + } - private static String ansiFormatVersion(String product) { - return new Ansi().bold(). // Setup - fgBright(Ansi.Color.MAGENTA).a("sashok724's "). // sashok724's - fgBright(Ansi.Color.CYAN).a(product). // Product - fgBright(Ansi.Color.WHITE).a(" v").fgBright(Ansi.Color.BLUE).a(Launcher.VERSION). // Version - fgBright(Ansi.Color.WHITE).a(" (build #").fgBright(Ansi.Color.RED).a(Launcher.BUILD).fgBright(Ansi.Color.WHITE).a(')'). // Build# - reset().toString(); // To string - } + private static String ansiFormatVersion(String product) { + return new Ansi().bold(). // Setup + fgBright(Color.MAGENTA).a("sashok724's "). // sashok724's + fgBright(Color.CYAN).a(product). // Product + fgBright(Color.WHITE).a(" v").fgBright(Color.BLUE).a(Launcher.VERSION). // Version + fgBright(Color.WHITE).a(" (build #").fgBright(Color.RED).a(Launcher.BUILD).fgBright(Color.WHITE).a(')'). // Build# + reset().toString(); // To string + } - private static String formatLog(Level level, String message, String dateTime, boolean sub) { - if (sub) { - message = ' ' + message; - } - return dateTime + " [" + level.name + "] " + message; - } + private static String formatLog(Level level, String message, String dateTime, boolean sub) { + if (sub) { + message = ' ' + message; + } + return dateTime + " [" + level.name + "] " + message; + } - private static String formatVersion(String product) { - return String.format("sashok724's %s v%s (build #%s)", product, Launcher.VERSION, Launcher.BUILD); - } + private static String formatVersion(String product) { + return String.format("sashok724's %s v%s (build #%s)", product, Launcher.VERSION, Launcher.BUILD); + } - static { - // Use JAnsi if available - boolean jansi; - try { + static { + // Use JAnsi if available + boolean jansi; + try { if (Boolean.getBoolean(NO_JANSI_PROPERTY)) { jansi = false; } else { Class.forName("org.fusesource.jansi.Ansi"); AnsiConsole.systemInstall(); jansi = true; - } - } catch (ClassNotFoundException ignored) { - jansi = false; - } - JANSI = jansi; + } + } catch (ClassNotFoundException ignored) { + jansi = false; + } + JANSI = jansi; - // Add std writer - STD_OUTPUT = System.out::println; - addOutput(STD_OUTPUT); + // Add std writer + STD_OUTPUT = System.out::println; + addOutput(STD_OUTPUT); - // Add file log writer - String logFile = System.getProperty("launcher.logFile"); - if (logFile != null) { - try { - addOutput(IOHelper.toPath(logFile)); - } catch (IOException e) { - error(e); - } - } - } + // Add file log writer + String logFile = System.getProperty("launcher.logFile"); + if (logFile != null) { + try { + addOutput(IOHelper.toPath(logFile)); + } catch (IOException e) { + error(e); + } + } + } - private static class WriterOutput implements Output, AutoCloseable { - private final Writer writer; + @LauncherAPI + @FunctionalInterface + public interface Output { + void println(String message); + } - private WriterOutput(Writer writer) throws IOException { - this.writer = writer; - } + @LauncherAPI + public enum Level { + DEBUG("DEBUG"), INFO("INFO"), WARNING("WARN"), ERROR("ERROR"); + public final String name; - @Override - public void close() throws IOException { - writer.close(); - } + Level(String name) { + this.name = name; + } - @Override - public void println(String message) { - try { - writer.write(message + System.lineSeparator()); - writer.flush(); - } catch (IOException ignored) { - // Do nothing? - } - } - } + @Override + public String toString() { + return name; + } + } - private static final class JAnsiOutput extends WriterOutput { - private JAnsiOutput(OutputStream output) throws IOException { - super(IOHelper.newWriter(new AnsiOutputStream(output))); - } - } + private static final class JAnsiOutput extends WriterOutput { + private JAnsiOutput(OutputStream output) throws IOException { + super(IOHelper.newWriter(new AnsiOutputStream(output))); + } + } - @LauncherAPI - @FunctionalInterface - public interface Output { - void println(String message); - } + private static class WriterOutput implements Output, AutoCloseable { + private final Writer writer; - @LauncherAPI - public enum Level { - DEBUG("DEBUG"), INFO("INFO"), WARNING("WARN"), ERROR("ERROR"); - public final String name; + private WriterOutput(Writer writer) { + this.writer = writer; + } - Level(String name) { - this.name = name; - } + @Override + public void close() throws IOException { + writer.close(); + } - @Override - public String toString() { - return name; - } - } + @Override + public void println(String message) { + try { + writer.write(message + System.lineSeparator()); + writer.flush(); + } catch (IOException ignored) { + // Do nothing? + } + } + } } diff --git a/Launcher/source/helper/SecurityHelper.java b/Launcher/source/helper/SecurityHelper.java index 064808f..64d429b 100644 --- a/Launcher/source/helper/SecurityHelper.java +++ b/Launcher/source/helper/SecurityHelper.java @@ -34,452 +34,452 @@ import sun.misc.Resource; public final class SecurityHelper { - // Algorithm constants - @LauncherAPI public static final String RSA_ALGO = "RSA"; - @LauncherAPI public static final String RSA_SIGN_ALGO = "SHA256withRSA"; - @LauncherAPI public static final String RSA_CIPHER_ALGO = "RSA/ECB/PKCS1Padding"; + // Algorithm constants + @LauncherAPI public static final String RSA_ALGO = "RSA"; + @LauncherAPI public static final String RSA_SIGN_ALGO = "SHA256withRSA"; + @LauncherAPI public static final String RSA_CIPHER_ALGO = "RSA/ECB/PKCS1Padding"; - // Algorithm size constants - @LauncherAPI public static final int TOKEN_LENGTH = 16; - @LauncherAPI public static final int TOKEN_STRING_LENGTH = TOKEN_LENGTH << 1; - @LauncherAPI public static final int RSA_KEY_LENGTH_BITS = 2048; - @LauncherAPI public static final int RSA_KEY_LENGTH = RSA_KEY_LENGTH_BITS / Byte.SIZE; - @LauncherAPI public static final int CRYPTO_MAX_LENGTH = 2048; + // Algorithm size constants + @LauncherAPI public static final int TOKEN_LENGTH = 16; + @LauncherAPI public static final int TOKEN_STRING_LENGTH = TOKEN_LENGTH << 1; + @LauncherAPI public static final int RSA_KEY_LENGTH_BITS = 2048; + @LauncherAPI public static final int RSA_KEY_LENGTH = RSA_KEY_LENGTH_BITS / Byte.SIZE; + @LauncherAPI public static final int CRYPTO_MAX_LENGTH = 2048; - // Certificate constants - @LauncherAPI public static final String CERTIFICATE_DIGEST = "fca9659209c6b3b510d9d0e328f37ea0e8df11b6f897c70e4fce440501f43075"; - @LauncherAPI public static final String HEX = "0123456789abcdef"; + // Certificate constants + @LauncherAPI public static final String CERTIFICATE_DIGEST = "fca9659209c6b3b510d9d0e328f37ea0e8df11b6f897c70e4fce440501f43075"; + @LauncherAPI public static final String HEX = "0123456789abcdef"; - // Random generator constants - private static final char[] VOWELS = { 'e', 'u', 'i', 'o', 'a' }; - private static final char[] CONS = { 'r', 't', 'p', 's', 'd', 'f', 'g', 'h', 'k', 'l', 'c', 'v', 'b', 'n', 'm' }; + // Random generator constants + private static final char[] VOWELS = { 'e', 'u', 'i', 'o', 'a' }; + private static final char[] CONS = { 'r', 't', 'p', 's', 'd', 'f', 'g', 'h', 'k', 'l', 'c', 'v', 'b', 'n', 'm' }; - private SecurityHelper() { - } + private SecurityHelper() { + } - @LauncherAPI - public static byte[] digest(DigestAlgorithm algo, String s) { - return digest(algo, IOHelper.encode(s)); - } + @LauncherAPI + public static byte[] digest(DigestAlgorithm algo, String s) { + return digest(algo, IOHelper.encode(s)); + } - @LauncherAPI - public static byte[] digest(DigestAlgorithm algo, URL url) throws IOException { - try (InputStream input = IOHelper.newInput(url)) { - return digest(algo, input); - } - } + @LauncherAPI + public static byte[] digest(DigestAlgorithm algo, URL url) throws IOException { + try (InputStream input = IOHelper.newInput(url)) { + return digest(algo, input); + } + } - @LauncherAPI - public static byte[] digest(DigestAlgorithm algo, Path file) throws IOException { - try (InputStream input = IOHelper.newInput(file)) { - return digest(algo, input); - } - } + @LauncherAPI + public static byte[] digest(DigestAlgorithm algo, Path file) throws IOException { + try (InputStream input = IOHelper.newInput(file)) { + return digest(algo, input); + } + } - @LauncherAPI - public static byte[] digest(DigestAlgorithm algo, byte[] bytes) { - return newDigest(algo).digest(bytes); - } + @LauncherAPI + public static byte[] digest(DigestAlgorithm algo, byte[] bytes) { + return newDigest(algo).digest(bytes); + } - @LauncherAPI - public static byte[] digest(DigestAlgorithm algo, InputStream input) throws IOException { - byte[] buffer = IOHelper.newBuffer(); - MessageDigest digest = newDigest(algo); - for (int length = input.read(buffer); length != -1; length = input.read(buffer)) { - digest.update(buffer, 0, length); - } - return digest.digest(); - } + @LauncherAPI + public static byte[] digest(DigestAlgorithm algo, InputStream input) throws IOException { + byte[] buffer = IOHelper.newBuffer(); + MessageDigest digest = newDigest(algo); + for (int length = input.read(buffer); length != -1; length = input.read(buffer)) { + digest.update(buffer, 0, length); + } + return digest.digest(); + } - @LauncherAPI - public static KeyPair genRSAKeyPair(SecureRandom random) { - try { - KeyPairGenerator generator = KeyPairGenerator.getInstance(RSA_ALGO); - generator.initialize(RSA_KEY_LENGTH_BITS, random); - return generator.genKeyPair(); - } catch (NoSuchAlgorithmException e) { - throw new InternalError(e); - } - } + @LauncherAPI + public static KeyPair genRSAKeyPair(SecureRandom random) { + try { + KeyPairGenerator generator = KeyPairGenerator.getInstance(RSA_ALGO); + generator.initialize(RSA_KEY_LENGTH_BITS, random); + return generator.genKeyPair(); + } catch (NoSuchAlgorithmException e) { + throw new InternalError(e); + } + } - @LauncherAPI - public static KeyPair genRSAKeyPair() { - return genRSAKeyPair(newRandom()); - } + @LauncherAPI + public static KeyPair genRSAKeyPair() { + return genRSAKeyPair(newRandom()); + } - @LauncherAPI - public static boolean isValidCertificate(Certificate cert) { - try { - return toHex(digest(DigestAlgorithm.SHA256, cert.getEncoded())).equals(CERTIFICATE_DIGEST); - } catch (CertificateEncodingException e) { - throw new InternalError(e); - } - } + @LauncherAPI + public static boolean isValidCertificate(Certificate cert) { + try { + return toHex(digest(DigestAlgorithm.SHA256, cert.getEncoded())).equals(CERTIFICATE_DIGEST); + } catch (CertificateEncodingException e) { + throw new InternalError(e); + } + } - @LauncherAPI - public static boolean isValidCertificates(Certificate... certs) { - return certs != null && certs.length == 1 && isValidCertificate(certs[0]); - } + @LauncherAPI + public static boolean isValidCertificates(Certificate... certs) { + return certs != null && certs.length == 1 && isValidCertificate(certs[0]); + } - @LauncherAPI - public static boolean isValidCertificates(Class clazz) { - // Verify META-INF/MANIFEST.MF certificate - Resource metaInf = JVMHelper.UCP.getResource(JarFile.MANIFEST_NAME); - if (metaInf == null || !isValidCertificates(metaInf.getCertificates())) { - return false; - } + @LauncherAPI + public static boolean isValidCertificates(Class clazz) { + // Verify META-INF/MANIFEST.MF certificate + Resource metaInf = JVMHelper.UCP.getResource(JarFile.MANIFEST_NAME); + if (metaInf == null || !isValidCertificates(metaInf.getCertificates())) { + return false; + } - // Verify class certificate - CodeSource source = clazz.getProtectionDomain().getCodeSource(); - return source != null && isValidCertificates(source.getCertificates()); - } + // Verify class certificate + CodeSource source = clazz.getProtectionDomain().getCodeSource(); + return source != null && isValidCertificates(source.getCertificates()); + } - @LauncherAPI - public static boolean isValidSign(Path path, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { - try (InputStream input = IOHelper.newInput(path)) { - return isValidSign(input, sign, publicKey); - } - } + @LauncherAPI + public static boolean isValidSign(Path path, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { + try (InputStream input = IOHelper.newInput(path)) { + return isValidSign(input, sign, publicKey); + } + } - @LauncherAPI - public static boolean isValidSign(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException { - Signature signature = newRSAVerifySignature(publicKey); - try { - signature.update(bytes); - } catch (SignatureException e) { - throw new InternalError(e); - } - return signature.verify(sign); - } + @LauncherAPI + public static boolean isValidSign(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException { + Signature signature = newRSAVerifySignature(publicKey); + try { + signature.update(bytes); + } catch (SignatureException e) { + throw new InternalError(e); + } + return signature.verify(sign); + } - @LauncherAPI - public static boolean isValidSign(InputStream input, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { - Signature signature = newRSAVerifySignature(publicKey); - updateSignature(input, signature); - return signature.verify(sign); - } + @LauncherAPI + public static boolean isValidSign(InputStream input, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { + Signature signature = newRSAVerifySignature(publicKey); + updateSignature(input, signature); + return signature.verify(sign); + } - @LauncherAPI - public static boolean isValidSign(URL url, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { - try (InputStream input = IOHelper.newInput(url)) { - return isValidSign(input, sign, publicKey); - } - } + @LauncherAPI + public static boolean isValidSign(URL url, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { + try (InputStream input = IOHelper.newInput(url)) { + return isValidSign(input, sign, publicKey); + } + } - @LauncherAPI - public static boolean isValidToken(CharSequence token) { - return token.length() == TOKEN_STRING_LENGTH && token.chars().allMatch(ch -> HEX.indexOf(ch) >= 0); - } + @LauncherAPI + public static boolean isValidToken(CharSequence token) { + return token.length() == TOKEN_STRING_LENGTH && token.chars().allMatch(ch -> HEX.indexOf(ch) >= 0); + } - @LauncherAPI - public static MessageDigest newDigest(DigestAlgorithm algo) { - VerifyHelper.verify(algo, a -> a != DigestAlgorithm.PLAIN, "PLAIN digest"); - try { - return MessageDigest.getInstance(algo.name); - } catch (NoSuchAlgorithmException e) { - throw new InternalError(e); - } - } + @LauncherAPI + public static MessageDigest newDigest(DigestAlgorithm algo) { + VerifyHelper.verify(algo, a -> a != DigestAlgorithm.PLAIN, "PLAIN digest"); + try { + return MessageDigest.getInstance(algo.name); + } catch (NoSuchAlgorithmException e) { + throw new InternalError(e); + } + } - @LauncherAPI - public static Cipher newRSADecryptCipher(RSAPrivateKey key) { - return newRSACipher(Cipher.DECRYPT_MODE, key); - } + @LauncherAPI + public static Cipher newRSADecryptCipher(RSAPrivateKey key) { + return newRSACipher(Cipher.DECRYPT_MODE, key); + } - @LauncherAPI - public static Cipher newRSAEncryptCipher(RSAPublicKey key) { - return newRSACipher(Cipher.ENCRYPT_MODE, key); - } + @LauncherAPI + public static Cipher newRSAEncryptCipher(RSAPublicKey key) { + return newRSACipher(Cipher.ENCRYPT_MODE, key); + } - @LauncherAPI - public static Signature newRSASignSignature(RSAPrivateKey key) { - Signature signature = newRSASignature(); - try { - signature.initSign(key); - } catch (InvalidKeyException e) { - throw new InternalError(e); - } - return signature; - } + @LauncherAPI + public static Signature newRSASignSignature(RSAPrivateKey key) { + Signature signature = newRSASignature(); + try { + signature.initSign(key); + } catch (InvalidKeyException e) { + throw new InternalError(e); + } + return signature; + } - @LauncherAPI - public static Signature newRSAVerifySignature(RSAPublicKey key) { - Signature signature = newRSASignature(); - try { - signature.initVerify(key); - } catch (InvalidKeyException e) { - throw new InternalError(e); - } - return signature; - } + @LauncherAPI + public static Signature newRSAVerifySignature(RSAPublicKey key) { + Signature signature = newRSASignature(); + try { + signature.initVerify(key); + } catch (InvalidKeyException e) { + throw new InternalError(e); + } + return signature; + } - @LauncherAPI - public static SecureRandom newRandom() { - return new SecureRandom(); - } + @LauncherAPI + public static SecureRandom newRandom() { + return new SecureRandom(); + } - @LauncherAPI - public static byte[] randomBytes(Random random, int length) { - byte[] bytes = new byte[length]; - random.nextBytes(bytes); - return bytes; - } + @LauncherAPI + public static byte[] randomBytes(Random random, int length) { + byte[] bytes = new byte[length]; + random.nextBytes(bytes); + return bytes; + } - @LauncherAPI - public static byte[] randomBytes(int length) { - return randomBytes(newRandom(), length); - } + @LauncherAPI + public static byte[] randomBytes(int length) { + return randomBytes(newRandom(), length); + } - @LauncherAPI - public static String randomStringToken(Random random) { - return toHex(randomToken(random)); - } + @LauncherAPI + public static String randomStringToken(Random random) { + return toHex(randomToken(random)); + } - @LauncherAPI - public static String randomStringToken() { - return randomStringToken(newRandom()); - } + @LauncherAPI + public static String randomStringToken() { + return randomStringToken(newRandom()); + } - @LauncherAPI - public static byte[] randomToken(Random random) { - return randomBytes(random, TOKEN_LENGTH); - } + @LauncherAPI + public static byte[] randomToken(Random random) { + return randomBytes(random, TOKEN_LENGTH); + } - @LauncherAPI - public static byte[] randomToken() { - return randomToken(newRandom()); - } + @LauncherAPI + public static byte[] randomToken() { + return randomToken(newRandom()); + } - @LauncherAPI - public static String randomUsername(Random random) { - int usernameLength = 3 + random.nextInt(7); // 3-9 + @LauncherAPI + public static String randomUsername(Random random) { + int usernameLength = 3 + random.nextInt(7); // 3-9 - // Choose prefix - String prefix; - int prefixType = random.nextInt(7); - if (usernameLength >= 5 && prefixType == 6) { // (6) 2-char - prefix = random.nextBoolean() ? "Mr" : "Dr"; - usernameLength -= 2; - } else if (usernameLength >= 6 && prefixType == 5) { // (5) 3-char - prefix = "Mrs"; - usernameLength -= 3; - } else { - prefix = ""; - } + // Choose prefix + String prefix; + int prefixType = random.nextInt(7); + if (usernameLength >= 5 && prefixType == 6) { // (6) 2-char + prefix = random.nextBoolean() ? "Mr" : "Dr"; + usernameLength -= 2; + } else if (usernameLength >= 6 && prefixType == 5) { // (5) 3-char + prefix = "Mrs"; + usernameLength -= 3; + } else { + prefix = ""; + } - // Choose suffix - String suffix; - int suffixType = random.nextInt(7); // 0-6, 7 values - if (usernameLength >= 5 && suffixType == 6) { // (6) 10-99 - suffix = String.valueOf(10 + random.nextInt(90)); - usernameLength -= 2; - } else if (usernameLength >= 7 && suffixType == 5) { // (5) 1990-2015 - suffix = String.valueOf(1990 + random.nextInt(26)); - usernameLength -= 4; - } else { - suffix = ""; - } + // Choose suffix + String suffix; + int suffixType = random.nextInt(7); // 0-6, 7 values + if (usernameLength >= 5 && suffixType == 6) { // (6) 10-99 + suffix = String.valueOf(10 + random.nextInt(90)); + usernameLength -= 2; + } else if (usernameLength >= 7 && suffixType == 5) { // (5) 1990-2015 + suffix = String.valueOf(1990 + random.nextInt(26)); + usernameLength -= 4; + } else { + suffix = ""; + } - // Choose name - int consRepeat = 0; - boolean consPrev = random.nextBoolean(); - char[] chars = new char[usernameLength]; - for (int i = 0; i < chars.length; i++) { - if (i > 1 && consPrev && random.nextInt(10) == 0) { // Doubled - chars[i] = chars[i - 1]; - continue; - } + // Choose name + int consRepeat = 0; + boolean consPrev = random.nextBoolean(); + char[] chars = new char[usernameLength]; + for (int i = 0; i < chars.length; i++) { + if (i > 1 && consPrev && random.nextInt(10) == 0) { // Doubled + chars[i] = chars[i - 1]; + continue; + } - // Choose next char - if (consRepeat < 1 && random.nextInt() == 5) { - consRepeat++; - } else { - consRepeat = 0; - consPrev ^= true; - } + // Choose next char + if (consRepeat < 1 && random.nextInt() == 5) { + consRepeat++; + } else { + consRepeat = 0; + consPrev ^= true; + } - // Choose char - char[] alphabet = consPrev ? CONS : VOWELS; - chars[i] = alphabet[random.nextInt(alphabet.length)]; - } + // Choose char + char[] alphabet = consPrev ? CONS : VOWELS; + chars[i] = alphabet[random.nextInt(alphabet.length)]; + } - // Make first letter uppercase - if (!prefix.isEmpty() || random.nextBoolean()) { - chars[0] = Character.toUpperCase(chars[0]); - } + // Make first letter uppercase + if (!prefix.isEmpty() || random.nextBoolean()) { + chars[0] = Character.toUpperCase(chars[0]); + } - // Return chosen name (and verify for sure) - return VerifyHelper.verifyUsername(prefix + new String(chars) + suffix); - } + // Return chosen name (and verify for sure) + return VerifyHelper.verifyUsername(prefix + new String(chars) + suffix); + } - @LauncherAPI - public static String randomUsername() { - return randomUsername(newRandom()); - } + @LauncherAPI + public static String randomUsername() { + return randomUsername(newRandom()); + } - @LauncherAPI - public static byte[] sign(InputStream input, RSAPrivateKey privateKey) throws IOException { - Signature signature = newRSASignSignature(privateKey); - updateSignature(input, signature); - try { - return signature.sign(); - } catch (SignatureException e) { - throw new InternalError(e); - } - } + @LauncherAPI + public static byte[] sign(InputStream input, RSAPrivateKey privateKey) throws IOException { + Signature signature = newRSASignSignature(privateKey); + updateSignature(input, signature); + try { + return signature.sign(); + } catch (SignatureException e) { + throw new InternalError(e); + } + } - @LauncherAPI - public static byte[] sign(byte[] bytes, RSAPrivateKey privateKey) { - Signature signature = newRSASignSignature(privateKey); - try { - signature.update(bytes); - return signature.sign(); - } catch (SignatureException e) { - throw new InternalError(e); - } - } + @LauncherAPI + public static byte[] sign(byte[] bytes, RSAPrivateKey privateKey) { + Signature signature = newRSASignSignature(privateKey); + try { + signature.update(bytes); + return signature.sign(); + } catch (SignatureException e) { + throw new InternalError(e); + } + } - @LauncherAPI - public static byte[] sign(Path path, RSAPrivateKey privateKey) throws IOException { - try (InputStream input = IOHelper.newInput(path)) { - return sign(input, privateKey); - } - } + @LauncherAPI + public static byte[] sign(Path path, RSAPrivateKey privateKey) throws IOException { + try (InputStream input = IOHelper.newInput(path)) { + return sign(input, privateKey); + } + } - @LauncherAPI - public static String toHex(byte[] bytes) { - int offset = 0; - char[] hex = new char[bytes.length << 1]; - for (byte currentByte : bytes) { - int ub = Byte.toUnsignedInt(currentByte); - hex[offset] = HEX.charAt(ub >>> 4); - offset++; - hex[offset] = HEX.charAt(ub & 0x0F); - offset++; - } - return new String(hex); - } + @LauncherAPI + public static String toHex(byte[] bytes) { + int offset = 0; + char[] hex = new char[bytes.length << 1]; + for (byte currentByte : bytes) { + int ub = Byte.toUnsignedInt(currentByte); + hex[offset] = HEX.charAt(ub >>> 4); + offset++; + hex[offset] = HEX.charAt(ub & 0x0F); + offset++; + } + return new String(hex); + } - @LauncherAPI - public static RSAPrivateKey toPrivateRSAKey(byte[] bytes) throws InvalidKeySpecException { - return (RSAPrivateKey) newRSAKeyFactory().generatePrivate(new PKCS8EncodedKeySpec(bytes)); - } + @LauncherAPI + public static RSAPrivateKey toPrivateRSAKey(byte[] bytes) throws InvalidKeySpecException { + return (RSAPrivateKey) newRSAKeyFactory().generatePrivate(new PKCS8EncodedKeySpec(bytes)); + } - @LauncherAPI - public static RSAPublicKey toPublicRSAKey(byte[] bytes) throws InvalidKeySpecException { - return (RSAPublicKey) newRSAKeyFactory().generatePublic(new X509EncodedKeySpec(bytes)); - } + @LauncherAPI + public static RSAPublicKey toPublicRSAKey(byte[] bytes) throws InvalidKeySpecException { + return (RSAPublicKey) newRSAKeyFactory().generatePublic(new X509EncodedKeySpec(bytes)); + } - @LauncherAPI - public static void verifyCertificates(Class clazz) { - if (!isValidCertificates(clazz)) { - throw new SecurityException("Invalid certificates"); - } - } + @LauncherAPI + public static void verifyCertificates(Class clazz) { + if (!isValidCertificates(clazz)) { + throw new SecurityException("Invalid certificates"); + } + } - @LauncherAPI - public static void verifySign(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException { - if (!isValidSign(bytes, sign, publicKey)) { - throw new SignatureException("Invalid sign"); - } - } + @LauncherAPI + public static void verifySign(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException { + if (!isValidSign(bytes, sign, publicKey)) { + throw new SignatureException("Invalid sign"); + } + } - @LauncherAPI - public static void verifySign(InputStream input, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { - if (!isValidSign(input, sign, publicKey)) { - throw new SignatureException("Invalid stream sign"); - } - } + @LauncherAPI + public static void verifySign(InputStream input, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { + if (!isValidSign(input, sign, publicKey)) { + throw new SignatureException("Invalid stream sign"); + } + } - @LauncherAPI - public static void verifySign(Path path, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { - if (!isValidSign(path, sign, publicKey)) { - throw new SignatureException(String.format("Invalid file sign: '%s'", path)); - } - } + @LauncherAPI + public static void verifySign(Path path, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { + if (!isValidSign(path, sign, publicKey)) { + throw new SignatureException(String.format("Invalid file sign: '%s'", path)); + } + } - @LauncherAPI - public static void verifySign(URL url, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { - if (!isValidSign(url, sign, publicKey)) { - throw new SignatureException(String.format("Invalid URL sign: '%s'", url)); - } - } + @LauncherAPI + public static void verifySign(URL url, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { + if (!isValidSign(url, sign, publicKey)) { + throw new SignatureException(String.format("Invalid URL sign: '%s'", url)); + } + } - @LauncherAPI - public static String verifyToken(String token) { - return VerifyHelper.verify(token, SecurityHelper::isValidToken, String.format("Invalid token: '%s'", token)); - } + @LauncherAPI + public static String verifyToken(String token) { + return VerifyHelper.verify(token, SecurityHelper::isValidToken, String.format("Invalid token: '%s'", token)); + } - private static Cipher newCipher(String algo) { - try { - return Cipher.getInstance(algo); - } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { - throw new InternalError(e); - } - } + private static Cipher newCipher(String algo) { + try { + return Cipher.getInstance(algo); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + throw new InternalError(e); + } + } - private static Cipher newRSACipher(int mode, RSAKey key) { - Cipher cipher = newCipher(RSA_CIPHER_ALGO); - try { - cipher.init(mode, (Key) key); - } catch (InvalidKeyException e) { - throw new InternalError(e); - } - return cipher; - } + private static Cipher newRSACipher(int mode, RSAKey key) { + Cipher cipher = newCipher(RSA_CIPHER_ALGO); + try { + cipher.init(mode, (Key) key); + } catch (InvalidKeyException e) { + throw new InternalError(e); + } + return cipher; + } - private static KeyFactory newRSAKeyFactory() { - try { - return KeyFactory.getInstance(RSA_ALGO); - } catch (NoSuchAlgorithmException e) { - throw new InternalError(e); - } - } + private static KeyFactory newRSAKeyFactory() { + try { + return KeyFactory.getInstance(RSA_ALGO); + } catch (NoSuchAlgorithmException e) { + throw new InternalError(e); + } + } - private static Signature newRSASignature() { - try { - return Signature.getInstance(RSA_SIGN_ALGO); - } catch (NoSuchAlgorithmException e) { - throw new InternalError(e); - } - } + private static Signature newRSASignature() { + try { + return Signature.getInstance(RSA_SIGN_ALGO); + } catch (NoSuchAlgorithmException e) { + throw new InternalError(e); + } + } - private static void updateSignature(InputStream input, Signature signature) throws IOException { - byte[] buffer = IOHelper.newBuffer(); - for (int length = input.read(buffer); length >= 0; length = input.read(buffer)) { - try { - signature.update(buffer, 0, length); - } catch (SignatureException e) { - throw new InternalError(e); - } - } - } + private static void updateSignature(InputStream input, Signature signature) throws IOException { + byte[] buffer = IOHelper.newBuffer(); + for (int length = input.read(buffer); length >= 0; length = input.read(buffer)) { + try { + signature.update(buffer, 0, length); + } catch (SignatureException e) { + throw new InternalError(e); + } + } + } - @LauncherAPI - public enum DigestAlgorithm { - PLAIN("plain"), MD5("MD5"), SHA1("SHA-1"), SHA224("SHA-224"), SHA256("SHA-256"), SHA512("SHA-512"); - private static final Map ALGORITHMS; - public final String name; + @LauncherAPI + public enum DigestAlgorithm { + PLAIN("plain"), MD5("MD5"), SHA1("SHA-1"), SHA224("SHA-224"), SHA256("SHA-256"), SHA512("SHA-512"); + private static final Map ALGORITHMS; + public final String name; - DigestAlgorithm(String name) { - this.name = name; - } + DigestAlgorithm(String name) { + this.name = name; + } - @Override - public String toString() { - return name; - } + @Override + public String toString() { + return name; + } - public static DigestAlgorithm byName(String name) { - return VerifyHelper.getMapValue(ALGORITHMS, name, String.format("Unknown digest algorithm: '%s'", name)); - } + public static DigestAlgorithm byName(String name) { + return VerifyHelper.getMapValue(ALGORITHMS, name, String.format("Unknown digest algorithm: '%s'", name)); + } - static { - DigestAlgorithm[] algorithmsValues = values(); - ALGORITHMS = new HashMap<>(algorithmsValues.length); - for (DigestAlgorithm algorithm : algorithmsValues) { - ALGORITHMS.put(algorithm.name, algorithm); - } - } - } + static { + DigestAlgorithm[] algorithmsValues = values(); + ALGORITHMS = new HashMap<>(algorithmsValues.length); + for (DigestAlgorithm algorithm : algorithmsValues) { + ALGORITHMS.put(algorithm.name, algorithm); + } + } + } } diff --git a/Launcher/source/helper/VerifyHelper.java b/Launcher/source/helper/VerifyHelper.java index f8e8fbc..6d8ae24 100644 --- a/Launcher/source/helper/VerifyHelper.java +++ b/Launcher/source/helper/VerifyHelper.java @@ -10,84 +10,84 @@ import launcher.LauncherAPI; public final class VerifyHelper { - @LauncherAPI public static final IntPredicate POSITIVE = i -> i > 0; - @LauncherAPI public static final IntPredicate NOT_NEGATIVE = i -> i >= 0; - @LauncherAPI public static final LongPredicate L_POSITIVE = l -> l > 0; - @LauncherAPI public static final LongPredicate L_NOT_NEGATIVE = l -> l >= 0; - @LauncherAPI public static final Predicate NOT_EMPTY = s -> !s.isEmpty(); - @LauncherAPI public static final Pattern USERNAME_PATTERN = Pattern.compile("[a-zA-Z0-9-_\\.]{1,16}"); + @LauncherAPI public static final IntPredicate POSITIVE = i -> i > 0; + @LauncherAPI public static final IntPredicate NOT_NEGATIVE = i -> i >= 0; + @LauncherAPI public static final LongPredicate L_POSITIVE = l -> l > 0; + @LauncherAPI public static final LongPredicate L_NOT_NEGATIVE = l -> l >= 0; + @LauncherAPI public static final Predicate NOT_EMPTY = s -> !s.isEmpty(); + @LauncherAPI public static final Pattern USERNAME_PATTERN = Pattern.compile("[a-zA-Z0-9-_\\.]{1,16}"); - private VerifyHelper() { - } + private VerifyHelper() { + } - @LauncherAPI - public static V getMapValue(Map map, K key, String error) { - return verify(map.get(key), v -> v != null, error); - } + @LauncherAPI + public static V getMapValue(Map map, K key, String error) { + return verify(map.get(key), v -> v != null, error); + } - @LauncherAPI - public static boolean isValidIDName(String name) { - return !name.isEmpty() && name.length() <= 255 && name.chars().allMatch(VerifyHelper::isValidIDNameChar); - } + @LauncherAPI + public static boolean isValidIDName(String name) { + return !name.isEmpty() && name.length() <= 255 && name.chars().allMatch(VerifyHelper::isValidIDNameChar); + } - @LauncherAPI - public static boolean isValidIDNameChar(int ch) { - return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '-' || ch == '_'; - } + @LauncherAPI + public static boolean isValidIDNameChar(int ch) { + return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '-' || ch == '_'; + } - @LauncherAPI - public static boolean isValidUsername(CharSequence username) { - return USERNAME_PATTERN.matcher(username).matches(); - } + @LauncherAPI + public static boolean isValidUsername(CharSequence username) { + return USERNAME_PATTERN.matcher(username).matches(); + } - public static void putIfAbsent(Map map, K key, V value, String error) { - verify(map.putIfAbsent(key, value), o -> o == null, error); - } + public static void putIfAbsent(Map map, K key, V value, String error) { + verify(map.putIfAbsent(key, value), o -> o == null, error); + } - @LauncherAPI - public static IntPredicate range(int min, int max) { - return i -> i >= min && i <= max; - } + @LauncherAPI + public static IntPredicate range(int min, int max) { + return i -> i >= min && i <= max; + } - @LauncherAPI - public static T verify(T object, Predicate predicate, String error) { - if (predicate.test(object)) { - return object; - } - throw new IllegalArgumentException(error); - } + @LauncherAPI + public static T verify(T object, Predicate predicate, String error) { + if (predicate.test(object)) { + return object; + } + throw new IllegalArgumentException(error); + } - @LauncherAPI - public static double verifyDouble(double d, DoublePredicate predicate, String error) { - if (predicate.test(d)) { - return d; - } - throw new IllegalArgumentException(error); - } + @LauncherAPI + public static double verifyDouble(double d, DoublePredicate predicate, String error) { + if (predicate.test(d)) { + return d; + } + throw new IllegalArgumentException(error); + } - @LauncherAPI - public static String verifyIDName(String name) { - return verify(name, VerifyHelper::isValidIDName, String.format("Invalid name: '%s'", name)); - } + @LauncherAPI + public static String verifyIDName(String name) { + return verify(name, VerifyHelper::isValidIDName, String.format("Invalid name: '%s'", name)); + } - @LauncherAPI - public static int verifyInt(int i, IntPredicate predicate, String error) { - if (predicate.test(i)) { - return i; - } - throw new IllegalArgumentException(error); - } + @LauncherAPI + public static int verifyInt(int i, IntPredicate predicate, String error) { + if (predicate.test(i)) { + return i; + } + throw new IllegalArgumentException(error); + } - @LauncherAPI - public static long verifyLong(long l, LongPredicate predicate, String error) { - if (predicate.test(l)) { - return l; - } - throw new IllegalArgumentException(error); - } + @LauncherAPI + public static long verifyLong(long l, LongPredicate predicate, String error) { + if (predicate.test(l)) { + return l; + } + throw new IllegalArgumentException(error); + } - @LauncherAPI - public static String verifyUsername(String username) { - return verify(username, VerifyHelper::isValidUsername, String.format("Invalid username: '%s'", username)); - } + @LauncherAPI + public static String verifyUsername(String username) { + return verify(username, VerifyHelper::isValidUsername, String.format("Invalid username: '%s'", username)); + } } diff --git a/Launcher/source/helper/js/JSApplication.java b/Launcher/source/helper/js/JSApplication.java index 37c629f..eed22e6 100644 --- a/Launcher/source/helper/js/JSApplication.java +++ b/Launcher/source/helper/js/JSApplication.java @@ -1,21 +1,21 @@ package launcher.helper.js; import java.util.concurrent.atomic.AtomicReference; - import javafx.application.Application; + import launcher.LauncherAPI; @LauncherAPI @SuppressWarnings("AbstractClassNeverImplemented") public abstract class JSApplication extends Application { - private static final AtomicReference INSTANCE = new AtomicReference<>(); + private static final AtomicReference INSTANCE = new AtomicReference<>(); - @SuppressWarnings("ConstructorNotProtectedInAbstractClass") - public JSApplication() { - INSTANCE.set(this); - } + @SuppressWarnings("ConstructorNotProtectedInAbstractClass") + public JSApplication() { + INSTANCE.set(this); + } - public static JSApplication getInstance() { - return INSTANCE.get(); - } -} \ No newline at end of file + public static JSApplication getInstance() { + return INSTANCE.get(); + } +} diff --git a/Launcher/source/request/CustomRequest.java b/Launcher/source/request/CustomRequest.java index 8971b54..100e291 100644 --- a/Launcher/source/request/CustomRequest.java +++ b/Launcher/source/request/CustomRequest.java @@ -1,39 +1,40 @@ package launcher.request; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.helper.VerifyHelper; import launcher.serialize.HInput; import launcher.serialize.HOutput; public abstract class CustomRequest extends Request { - @LauncherAPI - public CustomRequest(Launcher.Config config) { - super(config); - } + @LauncherAPI + public CustomRequest(Config config) { + super(config); + } - @LauncherAPI - public CustomRequest() { - this(null); - } + @LauncherAPI + public CustomRequest() { + this(null); + } - @Override - public final Type getType() { - return Type.CUSTOM; - } + @Override + public final Type getType() { + return Type.CUSTOM; + } - @Override - protected final T requestDo(HInput input, HOutput output) throws Exception { - output.writeASCII(VerifyHelper.verifyIDName(getName()), 255); - output.flush(); + @Override + protected final T requestDo(HInput input, HOutput output) throws Exception { + output.writeASCII(VerifyHelper.verifyIDName(getName()), 255); + output.flush(); - // Custom request redirect - return requestDoCustom(input, output); - } + // Custom request redirect + return requestDoCustom(input, output); + } - @LauncherAPI - public abstract String getName(); + @LauncherAPI + public abstract String getName(); - @LauncherAPI - protected abstract T requestDoCustom(HInput input, HOutput output); + @LauncherAPI + protected abstract T requestDoCustom(HInput input, HOutput output); } diff --git a/Launcher/source/request/PingRequest.java b/Launcher/source/request/PingRequest.java index 794d0bb..9e7f99b 100644 --- a/Launcher/source/request/PingRequest.java +++ b/Launcher/source/request/PingRequest.java @@ -3,34 +3,35 @@ import java.io.IOException; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.serialize.HInput; import launcher.serialize.HOutput; public final class PingRequest extends Request { - @LauncherAPI public static final byte EXPECTED_BYTE = 0b01010101; + @LauncherAPI public static final byte EXPECTED_BYTE = 0b01010101; - @LauncherAPI - public PingRequest(Launcher.Config config) { - super(config); - } + @LauncherAPI + public PingRequest(Config config) { + super(config); + } - @LauncherAPI - public PingRequest() { - this(null); - } + @LauncherAPI + public PingRequest() { + this(null); + } - @Override - public Type getType() { - return Type.PING; - } + @Override + public Type getType() { + return Type.PING; + } - @Override - protected Void requestDo(HInput input, HOutput output) throws IOException { - byte pong = (byte) input.readUnsignedByte(); - if (pong != EXPECTED_BYTE) { - throw new IOException("Illegal ping response: " + pong); - } - return null; - } + @Override + protected Void requestDo(HInput input, HOutput output) throws IOException { + byte pong = (byte) input.readUnsignedByte(); + if (pong != EXPECTED_BYTE) { + throw new IOException("Illegal ping response: " + pong); + } + return null; + } } diff --git a/Launcher/source/request/Request.java b/Launcher/source/request/Request.java index 0884f88..32c9b86 100644 --- a/Launcher/source/request/Request.java +++ b/Launcher/source/request/Request.java @@ -5,99 +5,101 @@ import java.util.concurrent.atomic.AtomicBoolean; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.helper.IOHelper; import launcher.helper.SecurityHelper; import launcher.serialize.HInput; import launcher.serialize.HOutput; import launcher.serialize.stream.EnumSerializer; +import launcher.serialize.stream.EnumSerializer.Itf; public abstract class Request { - private final AtomicBoolean started = new AtomicBoolean(false); - @LauncherAPI protected final Launcher.Config config; + @LauncherAPI protected final Config config; + private final AtomicBoolean started = new AtomicBoolean(false); - @LauncherAPI - protected Request(Launcher.Config config) { - this.config = config == null ? Launcher.getConfig() : config; - } + @LauncherAPI + protected Request(Config config) { + this.config = config == null ? Launcher.getConfig() : config; + } - @LauncherAPI - protected Request() { - this(null); - } + @LauncherAPI + protected Request() { + this(null); + } - @LauncherAPI - public abstract Type getType(); + @LauncherAPI + public abstract Type getType(); - @LauncherAPI - @SuppressWarnings("DesignForExtension") - public R request() throws Exception { - if (!started.compareAndSet(false, true)) { - throw new IllegalStateException("Request already started"); - } + @LauncherAPI + protected abstract R requestDo(HInput input, HOutput output) throws Exception; - // Make request to LaunchServer - try (Socket socket = IOHelper.newSocket()) { - socket.connect(IOHelper.resolve(config.address)); - try (HInput input = new HInput(socket.getInputStream()); - HOutput output = new HOutput(socket.getOutputStream())) { - writeHandshake(input, output); - return requestDo(input, output); - } - } - } + @LauncherAPI + @SuppressWarnings("DesignForExtension") + public R request() throws Exception { + if (!started.compareAndSet(false, true)) { + throw new IllegalStateException("Request already started"); + } - @LauncherAPI - protected final void readError(HInput input) throws IOException { - String error = input.readString(0); - if (!error.isEmpty()) { - requestError(error); - } - } + // Make request to LaunchServer + try (Socket socket = IOHelper.newSocket()) { + socket.connect(IOHelper.resolve(config.address)); + try (HInput input = new HInput(socket.getInputStream()); + HOutput output = new HOutput(socket.getOutputStream())) { + writeHandshake(input, output); + return requestDo(input, output); + } + } + } - @LauncherAPI - protected abstract R requestDo(HInput input, HOutput output) throws Exception; + @LauncherAPI + protected final void readError(HInput input) throws IOException { + String error = input.readString(0); + if (!error.isEmpty()) { + requestError(error); + } + } - private void writeHandshake(HInput input, HOutput output) throws IOException { - // Write handshake - output.writeInt(Launcher.PROTOCOL_MAGIC); - output.writeBigInteger(config.publicKey.getModulus(), SecurityHelper.RSA_KEY_LENGTH + 1); - EnumSerializer.write(output, getType()); - output.flush(); + private void writeHandshake(HInput input, HOutput output) throws IOException { + // Write handshake + output.writeInt(Launcher.PROTOCOL_MAGIC); + output.writeBigInteger(config.publicKey.getModulus(), SecurityHelper.RSA_KEY_LENGTH + 1); + EnumSerializer.write(output, getType()); + output.flush(); - // Verify is accepted - if (!input.readBoolean()) { - requestError("Serverside not accepted this connection"); - } - } + // Verify is accepted + if (!input.readBoolean()) { + requestError("Serverside not accepted this connection"); + } + } - @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); + } - @LauncherAPI - public enum Type implements EnumSerializer.Itf { - PING(0), // Ping request - LAUNCHER(1), UPDATE(2), UPDATE_LIST(3), // Update requests - AUTH(4), JOIN_SERVER(5), CHECK_SERVER(6), // Auth requests - PROFILE_BY_USERNAME(7), PROFILE_BY_UUID(8), BATCH_PROFILE_BY_USERNAME(9), // Profile requests - CUSTOM(255); // Custom requests - private static final EnumSerializer SERIALIZER = new EnumSerializer<>(Type.class); - private final int n; + @LauncherAPI + public enum Type implements Itf { + PING(0), // Ping request + LAUNCHER(1), UPDATE(2), UPDATE_LIST(3), // Update requests + AUTH(4), JOIN_SERVER(5), CHECK_SERVER(6), // Auth requests + PROFILE_BY_USERNAME(7), PROFILE_BY_UUID(8), BATCH_PROFILE_BY_USERNAME(9), // Profile requests + CUSTOM(255); // Custom requests + 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; + } - @LauncherAPI - public static Type read(HInput input) throws IOException { - return SERIALIZER.read(input); - } - } + @LauncherAPI + public static Type read(HInput input) throws IOException { + return SERIALIZER.read(input); + } + } } diff --git a/Launcher/source/request/RequestException.java b/Launcher/source/request/RequestException.java index d11853f..c0802ce 100644 --- a/Launcher/source/request/RequestException.java +++ b/Launcher/source/request/RequestException.java @@ -5,25 +5,25 @@ import launcher.LauncherAPI; public final class RequestException extends IOException { - private static final long serialVersionUID = 7558237657082664821L; + private static final long serialVersionUID = 7558237657082664821L; - @LauncherAPI - public RequestException(String message) { - super(message); - } + @LauncherAPI + public RequestException(String message) { + super(message); + } - @LauncherAPI - public RequestException(Throwable exc) { - super(exc); - } + @LauncherAPI + public RequestException(Throwable exc) { + super(exc); + } - @LauncherAPI - public RequestException(String message, Throwable exc) { - super(message, exc); - } + @LauncherAPI + public RequestException(String message, Throwable exc) { + super(message, exc); + } - @Override - public String toString() { - return getMessage(); - } + @Override + public String toString() { + return getMessage(); + } } diff --git a/Launcher/source/request/auth/AuthRequest.java b/Launcher/source/request/auth/AuthRequest.java index fe2cf4f..79924f0 100644 --- a/Launcher/source/request/auth/AuthRequest.java +++ b/Launcher/source/request/auth/AuthRequest.java @@ -4,55 +4,57 @@ import java.util.Arrays; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.client.PlayerProfile; import launcher.helper.SecurityHelper; import launcher.helper.VerifyHelper; import launcher.request.Request; +import launcher.request.auth.AuthRequest.Result; import launcher.serialize.HInput; import launcher.serialize.HOutput; -public final class AuthRequest extends Request { - private final String login; - private final byte[] encryptedPassword; +public final class AuthRequest extends Request { + private final String login; + private final byte[] encryptedPassword; - @LauncherAPI - public AuthRequest(Launcher.Config config, String login, byte[] encryptedPassword) { - super(config); - this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty"); - this.encryptedPassword = Arrays.copyOf(encryptedPassword, encryptedPassword.length); - } + @LauncherAPI + public AuthRequest(Config config, String login, byte[] encryptedPassword) { + super(config); + this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty"); + this.encryptedPassword = Arrays.copyOf(encryptedPassword, encryptedPassword.length); + } - @LauncherAPI - public AuthRequest(String login, byte[] encryptedPassword) { - this(null, login, encryptedPassword); - } + @LauncherAPI + public AuthRequest(String login, byte[] encryptedPassword) { + this(null, login, encryptedPassword); + } - @Override - public Type getType() { - return Type.AUTH; - } + @Override + public Type getType() { + return Type.AUTH; + } - @Override - protected Result requestDo(HInput input, HOutput output) throws IOException { - output.writeString(login, 255); - output.writeByteArray(encryptedPassword, SecurityHelper.CRYPTO_MAX_LENGTH); - output.flush(); + @Override + protected Result requestDo(HInput input, HOutput output) throws IOException { + output.writeString(login, 255); + output.writeByteArray(encryptedPassword, SecurityHelper.CRYPTO_MAX_LENGTH); + output.flush(); - // Read UUID and access token - readError(input); - PlayerProfile pp = new PlayerProfile(input); - String accessToken = input.readASCII(-SecurityHelper.TOKEN_STRING_LENGTH); - return new Result(pp, accessToken); - } + // Read UUID and access token + readError(input); + PlayerProfile pp = new PlayerProfile(input); + String accessToken = input.readASCII(-SecurityHelper.TOKEN_STRING_LENGTH); + return new Result(pp, accessToken); + } - public static final class Result { - @LauncherAPI public final PlayerProfile pp; - @LauncherAPI public final String accessToken; + public static final class Result { + @LauncherAPI public final PlayerProfile pp; + @LauncherAPI public final String accessToken; - private Result(PlayerProfile pp, String accessToken) { - this.pp = pp; - this.accessToken = accessToken; - } - } + private Result(PlayerProfile pp, String accessToken) { + this.pp = pp; + this.accessToken = accessToken; + } + } } diff --git a/Launcher/source/request/auth/CheckServerRequest.java b/Launcher/source/request/auth/CheckServerRequest.java index 90b14a6..1a5e18e 100644 --- a/Launcher/source/request/auth/CheckServerRequest.java +++ b/Launcher/source/request/auth/CheckServerRequest.java @@ -3,6 +3,7 @@ import java.io.IOException; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.client.PlayerProfile; import launcher.helper.VerifyHelper; @@ -11,34 +12,34 @@ import launcher.serialize.HOutput; public final class CheckServerRequest extends Request { - private final String username; - private final String serverID; + private final String username; + private final String serverID; - @LauncherAPI - public CheckServerRequest(Launcher.Config config, String username, String serverID) { - super(config); - this.username = VerifyHelper.verifyUsername(username); - this.serverID = JoinServerRequest.verifyServerID(serverID); - } + @LauncherAPI + public CheckServerRequest(Config config, String username, String serverID) { + super(config); + this.username = VerifyHelper.verifyUsername(username); + this.serverID = JoinServerRequest.verifyServerID(serverID); + } - @LauncherAPI - public CheckServerRequest(String username, String serverID) { - this(null, username, serverID); - } + @LauncherAPI + public CheckServerRequest(String username, String serverID) { + this(null, username, serverID); + } - @Override - public Type getType() { - return Type.CHECK_SERVER; - } + @Override + public Type getType() { + return Type.CHECK_SERVER; + } - @Override - protected PlayerProfile requestDo(HInput input, HOutput output) throws IOException { - output.writeASCII(username, 16); - output.writeASCII(serverID, 41); // 1 char for minus sign - output.flush(); + @Override + protected PlayerProfile requestDo(HInput input, HOutput output) throws IOException { + output.writeASCII(username, 16); + output.writeASCII(serverID, 41); // 1 char for minus sign + output.flush(); - // Read response - readError(input); - return input.readBoolean() ? new PlayerProfile(input) : null; - } + // Read response + readError(input); + return input.readBoolean() ? new PlayerProfile(input) : null; + } } diff --git a/Launcher/source/request/auth/JoinServerRequest.java b/Launcher/source/request/auth/JoinServerRequest.java index 04e9210..e1c3551 100644 --- a/Launcher/source/request/auth/JoinServerRequest.java +++ b/Launcher/source/request/auth/JoinServerRequest.java @@ -4,6 +4,7 @@ import java.util.regex.Pattern; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.helper.SecurityHelper; import launcher.helper.VerifyHelper; @@ -12,51 +13,51 @@ import launcher.serialize.HOutput; public final class JoinServerRequest extends Request { - private static final Pattern SERVERID_PATTERN = Pattern.compile("-?[0-9a-f]{1,40}"); + private static final Pattern SERVERID_PATTERN = Pattern.compile("-?[0-9a-f]{1,40}"); - // Instance - private final String username; - private final String accessToken; - private final String serverID; + // Instance + private final String username; + private final String accessToken; + private final String serverID; - @LauncherAPI - public JoinServerRequest(Launcher.Config config, String username, String accessToken, String serverID) { - super(config); - this.username = VerifyHelper.verifyUsername(username); - this.accessToken = SecurityHelper.verifyToken(accessToken); - this.serverID = verifyServerID(serverID); - } + @LauncherAPI + public JoinServerRequest(Config config, String username, String accessToken, String serverID) { + super(config); + this.username = VerifyHelper.verifyUsername(username); + this.accessToken = SecurityHelper.verifyToken(accessToken); + this.serverID = verifyServerID(serverID); + } - @LauncherAPI - public JoinServerRequest(String username, String accessToken, String serverID) { - this(null, username, accessToken, serverID); - } + @LauncherAPI + public JoinServerRequest(String username, String accessToken, String serverID) { + this(null, username, accessToken, serverID); + } - @Override - public Type getType() { - return Type.JOIN_SERVER; - } + @Override + public Type getType() { + return Type.JOIN_SERVER; + } - @Override - protected Boolean requestDo(HInput input, HOutput output) throws IOException { - output.writeASCII(username, 16); - output.writeASCII(accessToken, -SecurityHelper.TOKEN_STRING_LENGTH); - output.writeASCII(serverID, 41); // 1 char for minus sign - output.flush(); + @Override + protected Boolean requestDo(HInput input, HOutput output) throws IOException { + output.writeASCII(username, 16); + output.writeASCII(accessToken, -SecurityHelper.TOKEN_STRING_LENGTH); + output.writeASCII(serverID, 41); // 1 char for minus sign + output.flush(); - // Read response - readError(input); - return input.readBoolean(); - } + // Read response + readError(input); + return input.readBoolean(); + } - @LauncherAPI - public static boolean isValidServerID(CharSequence serverID) { - return SERVERID_PATTERN.matcher(serverID).matches(); - } + @LauncherAPI + public static boolean isValidServerID(CharSequence serverID) { + return SERVERID_PATTERN.matcher(serverID).matches(); + } - @LauncherAPI - public static String verifyServerID(String serverID) { - return VerifyHelper.verify(serverID, JoinServerRequest::isValidServerID, - String.format("Invalid server ID: '%s'", serverID)); - } + @LauncherAPI + public static String verifyServerID(String serverID) { + return VerifyHelper.verify(serverID, JoinServerRequest::isValidServerID, + String.format("Invalid server ID: '%s'", serverID)); + } } diff --git a/Launcher/source/request/update/LauncherRequest.java b/Launcher/source/request/update/LauncherRequest.java index e3e0f42..03f28e8 100644 --- a/Launcher/source/request/update/LauncherRequest.java +++ b/Launcher/source/request/update/LauncherRequest.java @@ -8,6 +8,7 @@ import java.util.List; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.client.ClientLauncher; import launcher.client.ClientProfile; @@ -16,86 +17,87 @@ import launcher.helper.LogHelper; import launcher.helper.SecurityHelper; import launcher.request.Request; +import launcher.request.update.LauncherRequest.Result; import launcher.serialize.HInput; import launcher.serialize.HOutput; import launcher.serialize.signed.SignedObjectHolder; -public final class LauncherRequest extends Request { - @LauncherAPI public static final Path BINARY_PATH = IOHelper.getCodeSource(Launcher.class); - @LauncherAPI public static final boolean EXE_BINARY = IOHelper.hasExtension(BINARY_PATH, "exe"); +public final class LauncherRequest extends Request { + @LauncherAPI public static final Path BINARY_PATH = IOHelper.getCodeSource(Launcher.class); + @LauncherAPI public static final boolean EXE_BINARY = IOHelper.hasExtension(BINARY_PATH, "exe"); - @LauncherAPI - public LauncherRequest(Launcher.Config config) { - super(config); - } + @LauncherAPI + public LauncherRequest(Config config) { + super(config); + } - @LauncherAPI - public LauncherRequest() { - this(null); - } + @LauncherAPI + public LauncherRequest() { + this(null); + } - @Override - public Type getType() { - return Type.LAUNCHER; - } + @Override + public Type getType() { + return Type.LAUNCHER; + } - @Override - @SuppressWarnings("CallToSystemExit") - protected Result requestDo(HInput input, HOutput output) throws Exception { - output.writeBoolean(EXE_BINARY); - output.flush(); - readError(input); + @Override + @SuppressWarnings("CallToSystemExit") + protected Result requestDo(HInput input, HOutput output) throws Exception { + output.writeBoolean(EXE_BINARY); + output.flush(); + readError(input); - // Verify launcher sign - RSAPublicKey publicKey = config.publicKey; - byte[] sign = input.readByteArray(-SecurityHelper.RSA_KEY_LENGTH); - boolean shouldUpdate = !SecurityHelper.isValidSign(BINARY_PATH, sign, publicKey); + // Verify launcher sign + RSAPublicKey publicKey = config.publicKey; + byte[] sign = input.readByteArray(-SecurityHelper.RSA_KEY_LENGTH); + boolean shouldUpdate = !SecurityHelper.isValidSign(BINARY_PATH, sign, publicKey); - // Update launcher if need - output.writeBoolean(shouldUpdate); - output.flush(); - if (shouldUpdate) { - byte[] binary = input.readByteArray(0); - SecurityHelper.verifySign(binary, sign, publicKey); + // Update launcher if need + output.writeBoolean(shouldUpdate); + output.flush(); + if (shouldUpdate) { + byte[] binary = input.readByteArray(0); + SecurityHelper.verifySign(binary, sign, publicKey); - // Prepare process builder to start new instance (java -jar works for Launch4J's EXE too) - ProcessBuilder builder = new ProcessBuilder(IOHelper.resolveJavaBin(null).toString(), - ClientLauncher.jvmProperty(LogHelper.DEBUG_PROPERTY, Boolean.toString(LogHelper.isDebugEnabled())), - "-jar", BINARY_PATH.toString()); - builder.inheritIO(); + // Prepare process builder to start new instance (java -jar works for Launch4J's EXE too) + ProcessBuilder builder = new ProcessBuilder(IOHelper.resolveJavaBin(null).toString(), + ClientLauncher.jvmProperty(LogHelper.DEBUG_PROPERTY, Boolean.toString(LogHelper.isDebugEnabled())), + "-jar", BINARY_PATH.toString()); + builder.inheritIO(); - // Rewrite and start new instance - IOHelper.write(BINARY_PATH, binary); - builder.start(); + // Rewrite and start new instance + IOHelper.write(BINARY_PATH, binary); + builder.start(); - // Kill current instance - JVMHelper.RUNTIME.exit(255); - throw new AssertionError("Why Launcher wasn't restarted?!"); - } + // Kill current instance + JVMHelper.RUNTIME.exit(255); + throw new AssertionError("Why Launcher wasn't restarted?!"); + } - // Read clients profiles list - int count = input.readLength(0); - List> profiles = new ArrayList<>(count); - for (int i = 0; i < count; i++) { - profiles.add(new SignedObjectHolder<>(input, publicKey, ClientProfile.RO_ADAPTER)); - } + // Read clients profiles list + int count = input.readLength(0); + List> profiles = new ArrayList<>(count); + for (int i = 0; i < count; i++) { + profiles.add(new SignedObjectHolder<>(input, publicKey, ClientProfile.RO_ADAPTER)); + } - // Return request result - return new Result(sign, profiles); - } + // Return request result + return new Result(sign, profiles); + } - public static final class Result { - @LauncherAPI public final List> profiles; - private final byte[] sign; + public static final class Result { + @LauncherAPI public final List> profiles; + private final byte[] sign; - private Result(byte[] sign, List> profiles) { - this.sign = Arrays.copyOf(sign, sign.length); - this.profiles = Collections.unmodifiableList(profiles); - } + private Result(byte[] sign, List> profiles) { + this.sign = Arrays.copyOf(sign, sign.length); + this.profiles = Collections.unmodifiableList(profiles); + } - @LauncherAPI - public byte[] getSign() { - return Arrays.copyOf(sign, sign.length); - } - } + @LauncherAPI + public byte[] getSign() { + return Arrays.copyOf(sign, sign.length); + } + } } diff --git a/Launcher/source/request/update/UpdateListRequest.java b/Launcher/source/request/update/UpdateListRequest.java index eabc16a..52272dd 100644 --- a/Launcher/source/request/update/UpdateListRequest.java +++ b/Launcher/source/request/update/UpdateListRequest.java @@ -6,6 +6,7 @@ import java.util.Set; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.helper.IOHelper; import launcher.request.Request; @@ -13,32 +14,32 @@ import launcher.serialize.HOutput; public final class UpdateListRequest extends Request> { - @LauncherAPI - public UpdateListRequest(Launcher.Config config) { - super(config); - } + @LauncherAPI + public UpdateListRequest(Config config) { + super(config); + } - @LauncherAPI - public UpdateListRequest() { - this(null); - } + @LauncherAPI + public UpdateListRequest() { + this(null); + } - @Override - public Type getType() { - return Type.UPDATE_LIST; - } + @Override + public Type getType() { + return Type.UPDATE_LIST; + } - @Override - protected Set requestDo(HInput input, HOutput output) throws IOException { - int count = input.readLength(0); + @Override + protected Set requestDo(HInput input, HOutput output) throws IOException { + int count = input.readLength(0); - // Read all update dirs names - Set result = new HashSet<>(count); - for (int i = 0; i < count; i++) { - result.add(IOHelper.verifyFileName(input.readString(255))); - } + // Read all update dirs names + Set result = new HashSet<>(count); + for (int i = 0; i < count; i++) { + result.add(IOHelper.verifyFileName(input.readString(255))); + } - // We're done. Make it unmodifiable and return - return Collections.unmodifiableSet(result); - } + // We're done. Make it unmodifiable and return + return Collections.unmodifiableSet(result); + } } diff --git a/Launcher/source/request/update/UpdateRequest.java b/Launcher/source/request/update/UpdateRequest.java index 252ab89..ac36412 100644 --- a/Launcher/source/request/update/UpdateRequest.java +++ b/Launcher/source/request/update/UpdateRequest.java @@ -11,398 +11,404 @@ import java.time.Instant; import java.util.LinkedList; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Queue; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.hasher.FileNameMatcher; import launcher.hasher.HashedDir; +import launcher.hasher.HashedDir.Diff; import launcher.hasher.HashedEntry; import launcher.hasher.HashedFile; import launcher.helper.IOHelper; import launcher.helper.SecurityHelper; +import launcher.helper.SecurityHelper.DigestAlgorithm; import launcher.request.Request; +import launcher.request.update.UpdateRequest.State.Callback; import launcher.serialize.HInput; import launcher.serialize.HOutput; import launcher.serialize.signed.SignedObjectHolder; import launcher.serialize.stream.EnumSerializer; +import launcher.serialize.stream.EnumSerializer.Itf; import launcher.serialize.stream.StreamObject; public final class UpdateRequest extends Request> { - @LauncherAPI public static final int MAX_QUEUE_SIZE = 128; + @LauncherAPI public static final int MAX_QUEUE_SIZE = 128; - // Instance - private final String dirName; - private final Path dir; - private final FileNameMatcher matcher; - private volatile State.Callback stateCallback; + // Instance + private final String dirName; + private final Path dir; + private final FileNameMatcher matcher; + private volatile Callback stateCallback; - // State - private HashedDir localDir; - private long totalDownloaded; - private long totalSize; - private Instant startTime; + // State + private HashedDir localDir; + private long totalDownloaded; + private long totalSize; + private Instant startTime; - @LauncherAPI - public UpdateRequest(Launcher.Config config, String dirName, Path dir, FileNameMatcher matcher) { - super(config); - this.dirName = IOHelper.verifyFileName(dirName); - this.dir = Objects.requireNonNull(dir, "dir"); - this.matcher = matcher; - } + @LauncherAPI + public UpdateRequest(Config config, String dirName, Path dir, FileNameMatcher matcher) { + super(config); + this.dirName = IOHelper.verifyFileName(dirName); + this.dir = Objects.requireNonNull(dir, "dir"); + this.matcher = matcher; + } - @LauncherAPI - public UpdateRequest(String dirName, Path dir, FileNameMatcher matcher) { - this(null, dirName, dir, matcher); - } + @LauncherAPI + public UpdateRequest(String dirName, Path dir, FileNameMatcher matcher) { + this(null, dirName, dir, matcher); + } - @Override - public Type getType() { - return Type.UPDATE; - } + @Override + public Type getType() { + return Type.UPDATE; + } - @Override - public SignedObjectHolder request() throws Exception { - Files.createDirectories(dir); - localDir = new HashedDir(dir, matcher, false); + @Override + public SignedObjectHolder request() throws Exception { + Files.createDirectories(dir); + localDir = new HashedDir(dir, matcher, false); - // Start request - return super.request(); - } + // Start request + return super.request(); + } - @Override - protected SignedObjectHolder requestDo(HInput input, HOutput output) throws IOException, SignatureException { - // Write update dir name - output.writeString(dirName, 255); - output.flush(); - readError(input); + @Override + protected SignedObjectHolder requestDo(HInput input, HOutput output) throws IOException, SignatureException { + // Write update dir name + output.writeString(dirName, 255); + output.flush(); + readError(input); - // Get diff between local and remote dir - SignedObjectHolder remoteHDirHolder = new SignedObjectHolder<>(input, config.publicKey, HashedDir::new); - HashedDir.Diff diff = remoteHDirHolder.object.diff(localDir, matcher); - totalSize = diff.mismatch.size(); + // Get diff between local and remote dir + SignedObjectHolder remoteHDirHolder = new SignedObjectHolder<>(input, config.publicKey, HashedDir::new); + Diff diff = remoteHDirHolder.object.diff(localDir, matcher); + totalSize = diff.mismatch.size(); - // Build actions queue - Queue queue = new LinkedList<>(); - fillActionsQueue(queue, diff.mismatch); - queue.add(Action.FINISH); + // Build actions queue + Queue queue = new LinkedList<>(); + fillActionsQueue(queue, diff.mismatch); + queue.add(Action.FINISH); - // Download missing first - // (otherwise it will cause mustdie indexing bug) - startTime = Instant.now(); - Path currentDir = dir; - Action[] actionsSlice = new Action[MAX_QUEUE_SIZE]; - while (!queue.isEmpty()) { - int length = Math.min(queue.size(), MAX_QUEUE_SIZE); + // Download missing first + // (otherwise it will cause mustdie indexing bug) + startTime = Instant.now(); + Path currentDir = dir; + Action[] actionsSlice = new Action[MAX_QUEUE_SIZE]; + while (!queue.isEmpty()) { + int length = Math.min(queue.size(), MAX_QUEUE_SIZE); - // Write actions slice - output.writeLength(length, MAX_QUEUE_SIZE); - for (int i = 0; i < length; i++) { - Action action = queue.remove(); - actionsSlice[i] = action; - action.write(output); - } - output.flush(); + // Write actions slice + output.writeLength(length, MAX_QUEUE_SIZE); + for (int i = 0; i < length; i++) { + Action action = queue.remove(); + actionsSlice[i] = action; + action.write(output); + } + output.flush(); - // Perform actions - for (int i = 0; i < length; i++) { - Action action = actionsSlice[i]; - switch (action.type) { - case CD: - currentDir = currentDir.resolve(action.name); - Files.createDirectories(currentDir); - break; - case GET: - downloadFile(currentDir.resolve(action.name), (HashedFile) action.entry, input); - break; - case CD_BACK: - currentDir = currentDir.getParent(); - break; - case FINISH: - break; - default: - throw new AssertionError(String.format("Unsupported action type: '%s'", action.type.name())); - } - } - } + // Perform actions + for (int i = 0; i < length; i++) { + Action action = actionsSlice[i]; + switch (action.type) { + case CD: + currentDir = currentDir.resolve(action.name); + Files.createDirectories(currentDir); + break; + case GET: + downloadFile(currentDir.resolve(action.name), (HashedFile) action.entry, input); + break; + case CD_BACK: + currentDir = currentDir.getParent(); + break; + case FINISH: + break; + default: + throw new AssertionError(String.format("Unsupported action type: '%s'", action.type.name())); + } + } + } - // Write update completed packet - deleteExtraDir(dir, diff.extra, diff.extra.flag); - return remoteHDirHolder; - } + // Write update completed packet + deleteExtraDir(dir, diff.extra, diff.extra.flag); + return remoteHDirHolder; + } - @LauncherAPI - public void setStateCallback(State.Callback callback) { - stateCallback = callback; - } + @LauncherAPI + public void setStateCallback(Callback callback) { + stateCallback = callback; + } - private void deleteExtraDir(Path subDir, HashedDir subHDir, boolean flag) throws IOException { - for (Map.Entry mapEntry : subHDir.map().entrySet()) { - String name = mapEntry.getKey(); - Path path = subDir.resolve(name); + private void deleteExtraDir(Path subDir, HashedDir subHDir, boolean flag) throws IOException { + for (Entry mapEntry : subHDir.map().entrySet()) { + String name = mapEntry.getKey(); + Path path = subDir.resolve(name); - // Delete files and dirs based on type - HashedEntry entry = mapEntry.getValue(); - HashedEntry.Type entryType = entry.getType(); - switch (entryType) { - case FILE: - updateState(IOHelper.toString(path), 0, 0); - Files.delete(path); - break; - case DIR: - deleteExtraDir(path, (HashedDir) entry, flag || entry.flag); - break; - default: - throw new AssertionError("Unsupported hashed entry type: " + entryType.name()); - } - } + // Delete files and dirs based on type + HashedEntry entry = mapEntry.getValue(); + HashedEntry.Type entryType = entry.getType(); + switch (entryType) { + case FILE: + updateState(IOHelper.toString(path), 0, 0); + Files.delete(path); + break; + case DIR: + deleteExtraDir(path, (HashedDir) entry, flag || entry.flag); + break; + default: + throw new AssertionError("Unsupported hashed entry type: " + entryType.name()); + } + } - // Delete! - if (flag) { - updateState(IOHelper.toString(subDir), 0, 0); - Files.delete(subDir); - } - } + // Delete! + if (flag) { + updateState(IOHelper.toString(subDir), 0, 0); + Files.delete(subDir); + } + } - private void downloadFile(Path file, HashedFile hFile, HInput input) throws IOException { - String filePath = IOHelper.toString(dir.relativize(file)); - updateState(filePath, 0L, hFile.size); + private void downloadFile(Path file, HashedFile hFile, HInput input) throws IOException { + String filePath = IOHelper.toString(dir.relativize(file)); + updateState(filePath, 0L, hFile.size); - // Start file update - MessageDigest digest = SecurityHelper.newDigest(SecurityHelper.DigestAlgorithm.MD5); - try (OutputStream fileOutput = IOHelper.newOutput(file)) { - long downloaded = 0L; + // Start file update + MessageDigest digest = SecurityHelper.newDigest(DigestAlgorithm.MD5); + try (OutputStream fileOutput = IOHelper.newOutput(file)) { + long downloaded = 0L; - // Download with digest update - byte[] bytes = IOHelper.newBuffer(); - while (downloaded < hFile.size) { - int remaining = (int) Math.min(hFile.size - downloaded, bytes.length); - int length = input.stream.read(bytes, 0, remaining); - if (length < 0) { - throw new EOFException(String.format("%d bytes remaining", hFile.size - downloaded)); - } + // Download with digest update + byte[] bytes = IOHelper.newBuffer(); + while (downloaded < hFile.size) { + int remaining = (int) Math.min(hFile.size - downloaded, bytes.length); + int length = input.stream.read(bytes, 0, remaining); + if (length < 0) { + throw new EOFException(String.format("%d bytes remaining", hFile.size - downloaded)); + } - // Update file - digest.update(bytes, 0, length); - fileOutput.write(bytes, 0, length); + // Update file + digest.update(bytes, 0, length); + fileOutput.write(bytes, 0, length); - // Update state - downloaded += length; - totalDownloaded += length; - updateState(filePath, downloaded, hFile.size); - } - } + // Update state + downloaded += length; + totalDownloaded += length; + updateState(filePath, downloaded, hFile.size); + } + } - // Verify digest - byte[] digestBytes = digest.digest(); - if (!hFile.isSameDigest(digestBytes)) { - throw new SecurityException(String.format("File digest mismatch: '%s'", filePath)); - } - } + // Verify digest + byte[] digestBytes = digest.digest(); + if (!hFile.isSameDigest(digestBytes)) { + throw new SecurityException(String.format("File digest mismatch: '%s'", filePath)); + } + } - private void fillActionsQueue(Queue queue, HashedDir mismatch) { - for (Map.Entry mapEntry : mismatch.map().entrySet()) { - String name = mapEntry.getKey(); - HashedEntry entry = mapEntry.getValue(); - HashedEntry.Type entryType = entry.getType(); - switch (entryType) { - case DIR: // cd - get - cd .. - queue.add(new Action(Action.Type.CD, name, entry)); - fillActionsQueue(queue, (HashedDir) entry); - queue.add(Action.CD_BACK); - break; - case FILE: // get - queue.add(new Action(Action.Type.GET, name, entry)); - break; - default: - throw new AssertionError("Unsupported hashed entry type: " + entryType.name()); - } - } - } + private void fillActionsQueue(Queue queue, HashedDir mismatch) { + for (Entry mapEntry : mismatch.map().entrySet()) { + String name = mapEntry.getKey(); + HashedEntry entry = mapEntry.getValue(); + HashedEntry.Type entryType = entry.getType(); + switch (entryType) { + case DIR: // cd - get - cd .. + queue.add(new Action(Action.Type.CD, name, entry)); + fillActionsQueue(queue, (HashedDir) entry); + queue.add(Action.CD_BACK); + break; + case FILE: // get + queue.add(new Action(Action.Type.GET, name, entry)); + break; + default: + throw new AssertionError("Unsupported hashed entry type: " + entryType.name()); + } + } + } - private void updateState(String filePath, long fileDownloaded, long fileSize) { - if (stateCallback != null) { - stateCallback.call(new State(filePath, fileDownloaded, fileSize, - totalDownloaded, totalSize, Duration.between(startTime, Instant.now()))); - } - } + private void updateState(String filePath, long fileDownloaded, long fileSize) { + if (stateCallback != null) { + stateCallback.call(new State(filePath, fileDownloaded, fileSize, + totalDownloaded, totalSize, Duration.between(startTime, Instant.now()))); + } + } - public static final class Action extends StreamObject { - public static final Action CD_BACK = new Action(Type.CD_BACK, null, null); - public static final Action FINISH = new Action(Type.FINISH, null, null); + public static final class Action extends StreamObject { + public static final Action CD_BACK = new Action(Type.CD_BACK, null, null); + public static final Action FINISH = new Action(Type.FINISH, null, null); - // Instance - public final Type type; - public final String name; - public final HashedEntry entry; + // Instance + public final Type type; + public final String name; + public final HashedEntry entry; - public Action(Type type, String name, HashedEntry entry) { - this.type = type; - this.name = name; - this.entry = entry; - } + public Action(Type type, String name, HashedEntry entry) { + this.type = type; + this.name = name; + this.entry = entry; + } - public Action(HInput input) throws IOException { - type = Type.read(input); - name = type == Type.CD || type == Type.GET ? IOHelper.verifyFileName(input.readString(255)) : null; - entry = null; - } + public Action(HInput input) throws IOException { + type = Type.read(input); + name = type == Type.CD || type == Type.GET ? IOHelper.verifyFileName(input.readString(255)) : null; + entry = null; + } - @Override - public void write(HOutput output) throws IOException { - EnumSerializer.write(output, type); - if (type == Type.CD || type == Type.GET) { - output.writeString(name, 255); - } - } + @Override + public void write(HOutput output) throws IOException { + EnumSerializer.write(output, type); + if (type == Type.CD || type == Type.GET) { + output.writeString(name, 255); + } + } - public enum Type implements EnumSerializer.Itf { - CD(1), CD_BACK(2), GET(3), FINISH(255); - private static final EnumSerializer SERIALIZER = new EnumSerializer<>(Type.class); - private final int n; + public enum Type implements Itf { + CD(1), CD_BACK(2), GET(3), FINISH(255); + 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); + } + } + } - public static final class State { - @LauncherAPI public final long fileDownloaded; - @LauncherAPI public final long fileSize; - @LauncherAPI public final long totalDownloaded; - @LauncherAPI public final long totalSize; - @LauncherAPI public final String filePath; - @LauncherAPI public final Duration duration; + public static final class State { + @LauncherAPI public final long fileDownloaded; + @LauncherAPI public final long fileSize; + @LauncherAPI public final long totalDownloaded; + @LauncherAPI public final long totalSize; + @LauncherAPI public final String filePath; + @LauncherAPI public final Duration duration; - public State(String filePath, long fileDownloaded, long fileSize, long totalDownloaded, long totalSize, Duration duration) { - this.filePath = filePath; - this.fileDownloaded = fileDownloaded; - this.fileSize = fileSize; - this.totalDownloaded = totalDownloaded; - this.totalSize = totalSize; + public State(String filePath, long fileDownloaded, long fileSize, long totalDownloaded, long totalSize, Duration duration) { + this.filePath = filePath; + this.fileDownloaded = fileDownloaded; + this.fileSize = fileSize; + this.totalDownloaded = totalDownloaded; + this.totalSize = totalSize; - // Also store time of creation - this.duration = duration; - } + // Also store time of creation + this.duration = duration; + } - @LauncherAPI - public double getBps() { - long seconds = duration.getSeconds(); - if (seconds == 0) { - return -1.0D; // Otherwise will throw /0 exception - } - return totalDownloaded / (double) seconds; - } + @LauncherAPI + public double getBps() { + long seconds = duration.getSeconds(); + if (seconds == 0) { + return -1.0D; // Otherwise will throw /0 exception + } + return totalDownloaded / (double) seconds; + } - @LauncherAPI - public Duration getEstimatedTime() { - double bps = getBps(); - if (bps <= 0.0D) { - return null; // Otherwise will throw /0 exception - } - return Duration.ofSeconds((long) (getTotalRemaining() / bps)); - } + @LauncherAPI + public Duration getEstimatedTime() { + double bps = getBps(); + if (bps <= 0.0D) { + return null; // Otherwise will throw /0 exception + } + return Duration.ofSeconds((long) (getTotalRemaining() / bps)); + } - @LauncherAPI - public double getFileDownloadedKiB() { - return fileDownloaded / 1024.0D; - } + @LauncherAPI + public double getFileDownloadedKiB() { + return fileDownloaded / 1024.0D; + } - @LauncherAPI - public double getFileDownloadedMiB() { - return getFileDownloadedKiB() / 1024.0D; - } + @LauncherAPI + public double getFileDownloadedMiB() { + return getFileDownloadedKiB() / 1024.0D; + } - @LauncherAPI - public double getFileDownloadedPart() { - if (fileSize == 0) { - return 0.0D; - } - return (double) fileDownloaded / fileSize; - } + @LauncherAPI + public double getFileDownloadedPart() { + if (fileSize == 0) { + return 0.0D; + } + return (double) fileDownloaded / fileSize; + } - @LauncherAPI - public long getFileRemaining() { - return fileSize - fileDownloaded; - } + @LauncherAPI + public long getFileRemaining() { + return fileSize - fileDownloaded; + } - @LauncherAPI - public double getFileRemainingKiB() { - return getFileRemaining() / 1024.0D; - } + @LauncherAPI + public double getFileRemainingKiB() { + return getFileRemaining() / 1024.0D; + } - @LauncherAPI - public double getFileRemainingMiB() { - return getFileRemainingKiB() / 1024.0D; - } + @LauncherAPI + public double getFileRemainingMiB() { + return getFileRemainingKiB() / 1024.0D; + } - @LauncherAPI - public double getFileSizeKiB() { - return fileSize / 1024.0D; - } + @LauncherAPI + public double getFileSizeKiB() { + return fileSize / 1024.0D; + } - @LauncherAPI - public double getFileSizeMiB() { - return getFileSizeKiB() / 1024.0D; - } + @LauncherAPI + public double getFileSizeMiB() { + return getFileSizeKiB() / 1024.0D; + } - @LauncherAPI - public double getTotalDownloadedKiB() { - return totalDownloaded / 1024.0D; - } + @LauncherAPI + public double getTotalDownloadedKiB() { + return totalDownloaded / 1024.0D; + } - @LauncherAPI - public double getTotalDownloadedMiB() { - return getTotalDownloadedKiB() / 1024.0D; - } + @LauncherAPI + public double getTotalDownloadedMiB() { + return getTotalDownloadedKiB() / 1024.0D; + } - @LauncherAPI - public double getTotalDownloadedPart() { - if (totalSize == 0) { - return 0.0D; - } - return (double) totalDownloaded / totalSize; - } + @LauncherAPI + public double getTotalDownloadedPart() { + if (totalSize == 0) { + return 0.0D; + } + return (double) totalDownloaded / totalSize; + } - @LauncherAPI - public long getTotalRemaining() { - return totalSize - totalDownloaded; - } + @LauncherAPI + public long getTotalRemaining() { + return totalSize - totalDownloaded; + } - @LauncherAPI - public double getTotalRemainingKiB() { - return getTotalRemaining() / 1024.0D; - } + @LauncherAPI + public double getTotalRemainingKiB() { + return getTotalRemaining() / 1024.0D; + } - @LauncherAPI - public double getTotalRemainingMiB() { - return getTotalRemainingKiB() / 1024.0D; - } + @LauncherAPI + public double getTotalRemainingMiB() { + return getTotalRemainingKiB() / 1024.0D; + } - @LauncherAPI - public double getTotalSizeKiB() { - return totalSize / 1024.0D; - } + @LauncherAPI + public double getTotalSizeKiB() { + return totalSize / 1024.0D; + } - @LauncherAPI - public double getTotalSizeMiB() { - return getTotalSizeKiB() / 1024.0D; - } + @LauncherAPI + public double getTotalSizeMiB() { + return getTotalSizeKiB() / 1024.0D; + } - @FunctionalInterface - public interface Callback { - void call(State state); - } - } + @FunctionalInterface + public interface Callback { + void call(State state); + } + } } diff --git a/Launcher/source/request/uuid/BatchProfileByUsernameRequest.java b/Launcher/source/request/uuid/BatchProfileByUsernameRequest.java index 724655e..1f13ac0 100644 --- a/Launcher/source/request/uuid/BatchProfileByUsernameRequest.java +++ b/Launcher/source/request/uuid/BatchProfileByUsernameRequest.java @@ -4,6 +4,7 @@ import java.util.Arrays; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.client.PlayerProfile; import launcher.helper.IOHelper; @@ -13,44 +14,44 @@ import launcher.serialize.HOutput; public final class BatchProfileByUsernameRequest extends Request { - @LauncherAPI public static final int MAX_BATCH_SIZE = 128; - private final String[] usernames; + @LauncherAPI public static final int MAX_BATCH_SIZE = 128; + private final String[] usernames; - @LauncherAPI - public BatchProfileByUsernameRequest(Launcher.Config config, String... usernames) throws IOException { - super(config); - this.usernames = Arrays.copyOf(usernames, usernames.length); - IOHelper.verifyLength(this.usernames.length, MAX_BATCH_SIZE); - for (String username : this.usernames) { - VerifyHelper.verifyUsername(username); - } - } + @LauncherAPI + public BatchProfileByUsernameRequest(Config config, String... usernames) throws IOException { + super(config); + this.usernames = Arrays.copyOf(usernames, usernames.length); + IOHelper.verifyLength(this.usernames.length, MAX_BATCH_SIZE); + for (String username : this.usernames) { + VerifyHelper.verifyUsername(username); + } + } - @LauncherAPI - public BatchProfileByUsernameRequest(String... usernames) throws IOException { - this(null, usernames); - } + @LauncherAPI + public BatchProfileByUsernameRequest(String... usernames) throws IOException { + this(null, usernames); + } - @Override - public Type getType() { - return Type.BATCH_PROFILE_BY_USERNAME; - } + @Override + public Type getType() { + return Type.BATCH_PROFILE_BY_USERNAME; + } - @Override - protected PlayerProfile[] requestDo(HInput input, HOutput output) throws IOException { - output.writeLength(usernames.length, MAX_BATCH_SIZE); - for (String username : usernames) { - output.writeASCII(username, 16); - } - output.flush(); + @Override + protected PlayerProfile[] requestDo(HInput input, HOutput output) throws IOException { + output.writeLength(usernames.length, MAX_BATCH_SIZE); + for (String username : usernames) { + output.writeASCII(username, 16); + } + output.flush(); - // Read profiles response - PlayerProfile[] profiles = new PlayerProfile[usernames.length]; - for (int i = 0; i < profiles.length; i++) { - profiles[i] = input.readBoolean() ? new PlayerProfile(input) : null; - } + // Read profiles response + PlayerProfile[] profiles = new PlayerProfile[usernames.length]; + for (int i = 0; i < profiles.length; i++) { + profiles[i] = input.readBoolean() ? new PlayerProfile(input) : null; + } - // Return result - return profiles; - } + // Return result + return profiles; + } } diff --git a/Launcher/source/request/uuid/ProfileByUUIDRequest.java b/Launcher/source/request/uuid/ProfileByUUIDRequest.java index c568b3d..56d3679 100644 --- a/Launcher/source/request/uuid/ProfileByUUIDRequest.java +++ b/Launcher/source/request/uuid/ProfileByUUIDRequest.java @@ -5,6 +5,7 @@ import java.util.UUID; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.client.PlayerProfile; import launcher.request.Request; @@ -12,30 +13,30 @@ import launcher.serialize.HOutput; public final class ProfileByUUIDRequest extends Request { - private final UUID uuid; + private final UUID uuid; - @LauncherAPI - public ProfileByUUIDRequest(Launcher.Config config, UUID uuid) { - super(config); - this.uuid = Objects.requireNonNull(uuid, "uuid"); - } + @LauncherAPI + public ProfileByUUIDRequest(Config config, UUID uuid) { + super(config); + this.uuid = Objects.requireNonNull(uuid, "uuid"); + } - @LauncherAPI - public ProfileByUUIDRequest(UUID uuid) { - this(null, uuid); - } + @LauncherAPI + public ProfileByUUIDRequest(UUID uuid) { + this(null, uuid); + } - @Override - public Type getType() { - return Type.PROFILE_BY_UUID; - } + @Override + public Type getType() { + return Type.PROFILE_BY_UUID; + } - @Override - protected PlayerProfile requestDo(HInput input, HOutput output) throws IOException { - output.writeUUID(uuid); - output.flush(); + @Override + protected PlayerProfile requestDo(HInput input, HOutput output) throws IOException { + output.writeUUID(uuid); + output.flush(); - // Return profile - return input.readBoolean() ? new PlayerProfile(input) : null; - } + // Return profile + return input.readBoolean() ? new PlayerProfile(input) : null; + } } diff --git a/Launcher/source/request/uuid/ProfileByUsernameRequest.java b/Launcher/source/request/uuid/ProfileByUsernameRequest.java index b1f8564..4157a9a 100644 --- a/Launcher/source/request/uuid/ProfileByUsernameRequest.java +++ b/Launcher/source/request/uuid/ProfileByUsernameRequest.java @@ -3,6 +3,7 @@ import java.io.IOException; import launcher.Launcher; +import launcher.Launcher.Config; import launcher.LauncherAPI; import launcher.client.PlayerProfile; import launcher.helper.VerifyHelper; @@ -11,30 +12,30 @@ import launcher.serialize.HOutput; public final class ProfileByUsernameRequest extends Request { - private final String username; + private final String username; - @LauncherAPI - public ProfileByUsernameRequest(Launcher.Config config, String username) { - super(config); - this.username = VerifyHelper.verifyUsername(username); - } + @LauncherAPI + public ProfileByUsernameRequest(Config config, String username) { + super(config); + this.username = VerifyHelper.verifyUsername(username); + } - @LauncherAPI - public ProfileByUsernameRequest(String username) { - this(null, username); - } + @LauncherAPI + public ProfileByUsernameRequest(String username) { + this(null, username); + } - @Override - public Type getType() { - return Type.PROFILE_BY_USERNAME; - } + @Override + public Type getType() { + return Type.PROFILE_BY_USERNAME; + } - @Override - protected PlayerProfile requestDo(HInput input, HOutput output) throws IOException { - output.writeASCII(username, 16); - output.flush(); + @Override + protected PlayerProfile requestDo(HInput input, HOutput output) throws IOException { + output.writeASCII(username, 16); + output.flush(); - // Return profile - return input.readBoolean() ? new PlayerProfile(input) : null; - } + // Return profile + return input.readBoolean() ? new PlayerProfile(input) : null; + } } diff --git a/Launcher/source/serialize/HInput.java b/Launcher/source/serialize/HInput.java index 97c9b96..1c8d868 100644 --- a/Launcher/source/serialize/HInput.java +++ b/Launcher/source/serialize/HInput.java @@ -12,127 +12,127 @@ import launcher.helper.IOHelper; public final class HInput implements AutoCloseable { - @LauncherAPI public final InputStream stream; + @LauncherAPI public final InputStream stream; - @LauncherAPI - public HInput(InputStream stream) { - this.stream = Objects.requireNonNull(stream, "stream"); - } + @LauncherAPI + public HInput(InputStream stream) { + this.stream = Objects.requireNonNull(stream, "stream"); + } - @LauncherAPI - public HInput(byte[] bytes) { - stream = new ByteArrayInputStream(bytes); - } + @LauncherAPI + public HInput(byte[] bytes) { + stream = new ByteArrayInputStream(bytes); + } - @Override - public void close() throws IOException { - stream.close(); - } + @Override + public void close() throws IOException { + stream.close(); + } - @LauncherAPI - public String readASCII(int maxBytes) throws IOException { - return IOHelper.decodeASCII(readByteArray(maxBytes)); - } + @LauncherAPI + public String readASCII(int maxBytes) throws IOException { + return IOHelper.decodeASCII(readByteArray(maxBytes)); + } - @LauncherAPI - public BigInteger readBigInteger(int maxBytes) throws IOException { - return new BigInteger(readByteArray(maxBytes)); - } + @LauncherAPI + public BigInteger readBigInteger(int maxBytes) throws IOException { + return new BigInteger(readByteArray(maxBytes)); + } - @LauncherAPI - public boolean readBoolean() throws IOException { - int b = readUnsignedByte(); - switch (b) { - case 0b0: - return false; - case 0b1: - return true; - default: - throw new IOException("Invalid boolean state: " + b); - } - } + @LauncherAPI + public boolean readBoolean() throws IOException { + int b = readUnsignedByte(); + switch (b) { + case 0b0: + return false; + case 0b1: + return true; + default: + throw new IOException("Invalid boolean state: " + b); + } + } - @LauncherAPI - public byte[] readByteArray(int max) throws IOException { - byte[] bytes = new byte[readLength(max)]; - IOHelper.read(stream, bytes); - return bytes; - } + @LauncherAPI + public byte[] readByteArray(int max) throws IOException { + byte[] bytes = new byte[readLength(max)]; + IOHelper.read(stream, bytes); + return bytes; + } - @LauncherAPI - public int readInt() throws IOException { - return (readUnsignedByte() << 24) + (readUnsignedByte() << 16) + (readUnsignedByte() << 8) + readUnsignedByte(); - } + @LauncherAPI + public int readInt() throws IOException { + return (readUnsignedByte() << 24) + (readUnsignedByte() << 16) + (readUnsignedByte() << 8) + readUnsignedByte(); + } - @LauncherAPI - public int readLength(int max) throws IOException { - if (max < 0) { - return -max; - } - return IOHelper.verifyLength(readVarInt(), max); - } + @LauncherAPI + public int readLength(int max) throws IOException { + if (max < 0) { + return -max; + } + return IOHelper.verifyLength(readVarInt(), max); + } - @LauncherAPI - public long readLong() throws IOException { - return (long) readInt() << 32 | readInt() & 0xFFFFFFFFL; - } + @LauncherAPI + public long readLong() throws IOException { + return (long) readInt() << 32 | readInt() & 0xFFFFFFFFL; + } - @LauncherAPI - public short readShort() throws IOException { - return (short) ((readUnsignedByte() << 8) + readUnsignedByte()); - } + @LauncherAPI + public short readShort() throws IOException { + return (short) ((readUnsignedByte() << 8) + readUnsignedByte()); + } - @LauncherAPI - public String readString(int maxBytes) throws IOException { - return IOHelper.decode(readByteArray(maxBytes)); - } + @LauncherAPI + public String readString(int maxBytes) throws IOException { + return IOHelper.decode(readByteArray(maxBytes)); + } - @LauncherAPI - public UUID readUUID() throws IOException { - return new UUID(readLong(), readLong()); - } + @LauncherAPI + public UUID readUUID() throws IOException { + return new UUID(readLong(), readLong()); + } - @LauncherAPI - public int readUnsignedByte() throws IOException { - int b = stream.read(); - if (b < 0) { - throw new EOFException("readUnsignedByte"); - } - return b; - } + @LauncherAPI + public int readUnsignedByte() throws IOException { + int b = stream.read(); + if (b < 0) { + throw new EOFException("readUnsignedByte"); + } + return b; + } - @LauncherAPI - public int readUnsignedShort() throws IOException { - return Short.toUnsignedInt(readShort()); - } + @LauncherAPI + public int readUnsignedShort() throws IOException { + return Short.toUnsignedInt(readShort()); + } - @LauncherAPI - public int readVarInt() throws IOException { - int shift = 0; - int result = 0; - while (shift < Integer.SIZE) { - int b = readUnsignedByte(); - result |= (b & 0x7F) << shift; - if ((b & 0x80) == 0) { - return result; - } - shift += 7; - } - throw new IOException("VarInt too big"); - } + @LauncherAPI + public int readVarInt() throws IOException { + int shift = 0; + int result = 0; + while (shift < Integer.SIZE) { + int b = readUnsignedByte(); + result |= (b & 0x7F) << shift; + if ((b & 0x80) == 0) { + return result; + } + shift += 7; + } + throw new IOException("VarInt too big"); + } - @LauncherAPI - public long readVarLong() throws IOException { - int shift = 0; - long result = 0; - while (shift < Long.SIZE) { - int b = readUnsignedByte(); - result |= (long) (b & 0x7F) << shift; - if ((b & 0x80) == 0) { - return result; - } - shift += 7; - } - throw new IOException("VarLong too big"); - } + @LauncherAPI + public long readVarLong() throws IOException { + int shift = 0; + long result = 0; + while (shift < Long.SIZE) { + int b = readUnsignedByte(); + result |= (long) (b & 0x7F) << shift; + if ((b & 0x80) == 0) { + return result; + } + shift += 7; + } + throw new IOException("VarLong too big"); + } } diff --git a/Launcher/source/serialize/HOutput.java b/Launcher/source/serialize/HOutput.java index 225579a..813315a 100644 --- a/Launcher/source/serialize/HOutput.java +++ b/Launcher/source/serialize/HOutput.java @@ -11,103 +11,103 @@ import launcher.helper.IOHelper; public final class HOutput implements AutoCloseable, Flushable { - @LauncherAPI public final OutputStream stream; + @LauncherAPI public final OutputStream stream; - @LauncherAPI - public HOutput(OutputStream stream) { - this.stream = Objects.requireNonNull(stream, "stream"); - } + @LauncherAPI + public HOutput(OutputStream stream) { + this.stream = Objects.requireNonNull(stream, "stream"); + } - @Override - public void close() throws IOException { - stream.close(); - } + @Override + public void close() throws IOException { + stream.close(); + } - @Override - public void flush() throws IOException { - stream.flush(); - } + @Override + public void flush() throws IOException { + stream.flush(); + } - @LauncherAPI - public void writeASCII(String s, int maxBytes) throws IOException { - writeByteArray(IOHelper.encodeASCII(s), maxBytes); - } + @LauncherAPI + public void writeASCII(String s, int maxBytes) throws IOException { + writeByteArray(IOHelper.encodeASCII(s), maxBytes); + } - @LauncherAPI - public void writeBigInteger(BigInteger bi, int max) throws IOException { - writeByteArray(bi.toByteArray(), max); - } + @LauncherAPI + public void writeBigInteger(BigInteger bi, int max) throws IOException { + writeByteArray(bi.toByteArray(), max); + } - @LauncherAPI - public void writeBoolean(boolean b) throws IOException { - writeUnsignedByte(b ? 0b1 : 0b0); - } + @LauncherAPI + public void writeBoolean(boolean b) throws IOException { + writeUnsignedByte(b ? 0b1 : 0b0); + } - @LauncherAPI - public void writeByteArray(byte[] bytes, int max) throws IOException { - writeLength(bytes.length, max); - stream.write(bytes); - } + @LauncherAPI + public void writeByteArray(byte[] bytes, int max) throws IOException { + writeLength(bytes.length, max); + stream.write(bytes); + } - @LauncherAPI - public void writeInt(int i) throws IOException { - writeUnsignedByte(i >>> 24 & 0xFF); - writeUnsignedByte(i >>> 16 & 0xFF); - writeUnsignedByte(i >>> 8 & 0xFF); - writeUnsignedByte(i & 0xFF); - } + @LauncherAPI + public void writeInt(int i) throws IOException { + writeUnsignedByte(i >>> 24 & 0xFF); + writeUnsignedByte(i >>> 16 & 0xFF); + writeUnsignedByte(i >>> 8 & 0xFF); + writeUnsignedByte(i & 0xFF); + } - @LauncherAPI - public void writeLength(int length, int max) throws IOException { - IOHelper.verifyLength(length, max); - if (max >= 0) { - writeVarInt(length); - } - } + @LauncherAPI + public void writeLength(int length, int max) throws IOException { + IOHelper.verifyLength(length, max); + if (max >= 0) { + writeVarInt(length); + } + } - @LauncherAPI - public void writeLong(long l) throws IOException { - writeInt((int) (l >> 32)); - writeInt((int) l); - } + @LauncherAPI + public void writeLong(long l) throws IOException { + writeInt((int) (l >> 32)); + writeInt((int) l); + } - @LauncherAPI - public void writeShort(short s) throws IOException { - writeUnsignedByte(s >>> 8 & 0xFF); - writeUnsignedByte(s & 0xFF); - } + @LauncherAPI + public void writeShort(short s) throws IOException { + writeUnsignedByte(s >>> 8 & 0xFF); + writeUnsignedByte(s & 0xFF); + } - @LauncherAPI - public void writeString(String s, int maxBytes) throws IOException { - writeByteArray(IOHelper.encode(s), maxBytes); - } + @LauncherAPI + public void writeString(String s, int maxBytes) throws IOException { + writeByteArray(IOHelper.encode(s), maxBytes); + } - @LauncherAPI - public void writeUUID(UUID uuid) throws IOException { - writeLong(uuid.getMostSignificantBits()); - writeLong(uuid.getLeastSignificantBits()); - } + @LauncherAPI + public void writeUUID(UUID uuid) throws IOException { + writeLong(uuid.getMostSignificantBits()); + writeLong(uuid.getLeastSignificantBits()); + } - @LauncherAPI - public void writeUnsignedByte(int b) throws IOException { - stream.write(b); - } + @LauncherAPI + public void writeUnsignedByte(int b) throws IOException { + stream.write(b); + } - @LauncherAPI - public void writeVarInt(int i) throws IOException { - while ((i & ~0x7FL) != 0) { - writeUnsignedByte(i & 0x7F | 0x80); - i >>>= 7; - } - writeUnsignedByte(i); - } + @LauncherAPI + public void writeVarInt(int i) throws IOException { + while ((i & ~0x7FL) != 0) { + writeUnsignedByte(i & 0x7F | 0x80); + i >>>= 7; + } + writeUnsignedByte(i); + } - @LauncherAPI - public void writeVarLong(long l) throws IOException { - while ((l & ~0x7FL) != 0) { - writeUnsignedByte((int) l & 0x7F | 0x80); - l >>>= 7; - } - writeUnsignedByte((int) l); - } + @LauncherAPI + public void writeVarLong(long l) throws IOException { + while ((l & ~0x7FL) != 0) { + writeUnsignedByte((int) l & 0x7F | 0x80); + l >>>= 7; + } + writeUnsignedByte((int) l); + } } diff --git a/Launcher/source/serialize/config/ConfigObject.java b/Launcher/source/serialize/config/ConfigObject.java index 8ea4da3..9d7d902 100644 --- a/Launcher/source/serialize/config/ConfigObject.java +++ b/Launcher/source/serialize/config/ConfigObject.java @@ -9,21 +9,21 @@ import launcher.serialize.stream.StreamObject; public abstract class ConfigObject extends StreamObject { - @LauncherAPI public final BlockConfigEntry block; + @LauncherAPI public final BlockConfigEntry block; - @LauncherAPI - protected ConfigObject(BlockConfigEntry block) { - this.block = Objects.requireNonNull(block, "block"); - } + @LauncherAPI + protected ConfigObject(BlockConfigEntry block) { + this.block = Objects.requireNonNull(block, "block"); + } - @Override - public final void write(HOutput output) throws IOException { - block.write(output); - } + @Override + public final void write(HOutput output) throws IOException { + block.write(output); + } - @FunctionalInterface - public interface Adapter { - @LauncherAPI - O convert(BlockConfigEntry entry); - } + @FunctionalInterface + public interface Adapter { + @LauncherAPI + O convert(BlockConfigEntry entry); + } } diff --git a/Launcher/source/serialize/config/TextConfigReader.java b/Launcher/source/serialize/config/TextConfigReader.java index 473d743..2696e9d 100644 --- a/Launcher/source/serialize/config/TextConfigReader.java +++ b/Launcher/source/serialize/config/TextConfigReader.java @@ -18,230 +18,230 @@ import launcher.serialize.config.entry.StringConfigEntry; public final class TextConfigReader { - private final LineNumberReader reader; - private final boolean ro; - private String skipped; - private int ch = -1; + private final LineNumberReader reader; + private final boolean ro; + private String skipped; + private int ch = -1; - private TextConfigReader(Reader reader, boolean ro) { - this.reader = new LineNumberReader(reader); - this.reader.setLineNumber(1); - this.ro = ro; - } + private TextConfigReader(Reader reader, boolean ro) { + this.reader = new LineNumberReader(reader); + this.reader.setLineNumber(1); + this.ro = ro; + } - private IOException newIOException(String message) { - return new IOException(message + " (line " + reader.getLineNumber() + ')'); - } + private IOException newIOException(String message) { + return new IOException(message + " (line " + reader.getLineNumber() + ')'); + } - private int nextChar(boolean eof) throws IOException { - ch = reader.read(); - if (eof && ch < 0) { - throw newIOException("Unexpected end of config"); - } - return ch; - } + private int nextChar(boolean eof) throws IOException { + ch = reader.read(); + if (eof && ch < 0) { + throw newIOException("Unexpected end of config"); + } + return ch; + } - private int nextClean(boolean eof) throws IOException { - nextChar(eof); - return skipWhitespace(eof); - } + private int nextClean(boolean eof) throws IOException { + nextChar(eof); + return skipWhitespace(eof); + } - private BlockConfigEntry readBlock(int cc) throws IOException { - Map> map = new LinkedHashMap<>(16); + private BlockConfigEntry readBlock(int cc) throws IOException { + Map> map = new LinkedHashMap<>(16); - // Read block entries - boolean brackets = ch == '{'; - while (nextClean(brackets) >= 0 && (!brackets || ch != '}')) { - String preNameComment = skipped; + // Read block entries + boolean brackets = ch == '{'; + while (nextClean(brackets) >= 0 && (!brackets || ch != '}')) { + String preNameComment = skipped; - // Read entry name - String name = readToken(); - if (skipWhitespace(true) != ':') { - throw newIOException("Value start expected"); - } - String postNameComment = skipped; + // Read entry name + String name = readToken(); + if (skipWhitespace(true) != ':') { + throw newIOException("Value start expected"); + } + String postNameComment = skipped; - // Read entry value - nextClean(true); - String preValueComment = skipped; - ConfigEntry entry = readEntry(4); - if (skipWhitespace(true) != ';') { - throw newIOException("Value end expected"); - } + // Read entry value + nextClean(true); + String preValueComment = skipped; + ConfigEntry entry = readEntry(4); + if (skipWhitespace(true) != ';') { + throw newIOException("Value end expected"); + } - // Set comments - entry.setComment(0, preNameComment); - entry.setComment(1, postNameComment); - entry.setComment(2, preValueComment); - entry.setComment(3, skipped); + // Set comments + entry.setComment(0, preNameComment); + entry.setComment(1, postNameComment); + entry.setComment(2, preValueComment); + entry.setComment(3, skipped); - // Try add entry to map - if (map.put(name, entry) != null) { - throw newIOException(String.format("Duplicate config entry: '%s'", name)); - } - } + // Try add entry to map + if (map.put(name, entry) != null) { + throw newIOException(String.format("Duplicate config entry: '%s'", name)); + } + } - // Set comment after last entry and return block - BlockConfigEntry block = new BlockConfigEntry(map, ro, cc + 1); - block.setComment(cc, skipped); - nextChar(false); - return block; - } + // Set comment after last entry and return block + BlockConfigEntry block = new BlockConfigEntry(map, ro, cc + 1); + block.setComment(cc, skipped); + nextChar(false); + return block; + } - private ConfigEntry readEntry(int cc) throws IOException { - // Try detect type by first char - switch (ch) { - case '"': // String - return readString(cc); - case '[': // List - return readList(cc); - case '{': // Block - return readBlock(cc); - default: - break; - } + private ConfigEntry readEntry(int cc) throws IOException { + // Try detect type by first char + switch (ch) { + case '"': // String + return readString(cc); + case '[': // List + return readList(cc); + case '{': // Block + return readBlock(cc); + default: + break; + } - // Possibly integer value - if (ch == '-' || ch >= '0' && ch <= '9') { - return readInteger(cc); - } + // Possibly integer value + if (ch == '-' || ch >= '0' && ch <= '9') { + return readInteger(cc); + } - // Statement? - String statement = readToken(); - switch (statement) { - case "true": - return new BooleanConfigEntry(Boolean.TRUE, ro, cc); - case "false": - return new BooleanConfigEntry(Boolean.FALSE, ro, cc); - default: - throw newIOException(String.format("Unknown statement: '%s'", statement)); - } - } + // Statement? + String statement = readToken(); + switch (statement) { + case "true": + return new BooleanConfigEntry(Boolean.TRUE, ro, cc); + case "false": + return new BooleanConfigEntry(Boolean.FALSE, ro, cc); + default: + throw newIOException(String.format("Unknown statement: '%s'", statement)); + } + } - private ConfigEntry readInteger(int cc) throws IOException { - return new IntegerConfigEntry(Integer.parseInt(readToken()), ro, cc); - } + private ConfigEntry readInteger(int cc) throws IOException { + return new IntegerConfigEntry(Integer.parseInt(readToken()), ro, cc); + } - private ConfigEntry>> readList(int cc) throws IOException { - List> listValue = new ArrayList<>(16); + private ConfigEntry>> readList(int cc) throws IOException { + List> listValue = new ArrayList<>(16); - // Read list elements - boolean hasNextElement = nextClean(true) != ']'; - String preValueComment = skipped; - while (hasNextElement) { - ConfigEntry element = readEntry(2); - hasNextElement = skipWhitespace(true) != ']'; - element.setComment(0, preValueComment); - element.setComment(1, skipped); - listValue.add(element); + // Read list elements + boolean hasNextElement = nextClean(true) != ']'; + String preValueComment = skipped; + while (hasNextElement) { + ConfigEntry element = readEntry(2); + hasNextElement = skipWhitespace(true) != ']'; + element.setComment(0, preValueComment); + element.setComment(1, skipped); + listValue.add(element); - // Prepare for next element read - if (hasNextElement) { - if (ch != ',') { - throw newIOException("Comma expected"); - } - nextClean(true); - preValueComment = skipped; - } - } + // Prepare for next element read + if (hasNextElement) { + if (ch != ',') { + throw newIOException("Comma expected"); + } + nextClean(true); + preValueComment = skipped; + } + } - // Set in-list comment (if no elements) - boolean additional = listValue.isEmpty(); - ConfigEntry>> list = new ListConfigEntry(listValue, ro, additional ? cc + 1 : cc); - if (additional) { - list.setComment(cc, skipped); - } + // Set in-list comment (if no elements) + boolean additional = listValue.isEmpty(); + ConfigEntry>> list = new ListConfigEntry(listValue, ro, additional ? cc + 1 : cc); + if (additional) { + list.setComment(cc, skipped); + } - // Return list - nextChar(false); - return list; - } + // Return list + nextChar(false); + return list; + } - private ConfigEntry readString(int cc) throws IOException { - StringBuilder builder = new StringBuilder(); + private ConfigEntry readString(int cc) throws IOException { + StringBuilder builder = new StringBuilder(); - // Read string chars - while (nextChar(true) != '"') { - switch (ch) { - case '\r': - case '\n': // String termination - throw newIOException("String termination"); - case '\\': - int next = nextChar(true); - switch (next) { - case 't': - builder.append('\t'); - break; - case 'b': - builder.append('\b'); - break; - case 'n': - builder.append('\n'); - break; - case 'r': - builder.append('\r'); - break; - case 'f': - builder.append('\f'); - break; - case '"': - case '\\': - builder.append((char) next); - break; - default: - throw newIOException("Illegal char escape: " + (char) next); - } - break; - default: // Normal character - builder.append((char) ch); - break; - } - } + // Read string chars + while (nextChar(true) != '"') { + switch (ch) { + case '\r': + case '\n': // String termination + throw newIOException("String termination"); + case '\\': + int next = nextChar(true); + switch (next) { + case 't': + builder.append('\t'); + break; + case 'b': + builder.append('\b'); + break; + case 'n': + builder.append('\n'); + break; + case 'r': + builder.append('\r'); + break; + case 'f': + builder.append('\f'); + break; + case '"': + case '\\': + builder.append((char) next); + break; + default: + throw newIOException("Illegal char escape: " + (char) next); + } + break; + default: // Normal character + builder.append((char) ch); + break; + } + } - // Return string - nextChar(false); - return new StringConfigEntry(builder.toString(), ro, cc); - } + // Return string + nextChar(false); + return new StringConfigEntry(builder.toString(), ro, cc); + } - private String readToken() throws IOException { - // Read token - StringBuilder builder = new StringBuilder(); - while (VerifyHelper.isValidIDNameChar(ch)) { - builder.append((char) ch); - nextChar(false); - } + private String readToken() throws IOException { + // Read token + StringBuilder builder = new StringBuilder(); + while (VerifyHelper.isValidIDNameChar(ch)) { + builder.append((char) ch); + nextChar(false); + } - // Return token as string - String token = builder.toString(); - if (token.isEmpty()) { - throw newIOException("Not a token"); - } - return token; - } + // Return token as string + String token = builder.toString(); + if (token.isEmpty()) { + throw newIOException("Not a token"); + } + return token; + } - private void skipComment(StringBuilder skippedBuilder, boolean eof) throws IOException { - while (ch >= 0 && ch != '\r' && ch != '\n') { - skippedBuilder.append((char) ch); - nextChar(eof); - } - } + private void skipComment(StringBuilder skippedBuilder, boolean eof) throws IOException { + while (ch >= 0 && ch != '\r' && ch != '\n') { + skippedBuilder.append((char) ch); + nextChar(eof); + } + } - private int skipWhitespace(boolean eof) throws IOException { - StringBuilder skippedBuilder = new StringBuilder(); - while (Character.isWhitespace(ch) || ch == '#') { - if (ch == '#') { - skipComment(skippedBuilder, eof); - continue; - } - skippedBuilder.append((char) ch); - nextChar(eof); - } - skipped = skippedBuilder.toString(); - return ch; - } + private int skipWhitespace(boolean eof) throws IOException { + StringBuilder skippedBuilder = new StringBuilder(); + while (Character.isWhitespace(ch) || ch == '#') { + if (ch == '#') { + skipComment(skippedBuilder, eof); + continue; + } + skippedBuilder.append((char) ch); + nextChar(eof); + } + skipped = skippedBuilder.toString(); + return ch; + } - @LauncherAPI - public static BlockConfigEntry read(Reader reader, boolean ro) throws IOException { - return new TextConfigReader(reader, ro).readBlock(0); - } + @LauncherAPI + public static BlockConfigEntry read(Reader reader, boolean ro) throws IOException { + return new TextConfigReader(reader, ro).readBlock(0); + } } diff --git a/Launcher/source/serialize/config/TextConfigWriter.java b/Launcher/source/serialize/config/TextConfigWriter.java index acb1871..324ee48 100644 --- a/Launcher/source/serialize/config/TextConfigWriter.java +++ b/Launcher/source/serialize/config/TextConfigWriter.java @@ -4,155 +4,157 @@ import java.io.Writer; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import launcher.LauncherAPI; 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; public final class TextConfigWriter { - private final Writer writer; - private final boolean comments; + private final Writer writer; + private final boolean comments; - private TextConfigWriter(Writer writer, boolean comments) { - this.writer = writer; - this.comments = comments; - } + private TextConfigWriter(Writer writer, boolean comments) { + this.writer = writer; + this.comments = comments; + } - private void writeBlock(BlockConfigEntry block, boolean brackets) throws IOException { - // Write start bracket - if (brackets) { - writer.write('{'); - } + private void writeBlock(BlockConfigEntry block, boolean brackets) throws IOException { + // Write start bracket + if (brackets) { + writer.write('{'); + } - // Write block entries - Map> map = block.getValue(); - for (Map.Entry> mapEntry : map.entrySet()) { - String name = mapEntry.getKey(); - ConfigEntry entry = mapEntry.getValue(); + // Write block entries + Map> map = block.getValue(); + for (Entry> mapEntry : map.entrySet()) { + String name = mapEntry.getKey(); + ConfigEntry entry = mapEntry.getValue(); - // Write entry name - writeComment(entry.getComment(0)); - writer.write(name); - writeComment(entry.getComment(1)); - writer.write(':'); + // Write entry name + writeComment(entry.getComment(0)); + writer.write(name); + writeComment(entry.getComment(1)); + writer.write(':'); - // Write entry value - writeComment(entry.getComment(2)); - writeEntry(entry); - writeComment(entry.getComment(3)); - writer.write(';'); - } - writeComment(block.getComment(-1)); + // Write entry value + writeComment(entry.getComment(2)); + writeEntry(entry); + writeComment(entry.getComment(3)); + writer.write(';'); + } + writeComment(block.getComment(-1)); - // Write end bracket - if (brackets) { - writer.write('}'); - } - } + // Write end bracket + if (brackets) { + writer.write('}'); + } + } - private void writeBoolean(BooleanConfigEntry entry) throws IOException { - writer.write(entry.getValue().toString()); - } + private void writeBoolean(BooleanConfigEntry entry) throws IOException { + writer.write(entry.getValue().toString()); + } - private void writeComment(String comment) throws IOException { - if (comments && comment != null) { - writer.write(comment); - } - } + private void writeComment(String comment) throws IOException { + if (comments && comment != null) { + writer.write(comment); + } + } - private void writeEntry(ConfigEntry entry) throws IOException { - ConfigEntry.Type type = entry.getType(); - switch (type) { - case BLOCK: - writeBlock((BlockConfigEntry) entry, true); - break; - case STRING: - writeString((StringConfigEntry) entry); - break; - case INTEGER: - writeInteger((IntegerConfigEntry) entry); - break; - case BOOLEAN: - writeBoolean((BooleanConfigEntry) entry); - break; - case LIST: - writeList((ListConfigEntry) entry); - break; - default: - throw new AssertionError("Unsupported config entry type: " + type.name()); - } - } + private void writeEntry(ConfigEntry entry) throws IOException { + Type type = entry.getType(); + switch (type) { + case BLOCK: + writeBlock((BlockConfigEntry) entry, true); + break; + case STRING: + writeString((StringConfigEntry) entry); + break; + case INTEGER: + writeInteger((IntegerConfigEntry) entry); + break; + case BOOLEAN: + writeBoolean((BooleanConfigEntry) entry); + break; + case LIST: + writeList((ListConfigEntry) entry); + break; + default: + throw new AssertionError("Unsupported config entry type: " + type.name()); + } + } - private void writeInteger(IntegerConfigEntry entry) throws IOException { - writer.write(Integer.toString(entry.getValue())); - } + private void writeInteger(IntegerConfigEntry entry) throws IOException { + writer.write(Integer.toString(entry.getValue())); + } - private void writeList(ListConfigEntry entry) throws IOException { - writer.write('['); + private void writeList(ListConfigEntry entry) throws IOException { + writer.write('['); - // Write list elements - List> value = entry.getValue(); - for (int i = 0; i < value.size(); i++) { - if (i > 0) { - writer.write(','); - } + // Write list elements + List> value = entry.getValue(); + for (int i = 0; i < value.size(); i++) { + if (i > 0) { + writer.write(','); + } - // Write element - ConfigEntry element = value.get(i); - writeComment(element.getComment(0)); - writeEntry(element); - writeComment(element.getComment(1)); - } - writeComment(entry.getComment(-1)); + // Write element + ConfigEntry element = value.get(i); + writeComment(element.getComment(0)); + writeEntry(element); + writeComment(element.getComment(1)); + } + writeComment(entry.getComment(-1)); - // Write end bracket - writer.write(']'); - } + // Write end bracket + writer.write(']'); + } - private void writeString(StringConfigEntry entry) throws IOException { - writer.write('"'); + private void writeString(StringConfigEntry entry) throws IOException { + writer.write('"'); - // Quote string - String s = entry.getValue(); - for (int i = 0; i < s.length(); i++) { - char ch = s.charAt(i); - switch (ch) { - case '\t': - writer.write("\\t"); - break; - case '\b': - writer.write("\\b"); - break; - case '\n': - writer.write("\\n"); - break; - case '\r': - writer.write("\\r"); - break; - case '\f': - writer.write("\\f"); - break; - case '"': - case '\\': - writer.write('\\'); - writer.write(ch); - break; - default: - writer.write(ch); - break; - } - } + // Quote string + String s = entry.getValue(); + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + switch (ch) { + case '\t': + writer.write("\\t"); + break; + case '\b': + writer.write("\\b"); + break; + case '\n': + writer.write("\\n"); + break; + case '\r': + writer.write("\\r"); + break; + case '\f': + writer.write("\\f"); + break; + case '"': + case '\\': + writer.write('\\'); + writer.write(ch); + break; + default: + writer.write(ch); + break; + } + } - // Write end quote - writer.write('"'); - } + // Write end quote + writer.write('"'); + } - @LauncherAPI - public static void write(BlockConfigEntry block, Writer writer, boolean comments) throws IOException { - new TextConfigWriter(writer, comments).writeBlock(block, false); - } + @LauncherAPI + public static void write(BlockConfigEntry block, Writer writer, boolean comments) throws IOException { + new TextConfigWriter(writer, comments).writeBlock(block, false); + } } diff --git a/Launcher/source/serialize/config/entry/BlockConfigEntry.java b/Launcher/source/serialize/config/entry/BlockConfigEntry.java index 5fae5e4..c6d4857 100644 --- a/Launcher/source/serialize/config/entry/BlockConfigEntry.java +++ b/Launcher/source/serialize/config/entry/BlockConfigEntry.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Set; @@ -13,96 +14,96 @@ import launcher.serialize.HOutput; public final class BlockConfigEntry extends ConfigEntry>> { - @LauncherAPI - public BlockConfigEntry(Map> map, boolean ro, int cc) { - super(map, ro, cc); - } + @LauncherAPI + public BlockConfigEntry(Map> map, boolean ro, int cc) { + super(map, ro, cc); + } - @LauncherAPI - public BlockConfigEntry(int cc) { - super(Collections.emptyMap(), false, cc); - } + @LauncherAPI + public BlockConfigEntry(int cc) { + super(Collections.emptyMap(), false, cc); + } - @LauncherAPI - public BlockConfigEntry(HInput input, boolean ro) throws IOException { - super(readMap(input, ro), ro, 0); - } + @LauncherAPI + public BlockConfigEntry(HInput input, boolean ro) throws IOException { + super(readMap(input, ro), ro, 0); + } - @Override - public Type getType() { - return Type.BLOCK; - } + @Override + public Type getType() { + return Type.BLOCK; + } - @Override - public Map> getValue() { - Map> value = super.getValue(); - return ro ? value : Collections.unmodifiableMap(value); // Already RO - } + @Override + public Map> getValue() { + Map> value = super.getValue(); + return ro ? value : Collections.unmodifiableMap(value); // Already RO + } - @Override - public void write(HOutput output) throws IOException { - Set>> entries = getValue().entrySet(); - output.writeLength(entries.size(), 0); - for (Map.Entry> mapEntry : entries) { - output.writeString(mapEntry.getKey(), 255); - writeEntry(mapEntry.getValue(), output); - } - } + @Override + protected void uncheckedSetValue(Map> value) { + Map> newValue = new LinkedHashMap<>(value); + newValue.keySet().stream().forEach(VerifyHelper::verifyIDName); - @Override - protected void uncheckedSetValue(Map> value) { - Map> newValue = new LinkedHashMap<>(value); - newValue.keySet().stream().forEach(VerifyHelper::verifyIDName); + // Call super method to actually set new value + super.uncheckedSetValue(ro ? Collections.unmodifiableMap(newValue) : newValue); + } - // Call super method to actually set new value - super.uncheckedSetValue(ro ? Collections.unmodifiableMap(newValue) : newValue); - } + @Override + public void write(HOutput output) throws IOException { + Set>> entries = getValue().entrySet(); + output.writeLength(entries.size(), 0); + for (Entry> mapEntry : entries) { + output.writeString(mapEntry.getKey(), 255); + writeEntry(mapEntry.getValue(), output); + } + } - @LauncherAPI - public void clear() { - super.getValue().clear(); - } + @LauncherAPI + public void clear() { + super.getValue().clear(); + } - @LauncherAPI - public > E getEntry(String name, Class clazz) { - Map> map = super.getValue(); - ConfigEntry value = map.get(name); - if (!clazz.isInstance(value)) { - throw new NoSuchElementException(name); - } - return clazz.cast(value); - } + @LauncherAPI + public > E getEntry(String name, Class clazz) { + Map> map = super.getValue(); + ConfigEntry value = map.get(name); + if (!clazz.isInstance(value)) { + throw new NoSuchElementException(name); + } + return clazz.cast(value); + } - @LauncherAPI - public > V getEntryValue(String name, Class clazz) { - return getEntry(name, clazz).getValue(); - } + @LauncherAPI + public > V getEntryValue(String name, Class clazz) { + return getEntry(name, clazz).getValue(); + } - @LauncherAPI - public boolean hasEntry(String name) { - return getValue().containsKey(name); - } + @LauncherAPI + public boolean hasEntry(String name) { + return getValue().containsKey(name); + } - @LauncherAPI - public void remove(String name) { - super.getValue().remove(name); - } + @LauncherAPI + public void remove(String name) { + super.getValue().remove(name); + } - @LauncherAPI - public void setEntry(String name, ConfigEntry entry) { - super.getValue().put(VerifyHelper.verifyIDName(name), entry); - } + @LauncherAPI + public void setEntry(String name, ConfigEntry entry) { + super.getValue().put(VerifyHelper.verifyIDName(name), entry); + } - private static Map> readMap(HInput input, boolean ro) throws IOException { - int entriesCount = input.readLength(0); - Map> map = new LinkedHashMap<>(entriesCount); - for (int i = 0; i < entriesCount; i++) { - String name = VerifyHelper.verifyIDName(input.readString(255)); - ConfigEntry entry = readEntry(input, ro); + private static Map> readMap(HInput input, boolean ro) throws IOException { + int entriesCount = input.readLength(0); + Map> map = new LinkedHashMap<>(entriesCount); + for (int i = 0; i < entriesCount; i++) { + String name = VerifyHelper.verifyIDName(input.readString(255)); + ConfigEntry entry = readEntry(input, ro); - // Try add entry to map - VerifyHelper.putIfAbsent(map, name, entry, String.format("Duplicate config entry: '%s'", name)); - } - return map; - } + // Try add entry to map + VerifyHelper.putIfAbsent(map, name, entry, String.format("Duplicate config entry: '%s'", name)); + } + return map; + } } diff --git a/Launcher/source/serialize/config/entry/BooleanConfigEntry.java b/Launcher/source/serialize/config/entry/BooleanConfigEntry.java index 8f4f0a5..a7a044d 100644 --- a/Launcher/source/serialize/config/entry/BooleanConfigEntry.java +++ b/Launcher/source/serialize/config/entry/BooleanConfigEntry.java @@ -7,23 +7,23 @@ import launcher.serialize.HOutput; public final class BooleanConfigEntry extends ConfigEntry { - @LauncherAPI - public BooleanConfigEntry(boolean value, boolean ro, int cc) { - super(value, ro, cc); - } + @LauncherAPI + public BooleanConfigEntry(boolean value, boolean ro, int cc) { + super(value, ro, cc); + } - @LauncherAPI - public BooleanConfigEntry(HInput input, boolean ro) throws IOException { - this(input.readBoolean(), ro, 0); - } + @LauncherAPI + public BooleanConfigEntry(HInput input, boolean ro) throws IOException { + this(input.readBoolean(), ro, 0); + } - @Override - public Type getType() { - return Type.BOOLEAN; - } + @Override + public Type getType() { + return Type.BOOLEAN; + } - @Override - public void write(HOutput output) throws IOException { - output.writeBoolean(getValue()); - } -} \ No newline at end of file + @Override + public void write(HOutput output) throws IOException { + output.writeBoolean(getValue()); + } +} diff --git a/Launcher/source/serialize/config/entry/ConfigEntry.java b/Launcher/source/serialize/config/entry/ConfigEntry.java index 0c4e7ea..c8e8de6 100644 --- a/Launcher/source/serialize/config/entry/ConfigEntry.java +++ b/Launcher/source/serialize/config/entry/ConfigEntry.java @@ -7,98 +7,99 @@ import launcher.serialize.HInput; import launcher.serialize.HOutput; import launcher.serialize.stream.EnumSerializer; +import launcher.serialize.stream.EnumSerializer.Itf; import launcher.serialize.stream.StreamObject; public abstract class ConfigEntry extends StreamObject { - @LauncherAPI public final boolean ro; - private final String[] comments; - private V value; + @LauncherAPI public final boolean ro; + private final String[] comments; + private V value; - protected ConfigEntry(V value, boolean ro, int cc) { - this.ro = ro; - comments = new String[cc]; - uncheckedSetValue(value); - } + protected ConfigEntry(V value, boolean ro, int cc) { + this.ro = ro; + comments = new String[cc]; + uncheckedSetValue(value); + } - @LauncherAPI - public final String getComment(int i) { - if (i < 0) { - i += comments.length; - } - return i >= comments.length ? null : comments[i]; - } + @LauncherAPI + public abstract Type getType(); - @LauncherAPI - public abstract Type getType(); + @LauncherAPI + public final String getComment(int i) { + if (i < 0) { + i += comments.length; + } + return i >= comments.length ? null : comments[i]; + } - @LauncherAPI - @SuppressWarnings("DesignForExtension") - public V getValue() { - return value; - } + @LauncherAPI + @SuppressWarnings("DesignForExtension") + public V getValue() { + return value; + } - @LauncherAPI - public final void setComment(int i, String comment) { - comments[i] = comment; - } + @LauncherAPI + public final void setValue(V value) { + ensureWritable(); + uncheckedSetValue(value); + } - @LauncherAPI - public final void setValue(V value) { - ensureWritable(); - uncheckedSetValue(value); - } + @LauncherAPI + public final void setComment(int i, String comment) { + comments[i] = comment; + } - protected final void ensureWritable() { - if (ro) { - throw new UnsupportedOperationException("Read-only"); - } - } + protected final void ensureWritable() { + if (ro) { + throw new UnsupportedOperationException("Read-only"); + } + } - @SuppressWarnings("DesignForExtension") - protected void uncheckedSetValue(V value) { - this.value = Objects.requireNonNull(value, "value"); - } + @SuppressWarnings("DesignForExtension") + protected void uncheckedSetValue(V value) { + this.value = Objects.requireNonNull(value, "value"); + } - protected static ConfigEntry readEntry(HInput input, boolean ro) throws IOException { - Type type = Type.read(input); - switch (type) { - case BOOLEAN: - return new BooleanConfigEntry(input, ro); - case INTEGER: - return new IntegerConfigEntry(input, ro); - case STRING: - return new StringConfigEntry(input, ro); - case LIST: - return new ListConfigEntry(input, ro); - case BLOCK: - return new BlockConfigEntry(input, ro); - default: - throw new AssertionError("Unsupported config entry type: " + type.name()); - } - } + protected static ConfigEntry readEntry(HInput input, boolean ro) throws IOException { + Type type = Type.read(input); + switch (type) { + case BOOLEAN: + return new BooleanConfigEntry(input, ro); + case INTEGER: + return new IntegerConfigEntry(input, ro); + case STRING: + return new StringConfigEntry(input, ro); + case LIST: + return new ListConfigEntry(input, ro); + case BLOCK: + return new BlockConfigEntry(input, ro); + default: + throw new AssertionError("Unsupported config entry type: " + type.name()); + } + } - protected static void writeEntry(ConfigEntry entry, HOutput output) throws IOException { - EnumSerializer.write(output, entry.getType()); - entry.write(output); - } + protected static void writeEntry(ConfigEntry entry, HOutput output) throws IOException { + EnumSerializer.write(output, entry.getType()); + entry.write(output); + } - @LauncherAPI - public enum Type implements EnumSerializer.Itf { - BLOCK(1), BOOLEAN(2), INTEGER(3), STRING(4), LIST(5); - private static final EnumSerializer SERIALIZER = new EnumSerializer<>(Type.class); - private final int n; + @LauncherAPI + public enum Type implements Itf { + BLOCK(1), BOOLEAN(2), INTEGER(3), STRING(4), LIST(5); + 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/serialize/config/entry/IntegerConfigEntry.java b/Launcher/source/serialize/config/entry/IntegerConfigEntry.java index 6d8d5e9..210aa6a 100644 --- a/Launcher/source/serialize/config/entry/IntegerConfigEntry.java +++ b/Launcher/source/serialize/config/entry/IntegerConfigEntry.java @@ -7,23 +7,23 @@ import launcher.serialize.HOutput; public final class IntegerConfigEntry extends ConfigEntry { - @LauncherAPI - public IntegerConfigEntry(int value, boolean ro, int cc) { - super(value, ro, cc); - } + @LauncherAPI + public IntegerConfigEntry(int value, boolean ro, int cc) { + super(value, ro, cc); + } - @LauncherAPI - public IntegerConfigEntry(HInput input, boolean ro) throws IOException { - this(input.readVarInt(), ro, 0); - } + @LauncherAPI + public IntegerConfigEntry(HInput input, boolean ro) throws IOException { + this(input.readVarInt(), ro, 0); + } - @Override - public Type getType() { - return Type.INTEGER; - } + @Override + public Type getType() { + return Type.INTEGER; + } - @Override - public void write(HOutput output) throws IOException { - output.writeVarInt(getValue()); - } -} \ No newline at end of file + @Override + public void write(HOutput output) throws IOException { + output.writeVarInt(getValue()); + } +} diff --git a/Launcher/source/serialize/config/entry/ListConfigEntry.java b/Launcher/source/serialize/config/entry/ListConfigEntry.java index 879ed81..8b0b9db 100644 --- a/Launcher/source/serialize/config/entry/ListConfigEntry.java +++ b/Launcher/source/serialize/config/entry/ListConfigEntry.java @@ -11,54 +11,54 @@ import launcher.serialize.HOutput; public final class ListConfigEntry extends ConfigEntry>> { - @LauncherAPI - public ListConfigEntry(List> value, boolean ro, int cc) { - super(value, ro, cc); - } + @LauncherAPI + public ListConfigEntry(List> value, boolean ro, int cc) { + super(value, ro, cc); + } - @LauncherAPI - public ListConfigEntry(HInput input, boolean ro) throws IOException { - super(readList(input, ro), ro, 0); - } + @LauncherAPI + public ListConfigEntry(HInput input, boolean ro) throws IOException { + super(readList(input, ro), ro, 0); + } - @Override - public Type getType() { - return Type.LIST; - } + @Override + public Type getType() { + return Type.LIST; + } - @Override - public void write(HOutput output) throws IOException { - List> value = getValue(); - output.writeLength(value.size(), 0); - for (ConfigEntry element : value) { - writeEntry(element, output); - } - } + @Override + protected void uncheckedSetValue(List> value) { + List> list = new ArrayList<>(value); + super.uncheckedSetValue(ro ? Collections.unmodifiableList(list) : list); + } - @Override - protected void uncheckedSetValue(List> value) { - List> list = new ArrayList<>(value); - super.uncheckedSetValue(ro ? Collections.unmodifiableList(list) : list); - } + @Override + public void write(HOutput output) throws IOException { + List> value = getValue(); + output.writeLength(value.size(), 0); + for (ConfigEntry element : value) { + writeEntry(element, output); + } + } - @LauncherAPI - public > Stream stream(Class clazz) { - return getValue().stream().map(clazz::cast).map(ConfigEntry::getValue); - } + @LauncherAPI + public > Stream stream(Class clazz) { + return getValue().stream().map(clazz::cast).map(ConfigEntry::getValue); + } - @LauncherAPI - public void verifyOfType(Type type) { - if (getValue().stream().anyMatch(e -> e.getType() != type)) { - throw new IllegalArgumentException("List type mismatch: " + type.name()); - } - } + @LauncherAPI + public void verifyOfType(Type type) { + if (getValue().stream().anyMatch(e -> e.getType() != type)) { + throw new IllegalArgumentException("List type mismatch: " + type.name()); + } + } - private static List> readList(HInput input, boolean ro) throws IOException { - int elementsCount = input.readLength(0); - List> list = new ArrayList<>(elementsCount); - for (int i = 0; i < elementsCount; i++) { - list.add(readEntry(input, ro)); - } - return list; - } + private static List> readList(HInput input, boolean ro) throws IOException { + int elementsCount = input.readLength(0); + List> list = new ArrayList<>(elementsCount); + for (int i = 0; i < elementsCount; i++) { + list.add(readEntry(input, ro)); + } + return list; + } } diff --git a/Launcher/source/serialize/config/entry/StringConfigEntry.java b/Launcher/source/serialize/config/entry/StringConfigEntry.java index bd12b5d..9afa8e1 100644 --- a/Launcher/source/serialize/config/entry/StringConfigEntry.java +++ b/Launcher/source/serialize/config/entry/StringConfigEntry.java @@ -7,28 +7,28 @@ import launcher.serialize.HOutput; public final class StringConfigEntry extends ConfigEntry { - @LauncherAPI - public StringConfigEntry(String value, boolean ro, int cc) { - super(value, ro, cc); - } + @LauncherAPI + public StringConfigEntry(String value, boolean ro, int cc) { + super(value, ro, cc); + } - @LauncherAPI - public StringConfigEntry(HInput input, boolean ro) throws IOException { - this(input.readString(0), ro, 0); - } + @LauncherAPI + public StringConfigEntry(HInput input, boolean ro) throws IOException { + this(input.readString(0), ro, 0); + } - @Override - public Type getType() { - return Type.STRING; - } + @Override + public Type getType() { + return Type.STRING; + } - @Override - public void write(HOutput output) throws IOException { - output.writeString(getValue(), 0); - } + @Override + protected void uncheckedSetValue(String value) { + super.uncheckedSetValue(value); + } - @Override - protected void uncheckedSetValue(String value) { - super.uncheckedSetValue(value); - } + @Override + public void write(HOutput output) throws IOException { + output.writeString(getValue(), 0); + } } diff --git a/Launcher/source/serialize/signed/SignedBytesHolder.java b/Launcher/source/serialize/signed/SignedBytesHolder.java index 1c05533..19b6729 100644 --- a/Launcher/source/serialize/signed/SignedBytesHolder.java +++ b/Launcher/source/serialize/signed/SignedBytesHolder.java @@ -13,40 +13,40 @@ import launcher.serialize.stream.StreamObject; public class SignedBytesHolder extends StreamObject { - protected final byte[] bytes; - private final byte[] sign; + protected final byte[] bytes; + private final byte[] sign; - @LauncherAPI - public SignedBytesHolder(HInput input, RSAPublicKey publicKey) throws IOException, SignatureException { - this(input.readByteArray(0), input.readByteArray(-SecurityHelper.RSA_KEY_LENGTH), publicKey); - } + @LauncherAPI + public SignedBytesHolder(HInput input, RSAPublicKey publicKey) throws IOException, SignatureException { + this(input.readByteArray(0), input.readByteArray(-SecurityHelper.RSA_KEY_LENGTH), publicKey); + } - @LauncherAPI - public SignedBytesHolder(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException { - SecurityHelper.verifySign(bytes, sign, publicKey); - this.bytes = Arrays.copyOf(bytes, bytes.length); - this.sign = Arrays.copyOf(sign, sign.length); - } + @LauncherAPI + public SignedBytesHolder(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException { + SecurityHelper.verifySign(bytes, sign, publicKey); + this.bytes = Arrays.copyOf(bytes, bytes.length); + this.sign = Arrays.copyOf(sign, sign.length); + } - @LauncherAPI - public SignedBytesHolder(byte[] bytes, RSAPrivateKey privateKey) { - this.bytes = Arrays.copyOf(bytes, bytes.length); - sign = SecurityHelper.sign(bytes, privateKey); - } + @LauncherAPI + public SignedBytesHolder(byte[] bytes, RSAPrivateKey privateKey) { + this.bytes = Arrays.copyOf(bytes, bytes.length); + sign = SecurityHelper.sign(bytes, privateKey); + } - @Override - public final void write(HOutput output) throws IOException { - output.writeByteArray(bytes, 0); - output.writeByteArray(sign, -SecurityHelper.RSA_KEY_LENGTH); - } + @Override + public final void write(HOutput output) throws IOException { + output.writeByteArray(bytes, 0); + output.writeByteArray(sign, -SecurityHelper.RSA_KEY_LENGTH); + } - @LauncherAPI - public final byte[] getBytes() { - return Arrays.copyOf(bytes, bytes.length); - } + @LauncherAPI + public final byte[] getBytes() { + return Arrays.copyOf(bytes, bytes.length); + } - @LauncherAPI - public final byte[] getSign() { - return Arrays.copyOf(sign, sign.length); - } + @LauncherAPI + public final byte[] getSign() { + return Arrays.copyOf(sign, sign.length); + } } diff --git a/Launcher/source/serialize/signed/SignedObjectHolder.java b/Launcher/source/serialize/signed/SignedObjectHolder.java index 5d3a5a5..5acd2de 100644 --- a/Launcher/source/serialize/signed/SignedObjectHolder.java +++ b/Launcher/source/serialize/signed/SignedObjectHolder.java @@ -10,39 +10,39 @@ import launcher.serialize.stream.StreamObject; public final class SignedObjectHolder extends SignedBytesHolder { - @LauncherAPI public final O object; + @LauncherAPI public final O object; - @LauncherAPI - public SignedObjectHolder(HInput input, RSAPublicKey publicKey, Adapter adapter) throws IOException, SignatureException { - super(input, publicKey); - object = newInstance(adapter); - } + @LauncherAPI + public SignedObjectHolder(HInput input, RSAPublicKey publicKey, Adapter adapter) throws IOException, SignatureException { + super(input, publicKey); + object = newInstance(adapter); + } - @LauncherAPI - public SignedObjectHolder(O object, RSAPrivateKey privateKey) throws IOException { - super(object.write(), privateKey); - this.object = object; - } + @LauncherAPI + public SignedObjectHolder(O object, RSAPrivateKey privateKey) throws IOException { + super(object.write(), privateKey); + this.object = object; + } - @LauncherAPI - public O newInstance(Adapter adapter) throws IOException { - try (HInput input = new HInput(bytes)) { - return adapter.convert(input); - } - } + @Override + public boolean equals(Object obj) { + return obj instanceof SignedObjectHolder && object.equals(((SignedObjectHolder) obj).object); + } - @Override - public boolean equals(Object obj) { - return obj instanceof SignedObjectHolder && object.equals(((SignedObjectHolder) obj).object); - } + @Override + public int hashCode() { + return object.hashCode(); + } - @Override - public int hashCode() { - return object.hashCode(); - } + @Override + public String toString() { + return object.toString(); + } - @Override - public String toString() { - return object.toString(); - } + @LauncherAPI + public O newInstance(Adapter adapter) throws IOException { + try (HInput input = new HInput(bytes)) { + return adapter.convert(input); + } + } } diff --git a/Launcher/source/serialize/stream/EnumSerializer.java b/Launcher/source/serialize/stream/EnumSerializer.java index 3a14cc4..8ad71fe 100644 --- a/Launcher/source/serialize/stream/EnumSerializer.java +++ b/Launcher/source/serialize/stream/EnumSerializer.java @@ -12,41 +12,41 @@ import launcher.serialize.stream.EnumSerializer.Itf; public final class EnumSerializer & Itf> { - private final Map map = new HashMap<>(16); + private final Map map = new HashMap<>(16); - @LauncherAPI - public EnumSerializer(Class clazz) { - for (Field field : clazz.getFields()) { - if (!field.isEnumConstant()) { - continue; - } + @LauncherAPI + public EnumSerializer(Class clazz) { + for (Field field : clazz.getFields()) { + if (!field.isEnumConstant()) { + continue; + } - // Add to map - Itf itf; - try { - itf = (Itf) field.get(null); - } catch (IllegalAccessException e) { - throw new InternalError(e); - } - VerifyHelper.putIfAbsent(map, itf.getNumber(), clazz.cast(itf), - "Duplicate number for enum constant " + field.getName()); - } - } + // Add to map + Itf itf; + try { + itf = (Itf) field.get(null); + } catch (IllegalAccessException e) { + throw new InternalError(e); + } + VerifyHelper.putIfAbsent(map, itf.getNumber(), clazz.cast(itf), + "Duplicate number for enum constant " + field.getName()); + } + } - @LauncherAPI - public E read(HInput input) throws IOException { - int n = input.readVarInt(); - return VerifyHelper.getMapValue(map, n, "Unknown enum number: " + n); - } + @LauncherAPI + public E read(HInput input) throws IOException { + int n = input.readVarInt(); + return VerifyHelper.getMapValue(map, n, "Unknown enum number: " + n); + } - @LauncherAPI - public static void write(HOutput output, Itf itf) throws IOException { - output.writeVarInt(itf.getNumber()); - } + @LauncherAPI + public static void write(HOutput output, Itf itf) throws IOException { + output.writeVarInt(itf.getNumber()); + } - @FunctionalInterface - public interface Itf { - @LauncherAPI - int getNumber(); - } + @FunctionalInterface + public interface Itf { + @LauncherAPI + int getNumber(); + } } diff --git a/Launcher/source/serialize/stream/StreamObject.java b/Launcher/source/serialize/stream/StreamObject.java index bc25537..7a81980 100644 --- a/Launcher/source/serialize/stream/StreamObject.java +++ b/Launcher/source/serialize/stream/StreamObject.java @@ -9,24 +9,24 @@ import launcher.serialize.HOutput; public abstract class StreamObject { - /* public StreamObject(HInput input) */ + /* public StreamObject(HInput input) */ - @LauncherAPI - public abstract void write(HOutput output) throws IOException; + @LauncherAPI + public abstract void write(HOutput output) throws IOException; - @LauncherAPI - public final byte[] write() throws IOException { - try (ByteArrayOutputStream array = IOHelper.newByteArrayOutput()) { - try (HOutput output = new HOutput(array)) { - write(output); - } - return array.toByteArray(); - } - } + @LauncherAPI + public final byte[] write() throws IOException { + try (ByteArrayOutputStream array = IOHelper.newByteArrayOutput()) { + try (HOutput output = new HOutput(array)) { + write(output); + } + return array.toByteArray(); + } + } - @FunctionalInterface - public interface Adapter { - @LauncherAPI - O convert(HInput input) throws IOException; - } + @FunctionalInterface + public interface Adapter { + @LauncherAPI + O convert(HInput input) throws IOException; + } } diff --git a/LauncherAuthlib/source/minecraft/MinecraftProfileTexture.java b/LauncherAuthlib/source/minecraft/MinecraftProfileTexture.java index 991a4c2..0d8434c 100644 --- a/LauncherAuthlib/source/minecraft/MinecraftProfileTexture.java +++ b/LauncherAuthlib/source/minecraft/MinecraftProfileTexture.java @@ -1,40 +1,40 @@ package com.mojang.authlib.minecraft; public final class MinecraftProfileTexture { - public static final int PROFILE_TEXTURE_COUNT = Type.values().length; + public static final int PROFILE_TEXTURE_COUNT = Type.values().length; - // Instance - private final String url; - private final String hash; + // Instance + private final String url; + private final String hash; - public MinecraftProfileTexture(String url, String hash) { - this.url = url; - this.hash = hash; - } + public MinecraftProfileTexture(String url, String hash) { + this.url = url; + this.hash = hash; + } - @SuppressWarnings("unused") - public String getHash() { - return hash; - } + @Override + public String toString() { + return String.format("MinecraftProfileTexture{url='%s',hash=%s}", url, hash); + } - @SuppressWarnings({ "unused", "SameReturnValue" }) - public String getMetadata(String key) { - return null; - } + @SuppressWarnings("unused") + public String getHash() { + return hash; + } - @SuppressWarnings("unused") - public String getUrl() { - return url; - } + @SuppressWarnings({ "unused", "SameReturnValue" }) + public String getMetadata(String key) { + return null; + } - @Override - public String toString() { - return String.format("MinecraftProfileTexture{url='%s',hash=%s}", url, hash); - } + @SuppressWarnings("unused") + public String getUrl() { + return url; + } - public enum Type { - SKIN, - CAPE, - ELYTRA - } + public enum Type { + SKIN, + CAPE, + ELYTRA + } } diff --git a/LauncherAuthlib/source/yggdrasil/LegacyBridge.java b/LauncherAuthlib/source/yggdrasil/LegacyBridge.java index e4c6bb7..018f669 100644 --- a/LauncherAuthlib/source/yggdrasil/LegacyBridge.java +++ b/LauncherAuthlib/source/yggdrasil/LegacyBridge.java @@ -8,42 +8,42 @@ import launcher.request.auth.JoinServerRequest; public final class LegacyBridge { - private LegacyBridge() { - } + private LegacyBridge() { + } - @SuppressWarnings("unused") - public static boolean checkServer(String username, String serverID) throws Exception { - LogHelper.debug("LegacyBridge.checkServer, Username: '%s', Server ID: %s", username, serverID); - return new CheckServerRequest(username, serverID).request() != null; - } + @SuppressWarnings("unused") + public static boolean checkServer(String username, String serverID) throws Exception { + LogHelper.debug("LegacyBridge.checkServer, Username: '%s', Server ID: %s", username, serverID); + return new CheckServerRequest(username, serverID).request() != null; + } - @SuppressWarnings("unused") - public static String getCloakURL(String username) { - LogHelper.debug("LegacyBridge.getCloakURL: '%s'", username); - return CommonHelper.replace(System.getProperty("launcher.legacy.cloaksURL", - "http://skins.minecraft.net/MinecraftCloaks/%username%.png"), "username", IOHelper.urlEncode(username)); - } + @SuppressWarnings("unused") + public static String getCloakURL(String username) { + LogHelper.debug("LegacyBridge.getCloakURL: '%s'", username); + return CommonHelper.replace(System.getProperty("launcher.legacy.cloaksURL", + "http://skins.minecraft.net/MinecraftCloaks/%username%.png"), "username", IOHelper.urlEncode(username)); + } - @SuppressWarnings("unused") - public static String getSkinURL(String username) { - LogHelper.debug("LegacyBridge.getSkinURL: '%s'", username); - return CommonHelper.replace(System.getProperty("launcher.legacy.skinsURL", - "http://skins.minecraft.net/MinecraftSkins/%username%.png"), "username", IOHelper.urlEncode(username)); - } + @SuppressWarnings("unused") + public static String getSkinURL(String username) { + LogHelper.debug("LegacyBridge.getSkinURL: '%s'", username); + return CommonHelper.replace(System.getProperty("launcher.legacy.skinsURL", + "http://skins.minecraft.net/MinecraftSkins/%username%.png"), "username", IOHelper.urlEncode(username)); + } - @SuppressWarnings("unused") - public static String joinServer(String username, String accessToken, String serverID) { - if (!ClientLauncher.isLaunched()) { - return "Bad Login (Cheater)"; - } + @SuppressWarnings("unused") + public static String joinServer(String username, String accessToken, String serverID) { + if (!ClientLauncher.isLaunched()) { + return "Bad Login (Cheater)"; + } - // Join server - LogHelper.debug("LegacyBridge.joinServer, Username: '%s', Access token: %s, Server ID: %s", - username, accessToken, serverID); - try { - return new JoinServerRequest(username, accessToken, serverID).request() ? "OK" : "Bad Login (Clientside)"; - } catch (Exception e) { - return e.toString(); - } - } + // Join server + LogHelper.debug("LegacyBridge.joinServer, Username: '%s', Access token: %s, Server ID: %s", + username, accessToken, serverID); + try { + return new JoinServerRequest(username, accessToken, serverID).request() ? "OK" : "Bad Login (Clientside)"; + } catch (Exception e) { + return e.toString(); + } + } } diff --git a/LauncherAuthlib/source/yggdrasil/YggdrasilAuthenticationService.java b/LauncherAuthlib/source/yggdrasil/YggdrasilAuthenticationService.java index e24a0a6..d30bfde 100644 --- a/LauncherAuthlib/source/yggdrasil/YggdrasilAuthenticationService.java +++ b/LauncherAuthlib/source/yggdrasil/YggdrasilAuthenticationService.java @@ -10,23 +10,23 @@ import launcher.helper.LogHelper; public final class YggdrasilAuthenticationService implements AuthenticationService { - @SuppressWarnings("UnusedParameters") - public YggdrasilAuthenticationService(Proxy proxy, String clientToken) { - LogHelper.debug("Patched AuthenticationService created: '%s'", clientToken); - } + @SuppressWarnings("UnusedParameters") + public YggdrasilAuthenticationService(Proxy proxy, String clientToken) { + LogHelper.debug("Patched AuthenticationService created: '%s'", clientToken); + } - @Override - public MinecraftSessionService createMinecraftSessionService() { - return new YggdrasilMinecraftSessionService(this); - } + @Override + public MinecraftSessionService createMinecraftSessionService() { + return new YggdrasilMinecraftSessionService(this); + } - @Override - public GameProfileRepository createProfileRepository() { - return new YggdrasilGameProfileRepository(); - } + @Override + public GameProfileRepository createProfileRepository() { + return new YggdrasilGameProfileRepository(); + } - @Override - public UserAuthentication createUserAuthentication(Agent agent) { - throw new UnsupportedOperationException("createUserAuthentication is used only by Mojang Launcher"); - } + @Override + public UserAuthentication createUserAuthentication(Agent agent) { + throw new UnsupportedOperationException("createUserAuthentication is used only by Mojang Launcher"); + } } diff --git a/LauncherAuthlib/source/yggdrasil/YggdrasilGameProfileRepository.java b/LauncherAuthlib/source/yggdrasil/YggdrasilGameProfileRepository.java index 5811205..163bb34 100644 --- a/LauncherAuthlib/source/yggdrasil/YggdrasilGameProfileRepository.java +++ b/LauncherAuthlib/source/yggdrasil/YggdrasilGameProfileRepository.java @@ -13,66 +13,66 @@ import launcher.request.uuid.BatchProfileByUsernameRequest; public final class YggdrasilGameProfileRepository implements GameProfileRepository { - private static final long BUSY_WAIT_MS = VerifyHelper.verifyLong( - Long.parseLong(System.getProperty("launcher.authlib.busyWait", Long.toString(100L))), - VerifyHelper.L_NOT_NEGATIVE, "launcher.authlib.busyWait can't be < 0"); - private static final long ERROR_BUSY_WAIT_MS = VerifyHelper.verifyLong( - Long.parseLong(System.getProperty("launcher.authlib.errorBusyWait", Long.toString(500L))), - VerifyHelper.L_NOT_NEGATIVE, "launcher.authlib.errorBusyWait can't be < 0"); + private static final long BUSY_WAIT_MS = VerifyHelper.verifyLong( + Long.parseLong(System.getProperty("launcher.authlib.busyWait", Long.toString(100L))), + VerifyHelper.L_NOT_NEGATIVE, "launcher.authlib.busyWait can't be < 0"); + private static final long ERROR_BUSY_WAIT_MS = VerifyHelper.verifyLong( + Long.parseLong(System.getProperty("launcher.authlib.errorBusyWait", Long.toString(500L))), + VerifyHelper.L_NOT_NEGATIVE, "launcher.authlib.errorBusyWait can't be < 0"); - public YggdrasilGameProfileRepository() { - LogHelper.debug("Patched GameProfileRepository created"); - } + public YggdrasilGameProfileRepository() { + LogHelper.debug("Patched GameProfileRepository created"); + } - @Override - public void findProfilesByNames(String[] usernames, Agent agent, ProfileLookupCallback callback) { - int offset = 0; - while (offset < usernames.length) { - String[] sliceUsernames = Arrays.copyOfRange(usernames, offset, - Math.min(offset + BatchProfileByUsernameRequest.MAX_BATCH_SIZE, usernames.length)); - offset += BatchProfileByUsernameRequest.MAX_BATCH_SIZE; + @Override + public void findProfilesByNames(String[] usernames, Agent agent, ProfileLookupCallback callback) { + int offset = 0; + while (offset < usernames.length) { + String[] sliceUsernames = Arrays.copyOfRange(usernames, offset, + Math.min(offset + BatchProfileByUsernameRequest.MAX_BATCH_SIZE, usernames.length)); + offset += BatchProfileByUsernameRequest.MAX_BATCH_SIZE; - // Batch Username-To-UUID request - PlayerProfile[] sliceProfiles; - try { - sliceProfiles = new BatchProfileByUsernameRequest(sliceUsernames).request(); - } catch (Exception e) { - for (String username : sliceUsernames) { - LogHelper.debug("Couldn't find profile '%s': %s", username, e); - callback.onProfileLookupFailed(new GameProfile((UUID) null, username), e); - } + // Batch Username-To-UUID request + PlayerProfile[] sliceProfiles; + try { + sliceProfiles = new BatchProfileByUsernameRequest(sliceUsernames).request(); + } catch (Exception e) { + for (String username : sliceUsernames) { + LogHelper.debug("Couldn't find profile '%s': %s", username, e); + callback.onProfileLookupFailed(new GameProfile((UUID) null, username), e); + } - // Busy wait, like in standard authlib - busyWait(ERROR_BUSY_WAIT_MS); - continue; - } + // Busy wait, like in standard authlib + busyWait(ERROR_BUSY_WAIT_MS); + continue; + } - // Request succeeded! - for (int i = 0; i < sliceProfiles.length; i++) { - PlayerProfile pp = sliceProfiles[i]; - if (pp == null) { - String username = sliceUsernames[i]; - LogHelper.debug("Couldn't find profile '%s'", username); - callback.onProfileLookupFailed(new GameProfile((UUID) null, username), - new ProfileNotFoundException("Server did not find the requested profile")); - continue; - } + // Request succeeded! + for (int i = 0; i < sliceProfiles.length; i++) { + PlayerProfile pp = sliceProfiles[i]; + if (pp == null) { + String username = sliceUsernames[i]; + LogHelper.debug("Couldn't find profile '%s'", username); + callback.onProfileLookupFailed(new GameProfile((UUID) null, username), + new ProfileNotFoundException("Server did not find the requested profile")); + continue; + } - // Report as looked up - LogHelper.debug("Successfully looked up profile '%s'", pp.username); - callback.onProfileLookupSucceeded(YggdrasilMinecraftSessionService.toGameProfile(pp)); - } + // Report as looked up + LogHelper.debug("Successfully looked up profile '%s'", pp.username); + callback.onProfileLookupSucceeded(YggdrasilMinecraftSessionService.toGameProfile(pp)); + } - // Busy wait, like in standard authlib - busyWait(BUSY_WAIT_MS); - } - } + // Busy wait, like in standard authlib + busyWait(BUSY_WAIT_MS); + } + } - private static void busyWait(long ms) { - try { - Thread.sleep(ms); - } catch (InterruptedException e) { - LogHelper.error(e); - } - } + private static void busyWait(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + LogHelper.error(e); + } + } } diff --git a/LauncherAuthlib/source/yggdrasil/YggdrasilMinecraftSessionService.java b/LauncherAuthlib/source/yggdrasil/YggdrasilMinecraftSessionService.java index aabd651..43f99fe 100644 --- a/LauncherAuthlib/source/yggdrasil/YggdrasilMinecraftSessionService.java +++ b/LauncherAuthlib/source/yggdrasil/YggdrasilMinecraftSessionService.java @@ -11,6 +11,7 @@ import com.mojang.authlib.exceptions.AuthenticationUnavailableException; import com.mojang.authlib.minecraft.BaseMinecraftSessionService; import com.mojang.authlib.minecraft.MinecraftProfileTexture; +import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import launcher.client.ClientLauncher; @@ -22,131 +23,131 @@ import launcher.request.uuid.ProfileByUUIDRequest; public final class YggdrasilMinecraftSessionService extends BaseMinecraftSessionService { - public YggdrasilMinecraftSessionService(AuthenticationService service) { - super(service); - LogHelper.debug("Patched MinecraftSessionService created"); - } + public YggdrasilMinecraftSessionService(AuthenticationService service) { + super(service); + LogHelper.debug("Patched MinecraftSessionService created"); + } - @Override - public GameProfile fillProfileProperties(GameProfile profile, boolean requireSecure) { - // Verify has UUID - UUID uuid = profile.getUUID(); - LogHelper.debug("fillProfileProperties, UUID: %s", uuid); - if (uuid == null) { - return profile; - } + @Override + public GameProfile fillProfileProperties(GameProfile profile, boolean requireSecure) { + // Verify has UUID + UUID uuid = profile.getUUID(); + LogHelper.debug("fillProfileProperties, UUID: %s", uuid); + if (uuid == null) { + return profile; + } - // Make profile request - PlayerProfile pp; - try { - pp = new ProfileByUUIDRequest(uuid).request(); - } catch (Exception e) { - LogHelper.debug("Couldn't fetch profile properties for '%s': %s", profile, e); - return profile; - } + // Make profile request + PlayerProfile pp; + try { + pp = new ProfileByUUIDRequest(uuid).request(); + } catch (Exception e) { + LogHelper.debug("Couldn't fetch profile properties for '%s': %s", profile, e); + return profile; + } - // Verify is found - if (pp == null) { - LogHelper.debug("Couldn't fetch profile properties for '%s' as the profile does not exist", profile); - return profile; - } + // Verify is found + if (pp == null) { + LogHelper.debug("Couldn't fetch profile properties for '%s' as the profile does not exist", profile); + return profile; + } - // Create new game profile from player profile - LogHelper.debug("Successfully fetched profile properties for '%s'", profile); - fillTextureProperties(profile, pp); - return toGameProfile(pp); - } + // Create new game profile from player profile + LogHelper.debug("Successfully fetched profile properties for '%s'", profile); + fillTextureProperties(profile, pp); + return toGameProfile(pp); + } - @Override - public Map getTextures(GameProfile profile, boolean requireSecure) { - LogHelper.debug("getTextures, Username: '%s'", profile.getName()); - Map textures = - new EnumMap<>(MinecraftProfileTexture.Type.class); + @Override + public Map getTextures(GameProfile profile, boolean requireSecure) { + LogHelper.debug("getTextures, Username: '%s'", profile.getName()); + Map textures = + new EnumMap<>(Type.class); - // Add skin URL to textures map - Iterator skinURL = profile.getProperties().get(ClientLauncher.SKIN_URL_PROPERTY).iterator(); - Iterator skinHash = profile.getProperties().get(ClientLauncher.SKIN_DIGEST_PROPERTY).iterator(); - if (skinURL.hasNext() && skinHash.hasNext()) { - String urlValue = skinURL.next().getValue(); - String hashValue = skinHash.next().getValue(); - textures.put(MinecraftProfileTexture.Type.SKIN, new MinecraftProfileTexture(urlValue, hashValue)); - } + // Add skin URL to textures map + Iterator skinURL = profile.getProperties().get(ClientLauncher.SKIN_URL_PROPERTY).iterator(); + Iterator skinHash = profile.getProperties().get(ClientLauncher.SKIN_DIGEST_PROPERTY).iterator(); + if (skinURL.hasNext() && skinHash.hasNext()) { + String urlValue = skinURL.next().getValue(); + String hashValue = skinHash.next().getValue(); + textures.put(Type.SKIN, new MinecraftProfileTexture(urlValue, hashValue)); + } - // Add cloak URL to textures map - Iterator cloakURL = profile.getProperties().get(ClientLauncher.CLOAK_URL_PROPERTY).iterator(); - Iterator cloakHash = profile.getProperties().get(ClientLauncher.CLOAK_DIGEST_PROPERTY).iterator(); - if (cloakURL.hasNext() && cloakHash.hasNext()) { - String urlValue = cloakURL.next().getValue(); - String hashValue = cloakHash.next().getValue(); - textures.put(MinecraftProfileTexture.Type.CAPE, new MinecraftProfileTexture(urlValue, hashValue)); - } + // Add cloak URL to textures map + Iterator cloakURL = profile.getProperties().get(ClientLauncher.CLOAK_URL_PROPERTY).iterator(); + Iterator cloakHash = profile.getProperties().get(ClientLauncher.CLOAK_DIGEST_PROPERTY).iterator(); + if (cloakURL.hasNext() && cloakHash.hasNext()) { + String urlValue = cloakURL.next().getValue(); + String hashValue = cloakHash.next().getValue(); + textures.put(Type.CAPE, new MinecraftProfileTexture(urlValue, hashValue)); + } - // Return filled textures - return textures; - } + // Return filled textures + return textures; + } - @Override - public GameProfile hasJoinedServer(GameProfile profile, String serverID) throws AuthenticationUnavailableException { - String username = profile.getName(); - LogHelper.debug("checkServer, Username: '%s', Server ID: %s", username, serverID); + @Override + public GameProfile hasJoinedServer(GameProfile profile, String serverID) throws AuthenticationUnavailableException { + String username = profile.getName(); + LogHelper.debug("checkServer, Username: '%s', Server ID: %s", username, serverID); - // Make checkServer request - PlayerProfile pp; - try { - pp = new CheckServerRequest(username, serverID).request(); - } catch (Exception e) { - LogHelper.error(e); - throw new AuthenticationUnavailableException(e); - } + // Make checkServer request + PlayerProfile pp; + try { + pp = new CheckServerRequest(username, serverID).request(); + } catch (Exception e) { + LogHelper.error(e); + throw new AuthenticationUnavailableException(e); + } - // Return profile if found - return pp == null ? null : toGameProfile(pp); - } + // Return profile if found + return pp == null ? null : toGameProfile(pp); + } - @Override - public void joinServer(GameProfile profile, String accessToken, String serverID) throws AuthenticationException { - if (!ClientLauncher.isLaunched()) { - throw new AuthenticationException("Bad Login (Cheater)"); - } + @Override + public void joinServer(GameProfile profile, String accessToken, String serverID) throws AuthenticationException { + if (!ClientLauncher.isLaunched()) { + throw new AuthenticationException("Bad Login (Cheater)"); + } - // Join server - String username = profile.getName(); - LogHelper.debug("joinServer, Username: '%s', Access token: %s, Server ID: %s", - username, accessToken, serverID); + // Join server + String username = profile.getName(); + LogHelper.debug("joinServer, Username: '%s', Access token: %s, Server ID: %s", + username, accessToken, serverID); - // Make joinServer request - boolean success; - try { - success = new JoinServerRequest(username, accessToken, serverID).request(); - } catch (Exception e) { - throw new AuthenticationUnavailableException(e); - } + // Make joinServer request + boolean success; + try { + success = new JoinServerRequest(username, accessToken, serverID).request(); + } catch (Exception e) { + throw new AuthenticationUnavailableException(e); + } - // Verify is success - if (!success) { - throw new AuthenticationException("Bad Login (Clientside)"); - } - } + // Verify is success + if (!success) { + throw new AuthenticationException("Bad Login (Clientside)"); + } + } - public static void fillTextureProperties(GameProfile profile, PlayerProfile pp) { - PropertyMap properties = profile.getProperties(); - if (pp.skin != null) { - properties.put(ClientLauncher.SKIN_URL_PROPERTY, new Property( - ClientLauncher.SKIN_URL_PROPERTY, pp.skin.url, "")); - properties.put(ClientLauncher.SKIN_DIGEST_PROPERTY, new Property( - ClientLauncher.SKIN_DIGEST_PROPERTY, SecurityHelper.toHex(pp.skin.digest), "")); - } - if (pp.cloak != null) { - properties.put(ClientLauncher.CLOAK_URL_PROPERTY, new Property( - ClientLauncher.CLOAK_URL_PROPERTY, pp.cloak.url, "")); - properties.put(ClientLauncher.CLOAK_DIGEST_PROPERTY, new Property( - ClientLauncher.CLOAK_DIGEST_PROPERTY, SecurityHelper.toHex(pp.cloak.digest), "")); - } - } + public static void fillTextureProperties(GameProfile profile, PlayerProfile pp) { + PropertyMap properties = profile.getProperties(); + if (pp.skin != null) { + properties.put(ClientLauncher.SKIN_URL_PROPERTY, new Property( + ClientLauncher.SKIN_URL_PROPERTY, pp.skin.url, "")); + properties.put(ClientLauncher.SKIN_DIGEST_PROPERTY, new Property( + ClientLauncher.SKIN_DIGEST_PROPERTY, SecurityHelper.toHex(pp.skin.digest), "")); + } + if (pp.cloak != null) { + properties.put(ClientLauncher.CLOAK_URL_PROPERTY, new Property( + ClientLauncher.CLOAK_URL_PROPERTY, pp.cloak.url, "")); + properties.put(ClientLauncher.CLOAK_DIGEST_PROPERTY, new Property( + ClientLauncher.CLOAK_DIGEST_PROPERTY, SecurityHelper.toHex(pp.cloak.digest), "")); + } + } - public static GameProfile toGameProfile(PlayerProfile pp) { - GameProfile profile = new GameProfile(pp.uuid, pp.username); - fillTextureProperties(profile, pp); - return profile; - } + public static GameProfile toGameProfile(PlayerProfile pp) { + GameProfile profile = new GameProfile(pp.uuid, pp.username); + fillTextureProperties(profile, pp); + return profile; + } } diff --git a/build.sh b/build.sh index 17ed120..f32ef95 100644 --- a/build.sh +++ b/build.sh @@ -6,7 +6,7 @@ # Build Launcher.jar echo 'Packing Launcher.jar binary' -zip -9 Launcher.jar buildnumber +zip -9 Launcher.jar buildnumber pack200 -E9 -Htrue -mlatest -Uerror -r Launcher.jar jarsigner -keystore build/sashok724.jks -storepass PSP1004 -sigfile LAUNCHER Launcher.jar sashok724 > /dev/null pack200 Launcher.pack.gz Launcher.jar