diff --git a/README.md b/README.md index 853e5a82..37e07506 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,11 @@ So they don't need to enter passwords. This is also called auto login (auto-logi * Detect paid accounts from others * Automatically login paid accounts (premium) * Support various of auth plugins -* Cauldron support -* Forge/Sponge message support * Premium UUID support * Forward skins * Detect username changed and will update the existing database record -* BungeeCord support +* BungeeCord/Velocity support * Auto register new premium players -* Plugin: ProtocolSupport is supported and can be used as an alternative to ProtocolLib * No client modifications needed * Good performance by using async operations * Locale messages @@ -103,8 +100,8 @@ This plugin performs network requests to: ### Spigot/Paper 1. Download and install ProtocolLib/ProtocolSupport -2. Download and install FastLogin (or `FastLoginBukkit` for newer versions) -3. Set your server in offline mode by setting the value `onlinemode` in your server.properties to false +2. Download and install `FastLoginBukkit` +3. Set your server in offline mode by setting the value `onlinemode` in your server.properties to `false` ### BungeeCord/Waterfall or Velocity @@ -119,8 +116,8 @@ Install the plugin on both platforms, that is proxy (BungeeCord or Velocity) and 4. Activate ip forwarding in your proxy config 5. Check your database settings in the config of FastLogin on your proxy * The proxies only ship with a limited set of drivers where Spigot supports more. Therefore, these are supported: - * BungeeCord: `com.mysql.jdbc.Driver` for MySQL/MariaDB - * Velocity: `fastlogin.mariadb.jdbc.Driver` for MySQL/MariaDB + * BungeeCord: `mysql` for MySQL/MariaDB + * Velocity: `mariadb` for MySQL/MariaDB * Note the embedded file storage SQLite is not available * MySQL/MariaDB requires an external database server running. Check your server provider if there is one available or install one. diff --git a/bukkit/pom.xml b/bukkit/pom.xml index ad359e3b..d528187d 100644 --- a/bukkit/pom.xml +++ b/bukkit/pom.xml @@ -122,14 +122,6 @@ https://papermc.io/repo/repository/maven-public/ - - sonatype-snapshots - https://s01.oss.sonatype.org/content/repositories/snapshots/ - - false - - - dmulloy2-repo diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java index 829dcce7..8194e4e1 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitLoginSession.java @@ -47,7 +47,6 @@ public class BukkitLoginSession extends LoginSession { private final ClientPublicKey clientPublicKey; private boolean verified; - private SkinProperty skinProperty; public BukkitLoginSession(String username, byte[] verifyToken, ClientPublicKey publicKey, boolean registered, @@ -109,7 +108,7 @@ public class BukkitLoginSession extends LoginSession { * * @param verified whether the player has valid session */ - public synchronized void setVerified(boolean verified) { + public synchronized void setVerifiedPremium(boolean verified) { this.verified = verified; } @@ -118,7 +117,7 @@ public class BukkitLoginSession extends LoginSession { * * @return whether the player has a valid session */ - public synchronized boolean isVerified() { + public synchronized boolean isVerifiedPremium() { return verified; } } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/CrackedCommand.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/CrackedCommand.java index 69632b17..b0ac8287 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/CrackedCommand.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/command/CrackedCommand.java @@ -95,7 +95,7 @@ public class CrackedCommand extends ToggleCommand { } //existing player is already cracked - if (profile.isSaved() && !profile.isOnlinemodePreferred()) { + if (profile.isExistingPlayer() && !profile.isOnlinemodePreferred()) { plugin.getCore().sendLocaleMessage("not-premium-other", sender); } else { plugin.getCore().sendLocaleMessage("remove-premium", sender); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java index aa971c43..9a906eeb 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/AuthMeHook.java @@ -45,9 +45,9 @@ import java.lang.reflect.Field; *

* Project page: *

- * Bukkit: ... + * Bukkit *

- * Spigot: ... + * Spigot */ public class AuthMeHook implements AuthPlugin, Listener { @@ -76,7 +76,7 @@ public class AuthMeHook implements AuthPlugin, Listener { Player player = restoreSessionEvent.getPlayer(); BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress()); - if (session != null && session.isVerified()) { + if (session != null && session.isVerifiedPremium()) { restoreSessionEvent.setCancelled(true); } } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/CrazyLoginHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/CrazyLoginHook.java index 066f2443..ccf6d819 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/CrazyLoginHook.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/CrazyLoginHook.java @@ -46,7 +46,7 @@ import java.util.concurrent.Future; *

* Project page: *

- * Bukkit: ... + * Bukkit */ public class CrazyLoginHook implements AuthPlugin { diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/LoginSecurityHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/LoginSecurityHook.java index c1ce96a9..85803bc3 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/LoginSecurityHook.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/LoginSecurityHook.java @@ -39,9 +39,9 @@ import org.bukkit.entity.Player; *

* Project page: *

- * Bukkit: ... + * Bukkit *

- * Spigot: ... + * Spigot */ public class LoginSecurityHook implements AuthPlugin { diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/UltraAuthHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/UltraAuthHook.java index f7cd74ec..78dd1403 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/UltraAuthHook.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/UltraAuthHook.java @@ -38,9 +38,9 @@ import java.util.concurrent.Future; /** * Project page: *

- * Bukkit: ... + * Bukkit *

- * Spigot: ... + * Spigot */ public class UltraAuthHook implements AuthPlugin { diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/XAuthHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/XAuthHook.java index 27d44a3e..0e0364b8 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/XAuthHook.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hook/XAuthHook.java @@ -40,7 +40,7 @@ import java.util.concurrent.Future; *

* Project page: *

- * Bukkit: ... + * Bukkit */ public class XAuthHook implements AuthPlugin { diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeListener.java index 0c5ed937..14cc9fa7 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BungeeListener.java @@ -123,7 +123,7 @@ public class BungeeListener implements PluginMessageListener { } private void startLoginTaskIfReady(Player player, BukkitLoginSession session) { - session.setVerified(true); + session.setVerifiedPremium(true); plugin.putSession(player.spigot().getRawAddress(), session); // only start a new login task if the join event fired earlier. This event then didn't diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java index c7c70015..2f861048 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibListener.java @@ -52,6 +52,7 @@ import io.netty.util.AttributeKey; import lombok.val; import org.bukkit.entity.Player; import org.geysermc.floodgate.api.player.FloodgatePlayer; +import org.jetbrains.annotations.NotNull; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; @@ -114,22 +115,10 @@ public class ProtocolLibListener extends PacketAdapter { } Player sender = packetEvent.getPlayer(); - PacketType packetType = packetEvent.getPacketType(); + PacketType packetType = getOverriddenType(packetEvent.getPacketType()); plugin.getLog().info("New packet {} from {}", packetType, sender); try { - if (packetType.isDynamic()) { - String vanillaName = packetType.getPacketClass().getName(); - plugin.getLog().info("Overriding packet type for unregistered packet type to fix ProtocolLib bug"); - if (vanillaName.endsWith("ServerboundHelloPacket")) { - packetType = START; - } - - if (vanillaName.endsWith("ServerboundKeyPacket")) { - packetType = ENCRYPTION_BEGIN; - } - } - if (packetType == START) { if (plugin.getFloodgateService() != null) { boolean success = processFloodgateTasks(packetEvent); @@ -169,6 +158,22 @@ public class ProtocolLibListener extends PacketAdapter { } } + private @NotNull PacketType getOverriddenType(PacketType packetType) { + if (packetType.isDynamic()) { + String vanillaName = packetType.getPacketClass().getName(); + plugin.getLog().info("Overriding packet type for unregistered packet type to fix ProtocolLib bug"); + if (vanillaName.endsWith("ServerboundHelloPacket")) { + return START; + } + + if (vanillaName.endsWith("ServerboundKeyPacket")) { + return ENCRYPTION_BEGIN; + } + } + + return packetType; + } + private void onEncryptionBegin(PacketEvent packetEvent, Player sender) { byte[] sharedSecret = packetEvent.getPacket().getByteArrays().read(0); @@ -240,7 +245,7 @@ public class ProtocolLibListener extends PacketAdapter { PacketContainer packet = packetEvent.getPacket(); Optional clientKey; if (new MinecraftVersion(1, 19, 3).atOrAbove()) { - // public key sent separate + // public key is sent separate clientKey = Optional.empty(); } else { val profileKey = packet.getOptionals(BukkitConverters.getWrappedPublicKeyDataConverter()) diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java index e02a6d87..f32f3fa4 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/ProtocolLibLoginSource.java @@ -51,7 +51,6 @@ class ProtocolLibLoginSource implements LoginSource { private final ClientPublicKey clientKey; private final PublicKey publicKey; - private final String serverId = ""; private byte[] verifyToken; ProtocolLibLoginSource(Player player, Random random, PublicKey serverPublicKey, ClientPublicKey clientKey) { @@ -72,7 +71,7 @@ class ProtocolLibLoginSource implements LoginSource { */ PacketContainer newPacket = new PacketContainer(ENCRYPTION_BEGIN); - newPacket.getStrings().write(0, serverId); + newPacket.getStrings().write(0, ""); StructureModifier keyModifier = newPacket.getSpecificModifier(PublicKey.class); int verifyField = 0; if (keyModifier.getFields().isEmpty()) { @@ -117,10 +116,6 @@ class ProtocolLibLoginSource implements LoginSource { return clientKey; } - public String getServerId() { - return serverId; - } - public byte[] getVerifyToken() { return verifyToken.clone(); } @@ -130,7 +125,6 @@ class ProtocolLibLoginSource implements LoginSource { return this.getClass().getSimpleName() + '{' + "player=" + player + ", random=" + random - + ", serverId='" + serverId + '\'' + ", verifyToken=" + Arrays.toString(verifyToken) + '}'; } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java index 42f7598e..55f3b960 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocollib/VerifyResponseTask.java @@ -195,7 +195,7 @@ public class VerifyResponseTask implements Runnable { session.setVerifiedUsername(realUsername); session.setUuid(verification.getId()); - session.setVerified(true); + session.setVerifiedPremium(true); setPremiumUUID(session.getUuid()); receiveFakeStartPacket(realUsername, session.getClientPublicKey(), session.getUuid()); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java index 61132437..5e513945 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java @@ -101,7 +101,7 @@ public class ProtocolSupportListener extends JoinManagement { } else { profile.setFloodgate(FloodgateState.FALSE); core.getPlugin().getLog().info( - "Player {} will be migrated to the v2 database schema as a JAVA user", username); + "Player {} will be migrated to the v2 database schema as a JAVA user", username + ); } callFastLoginPreLoginEvent(username, source, profile); - Configuration config = core.getConfig(); String ip = source.getAddress().getAddress().getHostAddress(); profile.setLastIp(ip); - try { - if (profile.isSaved()) { - if (profile.isOnlinemodePreferred()) { - core.getPlugin().getLog().info("Requesting premium login for registered player: {}", username); - requestPremiumLogin(source, profile, username, true); - } else { - if (isValidUsername(source, profile)) { - startCrackedSession(source, profile, username); - } - } + if (profile.isExistingPlayer()) { + if (profile.isOnlinemodePreferred()) { + core.getPlugin().getLog().info("Requesting premium login for registered player: {}", username); + requestPremiumLogin(source, profile, username, true); } else { - if (core.hasFailedLogin(ip, username)) { - core.getPlugin().getLog().info("Second attempt login -> cracked {}", username); - - //first login request failed so make a cracked session - startCrackedSession(source, profile, username); - return; - } - - Optional premiumUUID = Optional.empty(); - if (config.get("nameChangeCheck", false) || config.get("autoRegister", false)) { - premiumUUID = core.getResolver().findProfile(username); - } - - if (!premiumUUID.isPresent() - || (!checkNameChange(source, username, premiumUUID.get()) - && !checkPremiumName(source, username, profile))) { - //nothing detected the player as premium -> start a cracked session - if (core.getConfig().get("switchMode", false)) { - source.kick(core.getMessage("switch-kick-message")); - return; - } - + if (isValidUsername(source, profile)) { startCrackedSession(source, profile, username); } } + } else { + performNewPlayerLogin(username, source, ip, profile); + } + } + + private void performNewPlayerLogin(String username, S source, String ip, StoredProfile profile) { + try { + if (core.hasFailedLogin(ip, username)) { + core.getPlugin().getLog().info("Second attempt login -> cracked {}", username); + + //first login request failed so make a cracked session + startCrackedSession(source, profile, username); + return; + } + + Configuration config = core.getConfig(); + Optional premiumUUID = Optional.empty(); + if (config.get("nameChangeCheck", false) || config.get("autoRegister", false)) { + premiumUUID = core.getResolver().findProfile(username); + } + + if (!premiumUUID.isPresent() + || (!isNameChanged(source, username, premiumUUID.get()) + && !isUsernameAvailable(source, username, profile))) { + //nothing detected the player as premium -> start a cracked session + if (core.getConfig().get("switchMode", false)) { + source.kick(core.getMessage("switch-kick-message")); + return; + } + + startCrackedSession(source, profile, username); + } } catch (RateLimitException rateLimitEx) { core.getPlugin().getLog().error("Mojang's rate limit reached for {}. The public IPv4 address of this" - + " server issued more than 600 Name -> UUID requests within 10 minutes. After those 10" - + " minutes we can make requests again.", username); + + " server issued more than 600 Name -> UUID requests within 10 minutes. After those 10" + + " minutes we can make requests again.", username); } catch (Exception ex) { core.getPlugin().getLog().error("Failed to check premium state of {}", username, ex); } } - protected boolean isValidUsername(LoginSource source, StoredProfile profile) throws Exception { + protected boolean isValidUsername(LoginSource source, StoredProfile profile) { if (bedrockService != null && bedrockService.isUsernameForbidden(profile)) { core.getPlugin().getLog().info("Floodgate Prefix detected on cracked player"); source.kick("Your username contains illegal characters"); @@ -134,7 +139,7 @@ public abstract class JoinManagement

{ return true; } - private boolean checkPremiumName(S source, String username, StoredProfile profile) throws Exception { + private boolean isUsernameAvailable(S source, String username, StoredProfile profile) throws Exception { core.getPlugin().getLog().info("GameProfile {} uses a premium username", username); if (core.getConfig().get("autoRegister", false) && (authHook == null || !authHook.isRegistered(username))) { requestPremiumLogin(source, profile, username, false); @@ -144,7 +149,7 @@ public abstract class JoinManagement

{ return false; } - private boolean checkNameChange(S source, String username, Profile profile) { + private boolean isNameChanged(S source, String username, Profile profile) { //user not exists in the db if (core.getConfig().get("nameChangeCheck", false)) { StoredProfile storedProfile = core.getStorage().loadProfile(profile.getId()); diff --git a/core/src/main/java/com/github/games647/fastlogin/core/shared/LoginSource.java b/core/src/main/java/com/github/games647/fastlogin/core/shared/LoginSource.java index d99f403c..4ce5cc5e 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/shared/LoginSource.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/shared/LoginSource.java @@ -31,7 +31,7 @@ public interface LoginSource { void enableOnlinemode() throws Exception; - void kick(String message) throws Exception; + void kick(String message); InetSocketAddress getAddress(); } diff --git a/core/src/main/java/com/github/games647/fastlogin/core/storage/SQLStorage.java b/core/src/main/java/com/github/games647/fastlogin/core/storage/SQLStorage.java index bdc1a8fd..8eb70035 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/storage/SQLStorage.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/storage/SQLStorage.java @@ -176,7 +176,7 @@ public abstract class SQLStorage implements AuthStorage { playerProfile.getSaveLock().lock(); try { - if (playerProfile.isSaved()) { + if (playerProfile.isExistingPlayer()) { try (PreparedStatement saveStmt = con.prepareStatement(UPDATE_PROFILE)) { saveStmt.setString(1, uuid); saveStmt.setString(2, playerProfile.getName()); diff --git a/core/src/main/java/com/github/games647/fastlogin/core/storage/StoredProfile.java b/core/src/main/java/com/github/games647/fastlogin/core/storage/StoredProfile.java index de1f24d7..e80d9d12 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/storage/StoredProfile.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/storage/StoredProfile.java @@ -68,7 +68,7 @@ public class StoredProfile extends Profile { return saveLock; } - public synchronized boolean isSaved() { + public synchronized boolean isExistingPlayer() { return rowId >= 0; } diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 2c5405a3..3685a3ae 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -9,7 +9,7 @@ # problem. Low level firewalls like uwf (or iptables direct) are more efficient than a Minecraft plugin. TCP reverse # proxies could also be used and offload some work even to different host. # -# The settings wil limit how many connections this plugin will handle. After hitting this limit. FastLogin will +# The settings will limit how many connections this plugin will handle. After hitting this limit. FastLogin will # completely ignore incoming connections. Effectively there will be no database requests and network requests. # Therefore, auto logins won't be possible. anti-bot: diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/VelocityLoginSource.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/VelocityLoginSource.java index 16f36d4f..dfd98acb 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/VelocityLoginSource.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/VelocityLoginSource.java @@ -66,8 +66,4 @@ public class VelocityLoginSource implements LoginSource { public InetSocketAddress getAddress() { return connection.getRemoteAddress(); } - - public InboundConnection getConnection() { - return connection; - } } diff --git a/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/AsyncPremiumCheck.java b/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/AsyncPremiumCheck.java index 28d26eff..321afa79 100644 --- a/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/AsyncPremiumCheck.java +++ b/velocity/src/main/java/com/github/games647/fastlogin/velocity/task/AsyncPremiumCheck.java @@ -82,7 +82,7 @@ public class AsyncPremiumCheck extends JoinManagement