From cb7937f5c6a6677d52efed7caef935dc2e397157 Mon Sep 17 00:00:00 2001 From: SoniEx2 Date: Mon, 25 Jul 2022 23:08:13 -0300 Subject: Finish world key machinery API Still need to implement the actual functionality. --- .../friendcode/client/FriendCodeScreen.java | 152 ++++++++++++--------- .../ganarchy/friendcode/client/I2PSamPinger.java | 6 +- .../client/WaitingForFriendCodeScreen.java | 16 ++- .../java/ganarchy/friendcode/util/KeyUtil.java | 19 ++- 4 files changed, 123 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/main/java/ganarchy/friendcode/client/FriendCodeScreen.java b/src/main/java/ganarchy/friendcode/client/FriendCodeScreen.java index 4bd4971..9c96bee 100644 --- a/src/main/java/ganarchy/friendcode/client/FriendCodeScreen.java +++ b/src/main/java/ganarchy/friendcode/client/FriendCodeScreen.java @@ -2,7 +2,8 @@ package ganarchy.friendcode.client; import ganarchy.friendcode.FriendCode; import ganarchy.friendcode.mixin.FriendCodeIntegratedServerExt; -import ganarchy.friendcode.util.KeyUtil;import net.fabricmc.api.EnvType; +import ganarchy.friendcode.util.KeyUtil; +import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.OpenToLanScreen; @@ -15,7 +16,8 @@ import net.minecraft.screen.ScreenTexts; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.MutableText; import net.minecraft.text.Text; -import net.minecraft.util.WorldSavePath;import net.minecraft.world.GameMode; +import net.minecraft.util.WorldSavePath; +import net.minecraft.world.GameMode; import java.io.IOException; @@ -52,57 +54,57 @@ public class FriendCodeScreen extends Screen { // game setting buttons this.addDrawableChild( CyclingButtonWidget - .builder(GameMode::getSimpleTranslatableName) - .values( - GameMode.SURVIVAL, - GameMode.SPECTATOR, - GameMode.CREATIVE, - GameMode.ADVENTURE - ) - .initially(this.gameMode) - .build( - this.width / 2 - 155, - 100, - 150, - 20, - GAME_MODE_TEXT, - (button, gameMode) -> { - this.gameMode = gameMode; - } - ) + .builder(GameMode::getSimpleTranslatableName) + .values( + GameMode.SURVIVAL, + GameMode.SPECTATOR, + GameMode.CREATIVE, + GameMode.ADVENTURE + ) + .initially(this.gameMode) + .build( + this.width / 2 - 155, + 100, + 150, + 20, + GAME_MODE_TEXT, + (button, gameMode) -> { + this.gameMode = gameMode; + } + ) ); this.addDrawableChild( CyclingButtonWidget - .onOffBuilder(this.allowCommands) - .build( - this.width / 2 + 5, - 100, - 150, - 20, - ALLOW_COMMANDS_TEXT, - (button, allowCommands) -> { - this.allowCommands = allowCommands; - } - ) + .onOffBuilder(this.allowCommands) + .build( + this.width / 2 + 5, + 100, + 150, + 20, + ALLOW_COMMANDS_TEXT, + (button, allowCommands) -> { + this.allowCommands = allowCommands; + } + ) ); // friend code type button this.addDrawableChild( CyclingButtonWidget - .builder(CodeType::getSimpleTranslatableName) - .values(CodeType.SESSION, CodeType.WORLD) - .initially(this.codeType) - .build( - this.width / 2 - 155, - 125, - 310, - 20, - CODE_TYPE_TEXT, - (button, codeType) -> { - this.codeType = codeType; - } - ) - ).active = false; + .builder(CodeType::getSimpleTranslatableName) + .values(CodeType.SESSION, CodeType.WORLD) + .initially(this.codeType) + .build( + this.width / 2 - 155, + 125, + 310, + 20, + CODE_TYPE_TEXT, + (button, codeType) -> { + this.codeType = codeType; + } + ) + ); // start sharing this.addDrawableChild(new ButtonWidget( @@ -112,13 +114,22 @@ public class FriendCodeScreen extends Screen { 20, START_SHARING, button -> { - // FIXME int i = NetworkUtils.findLocalPort(); - var samPinger = openToFriends(this.client, this.codeType, this.gameMode, this.allowCommands, i); - MutableText text = samPinger != null ? Text.translatable("commands.publish.started", i) : Text.translatable("commands.publish.failed"); + var samPinger = openToFriends( + this.client, this.codeType, this.gameMode, + this.allowCommands, i + ); + MutableText text; + if (samPinger != null) { + text = Text.translatable("commands.publish.started", i); + } else { + text = Text.translatable("commands.publish.failed"); + } this.client.inGameHud.getChatHud().addMessage(text); this.client.updateWindowTitle(); - this.client.setScreen(new WaitingForFriendCodeScreen(samPinger)); + this.client.setScreen(new WaitingForFriendCodeScreen( + this.codeType, samPinger + )); } )); @@ -133,41 +144,52 @@ public class FriendCodeScreen extends Screen { )); } - private static I2PSamPinger openToFriends(MinecraftClient client, CodeType codeType, GameMode gameMode, boolean allowCommands, int port) { + private static I2PSamPinger openToFriends( + MinecraftClient client, CodeType codeType, GameMode gameMode, + boolean allowCommands, int port + ) { try { + var server = client.getServer(); String privateKey = null; if (codeType == CodeType.WORLD) { - // FIXME this currently does nothing. - var worldDir = client.getServer().submit(() -> client.getServer().getSavePath(WorldSavePath.ROOT)).join(); + var worldDir = server.submit(() -> { + return server.getSavePath(WorldSavePath.ROOT); + }).join(); var keyFile = worldDir.resolve("friendcode.key"); privateKey = KeyUtil.readKeyFile(keyFile); } client.loadBlockList(); - client.getServer().getNetworkIo().bind(null, port); + server.getNetworkIo().bind(null, port); FriendCode.LOGGER.info("Started serving on {}", port); - ((FriendCodeIntegratedServerExt) client.getServer()).lanPort(port); + ((FriendCodeIntegratedServerExt) server).lanPort(port); // reuse LAN pinger machinery instead of rolling our own - var lanPinger = new I2PSamPinger(client.getServer().getServerMotd(), "" + port, privateKey); - ((FriendCodeIntegratedServerExt) client.getServer()).lanPinger(lanPinger); + var lanPinger = new I2PSamPinger( + server.getServerMotd(), "" + port, privateKey + ); + ((FriendCodeIntegratedServerExt) server).lanPinger(lanPinger); lanPinger.start(); - ((FriendCodeIntegratedServerExt) client.getServer()).forcedGameMode(gameMode); - client.getServer().getPlayerManager().setCheatsAllowed(allowCommands); - int i = client.getServer().getPermissionLevel(client.player.getGameProfile()); + ((FriendCodeIntegratedServerExt) server).forcedGameMode(gameMode); + server.getPlayerManager().setCheatsAllowed(allowCommands); + int i = server.getPermissionLevel(client.player.getGameProfile()); client.player.setClientPermissionLevel(i); - for (ServerPlayerEntity serverPlayerEntity : client.getServer().getPlayerManager().getPlayerList()) { - client.getServer().getCommandManager().sendCommandTree(serverPlayerEntity); + for (var player : server.getPlayerManager().getPlayerList()) { + server.getCommandManager().sendCommandTree(player); } return lanPinger; - } - catch (IOException iOException) { + } catch (IOException iOException) { return null; } } @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { + public void render( + MatrixStack matrices, int mouseX, int mouseY, float delta + ) { this.renderBackground(matrices); - FriendCodeScreen.drawCenteredText(matrices, this.textRenderer, OTHER_PLAYERS_TEXT, this.width / 2, 82, 0xFFFFFF); + FriendCodeScreen.drawCenteredText( + matrices, this.textRenderer, OTHER_PLAYERS_TEXT, + this.width / 2, 82, 0xFFFFFF + ); super.render(matrices, mouseX, mouseY, delta); } } diff --git a/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java b/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java index e0824b9..9bc46e2 100644 --- a/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java +++ b/src/main/java/ganarchy/friendcode/client/I2PSamPinger.java @@ -95,7 +95,7 @@ public class I2PSamPinger extends LanServerPinger implements LanSendPing { return this.status; } - public String pubkey() { + public String publicKey() { return this.sam.publicKey(); } @@ -103,6 +103,10 @@ public class I2PSamPinger extends LanServerPinger implements LanSendPing { this.stopSam = true; } + public String privateKey() { + return this.sam.privateKey(); + } + public enum Status { IDLE, RUNNING, diff --git a/src/main/java/ganarchy/friendcode/client/WaitingForFriendCodeScreen.java b/src/main/java/ganarchy/friendcode/client/WaitingForFriendCodeScreen.java index 8429a41..79c12f7 100644 --- a/src/main/java/ganarchy/friendcode/client/WaitingForFriendCodeScreen.java +++ b/src/main/java/ganarchy/friendcode/client/WaitingForFriendCodeScreen.java @@ -1,5 +1,7 @@ package ganarchy.friendcode.client; +import ganarchy.friendcode.FriendCode; +import ganarchy.friendcode.util.KeyUtil; import net.minecraft.client.gui.screen.LoadingDisplay; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; @@ -8,6 +10,7 @@ import net.minecraft.screen.ScreenTexts; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Util; +import net.minecraft.util.WorldSavePath; import org.apache.commons.codec.binary.Base32; import java.nio.charset.StandardCharsets; @@ -18,9 +21,11 @@ import java.util.Locale; public class WaitingForFriendCodeScreen extends Screen { private final I2PSamPinger samPinger; + private final CodeType codeType; - public WaitingForFriendCodeScreen(I2PSamPinger samPinger) { + public WaitingForFriendCodeScreen(CodeType codeType, I2PSamPinger samPinger) { super(Text.translatable("friendcode.opening")); + this.codeType = codeType; this.samPinger = samPinger; } @@ -71,8 +76,15 @@ public class WaitingForFriendCodeScreen extends Screen { break; } case RUNNING -> { + if (codeType == CodeType.WORLD) { + var worldDir = client.getServer().submit(() -> client.getServer().getSavePath(WorldSavePath.ROOT)).join(); + var keyFile = worldDir.resolve("friendcode.key"); + if (!KeyUtil.writeKeyFile(keyFile, samPinger.privateKey())) { + FriendCode.LOGGER.error("Couldn't save world code. It will be regenerated next time."); + } + } // convert from I2P base64 to URL-safe base64 so we don't have to write our own Base64 decoder - final String pubkey_b64 = samPinger.pubkey().replace('~', '_'); + final String pubkey_b64 = samPinger.publicKey().replace('~', '_'); final byte[] pubkey = Base64.getUrlDecoder().decode(pubkey_b64.getBytes(StandardCharsets.UTF_8)); // a .b32.i2p is just a Base32-encoded SHA256 final String b32; diff --git a/src/main/java/ganarchy/friendcode/util/KeyUtil.java b/src/main/java/ganarchy/friendcode/util/KeyUtil.java index e8e07e5..ab5d614 100644 --- a/src/main/java/ganarchy/friendcode/util/KeyUtil.java +++ b/src/main/java/ganarchy/friendcode/util/KeyUtil.java @@ -3,12 +3,27 @@ package ganarchy.friendcode.util; import java.nio.file.Path; /** -* Helper to deal with private keys. -*/ + * Helper to deal with private keys. + */ public class KeyUtil { + /** + * Reads and decrypts a private key file. + * + * @param keyFile The path to the key file. + * @return The decrypted private key, or null if it doesn't exist. + */ public static String readKeyFile(Path keyFile) { return null; } + + + /** + * Encrypts and writes a private key file. + * + * @param keyFile The path to the key file. + * @param key The private key. + * @return Whether writing the key succeeded. + */ public static boolean writeKeyFile(Path keyFile, String key) { return false; } -- cgit 1.4.1