diff --git a/Launcher/runtime/dialog/dialog.js b/Launcher/runtime/dialog/dialog.js index 40d31fc..d98074a 100644 --- a/Launcher/runtime/dialog/dialog.js +++ b/Launcher/runtime/dialog/dialog.js @@ -170,33 +170,33 @@ makeUpdateRequest(jvmDirName, jvmDir, null, function(jvmHDir) { settings.lastHDirs.put(jvmDirName, jvmHDir); - // Update assets + // Update asset dir update.resetOverlay("Обновление файлов ресурсов"); var assetDirName = profile.object.block.getEntryValue("assetDir", StringConfigEntryClass); var assetDir = settings.updatesDir.resolve(assetDirName); - makeUpdateRequest(assetDirName, assetDir, null, function(assetHDir) { + var assetMatcher = profile.object.getAssetUpdateMatcher(); + makeUpdateRequest(assetDirName, assetDir, assetMatcher, function(assetHDir) { settings.lastHDirs.put(assetDirName, assetHDir); - // Update clients + // Update client dir update.resetOverlay("Обновление файлов клиента"); var clientDirName = profile.object.block.getEntryValue("dir", StringConfigEntryClass); var clientDir = settings.updatesDir.resolve(clientDirName); - makeUpdateRequest(clientDirName, clientDir, profile.object.getUpdateMatcher(), function(clientHDir) { + var clientMatcher = profile.object.getClientUpdateMatcher(); + makeUpdateRequest(clientDirName, clientDir, clientMatcher, function(clientHDir) { settings.lastHDirs.put(clientDirName, clientHDir); - - // Launch client - doLaunchClient(jvmDir, jvmHDir, clientHDir, assetDir, clientDir, profile, pp, accessToken); + doLaunchClient(jvmDir, jvmHDir, assetDir, assetHDir, clientDir, clientHDir, profile, pp, accessToken); }); }); }); }); } -function doLaunchClient(jvmDir, jvmHDir, clientHDir, assetDir, clientDir, profile, pp, accessToken) { +function doLaunchClient(jvmDir, jvmHDir, assetDir, assetHDir, clientDir, clientHDir, profile, pp, accessToken) { processing.resetOverlay(); overlay.swap(0, processing.overlay, function(event) - launchClient(jvmDir, jvmHDir, clientHDir, profile, new ClientLauncherParams(settings.lastSign, assetDir, clientDir, - pp, accessToken, settings.autoEnter, settings.fullScreen, settings.ram, 0, 0), doDebugClient) + launchClient(jvmDir, jvmHDir, assetHDir, clientHDir, profile, new ClientLauncherParams(settings.lastSign, + assetDir, clientDir, pp, accessToken, settings.autoEnter, settings.fullScreen, settings.ram, 0, 0), doDebugClient) ); } diff --git a/Launcher/runtime/dialog/overlay/processing/processing.js b/Launcher/runtime/dialog/overlay/processing/processing.js index ba8eb77..9a45cbb 100644 --- a/Launcher/runtime/dialog/overlay/processing/processing.js +++ b/Launcher/runtime/dialog/overlay/processing/processing.js @@ -109,9 +109,9 @@ startTask(task); } -function launchClient(jvmDir, jvmHDir, clientHDir, profile, params, callback) { - var task = newTask(function() ClientLauncher.launch(jvmDir, jvmHDir, - clientHDir, profile, params, LogHelper.isDebugEnabled())); +function launchClient(jvmDir, jvmHDir, assetHDir, clientHDir, profile, params, callback) { + var task = newTask(function() ClientLauncher.launch(jvmDir, jvmHDir, assetHDir, clientHDir, + profile, params, LogHelper.isDebugEnabled())); processing.setTaskProperties(task, callback, null, true); task.updateMessage("Запуск выбранного клиента"); startTask(task); diff --git a/Launcher/runtime/dialog/overlay/settings/settings.js b/Launcher/runtime/dialog/overlay/settings/settings.js index 13e5ed6..b41590a 100644 --- a/Launcher/runtime/dialog/overlay/settings/settings.js +++ b/Launcher/runtime/dialog/overlay/settings/settings.js @@ -234,7 +234,7 @@ deleteUpdatesDir: function() { processing.description.setText("Удаление директории загрузок"); overlay.swap(0, processing.overlay, function(event) { - var task = newTask(function() IOHelper.deleteDir(updatesDir, false)); + var task = newTask(function() IOHelper.deleteDir(settings.updatesDir, false)); task.setOnSucceeded(function(event) overlay.swap(0, settings.overlay, null)); task.setOnFailed(function(event) { processing.setError(task.getException()); diff --git a/Launcher/runtime/dialog/overlay/update/update.js b/Launcher/runtime/dialog/overlay/update/update.js index 794a51b..b403a5a 100644 --- a/Launcher/runtime/dialog/overlay/update/update.js +++ b/Launcher/runtime/dialog/overlay/update/update.js @@ -79,15 +79,8 @@ return; } - // Verify dir with matcher - var verifyMatcher = matcher === null ? null : matcher.verifyOnly(); - var currentHDir = new HashedDir(dir, verifyMatcher); - if (!hdir.object.diff(currentHDir, verifyMatcher).isSame()) { - Request.requestError(java.lang.String.format("Директория '%s' была изменена", dirName)); - return; - } - - // Return last hdir + // Verify dir with matcher using ClientLauncher's API + ClientLauncher.verifyHDir(dir, hdir, matcher); return hdir; }; } diff --git a/Launcher/source/client/ClientLauncher.java b/Launcher/source/client/ClientLauncher.java index 20b6dd6..e216fec 100644 --- a/Launcher/source/client/ClientLauncher.java +++ b/Launcher/source/client/ClientLauncher.java @@ -77,15 +77,20 @@ } @LauncherAPI - public static Process launch(Path jvmDir, SignedObjectHolder jvmHDir, SignedObjectHolder clientHDir, SignedObjectHolder profile, Params params, boolean pipeOutput) throws Throwable { + 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); - jvmHDir.write(output); - clientHDir.write(output); profile.write(output); + + // Write hdirs + jvmHDir.write(output); + assetHDir.write(output); + clientHDir.write(output); } // Resolve java bin and set permissions @@ -136,17 +141,17 @@ // Read and delete params file LogHelper.debug("Reading ClientLauncher params file"); Params params; - SignedObjectHolder jvmHDir; - SignedObjectHolder clientHDir; SignedObjectHolder profile; + SignedObjectHolder jvmHDir, assetHDir, clientHDir; RSAPublicKey publicKey = Launcher.getConfig().publicKey; try (HInput input = new HInput(IOHelper.newInput(paramsFile))) { params = new Params(input); - - // Read signed params - jvmHDir = new SignedObjectHolder<>(input, publicKey, HashedDir::new); - clientHDir = new SignedObjectHolder<>(input, publicKey, HashedDir::new); 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); } @@ -164,21 +169,19 @@ // Start client with WatchService monitoring LogHelper.debug("Starting JVM and client WatchService"); - FileNameMatcher profileMatcher = profile.object.getUpdateMatcher(); + FileNameMatcher assetMatcher = profile.object.getAssetUpdateMatcher(); + FileNameMatcher clientMatcher = profile.object.getClientUpdateMatcher(); try (DirWatcher jvmWatcher = new DirWatcher(IOHelper.JVM_DIR, jvmHDir.object, null); // JVM Watcher - DirWatcher clientWatcher = new DirWatcher(params.clientDir, clientHDir.object, profileMatcher)) { - // Verify current state of JVM and client dirs - HashedDir currentJVM = new HashedDir(IOHelper.JVM_DIR, null); - if (!jvmHDir.object.diff(currentJVM, null).isSame()) { - throw new SecurityException("Forbidden JVM modification"); - } - HashedDir currentClient = new HashedDir(params.clientDir, profileMatcher); - if (!clientHDir.object.diff(currentClient, profileMatcher).isSame()) { - throw new SecurityException("Forbidden client modification"); - } + 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, null); + verifyHDir(params.clientDir, clientHDir.object, null); // 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); } @@ -189,6 +192,15 @@ return UUID_PATTERN.matcher(uuid.toString()).replaceAll(""); } + @LauncherAPI + public static void verifyHDir(Path dir, HashedDir hdir, FileNameMatcher matcher) throws IOException { + // Hash directory and compare (ignore update-only matcher entries, it will break offline-mode) + HashedDir currentHDir = new HashedDir(dir, matcher == null ? null : matcher.verifyOnly()); + if (!hdir.diff(currentHDir, null).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; @@ -304,7 +316,8 @@ @LauncherAPI public final int height; @LauncherAPI - public Params(byte[] launcherSign, Path assetDir, Path clientDir, PlayerProfile pp, String accessToken, boolean autoEnter, boolean fullScreen, int ram, int width, int height) { + 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 paths diff --git a/Launcher/source/client/ClientProfile.java b/Launcher/source/client/ClientProfile.java index 6615e06..f35f413 100644 --- a/Launcher/source/client/ClientProfile.java +++ b/Launcher/source/client/ClientProfile.java @@ -21,6 +21,8 @@ @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]); // Version private final StringConfigEntry version; @@ -80,6 +82,11 @@ } @LauncherAPI + public FileNameMatcher getAssetUpdateMatcher() { + return getVersion().compareTo(Version.MC1710) >= 0 ? ASSET_MATCHER : null; + } + + @LauncherAPI public String[] getClassPath() { return classPath.stream(StringConfigEntry.class).toArray(String[]::new); } @@ -125,7 +132,7 @@ } @LauncherAPI - public FileNameMatcher getUpdateMatcher() { + 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); diff --git a/compat/BungeeCord.patch b/compat/BungeeCord.patch index 4625d69..c75adda 100644 --- a/compat/BungeeCord.patch +++ b/compat/BungeeCord.patch @@ -210,6 +210,22 @@ - ctx.pipeline().remove( this ); - } -} +diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java b/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java +index 0f3b5b6..870bf0f 100644 +--- a/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java ++++ b/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java +@@ -29,11 +29,6 @@ public class Varint21FrameDecoder extends ByteToMessageDecoder + if ( buf[i] >= 0 ) + { + int length = DefinedPacket.readVarInt( Unpooled.wrappedBuffer( buf ) ); +- if ( length == 0 ) +- { +- throw new CorruptedFrameException( "Empty Packet!" ); +- } +- + if ( in.readableBytes() < length ) + { + in.resetReaderIndex(); diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyHandshake.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/LegacyHandshake.java deleted file mode 100644 index 50d7381..0000000