From 0c8505293d92034b5eac7a03644ff45a56a2aa22 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Sat, 17 Oct 2020 21:18:48 +0200 Subject: [PATCH 01/18] Increasing shutdown time limit --- src/main/java/org/samo_lego/simpleauth/SimpleAuth.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java index 072adb6..37a0e2f 100644 --- a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java +++ b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java @@ -131,7 +131,7 @@ public class SimpleAuth implements DedicatedServerModInitializer { // Closing threads try { THREADPOOL.shutdownNow(); - if (!THREADPOOL.awaitTermination(100, TimeUnit.MICROSECONDS)) { + if (!THREADPOOL.awaitTermination(500, TimeUnit.MILLISECONDS)) { Thread.currentThread().interrupt(); } } catch (InterruptedException e) { From c0111895729922ed4d3d624d81e91603d9fefd17 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Sat, 17 Oct 2020 22:00:36 +0200 Subject: [PATCH 02/18] Removing stdout --- .../java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java index 674c9a3..9553c4d 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java @@ -50,7 +50,6 @@ public abstract class MixinPlayerEntity implements PlayerAuth { assert server != null; PlayerCache cache = playerCacheMap.get(this.getFakeUuid()); - System.out.println("Teleporting Player. hide:" + hide); if (hide) { // Saving position cache.lastLocation.dimension = player.getServerWorld(); From e92fc4c9a83655d4d7ffd7baa85dd91bc1969c7d Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Mon, 19 Oct 2020 09:19:41 +0200 Subject: [PATCH 03/18] Version bump --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index a678e85..aadbdf6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ loader_version=0.9.3+build.207 fabric_version=0.20.2+build.402-1.16 # Mod Properties -mod_version = 1.6.0 +mod_version = 1.6.1 maven_group = org.samo_lego archives_base_name = simpleauth From 82537de884322afe64c6242e2aac00652876902c Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Wed, 21 Oct 2020 20:47:04 +0200 Subject: [PATCH 04/18] Implementing #23 --- .../org/samo_lego/simpleauth/SimpleAuth.java | 21 +++- .../simpleauth/mixin/MixinPlayerEntity.java | 29 ++++- .../mixin/MixinServerLoginNetworkHandler.java | 108 ++++++++++++++++++ .../simpleauth/storage/AuthConfig.java | 11 ++ .../simpleauth/utils/PlayerAuth.java | 6 + src/main/resources/mixins.simpleauth.json | 1 + 6 files changed, 164 insertions(+), 12 deletions(-) create mode 100644 src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java diff --git a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java index 37a0e2f..e77ad29 100644 --- a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java +++ b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java @@ -22,6 +22,7 @@ import java.io.FileReader; import java.io.IOException; import java.nio.file.Path; import java.util.HashMap; +import java.util.HashSet; import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -46,6 +47,14 @@ public class SimpleAuth implements DedicatedServerModInitializer { */ public static HashMap playerCacheMap = new HashMap<>(); + /** + * HashSet of player names that have Mojang accounts. + * If player is saved in here, they will be treated as online-mode ones. + */ + public static HashSet mojangAccountNamesCache = new HashSet<>(); + + public static HashSet accountStatusCache = new HashSet<>(); + // Getting game directory public static final Path gameDirectory = FabricLoader.getInstance().getGameDir(); @@ -62,6 +71,12 @@ public class SimpleAuth implements DedicatedServerModInitializer { // The support on discord was great! I really appreciate your help. logInfo("This mod wouldn't exist without the awesome Fabric Community. TYSM guys!"); + try { + serverProp.load(new FileReader(gameDirectory + "/server.properties")); + } catch (IOException e) { + logError("Error while reading server properties: " + e.getMessage()); + } + // Creating data directory (database and config files are stored there) File file = new File(gameDirectory + "/mods/SimpleAuth/leveldbStore"); if (!file.exists() && !file.mkdirs()) @@ -71,12 +86,6 @@ public class SimpleAuth implements DedicatedServerModInitializer { // Connecting to db DB.openConnection(); - try { - serverProp.load(new FileReader(gameDirectory + "/server.properties")); - } catch (IOException e) { - logError("Error while reading server properties: " + e.getMessage()); - } - // Registering the commands CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> { diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java index 9553c4d..2b46435 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java @@ -1,5 +1,6 @@ package org.samo_lego.simpleauth.mixin; +import com.mojang.authlib.GameProfile; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket; @@ -17,7 +18,9 @@ import org.samo_lego.simpleauth.SimpleAuth; import org.samo_lego.simpleauth.event.item.DropItemCallback; import org.samo_lego.simpleauth.storage.PlayerCache; import org.samo_lego.simpleauth.utils.PlayerAuth; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -26,10 +29,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import static org.samo_lego.simpleauth.SimpleAuth.config; import static org.samo_lego.simpleauth.SimpleAuth.playerCacheMap; import static org.samo_lego.simpleauth.utils.CarpetHelper.isPlayerCarpetFake; +import static org.samo_lego.simpleauth.utils.SimpleLogger.logInfo; @Mixin(PlayerEntity.class) public abstract class MixinPlayerEntity implements PlayerAuth { + @Shadow @Final private GameProfile gameProfile; private final ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; // * 20 for 20 ticks in second @@ -50,6 +55,8 @@ public abstract class MixinPlayerEntity implements PlayerAuth { assert server != null; PlayerCache cache = playerCacheMap.get(this.getFakeUuid()); + if(config.main.spawnOnJoin) + logInfo("Teleporting " + player.getName().asString() + (hide ? " to spawn." : " to original position.")); if (hide) { // Saving position cache.lastLocation.dimension = player.getServerWorld(); @@ -90,14 +97,15 @@ public abstract class MixinPlayerEntity implements PlayerAuth { public String getFakeUuid() { // If server is in online mode online-mode UUIDs should be used assert server != null; - if(server.isOnlineMode()) + if(server.isOnlineMode() && this.isUsingMojangAccount()) return player.getUuidAsString(); /* Lower case is used for Player and PlAyEr to get same UUID (for password storing) Mimicking Mojang behaviour, where players cannot set their name to ExAmple if Example is already taken. */ - String playername = player.getName().asString().toLowerCase(); + // Getting player+s name via GameProfile, in order to be compatible with Drogtor mod + String playername = player.getGameProfile().getName().toLowerCase(); return PlayerEntity.getOfflinePlayerUuid(playername).toString(); } @@ -172,14 +180,23 @@ public abstract class MixinPlayerEntity implements PlayerAuth { } /** - * Checks whether player is a fake player (from CarpetMod). + * Checks whether player can skip authentication process. * - * @return true if player is fake (can skip authentication process), otherwise false + * @return true if can skip authentication process, otherwise false */ @Override public boolean canSkipAuth() { // We ask CarpetHelper class since it has the imports needed - return this.isRunningCarpet && isPlayerCarpetFake(this.player); + return (this.isRunningCarpet && isPlayerCarpetFake(this.player)) || (isUsingMojangAccount() && config.experimental.premiumAutologin); + } + + /** + * Whether the player is using the mojang account. + * @return true if paid, otherwise false + */ + @Override + public boolean isUsingMojangAccount() { + return !gameProfile.getId().equals(PlayerEntity.getOfflinePlayerUuid(gameProfile.getName())); } /** @@ -190,7 +207,7 @@ public abstract class MixinPlayerEntity implements PlayerAuth { @Override public boolean isAuthenticated() { String uuid = ((PlayerAuth) player).getFakeUuid(); - return playerCacheMap.containsKey(uuid) && playerCacheMap.get(uuid).isAuthenticated; + return this.canSkipAuth() || (playerCacheMap.containsKey(uuid) && playerCacheMap.get(uuid).isAuthenticated); } @Inject(method = "tick()V", at = @At("HEAD"), cancellable = true) diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java new file mode 100644 index 0000000..0d183c2 --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java @@ -0,0 +1,108 @@ +package org.samo_lego.simpleauth.mixin; + +import com.mojang.authlib.GameProfile; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.packet.c2s.login.LoginHelloC2SPacket; +import net.minecraft.server.network.ServerLoginNetworkHandler; +import net.minecraft.text.TranslatableText; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import javax.net.ssl.HttpsURLConnection; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; + +import static org.samo_lego.simpleauth.SimpleAuth.*; +import static org.samo_lego.simpleauth.utils.SimpleLogger.logError; + +@Mixin(ServerLoginNetworkHandler.class) +public class MixinServerLoginNetworkHandler { + + @Shadow + private GameProfile profile; + @Shadow + private int loginTicks; + + /** + * Fake state of current player. + */ + private boolean acceptCrackedPlayer = false; + + /** + * Mimicks the ticking if autologin is enabled. + * @param ci + */ + @Inject(method = "tick()V", at = @At("HEAD"), cancellable = true) + private void preTick(CallbackInfo ci) { + if (this.acceptCrackedPlayer && config.experimental.premiumAutologin) { + ((ServerLoginNetworkHandler) (Object) this).acceptPlayer(); + + if (this.loginTicks++ == 600) + ((ServerLoginNetworkHandler) (Object) this).disconnect(new TranslatableText("multiplayer.disconnect.slow_login")); + ci.cancel(); + } + } + + /** + * Checks whether the player has purchased an account. + * If so, server is presented as online, and continues as in normal-online mode. + * Otherwise, player is marked as ready to be accepted into the game. + * @param packet + * @param ci + */ + @Inject( + method = "onHello(Lnet/minecraft/network/packet/c2s/login/LoginHelloC2SPacket;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/network/packet/c2s/login/LoginHelloC2SPacket;getProfile()Lcom/mojang/authlib/GameProfile;", + shift = At.Shift.AFTER + ), + cancellable = true + ) + private void checkPremium(LoginHelloC2SPacket packet, CallbackInfo ci) { + if(config.experimental.premiumAutologin) { + try { + String playername = packet.getProfile().getName().toLowerCase(); + if(playerCacheMap.containsKey(PlayerEntity.getOfflinePlayerUuid(playername).toString())) { + // Player definitely doesn't have a mojang account + this.acceptCrackedPlayer = true; + + this.profile = packet.getProfile(); + ci.cancel(); + } + else if(!mojangAccountNamesCache.contains(playername)) { + // Checking account status from API + HttpsURLConnection httpsURLConnection = (HttpsURLConnection) new URL("https://api.mojang.com/users/profiles/minecraft/" + playername).openConnection(); + httpsURLConnection.setRequestMethod("GET"); + httpsURLConnection.setConnectTimeout(5000); + httpsURLConnection.setReadTimeout(5000); + + int response = httpsURLConnection.getResponseCode(); + if (response == HttpURLConnection.HTTP_OK) { + // Player has a Mojang account + httpsURLConnection.disconnect(); + + + // Caches the request + mojangAccountNamesCache.add(playername); + // Authentication continues in original method + } + else if(response == HttpURLConnection.HTTP_NO_CONTENT) { + // Player doesn't have a Mojang account + httpsURLConnection.disconnect(); + this.acceptCrackedPlayer = true; + + this.profile = packet.getProfile(); + ci.cancel(); + } + } + } catch (IOException e) { + logError(e.getMessage()); + } + } + } +} diff --git a/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java b/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java index 7b58941..34af65a 100644 --- a/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java +++ b/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java @@ -23,6 +23,7 @@ import com.google.gson.GsonBuilder; import java.io.*; import java.nio.charset.StandardCharsets; +import static org.samo_lego.simpleauth.SimpleAuth.serverProp; import static org.samo_lego.simpleauth.utils.SimpleLogger.logError; public class AuthConfig { @@ -191,6 +192,12 @@ public class AuthConfig { * @see wiki */ public boolean useBCryptLibrary = false; + /** + * Whether players who have a valid session should skip the authentication process. + * You have to set online-mode to true in server.properties! + * (cracked players will still be able to enter, but they'll need to login) + */ + public boolean premiumAutologin = false; } public MainConfig main = new MainConfig(); @@ -212,6 +219,10 @@ public class AuthConfig { new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8) )) { config = gson.fromJson(fileReader, AuthConfig.class); + if(config.experimental.premiumAutologin && !Boolean.parseBoolean(serverProp.getProperty("online-mode"))) { + logError("You cannot use server in offline mode and premiumAutologin! Disabling the latter."); + config.experimental.premiumAutologin = false; + } } catch (IOException e) { throw new RuntimeException("[SimpleAuth] Problem occurred when trying to load config: ", e); } diff --git a/src/main/java/org/samo_lego/simpleauth/utils/PlayerAuth.java b/src/main/java/org/samo_lego/simpleauth/utils/PlayerAuth.java index 6aebecc..35abc37 100644 --- a/src/main/java/org/samo_lego/simpleauth/utils/PlayerAuth.java +++ b/src/main/java/org/samo_lego/simpleauth/utils/PlayerAuth.java @@ -58,4 +58,10 @@ public interface PlayerAuth { * @see See implementation */ boolean canSkipAuth(); + + /** + * Whether the player is using the mojang account + * @return true if paid, false if cracked + */ + boolean isUsingMojangAccount(); } diff --git a/src/main/resources/mixins.simpleauth.json b/src/main/resources/mixins.simpleauth.json index 4da9d2d..c069d4a 100644 --- a/src/main/resources/mixins.simpleauth.json +++ b/src/main/resources/mixins.simpleauth.json @@ -6,6 +6,7 @@ "server": [ "MixinPlayerEntity", "MixinPlayerManager", + "MixinServerLoginNetworkHandler", "MixinServerPlayNetworkHandler", "MixinSlot" ], From d6d369c9527d5005fafba3196d14aeed045ed663 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Wed, 21 Oct 2020 20:59:22 +0200 Subject: [PATCH 05/18] Version bump --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index aadbdf6..5a9566b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ loader_version=0.9.3+build.207 fabric_version=0.20.2+build.402-1.16 # Mod Properties -mod_version = 1.6.1 +mod_version = 1.6.2 maven_group = org.samo_lego archives_base_name = simpleauth From 4247fad3c03acbba7d3d34d0827747f5eb240365 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Sun, 25 Oct 2020 22:37:42 +0100 Subject: [PATCH 06/18] Auto-migrate player data (#23) --- gradle.properties | 2 +- .../org/samo_lego/simpleauth/SimpleAuth.java | 6 +- .../mixin/MixinServerLoginNetworkHandler.java | 2 + .../mixin/MixinWorldSaveHandler.java | 88 +++++++++++++++++++ src/main/resources/mixins.simpleauth.json | 3 +- 5 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java diff --git a/gradle.properties b/gradle.properties index 5a9566b..23dc3e8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ loader_version=0.9.3+build.207 fabric_version=0.20.2+build.402-1.16 # Mod Properties -mod_version = 1.6.2 +mod_version = 1.6.3 maven_group = org.samo_lego archives_base_name = simpleauth diff --git a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java index e77ad29..66e08a7 100644 --- a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java +++ b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java @@ -53,15 +53,15 @@ public class SimpleAuth implements DedicatedServerModInitializer { */ public static HashSet mojangAccountNamesCache = new HashSet<>(); - public static HashSet accountStatusCache = new HashSet<>(); - // Getting game directory public static final Path gameDirectory = FabricLoader.getInstance().getGameDir(); // Server properties public static Properties serverProp = new Properties(); - // Mod config + /** + * Config of the SimpleAuth mod. + */ public static AuthConfig config; @Override diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java index 0d183c2..7e33ad7 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java @@ -7,6 +7,7 @@ import net.minecraft.server.network.ServerLoginNetworkHandler; import net.minecraft.text.TranslatableText; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -30,6 +31,7 @@ public class MixinServerLoginNetworkHandler { /** * Fake state of current player. */ + @Unique private boolean acceptCrackedPlayer = false; /** diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java new file mode 100644 index 0000000..ff5a83c --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java @@ -0,0 +1,88 @@ +package org.samo_lego.simpleauth.mixin; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.world.WorldSaveHandler; +import org.apache.logging.log4j.Logger; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +import static org.samo_lego.simpleauth.SimpleAuth.config; +import static org.samo_lego.simpleauth.SimpleAuth.mojangAccountNamesCache; + +@Mixin(WorldSaveHandler.class) +public class MixinWorldSaveHandler { + + @Final + @Shadow + private File playerDataDir; + + @Unique + private boolean fileExists; + + @Final + @Shadow + private static Logger LOGGER; + + /** + * Saves whether player save file exists. + * + * @param playerEntity + * @param cir + * @param compoundTag + * @param file + */ + @Inject( + method = "loadPlayerData(Lnet/minecraft/entity/player/PlayerEntity;)Lnet/minecraft/nbt/CompoundTag;", + at = @At( + value = "INVOKE", + target = "Ljava/io/File;exists()Z" + ), + locals = LocalCapture.CAPTURE_FAILHARD + ) + private void fileExists(PlayerEntity playerEntity, CallbackInfoReturnable cir, CompoundTag compoundTag, File file) { + // @ModifyVariable cannot capture locals + this.fileExists = file.exists(); + } + + /** + * Loads offline-uuid player data to compoundTag in order to migrate from offline to online. + * + * @param compoundTag null compound tag. + * @param player player who might need migration of datd. + * @return compoundTag containing migrated data. + */ + @ModifyVariable( + method = "loadPlayerData(Lnet/minecraft/entity/player/PlayerEntity;)Lnet/minecraft/nbt/CompoundTag;", + at = @At( + value = "INVOKE", + target = "Ljava/io/File;exists()Z" + ) + ) + private CompoundTag migratePlayerData(CompoundTag compoundTag, PlayerEntity player) { + // Checking for offline player data only if online doesn't exist yet + if(config.experimental.premiumAutologin && mojangAccountNamesCache.contains(player.getGameProfile().getName()) && !this.fileExists) { + File file = new File(this.playerDataDir, PlayerEntity.getOfflinePlayerUuid(player.getGameProfile().getName()) + ".dat"); + if (file.exists() && file.isFile()) + try { + compoundTag = NbtIo.readCompressed(new FileInputStream(file)); + } + catch (IOException e) { + LOGGER.warn("Failed to load player data for {}", player.getGameProfile().getName()); + } + } + return compoundTag; + } +} diff --git a/src/main/resources/mixins.simpleauth.json b/src/main/resources/mixins.simpleauth.json index c069d4a..0539766 100644 --- a/src/main/resources/mixins.simpleauth.json +++ b/src/main/resources/mixins.simpleauth.json @@ -8,7 +8,8 @@ "MixinPlayerManager", "MixinServerLoginNetworkHandler", "MixinServerPlayNetworkHandler", - "MixinSlot" + "MixinSlot", + "MixinWorldSaveHandler" ], "injectors": { "defaultRequire": 1 From b297ae6cbe257216abba53b73828f27aab7632bf Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Thu, 29 Oct 2020 13:02:50 +0100 Subject: [PATCH 07/18] Code cleanup --- .../simpleauth/commands/LogoutCommand.java | 9 +- .../simpleauth/event/AuthEventHandler.java | 26 +- .../simpleauth/mixin/MixinPlayerEntity.java | 224 +----------------- .../mixin/MixinServerPlayerEntity.java | 216 +++++++++++++++++ .../simpleauth/storage/AuthConfig.java | 8 +- .../simpleauth/storage/PlayerCache.java | 43 +--- src/main/resources/mixins.simpleauth.json | 1 + 7 files changed, 235 insertions(+), 292 deletions(-) create mode 100644 src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayerEntity.java diff --git a/src/main/java/org/samo_lego/simpleauth/commands/LogoutCommand.java b/src/main/java/org/samo_lego/simpleauth/commands/LogoutCommand.java index 4266829..7e975f9 100644 --- a/src/main/java/org/samo_lego/simpleauth/commands/LogoutCommand.java +++ b/src/main/java/org/samo_lego/simpleauth/commands/LogoutCommand.java @@ -9,6 +9,7 @@ import org.samo_lego.simpleauth.utils.PlayerAuth; import static net.minecraft.server.command.CommandManager.literal; import static org.samo_lego.simpleauth.SimpleAuth.config; +import static org.samo_lego.simpleauth.SimpleAuth.mojangAccountNamesCache; public class LogoutCommand { @@ -22,8 +23,12 @@ public class LogoutCommand { private static int logout(ServerCommandSource serverCommandSource) throws CommandSyntaxException { ServerPlayerEntity player = serverCommandSource.getPlayer(); - ((PlayerAuth) player).setAuthenticated(false); - player.sendMessage(new LiteralText(config.lang.successfulLogout), false); + if(mojangAccountNamesCache.contains(player.getGameProfile().getName().toLowerCase())) { + ((PlayerAuth) player).setAuthenticated(false); + player.sendMessage(new LiteralText(config.lang.successfulLogout), false); + } + else + player.sendMessage(new LiteralText(config.lang.cannotLogout), false); return 1; } } diff --git a/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java b/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java index a20be4e..580999f 100644 --- a/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java +++ b/src/main/java/org/samo_lego/simpleauth/event/AuthEventHandler.java @@ -63,7 +63,6 @@ public class AuthEventHandler { // Player joining the server public static void onPlayerJoin(ServerPlayerEntity player) { - // If player is fake auth is not needed if (((PlayerAuth) player).canSkipAuth()) return; // Checking if session is still valid @@ -76,22 +75,12 @@ public class AuthEventHandler { playerCache.validUntil >= System.currentTimeMillis() && player.getIp().equals(playerCache.lastIp) ) { + // Valid session ((PlayerAuth) player).setAuthenticated(true); return; } - player.setInvulnerable(config.experimental.playerInvulnerable); - player.setInvisible(config.experimental.playerInvisible); - - // Invalidating session - playerCache.isAuthenticated = false; - if(config.main.spawnOnJoin) - ((PlayerAuth) player).hidePosition(true); - } - else { - ((PlayerAuth) player).setAuthenticated(false); - playerCache = playerCacheMap.get(uuid); - playerCache.wasOnFire = false; } + ((PlayerAuth) player).setAuthenticated(false); // Tries to rescue player from nether portal @@ -116,10 +105,8 @@ public class AuthEventHandler { String uuid = ((PlayerAuth) player).getFakeUuid(); PlayerCache playerCache = playerCacheMap.get(uuid); - if(((PlayerAuth) player).isAuthenticated()) { + if(playerCache.isAuthenticated) { playerCache.lastIp = player.getIp(); - playerCache.lastAir = player.getAir(); - playerCache.wasOnFire = player.isOnFire(); playerCache.wasInPortal = player.getBlockState().getBlock().equals(Blocks.NETHER_PORTAL); // Setting the session expire time @@ -151,13 +138,8 @@ public class AuthEventHandler { public static ActionResult onPlayerMove(PlayerEntity player) { // Player will fall if enabled (prevent fly kick) boolean auth = ((PlayerAuth) player).isAuthenticated(); - if(!auth && config.main.allowFalling && !player.isOnGround() && !player.isInsideWaterOrBubbleColumn()) { - if(player.isInvulnerable()) - player.setInvulnerable(false); - return ActionResult.PASS; - } // Otherwise movement should be disabled - else if(!auth && !config.experimental.allowMovement) { + if(!auth && !config.experimental.allowMovement) { if(!player.isInvulnerable()) player.setInvulnerable(true); return ActionResult.FAIL; diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java index 2b46435..73655f2 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerEntity.java @@ -1,231 +1,17 @@ package org.samo_lego.simpleauth.mixin; -import com.mojang.authlib.GameProfile; -import net.fabricmc.loader.api.FabricLoader; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; -import net.minecraft.text.Text; import net.minecraft.util.ActionResult; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.RegistryKey; -import net.minecraft.world.World; -import org.samo_lego.simpleauth.SimpleAuth; import org.samo_lego.simpleauth.event.item.DropItemCallback; -import org.samo_lego.simpleauth.storage.PlayerCache; -import org.samo_lego.simpleauth.utils.PlayerAuth; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import static org.samo_lego.simpleauth.SimpleAuth.config; -import static org.samo_lego.simpleauth.SimpleAuth.playerCacheMap; -import static org.samo_lego.simpleauth.utils.CarpetHelper.isPlayerCarpetFake; -import static org.samo_lego.simpleauth.utils.SimpleLogger.logInfo; - @Mixin(PlayerEntity.class) -public abstract class MixinPlayerEntity implements PlayerAuth { +public class MixinPlayerEntity { - @Shadow @Final private GameProfile gameProfile; - private final ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; - - // * 20 for 20 ticks in second - private int kickTimer = config.main.kickTime * 20; - - private final boolean isRunningCarpet = FabricLoader.getInstance().isModLoaded("carpet"); - - private final MinecraftServer server = player.getServer(); - - /** - * Teleports player to spawn or last location that is recorded. - * Last location means the location before de-authentication. - * - * @param hide whether to teleport player to spawn (provided in config) or last recorded position - */ - @Override - public void hidePosition(boolean hide) { - assert server != null; - - PlayerCache cache = playerCacheMap.get(this.getFakeUuid()); - if(config.main.spawnOnJoin) - logInfo("Teleporting " + player.getName().asString() + (hide ? " to spawn." : " to original position.")); - if (hide) { - // Saving position - cache.lastLocation.dimension = player.getServerWorld(); - cache.lastLocation.position = player.getPos(); - cache.lastLocation.yaw = player.yaw; - cache.lastLocation.pitch = player.pitch; - - // Teleports player to spawn - player.teleport( - server.getWorld(RegistryKey.of(Registry.DIMENSION, new Identifier(config.worldSpawn.dimension))), - config.worldSpawn.x, - config.worldSpawn.y, - config.worldSpawn.z, - config.worldSpawn.yaw, - config.worldSpawn.pitch - ); - return; - } - // Puts player to last cached position - player.teleport( - cache.lastLocation.dimension, - cache.lastLocation.position.getX(), - cache.lastLocation.position.getY(), - cache.lastLocation.position.getZ(), - cache.lastLocation.yaw, - cache.lastLocation.pitch - ); - } - - /** - * Converts player uuid, to ensure player with "nAmE" and "NamE" get same uuid. - * Both players are not allowed to play, since mod mimics Mojang behaviour. - * of not allowing accounts with same names but different capitalization. - * - * @return converted UUID as string - */ - @Override - public String getFakeUuid() { - // If server is in online mode online-mode UUIDs should be used - assert server != null; - if(server.isOnlineMode() && this.isUsingMojangAccount()) - return player.getUuidAsString(); - /* - Lower case is used for Player and PlAyEr to get same UUID (for password storing) - Mimicking Mojang behaviour, where players cannot set their name to - ExAmple if Example is already taken. - */ - // Getting player+s name via GameProfile, in order to be compatible with Drogtor mod - String playername = player.getGameProfile().getName().toLowerCase(); - return PlayerEntity.getOfflinePlayerUuid(playername).toString(); - - } - - /** - * Sets the authentication status of the player. - * - * @param authenticated whether player should be authenticated - */ - @Override - public void setAuthenticated(boolean authenticated) { - PlayerCache playerCache; - - if(!playerCacheMap.containsKey(this.getFakeUuid())) { - // First join - playerCache = new PlayerCache(this.getFakeUuid(), player); - playerCacheMap.put(this.getFakeUuid(), playerCache); - } - else { - playerCache = playerCacheMap.get(this.getFakeUuid()); - if(this.isAuthenticated() == authenticated) - return; - playerCache.isAuthenticated = authenticated; - } - - player.setInvulnerable(!authenticated && config.experimental.playerInvulnerable); - player.setInvisible(!authenticated && config.experimental.playerInvisible); - - // Teleporting player (hiding / restoring position) - if(config.main.spawnOnJoin) - this.hidePosition(!authenticated); - - if(authenticated) { - kickTimer = config.main.kickTime * 20; - // Updating blocks if needed (if portal rescue action happened) - if(playerCache.wasInPortal) { - World world = player.getEntityWorld(); - BlockPos pos = player.getBlockPos(); - - // Sending updates to portal blocks - // This is technically not needed, but it cleans the "messed portal" on the client - world.updateListeners(pos, world.getBlockState(pos), world.getBlockState(pos), 3); - world.updateListeners(pos.up(), world.getBlockState(pos.up()), world.getBlockState(pos.up()), 3); - } - - // Setting last air to player - if(player.isSubmergedInWater()) - player.setAir(playerCache.lastAir); - - // In case player is in lava during authentication proccess - if(!playerCache.wasOnFire) - player.setFireTicks(0); - } - } - - /** - * Gets the text which tells the player - * to login or register, depending on account status. - * - * @return LiteralText with appropriate string (login or register) - */ - @Override - public Text getAuthMessage() { - final PlayerCache cache = playerCacheMap.get(((PlayerAuth) player).getFakeUuid()); - if(SimpleAuth.config.main.enableGlobalPassword || cache.isRegistered) - return new LiteralText( - SimpleAuth.config.lang.notAuthenticated + "\n" + SimpleAuth.config.lang.loginRequired - ); - return new LiteralText( - SimpleAuth.config.lang.notAuthenticated+ "\n" + SimpleAuth.config.lang.registerRequired - ); - } - - /** - * Checks whether player can skip authentication process. - * - * @return true if can skip authentication process, otherwise false - */ - @Override - public boolean canSkipAuth() { - // We ask CarpetHelper class since it has the imports needed - return (this.isRunningCarpet && isPlayerCarpetFake(this.player)) || (isUsingMojangAccount() && config.experimental.premiumAutologin); - } - - /** - * Whether the player is using the mojang account. - * @return true if paid, otherwise false - */ - @Override - public boolean isUsingMojangAccount() { - return !gameProfile.getId().equals(PlayerEntity.getOfflinePlayerUuid(gameProfile.getName())); - } - - /** - * Checks whether player is authenticated. - * - * @return false if player is not authenticated, otherwise true. - */ - @Override - public boolean isAuthenticated() { - String uuid = ((PlayerAuth) player).getFakeUuid(); - return this.canSkipAuth() || (playerCacheMap.containsKey(uuid) && playerCacheMap.get(uuid).isAuthenticated); - } - - @Inject(method = "tick()V", at = @At("HEAD"), cancellable = true) - private void tick(CallbackInfo ci) { - if(!this.isAuthenticated()) { - // Checking player timer - if(kickTimer <= 0 && player.networkHandler.getConnection().isOpen()) { - player.networkHandler.disconnect(new LiteralText(config.lang.timeExpired)); - } - else { - // Sending authentication prompt every 10 seconds - if(kickTimer % 200 == 0) - player.sendMessage(this.getAuthMessage(), false); - kickTimer--; - } - ci.cancel(); - } - } // Player item dropping @Inject(method = "dropSelectedItem(Z)Z", at = @At("HEAD"), cancellable = true) @@ -234,14 +20,6 @@ public abstract class MixinPlayerEntity implements PlayerAuth { ActionResult result = DropItemCallback.EVENT.invoker().onDropItem(player); if (result == ActionResult.FAIL) { - // Canceling the item drop, as well as giving the items back to player (and updating inv with packet) - player.networkHandler.sendPacket( - new ScreenHandlerSlotUpdateS2CPacket( - -2, - player.inventory.selectedSlot, - player.inventory.getStack(player.inventory.selectedSlot)) - ); - player.networkHandler.sendPacket(new ScreenHandlerSlotUpdateS2CPacket(-1, -1, player.inventory.getCursorStack())); cir.setReturnValue(false); } } diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayerEntity.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayerEntity.java new file mode 100644 index 0000000..753db51 --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerPlayerEntity.java @@ -0,0 +1,216 @@ +package org.samo_lego.simpleauth.mixin; + +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.World; +import org.samo_lego.simpleauth.SimpleAuth; +import org.samo_lego.simpleauth.storage.PlayerCache; +import org.samo_lego.simpleauth.utils.PlayerAuth; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static org.samo_lego.simpleauth.SimpleAuth.*; +import static org.samo_lego.simpleauth.utils.CarpetHelper.isPlayerCarpetFake; +import static org.samo_lego.simpleauth.utils.SimpleLogger.logInfo; + +@Mixin(ServerPlayerEntity.class) +public class MixinServerPlayerEntity implements PlayerAuth { + + private final ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; + + // * 20 for 20 ticks in second + private int kickTimer = config.main.kickTime * 20; + + private final boolean isRunningCarpet = FabricLoader.getInstance().isModLoaded("carpet"); + + @Final + @Shadow + public MinecraftServer server; + + /** + * Teleports player to spawn or last location that is recorded. + * Last location means the location before de-authentication. + * + * @param hide whether to teleport player to spawn (provided in config) or last recorded position + */ + @Override + public void hidePosition(boolean hide) { + assert server != null; + + PlayerCache cache = playerCacheMap.get(this.getFakeUuid()); + if(config.main.spawnOnJoin) + logInfo("Teleporting " + player.getName().asString() + (hide ? " to spawn." : " to original position.")); + if (hide) { + // Saving position + cache.lastLocation.dimension = player.getServerWorld(); + cache.lastLocation.position = player.getPos(); + cache.lastLocation.yaw = player.yaw; + cache.lastLocation.pitch = player.pitch; + + // Teleports player to spawn + player.teleport( + server.getWorld(RegistryKey.of(Registry.DIMENSION, new Identifier(config.worldSpawn.dimension))), + config.worldSpawn.x, + config.worldSpawn.y, + config.worldSpawn.z, + config.worldSpawn.yaw, + config.worldSpawn.pitch + ); + return; + } + // Puts player to last cached position + player.teleport( + cache.lastLocation.dimension, + cache.lastLocation.position.getX(), + cache.lastLocation.position.getY(), + cache.lastLocation.position.getZ(), + cache.lastLocation.yaw, + cache.lastLocation.pitch + ); + } + + /** + * Converts player uuid, to ensure player with "nAmE" and "NamE" get same uuid. + * Both players are not allowed to play, since mod mimics Mojang behaviour. + * of not allowing accounts with same names but different capitalization. + * + * @return converted UUID as string + */ + @Override + public String getFakeUuid() { + // If server is in online mode online-mode UUIDs should be used + assert server != null; + if(server.isOnlineMode() && this.isUsingMojangAccount()) + return player.getUuidAsString(); + /* + Lower case is used for Player and PlAyEr to get same UUID (for password storing) + Mimicking Mojang behaviour, where players cannot set their name to + ExAmple if Example is already taken. + */ + // Getting player+s name via GameProfile, in order to be compatible with Drogtor mod + String playername = player.getGameProfile().getName().toLowerCase(); + return PlayerEntity.getOfflinePlayerUuid(playername).toString(); + + } + + /** + * Sets the authentication status of the player. + * + * @param authenticated whether player should be authenticated + */ + @Override + public void setAuthenticated(boolean authenticated) { + PlayerCache playerCache; + + if(!playerCacheMap.containsKey(this.getFakeUuid())) { + // First join + playerCache = new PlayerCache(this.getFakeUuid(), player); + playerCacheMap.put(this.getFakeUuid(), playerCache); + } + else { + playerCache = playerCacheMap.get(this.getFakeUuid()); + if(this.isAuthenticated() == authenticated) + return; + playerCache.isAuthenticated = authenticated; + } + + player.setInvulnerable(!authenticated && config.experimental.playerInvulnerable); + player.setInvisible(!authenticated && config.experimental.playerInvisible); + + // Teleporting player (hiding / restoring position) + if(config.main.spawnOnJoin) + this.hidePosition(!authenticated); + + if(authenticated) { + kickTimer = config.main.kickTime * 20; + // Updating blocks if needed (if portal rescue action happened) + if(playerCache.wasInPortal) { + World world = player.getEntityWorld(); + BlockPos pos = player.getBlockPos(); + + // Sending updates to portal blocks + // This is technically not needed, but it cleans the "messed portal" on the client + world.updateListeners(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + world.updateListeners(pos.up(), world.getBlockState(pos.up()), world.getBlockState(pos.up()), 3); + } + } + } + + /** + * Gets the text which tells the player + * to login or register, depending on account status. + * + * @return LiteralText with appropriate string (login or register) + */ + @Override + public Text getAuthMessage() { + final PlayerCache cache = playerCacheMap.get(((PlayerAuth) player).getFakeUuid()); + if(SimpleAuth.config.main.enableGlobalPassword || cache.isRegistered) + return new LiteralText( + SimpleAuth.config.lang.notAuthenticated + "\n" + SimpleAuth.config.lang.loginRequired + ); + return new LiteralText( + SimpleAuth.config.lang.notAuthenticated+ "\n" + SimpleAuth.config.lang.registerRequired + ); + } + + /** + * Checks whether player can skip authentication process. + * + * @return true if can skip authentication process, otherwise false + */ + @Override + public boolean canSkipAuth() { + // We ask CarpetHelper class since it has the imports needed + return (this.isRunningCarpet && isPlayerCarpetFake(this.player)) || (isUsingMojangAccount() && config.experimental.premiumAutologin); + } + + /** + * Whether the player is using the mojang account. + * @return true if paid, otherwise false + */ + @Override + public boolean isUsingMojangAccount() { + return mojangAccountNamesCache.contains(player.getGameProfile().getName().toLowerCase()); + } + + /** + * Checks whether player is authenticated. + * + * @return false if player is not authenticated, otherwise true. + */ + @Override + public boolean isAuthenticated() { + String uuid = ((PlayerAuth) player).getFakeUuid(); + return this.canSkipAuth() || (playerCacheMap.containsKey(uuid) && playerCacheMap.get(uuid).isAuthenticated); + } + + @Inject(method = "playerTick()V", at = @At("HEAD"), cancellable = true) + private void playerTick(CallbackInfo ci) { + if(!this.isAuthenticated()) { + // Checking player timer + if(kickTimer <= 0 && player.networkHandler.getConnection().isOpen()) { + player.networkHandler.disconnect(new LiteralText(config.lang.timeExpired)); + } + else { + // Sending authentication prompt every 10 seconds + if(kickTimer % 200 == 0) + player.sendMessage(this.getAuthMessage(), false); + --kickTimer; + } + ci.cancel(); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java b/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java index 34af65a..34b5647 100644 --- a/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java +++ b/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java @@ -81,11 +81,6 @@ public class AuthConfig { */ public int sessionTimeoutTime = 60; - /** - * Should deauthenticated players fall if the login mid-air? - */ - public boolean allowFalling = false; - /** * Whether to tp player to spawn when joining (to hide original player coordinates) */ @@ -125,7 +120,7 @@ public class AuthConfig { public String timeExpired = "§cTime for authentication has expired."; public String registerRequired = "§6Type /register to claim this account."; public String alreadyRegistered = "§6This account name is already registered!"; - public String registerSuccess = "§aYou are now authenticated."; + public String registerSuccess = "§aAccount was created."; public String userdataDeleted = "§aUserdata deleted."; public String userdataUpdated = "§aUserdata updated."; public String accountDeleted = "§aYour account was successfully deleted!"; @@ -137,6 +132,7 @@ public class AuthConfig { public String worldSpawnSet = "§aSpawn for logging in was set successfully."; public String corruptedPlayerData = "§cYour data is probably corrupted. Please contact admin."; public String userNotRegistered = "§cThis player is not registered!"; + public String cannotLogout = "§cYou cannot logout!"; } public static class ExperimentalConfig { /** diff --git a/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java b/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java index c814558..0c5b17b 100644 --- a/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java +++ b/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java @@ -1,16 +1,14 @@ package org.samo_lego.simpleauth.storage; -import com.google.gson.*; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; import net.minecraft.block.Blocks; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.text.LiteralText; -import net.minecraft.util.Identifier; import net.minecraft.util.math.Vec3d; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.RegistryKey; - -import java.util.Objects; import static org.samo_lego.simpleauth.SimpleAuth.DB; import static org.samo_lego.simpleauth.SimpleAuth.config; @@ -50,8 +48,6 @@ public class PlayerCache { /** * Player stats before de-authentication. */ - public int lastAir; - public boolean wasOnFire; public boolean wasInPortal; /** @@ -78,9 +74,6 @@ public class PlayerCache { logInfo("Creating cache for " + player.getName().asString()); this.lastIp = player.getIp(); - this.lastAir = player.getAir(); - this.wasOnFire = player.isOnFire(); - // Setting position cache this.lastLocation.dimension = player.getServerWorld(); this.lastLocation.position = player.getPos(); @@ -90,9 +83,7 @@ public class PlayerCache { this.wasInPortal = player.getBlockState().getBlock().equals(Blocks.NETHER_PORTAL); } else { - this.wasOnFire = false; this.wasInPortal = false; - this.lastAir = 300; } String data = DB.getData(uuid); @@ -114,32 +105,6 @@ public class PlayerCache { this.password = passwordElement.getAsString(); this.isRegistered = !this.password.isEmpty(); } - - - // DEPRECATED, UGLY - if(config.main.spawnOnJoin) { - try { - JsonElement lastLoc = json.get("lastLocation"); - if (lastLoc != null) { - // Getting DB coords - JsonObject lastLocation = gson.fromJson(lastLoc.getAsString(), JsonObject.class); - assert player != null; - this.lastLocation.dimension = Objects.requireNonNull(player.getServer()).getWorld(RegistryKey.of(Registry.DIMENSION, new Identifier( - lastLocation.get("dim").isJsonNull() ? config.worldSpawn.dimension : lastLocation.get("dim").getAsString()))); - - this.lastLocation.position = new Vec3d( - lastLocation.get("x").isJsonNull() ? config.worldSpawn.x : lastLocation.get("x").getAsDouble(), - lastLocation.get("y").isJsonNull() ? config.worldSpawn.y : lastLocation.get("y").getAsDouble(), - lastLocation.get("z").isJsonNull() ? config.worldSpawn.z : lastLocation.get("z").getAsDouble() - ); - this.lastLocation.yaw = lastLocation.get("yaw") == null ? 90 : lastLocation.get("yaw").getAsFloat(); - this.lastLocation.pitch = lastLocation.get("pitch") == null ? 0 : lastLocation.get("pitch").getAsFloat(); - - } - } catch (JsonSyntaxException ignored) { - // Player didn't have any coords in db to tp to - } - } } else { this.isRegistered = false; diff --git a/src/main/resources/mixins.simpleauth.json b/src/main/resources/mixins.simpleauth.json index 0539766..d1b281d 100644 --- a/src/main/resources/mixins.simpleauth.json +++ b/src/main/resources/mixins.simpleauth.json @@ -7,6 +7,7 @@ "MixinPlayerEntity", "MixinPlayerManager", "MixinServerLoginNetworkHandler", + "MixinServerPlayerEntity", "MixinServerPlayNetworkHandler", "MixinSlot", "MixinWorldSaveHandler" From 0e369bf99fac8f50f78bbb4cdce2ee4cd26bf88e Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Sat, 31 Oct 2020 17:56:13 +0100 Subject: [PATCH 08/18] Migrating advancements (#23) --- .../mixin/MixinPlayerAdvancementTracker.java | 47 +++++++++++++++++++ .../simpleauth/mixin/MixinPlayerManager.java | 1 - .../simpleauth/storage/AuthConfig.java | 15 ++++++ src/main/resources/mixins.simpleauth.json | 1 + 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java new file mode 100644 index 0000000..d2076ba --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java @@ -0,0 +1,47 @@ +package org.samo_lego.simpleauth.mixin; + +import net.minecraft.advancement.PlayerAdvancementTracker; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.ServerAdvancementLoader; +import net.minecraft.server.network.ServerPlayerEntity; +import org.samo_lego.simpleauth.utils.PlayerAuth; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.io.File; + +import static org.samo_lego.simpleauth.SimpleAuth.config; + +@Mixin(PlayerAdvancementTracker.class) +public class MixinPlayerAdvancementTracker { + + @Mutable + @Shadow + @Final + private File advancementFile; + + @Shadow + private ServerPlayerEntity owner; + + @Inject(method = "load(Lnet/minecraft/server/ServerAdvancementLoader;)V", at = @At("HEAD")) + private void startMigratingOfflineAdvancements(ServerAdvancementLoader advancementLoader, CallbackInfo ci) { + System.out.println(this.advancementFile.isFile()); + if(config.experimental.premiumAutologin && ((PlayerAuth) this.owner).isUsingMojangAccount() && !this.advancementFile.isFile()) { + // Migrate + String playername = owner.getGameProfile().getName().toLowerCase(); + this.advancementFile = new File(this.advancementFile.getParent(), PlayerEntity.getOfflinePlayerUuid(playername).toString() + ".json"); + } + } + + @Inject(method = "load(Lnet/minecraft/server/ServerAdvancementLoader;)V", at = @At("TAIL")) + private void endMigratingOfflineAdvancements(ServerAdvancementLoader advancementLoader, CallbackInfo ci) { + if(config.experimental.premiumAutologin && ((PlayerAuth) this.owner).isUsingMojangAccount()) { + this.advancementFile = new File(this.advancementFile.getParent(), owner.getUuid() + ".json"); + } + } +} diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java index d0ae290..1e2788e 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java @@ -30,7 +30,6 @@ public abstract class MixinPlayerManager { PlayerLeaveServerCallback.EVENT.invoker().onPlayerLeave(serverPlayerEntity); } - // Method for kicking player for @Inject(method = "checkCanJoin(Ljava/net/SocketAddress;Lcom/mojang/authlib/GameProfile;)Lnet/minecraft/text/Text;", at = @At("HEAD"), cancellable = true) private void checkCanJoin(SocketAddress socketAddress, GameProfile profile, CallbackInfoReturnable cir) { // Getting the player that is trying to join the server diff --git a/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java b/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java index 34b5647..30064ad 100644 --- a/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java +++ b/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java @@ -192,8 +192,23 @@ public class AuthConfig { * Whether players who have a valid session should skip the authentication process. * You have to set online-mode to true in server.properties! * (cracked players will still be able to enter, but they'll need to login) + * + * This protects premium usernames from being stolen, since cracked players + * with name that is found in Mojang database, are kicked. */ public boolean premiumAutologin = false; + /** + * Whether to modify player uuids to offline style. + * Note: this should be used only if you had your server + * running in offline mode and you made the switch to use + * AuthConfig#premiumAutoLogin AND your players already + * have e.g. villager discounts, which are based on uuid. + * Other things (advancements, playerdata) are migrated + * automatically, so think before enabling this. In case + * an online-mode player changes username, they'll loose all + * their stuff, unless you migrate it manually. + */ + public boolean forceoOfflineUuids = false; } public MainConfig main = new MainConfig(); diff --git a/src/main/resources/mixins.simpleauth.json b/src/main/resources/mixins.simpleauth.json index d1b281d..b9b884e 100644 --- a/src/main/resources/mixins.simpleauth.json +++ b/src/main/resources/mixins.simpleauth.json @@ -4,6 +4,7 @@ "compatibilityLevel": "JAVA_8", "mixins": [], "server": [ + "MixinPlayerAdvancementTracker", "MixinPlayerEntity", "MixinPlayerManager", "MixinServerLoginNetworkHandler", From b0fe67669c515ca901424d04a7de1583e8864ace Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Sat, 31 Oct 2020 18:28:17 +0100 Subject: [PATCH 09/18] Adding `forceOfflineUuids` option, some minor fixes --- .../java/org/samo_lego/simpleauth/SimpleAuth.java | 8 ++++---- .../simpleauth/commands/LogoutCommand.java | 2 +- .../mixin/MixinPlayerAdvancementTracker.java | 1 - .../mixin/MixinServerLoginNetworkHandler.java | 11 ++++++++++- .../samo_lego/simpleauth/storage/AuthConfig.java | 13 ++++++++++--- .../samo_lego/simpleauth/storage/PlayerCache.java | 2 +- .../simpleauth/storage/SimpleAuthDatabase.java | 2 ++ .../org/samo_lego/simpleauth/utils/AuthHelper.java | 8 -------- 8 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java index 66e08a7..811747c 100644 --- a/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java +++ b/src/main/java/org/samo_lego/simpleauth/SimpleAuth.java @@ -36,7 +36,7 @@ import static org.samo_lego.simpleauth.utils.SimpleLogger.logInfo; public class SimpleAuth implements DedicatedServerModInitializer { - public static SimpleAuthDatabase DB = new SimpleAuthDatabase(); + public static final SimpleAuthDatabase DB = new SimpleAuthDatabase(); public static final ExecutorService THREADPOOL = Executors.newCachedThreadPool(); @@ -45,19 +45,19 @@ public class SimpleAuth implements DedicatedServerModInitializer { * It's cleared on server stop in order to save some interactions with database during runtime. * Stores their data as {@link org.samo_lego.simpleauth.storage.PlayerCache PlayerCache} object. */ - public static HashMap playerCacheMap = new HashMap<>(); + public static final HashMap playerCacheMap = new HashMap<>(); /** * HashSet of player names that have Mojang accounts. * If player is saved in here, they will be treated as online-mode ones. */ - public static HashSet mojangAccountNamesCache = new HashSet<>(); + public static final HashSet mojangAccountNamesCache = new HashSet<>(); // Getting game directory public static final Path gameDirectory = FabricLoader.getInstance().getGameDir(); // Server properties - public static Properties serverProp = new Properties(); + public static final Properties serverProp = new Properties(); /** * Config of the SimpleAuth mod. diff --git a/src/main/java/org/samo_lego/simpleauth/commands/LogoutCommand.java b/src/main/java/org/samo_lego/simpleauth/commands/LogoutCommand.java index 7e975f9..d9dac8c 100644 --- a/src/main/java/org/samo_lego/simpleauth/commands/LogoutCommand.java +++ b/src/main/java/org/samo_lego/simpleauth/commands/LogoutCommand.java @@ -23,7 +23,7 @@ public class LogoutCommand { private static int logout(ServerCommandSource serverCommandSource) throws CommandSyntaxException { ServerPlayerEntity player = serverCommandSource.getPlayer(); - if(mojangAccountNamesCache.contains(player.getGameProfile().getName().toLowerCase())) { + if(!mojangAccountNamesCache.contains(player.getGameProfile().getName().toLowerCase())) { ((PlayerAuth) player).setAuthenticated(false); player.sendMessage(new LiteralText(config.lang.successfulLogout), false); } diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java index d2076ba..ba4db49 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java @@ -30,7 +30,6 @@ public class MixinPlayerAdvancementTracker { @Inject(method = "load(Lnet/minecraft/server/ServerAdvancementLoader;)V", at = @At("HEAD")) private void startMigratingOfflineAdvancements(ServerAdvancementLoader advancementLoader, CallbackInfo ci) { - System.out.println(this.advancementFile.isFile()); if(config.experimental.premiumAutologin && ((PlayerAuth) this.owner).isUsingMojangAccount() && !this.advancementFile.isFile()) { // Migrate String playername = owner.getGameProfile().getName().toLowerCase(); diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java index 7e33ad7..a31d868 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java @@ -21,13 +21,15 @@ import static org.samo_lego.simpleauth.SimpleAuth.*; import static org.samo_lego.simpleauth.utils.SimpleLogger.logError; @Mixin(ServerLoginNetworkHandler.class) -public class MixinServerLoginNetworkHandler { +public abstract class MixinServerLoginNetworkHandler { @Shadow private GameProfile profile; @Shadow private int loginTicks; + @Shadow protected abstract GameProfile toOfflineProfile(GameProfile profile); + /** * Fake state of current player. */ @@ -49,6 +51,13 @@ public class MixinServerLoginNetworkHandler { } } + @Inject(method = "acceptPlayer()V", at = @At("HEAD")) + private void acceptPlayer(CallbackInfo ci) { + if(config.experimental.forceoOfflineUuids) { + this.profile = this.toOfflineProfile(this.profile); + } + } + /** * Checks whether the player has purchased an account. * If so, server is presented as online, and continues as in normal-online mode. diff --git a/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java b/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java index 30064ad..3fe71ff 100644 --- a/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java +++ b/src/main/java/org/samo_lego/simpleauth/storage/AuthConfig.java @@ -25,6 +25,7 @@ import java.nio.charset.StandardCharsets; import static org.samo_lego.simpleauth.SimpleAuth.serverProp; import static org.samo_lego.simpleauth.utils.SimpleLogger.logError; +import static org.samo_lego.simpleauth.utils.SimpleLogger.logInfo; public class AuthConfig { private static final Gson gson = new GsonBuilder() @@ -230,9 +231,15 @@ public class AuthConfig { new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8) )) { config = gson.fromJson(fileReader, AuthConfig.class); - if(config.experimental.premiumAutologin && !Boolean.parseBoolean(serverProp.getProperty("online-mode"))) { - logError("You cannot use server in offline mode and premiumAutologin! Disabling the latter."); - config.experimental.premiumAutologin = false; + if(!Boolean.parseBoolean(serverProp.getProperty("online-mode"))) { + if(config.experimental.forceoOfflineUuids) { + logInfo("Server is in offline mode, forceoOfflineUuids option is irrelevant. Setting it to false."); + config.experimental.forceoOfflineUuids = false; + } + if(config.experimental.premiumAutologin) { + logError("You cannot use server in offline mode and premiumAutologin! Disabling the latter."); + config.experimental.premiumAutologin = false; + } } } catch (IOException e) { throw new RuntimeException("[SimpleAuth] Problem occurred when trying to load config: ", e); diff --git a/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java b/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java index 0c5b17b..526af00 100644 --- a/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java +++ b/src/main/java/org/samo_lego/simpleauth/storage/PlayerCache.java @@ -60,7 +60,7 @@ public class PlayerCache { public float pitch; } - public PlayerCache.LastLocation lastLocation = new PlayerCache.LastLocation(); + public final PlayerCache.LastLocation lastLocation = new PlayerCache.LastLocation(); private static final Gson gson = new Gson(); diff --git a/src/main/java/org/samo_lego/simpleauth/storage/SimpleAuthDatabase.java b/src/main/java/org/samo_lego/simpleauth/storage/SimpleAuthDatabase.java index 020a406..6b551f2 100644 --- a/src/main/java/org/samo_lego/simpleauth/storage/SimpleAuthDatabase.java +++ b/src/main/java/org/samo_lego/simpleauth/storage/SimpleAuthDatabase.java @@ -64,6 +64,7 @@ public class SimpleAuthDatabase { * @param data data to put inside database * @return true if operation was successful, otherwise false */ + @Deprecated public boolean registerUser(String uuid, String data) { try { if(!this.isUserRegistered(uuid)) { @@ -111,6 +112,7 @@ public class SimpleAuthDatabase { * @param uuid uuid of the player to update data for * @param data data to put inside database */ + @Deprecated public void updateUserData(String uuid, String data) { try { levelDBStore.put(bytes("UUID:" + uuid), bytes("data:" + data)); diff --git a/src/main/java/org/samo_lego/simpleauth/utils/AuthHelper.java b/src/main/java/org/samo_lego/simpleauth/utils/AuthHelper.java index cd39534..1eaa013 100644 --- a/src/main/java/org/samo_lego/simpleauth/utils/AuthHelper.java +++ b/src/main/java/org/samo_lego/simpleauth/utils/AuthHelper.java @@ -1,10 +1,5 @@ package org.samo_lego.simpleauth.utils; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import org.samo_lego.simpleauth.SimpleAuth; import org.samo_lego.simpleauth.utils.hashing.HasherArgon2; import org.samo_lego.simpleauth.utils.hashing.HasherBCrypt; @@ -12,9 +7,6 @@ import static org.samo_lego.simpleauth.SimpleAuth.config; import static org.samo_lego.simpleauth.SimpleAuth.playerCacheMap; public class AuthHelper { - // Json parser - private static final JsonParser parser = new JsonParser(); - /** * Checks password of user * From 1582b2dcacad0bc885d5ea07a913357435658157 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Sat, 31 Oct 2020 20:44:03 +0100 Subject: [PATCH 10/18] Migrating stats --- .../mixin/MixinPlayerAdvancementTracker.java | 6 +-- .../simpleauth/mixin/MixinPlayerManager.java | 49 +++++++++++++++++++ .../mixin/ServerStatHandlerAccessor.java | 17 +++++++ src/main/resources/mixins.simpleauth.json | 3 +- 4 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/samo_lego/simpleauth/mixin/ServerStatHandlerAccessor.java diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java index ba4db49..61a7581 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerAdvancementTracker.java @@ -30,16 +30,16 @@ public class MixinPlayerAdvancementTracker { @Inject(method = "load(Lnet/minecraft/server/ServerAdvancementLoader;)V", at = @At("HEAD")) private void startMigratingOfflineAdvancements(ServerAdvancementLoader advancementLoader, CallbackInfo ci) { - if(config.experimental.premiumAutologin && ((PlayerAuth) this.owner).isUsingMojangAccount() && !this.advancementFile.isFile()) { + if(config.experimental.premiumAutologin && !config.experimental.forceoOfflineUuids && ((PlayerAuth) this.owner).isUsingMojangAccount() && !this.advancementFile.isFile()) { // Migrate - String playername = owner.getGameProfile().getName().toLowerCase(); + String playername = owner.getGameProfile().getName(); this.advancementFile = new File(this.advancementFile.getParent(), PlayerEntity.getOfflinePlayerUuid(playername).toString() + ".json"); } } @Inject(method = "load(Lnet/minecraft/server/ServerAdvancementLoader;)V", at = @At("TAIL")) private void endMigratingOfflineAdvancements(ServerAdvancementLoader advancementLoader, CallbackInfo ci) { - if(config.experimental.premiumAutologin && ((PlayerAuth) this.owner).isUsingMojangAccount()) { + if(config.experimental.premiumAutologin && !config.experimental.forceoOfflineUuids && ((PlayerAuth) this.owner).isUsingMojangAccount()) { this.advancementFile = new File(this.advancementFile.getParent(), owner.getUuid() + ".json"); } } diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java index 1e2788e..a101c7d 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java @@ -1,25 +1,39 @@ package org.samo_lego.simpleauth.mixin; import com.mojang.authlib.GameProfile; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.network.ClientConnection; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.PlayerManager; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.stat.ServerStatHandler; import net.minecraft.text.LiteralText; import net.minecraft.text.Text; import org.samo_lego.simpleauth.event.entity.player.PlayerJoinServerCallback; import org.samo_lego.simpleauth.event.entity.player.PlayerLeaveServerCallback; import org.samo_lego.simpleauth.event.entity.player.PrePlayerJoinCallback; +import org.samo_lego.simpleauth.utils.PlayerAuth; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import java.io.File; import java.net.SocketAddress; +import java.util.UUID; + +import static org.samo_lego.simpleauth.SimpleAuth.config; @Mixin(PlayerManager.class) public abstract class MixinPlayerManager { + @Shadow @Final private MinecraftServer server; + @Inject(method = "onPlayerConnect(Lnet/minecraft/network/ClientConnection;Lnet/minecraft/server/network/ServerPlayerEntity;)V", at = @At("RETURN")) private void onPlayerConnect(ClientConnection clientConnection, ServerPlayerEntity serverPlayerEntity, CallbackInfo ci) { PlayerJoinServerCallback.EVENT.invoker().onPlayerJoin(serverPlayerEntity); @@ -42,4 +56,39 @@ public abstract class MixinPlayerManager { cir.setReturnValue(returnText); } } + + @ModifyVariable( + method = "createStatHandler(Lnet/minecraft/entity/player/PlayerEntity;)Lnet/minecraft/stat/ServerStatHandler;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/entity/player/PlayerEntity;getName()Lnet/minecraft/text/Text;" + ), + ordinal = 1 + ) + private File migrateOfflineStats(File file, PlayerEntity player) { + if(config.experimental.premiumAutologin && !config.experimental.forceoOfflineUuids && ((PlayerAuth) player).isUsingMojangAccount()) { + String playername = player.getGameProfile().getName(); + file = new File(file.getParent(), PlayerEntity.getOfflinePlayerUuid(playername) + ".json"); + } + return file; + } + + @Inject( + method = "createStatHandler(Lnet/minecraft/entity/player/PlayerEntity;)Lnet/minecraft/stat/ServerStatHandler;", + at = @At( + value = "INVOKE", + target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;" + ), + locals = LocalCapture.CAPTURE_FAILHARD + ) + private void migrateOfflineStats(PlayerEntity player, CallbackInfoReturnable cir, UUID uUID, ServerStatHandler serverStatHandler, File serverStatsDir, File playerStatFile) { + File onlineFile = new File(serverStatsDir, uUID + ".json"); + if(config.experimental.premiumAutologin && !config.experimental.forceoOfflineUuids && ((PlayerAuth) player).isUsingMojangAccount() && !onlineFile.exists()) { + ((ServerStatHandlerAccessor) serverStatHandler).setFile(onlineFile); + System.out.println("File: " + ((ServerStatHandlerAccessor) serverStatHandler).getFile().getName()); + } + else + System.out.println("Nope: " + ((ServerStatHandlerAccessor) serverStatHandler).getFile().getName()); + + } } diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/ServerStatHandlerAccessor.java b/src/main/java/org/samo_lego/simpleauth/mixin/ServerStatHandlerAccessor.java new file mode 100644 index 0000000..f329057 --- /dev/null +++ b/src/main/java/org/samo_lego/simpleauth/mixin/ServerStatHandlerAccessor.java @@ -0,0 +1,17 @@ +package org.samo_lego.simpleauth.mixin; + +import net.minecraft.stat.ServerStatHandler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.io.File; + +@Mixin(ServerStatHandler.class) +public interface ServerStatHandlerAccessor { + + @Accessor("file") + File getFile(); + + @Accessor("file") + void setFile(File file); +} diff --git a/src/main/resources/mixins.simpleauth.json b/src/main/resources/mixins.simpleauth.json index b9b884e..0713648 100644 --- a/src/main/resources/mixins.simpleauth.json +++ b/src/main/resources/mixins.simpleauth.json @@ -11,7 +11,8 @@ "MixinServerPlayerEntity", "MixinServerPlayNetworkHandler", "MixinSlot", - "MixinWorldSaveHandler" + "MixinWorldSaveHandler", + "ServerStatHandlerAccessor" ], "injectors": { "defaultRequire": 1 From 7f238e7d0c7f9051c0fd5e225b5836144096a24e Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Sat, 31 Oct 2020 22:34:25 +0100 Subject: [PATCH 11/18] Version bump --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 23dc3e8..b1e27ca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ loader_version=0.9.3+build.207 fabric_version=0.20.2+build.402-1.16 # Mod Properties -mod_version = 1.6.3 +mod_version = 1.6.4 maven_group = org.samo_lego archives_base_name = simpleauth From 7716b751a5da4f9c1e25a669604a1ede62e13130 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Sun, 1 Nov 2020 17:21:48 +0100 Subject: [PATCH 12/18] Removing STDOUT (oops) --- .../org/samo_lego/simpleauth/mixin/MixinPlayerManager.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java index a101c7d..784d5c1 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinPlayerManager.java @@ -85,10 +85,6 @@ public abstract class MixinPlayerManager { File onlineFile = new File(serverStatsDir, uUID + ".json"); if(config.experimental.premiumAutologin && !config.experimental.forceoOfflineUuids && ((PlayerAuth) player).isUsingMojangAccount() && !onlineFile.exists()) { ((ServerStatHandlerAccessor) serverStatHandler).setFile(onlineFile); - System.out.println("File: " + ((ServerStatHandlerAccessor) serverStatHandler).getFile().getName()); } - else - System.out.println("Nope: " + ((ServerStatHandlerAccessor) serverStatHandler).getFile().getName()); - } } From e020797d0cdd15577707573ae9fa83f5bccccf26 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Sun, 1 Nov 2020 17:58:17 +0100 Subject: [PATCH 13/18] More debuging options --- .../mixin/MixinWorldSaveHandler.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java index ff5a83c..0536d6f 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java @@ -21,6 +21,7 @@ import java.io.IOException; import static org.samo_lego.simpleauth.SimpleAuth.config; import static org.samo_lego.simpleauth.SimpleAuth.mojangAccountNamesCache; +import static org.samo_lego.simpleauth.utils.SimpleLogger.logInfo; @Mixin(WorldSaveHandler.class) public class MixinWorldSaveHandler { @@ -73,16 +74,27 @@ public class MixinWorldSaveHandler { ) private CompoundTag migratePlayerData(CompoundTag compoundTag, PlayerEntity player) { // Checking for offline player data only if online doesn't exist yet - if(config.experimental.premiumAutologin && mojangAccountNamesCache.contains(player.getGameProfile().getName()) && !this.fileExists) { - File file = new File(this.playerDataDir, PlayerEntity.getOfflinePlayerUuid(player.getGameProfile().getName()) + ".dat"); + String playername = player.getGameProfile().getName().toLowerCase(); + if(config.experimental.premiumAutologin && mojangAccountNamesCache.contains(playername) && !this.fileExists) { + if(config.experimental.debugMode) + logInfo("Migrating data for " + playername); + File file = new File(this.playerDataDir, PlayerEntity.getOfflinePlayerUuid(player.getGameProfile().getName()) + ".dat"); if (file.exists() && file.isFile()) try { compoundTag = NbtIo.readCompressed(new FileInputStream(file)); } catch (IOException e) { - LOGGER.warn("Failed to load player data for {}", player.getGameProfile().getName()); + LOGGER.warn("Failed to load player data for {}", playername); } } + else if(config.experimental.debugMode) + logInfo("Not migrating " + + playername + + ", as premium status is: " + + mojangAccountNamesCache.contains(playername) + + "and data file is " + (this.fileExists ? "" : "not") + + " present." + ); return compoundTag; } } From 37b31029196155cfec3de022fee127c72dea82f3 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Mon, 2 Nov 2020 08:51:57 +0100 Subject: [PATCH 14/18] Updating build script --- .github/workflows/main.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.sh b/.github/workflows/main.sh index 0a145b7..277b6ca 100644 --- a/.github/workflows/main.sh +++ b/.github/workflows/main.sh @@ -21,7 +21,7 @@ echo "MC_VERSION=$mcVersion" >> $GITHUB_ENV # Checks if build is stable (I always bump version when I release stable, uploadable version) -latestRelease=$(curl -s "https://api.github.com/repos/$GITHUB_REPOSITORY/releases/latest" | grep -oP '"tag_name": "\K(.*)(?=")') +latestRelease=$(curl -s "https://api.github.com/repos/$GITHUB_REPOSITORY/releases" | grep -oP '(?<="tag_name": ")[^"]*' | head -n 1) echo "Latest release is: $latestRelease" From 9a85914d4febb3c44bcc79347be65ff188527c51 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Mon, 2 Nov 2020 09:24:12 +0100 Subject: [PATCH 15/18] Including regex check for autologin --- .../simpleauth/mixin/MixinServerLoginNetworkHandler.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java index a31d868..6fa1ac6 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinServerLoginNetworkHandler.java @@ -16,6 +16,8 @@ import javax.net.ssl.HttpsURLConnection; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.samo_lego.simpleauth.SimpleAuth.*; import static org.samo_lego.simpleauth.utils.SimpleLogger.logError; @@ -78,7 +80,9 @@ public abstract class MixinServerLoginNetworkHandler { if(config.experimental.premiumAutologin) { try { String playername = packet.getProfile().getName().toLowerCase(); - if(playerCacheMap.containsKey(PlayerEntity.getOfflinePlayerUuid(playername).toString())) { + Pattern pattern = Pattern.compile("^[a-z0-9_]{3,16}$"); + Matcher matcher = pattern.matcher(playername); + if(playerCacheMap.containsKey(PlayerEntity.getOfflinePlayerUuid(playername).toString()) || !matcher.matches()) { // Player definitely doesn't have a mojang account this.acceptCrackedPlayer = true; From c0f78d6c3f3005852878a0f1ad770fc6cb4307f4 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Tue, 3 Nov 2020 10:47:05 +0100 Subject: [PATCH 16/18] 1.16.4 --- gradle.properties | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index b1e27ca..a446c27 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,15 +2,15 @@ org.gradle.jvmargs=-Xmx1G # Fabric properties -minecraft_version=1.16.3 -yarn_mappings=1.16.3+build.1 -loader_version=0.9.3+build.207 +minecraft_version=1.16.4 +yarn_mappings=1.16.4+build.1 +loader_version=0.10.6+build.214 #Fabric api -fabric_version=0.20.2+build.402-1.16 +fabric_version=0.25.1+build.416-1.16 # Mod Properties -mod_version = 1.6.4 +mod_version = 1.6.5 maven_group = org.samo_lego archives_base_name = simpleauth From b30d336f8732298cf135f9c88b18fddf48f9dfd6 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Tue, 3 Nov 2020 11:10:11 +0100 Subject: [PATCH 17/18] Adding space in debug output --- .../org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java b/src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java index 0536d6f..3651d48 100644 --- a/src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java +++ b/src/main/java/org/samo_lego/simpleauth/mixin/MixinWorldSaveHandler.java @@ -92,7 +92,7 @@ public class MixinWorldSaveHandler { playername + ", as premium status is: " + mojangAccountNamesCache.contains(playername) + - "and data file is " + (this.fileExists ? "" : "not") + + " and data file is " + (this.fileExists ? "" : "not") + " present." ); return compoundTag; From a5bc9d07503c5b335f901fb8254d6cfbf99f4365 Mon Sep 17 00:00:00 2001 From: samo_lego <34912839+samolego@users.noreply.github.com> Date: Thu, 5 Nov 2020 10:37:52 +0100 Subject: [PATCH 18/18] Gradle update --- gradle/wrapper/gradle-wrapper.jar | Bin 58694 -> 58910 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 490fda8577df6c95960ba7077c43220e5bb2c0d9..62d4c053550b91381bbd28b1afc82d634bf73a8a 100644 GIT binary patch delta 6447 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 F{|nTN-B$nr diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 804ccdc..99fd715 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ #Thu Jun 04 11:39:28 CEST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStorePath=wrapper/dists