forked from TuxCoding/FastLogin
Modularize authentication backends
This commit is contained in:
@ -16,9 +16,11 @@
|
||||
|
||||
## Removed
|
||||
|
||||
Dropped some features listed below. Please contact us if you still need them
|
||||
|
||||
* Dropped Java support < 11
|
||||
* Removed configuration option to add multiple outgoing IPv4 towards Mojang
|
||||
* Was this really used?
|
||||
* Dropped support for ProtocolSupport seems to unsupported
|
||||
|
||||
[...] A lot of changes
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
package com.github.games647.fastlogin.bukkit;
|
||||
|
||||
import com.github.games647.craftapi.model.skin.SkinProperty;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.core.shared.LoginSession;
|
||||
import com.github.games647.fastlogin.core.storage.StoredProfile;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -25,23 +25,21 @@
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.github.games647.fastlogin.bukkit.auth.AuthenticationBackend;
|
||||
import com.github.games647.fastlogin.bukkit.auth.ConnectionListener;
|
||||
import com.github.games647.fastlogin.bukkit.auth.protocollib.ProtocolAuthentication;
|
||||
import com.github.games647.fastlogin.bukkit.auth.proxy.ProxyAuthentication;
|
||||
import com.github.games647.fastlogin.bukkit.command.CrackedCommand;
|
||||
import com.github.games647.fastlogin.bukkit.command.PremiumCommand;
|
||||
import com.github.games647.fastlogin.bukkit.listener.ConnectionListener;
|
||||
import com.github.games647.fastlogin.bukkit.listener.PaperCacheListener;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.ProtocolLibListener;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.SkinApplyListener;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocolsupport.ProtocolSupportListener;
|
||||
import com.github.games647.fastlogin.bukkit.task.DelayedAuthHook;
|
||||
import com.github.games647.fastlogin.bukkit.hook.DelayedAuthHook;
|
||||
import com.github.games647.fastlogin.core.CommonUtil;
|
||||
import com.github.games647.fastlogin.core.PremiumStatus;
|
||||
import com.github.games647.fastlogin.core.antibot.AntiBotService;
|
||||
import com.github.games647.fastlogin.core.hooks.bedrock.BedrockService;
|
||||
import com.github.games647.fastlogin.core.hooks.bedrock.FloodgateService;
|
||||
import com.github.games647.fastlogin.core.hooks.bedrock.GeyserService;
|
||||
import com.github.games647.fastlogin.core.shared.FastLoginCore;
|
||||
import com.github.games647.fastlogin.core.shared.PlatformPlugin;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -71,18 +69,26 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
Duration.ofMinutes(1), -1
|
||||
);
|
||||
|
||||
@Getter
|
||||
private final Map<UUID, PremiumStatus> premiumPlayers = new ConcurrentHashMap<>();
|
||||
private final Logger logger;
|
||||
|
||||
private boolean serverStarted;
|
||||
private BungeeManager bungeeManager;
|
||||
private final BukkitScheduler scheduler;
|
||||
|
||||
@Getter
|
||||
private FastLoginCore<Player, CommandSender, FastLoginBukkit> core;
|
||||
|
||||
@Getter
|
||||
private FloodgateService floodgateService;
|
||||
private GeyserService geyserService;
|
||||
|
||||
private PremiumPlaceholder premiumPlaceholder;
|
||||
|
||||
private AuthenticationBackend backend;
|
||||
|
||||
@Getter
|
||||
private boolean initialized;
|
||||
|
||||
public FastLoginBukkit() {
|
||||
this.logger = CommonUtil.initializeLoggerService(getLogger());
|
||||
this.scheduler = new BukkitScheduler(this, logger);
|
||||
@ -104,51 +110,42 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
bungeeManager = new BungeeManager(this);
|
||||
bungeeManager.initialize();
|
||||
|
||||
PluginManager pluginManager = getServer().getPluginManager();
|
||||
if (bungeeManager.isEnabled()) {
|
||||
markInitialized();
|
||||
} else {
|
||||
if (!core.setupDatabase()) {
|
||||
setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
AntiBotService antiBotService = core.getAntiBotService();
|
||||
if (pluginManager.isPluginEnabled("ProtocolSupport")) {
|
||||
pluginManager.registerEvents(new ProtocolSupportListener(this, antiBotService), this);
|
||||
} else if (pluginManager.isPluginEnabled("ProtocolLib")) {
|
||||
ProtocolLibListener.register(this, antiBotService, core.getConfig().getBoolean("verifyClientKeys"));
|
||||
|
||||
//if server is using paper - we need to set the skin at pre login anyway, so no need for this listener
|
||||
if (!isPaper() && getConfig().getBoolean("forwardSkin")) {
|
||||
pluginManager.registerEvents(new SkinApplyListener(this), this);
|
||||
}
|
||||
} else {
|
||||
logger.warn("Either ProtocolLib or ProtocolSupport have to be installed if you don't use BungeeCord");
|
||||
setEnabled(false);
|
||||
return;
|
||||
}
|
||||
backend = initializeAuthenticationBackend();
|
||||
if (backend == null) {
|
||||
logger.warn("Either ProtocolLib or ProtocolSupport have to be installed if you don't use BungeeCord");
|
||||
setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
//delay dependency setup because we load the plugin very early where plugins are initialized yet
|
||||
getServer().getScheduler().runTaskLater(this, new DelayedAuthHook(this), 5L);
|
||||
backend.init(getServer().getPluginManager());
|
||||
PluginManager pluginManager = getServer().getPluginManager();
|
||||
|
||||
pluginManager.registerEvents(new ConnectionListener(this), this);
|
||||
|
||||
//if server is using paper - we need to add one more listener to correct the user cache usage
|
||||
if (isPaper()) {
|
||||
pluginManager.registerEvents(new PaperCacheListener(this), this);
|
||||
}
|
||||
|
||||
registerCommands();
|
||||
|
||||
if (pluginManager.isPluginEnabled("PlaceholderAPI")) {
|
||||
premiumPlaceholder = new PremiumPlaceholder(this);
|
||||
premiumPlaceholder.register();
|
||||
}
|
||||
|
||||
// delay dependency setup because we load the plugin very early where plugins are initialized yet
|
||||
getServer().getScheduler().runTaskLater(this, new DelayedAuthHook(this), 5L);
|
||||
}
|
||||
|
||||
private AuthenticationBackend initializeAuthenticationBackend() {
|
||||
AuthenticationBackend proxyVerifier = new ProxyAuthentication(this);
|
||||
if (proxyVerifier.isAvailable()) {
|
||||
return proxyVerifier;
|
||||
}
|
||||
|
||||
logger.warn("Disabling Minecraft proxy configuration. Assuming direct connections from now on.");
|
||||
AuthenticationBackend protocolAuthentication = new ProtocolAuthentication(this);
|
||||
if (protocolAuthentication.isAvailable()) {
|
||||
return protocolAuthentication;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerCommands() {
|
||||
@ -182,25 +179,13 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
core.close();
|
||||
}
|
||||
|
||||
if (bungeeManager != null) {
|
||||
bungeeManager.cleanup();
|
||||
if (backend != null) {
|
||||
backend.stop();
|
||||
}
|
||||
|
||||
if (premiumPlaceholder != null && getServer().getPluginManager().isPluginEnabled("PlaceholderAPI")) {
|
||||
try {
|
||||
premiumPlaceholder.unregister();
|
||||
} catch (Exception | NoSuchMethodError exception) {
|
||||
logger.error("Failed to unregister placeholder", exception);
|
||||
}
|
||||
premiumPlaceholder.unregister();
|
||||
}
|
||||
|
||||
if (getServer().getPluginManager().isPluginEnabled("ProtocolLib")) {
|
||||
ProtocolLibrary.getProtocolManager().getAsynchronousManager().unregisterAsyncHandlers(this);
|
||||
}
|
||||
}
|
||||
|
||||
public FastLoginCore<Player, CommandSender, FastLoginBukkit> getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,10 +217,6 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
loginSession.remove(id);
|
||||
}
|
||||
|
||||
public Map<UUID, PremiumStatus> getPremiumPlayers() {
|
||||
return premiumPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the premium status of an online player.
|
||||
* {@snippet :
|
||||
@ -263,24 +244,6 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
return premiumPlayers.getOrDefault(onlinePlayer, PremiumStatus.UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait before the server is fully started. This is workaround, because connections right on startup are not
|
||||
* injected by ProtocolLib
|
||||
*
|
||||
* @return true if ProtocolLib can now intercept packets
|
||||
*/
|
||||
public boolean isServerFullyStarted() {
|
||||
return serverStarted;
|
||||
}
|
||||
|
||||
public void markInitialized() {
|
||||
this.serverStarted = true;
|
||||
}
|
||||
|
||||
public BungeeManager getBungeeManager() {
|
||||
return bungeeManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPluginFolder() {
|
||||
return getDataFolder().toPath();
|
||||
@ -313,12 +276,17 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
return Bukkit.getServer().getPluginManager().getPlugin(name) != null;
|
||||
}
|
||||
|
||||
public FloodgateService getFloodgateService() {
|
||||
return floodgateService;
|
||||
}
|
||||
public void setInitialized(boolean hookFound) {
|
||||
if (backend instanceof ProxyAuthentication) {
|
||||
logger.info("BungeeCord setting detected. No auth plugin is required");
|
||||
} else if (!hookFound) {
|
||||
logger.warn("No auth plugin were found by this plugin "
|
||||
+ "(other plugins could hook into this after the initialization of this plugin)"
|
||||
+ "and BungeeCord is deactivated. "
|
||||
+ "Either one or both of the checks have to pass in order to use this plugin");
|
||||
}
|
||||
|
||||
public GeyserService getGeyserService() {
|
||||
return geyserService;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -326,19 +294,7 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
|
||||
if (floodgateService != null) {
|
||||
return floodgateService;
|
||||
}
|
||||
|
||||
return geyserService;
|
||||
}
|
||||
|
||||
private boolean isPaper() {
|
||||
return isClassAvailable("com.destroystokyo.paper.PaperConfig").isPresent()
|
||||
|| isClassAvailable("io.papermc.paper.configuration.Configuration").isPresent();
|
||||
}
|
||||
|
||||
private Optional<Class<?>> isClassAvailable(String clazzName) {
|
||||
try {
|
||||
return Optional.of(Class.forName(clazzName));
|
||||
} catch (ClassNotFoundException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,44 +23,15 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener.protocolsupport;
|
||||
package com.github.games647.fastlogin.bukkit.auth;
|
||||
|
||||
import com.github.games647.fastlogin.core.shared.LoginSource;
|
||||
import protocolsupport.api.events.PlayerLoginStartEvent;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
public interface AuthenticationBackend {
|
||||
|
||||
public class ProtocolLoginSource implements LoginSource {
|
||||
boolean isAvailable();
|
||||
|
||||
private final PlayerLoginStartEvent loginStartEvent;
|
||||
void init(PluginManager pluginManager);
|
||||
|
||||
public ProtocolLoginSource(PlayerLoginStartEvent loginStartEvent) {
|
||||
this.loginStartEvent = loginStartEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableOnlinemode() {
|
||||
loginStartEvent.setOnlineMode(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kick(String message) {
|
||||
loginStartEvent.denyLogin(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getAddress() {
|
||||
return loginStartEvent.getConnection().getRawAddress();
|
||||
}
|
||||
|
||||
public PlayerLoginStartEvent getLoginStartEvent() {
|
||||
return loginStartEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + '{'
|
||||
+ "loginStartEvent=" + loginStartEvent
|
||||
+ '}';
|
||||
}
|
||||
void stop();
|
||||
}
|
@ -23,23 +23,17 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener;
|
||||
package com.github.games647.fastlogin.bukkit.auth;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.task.FloodgateAuthTask;
|
||||
import com.github.games647.fastlogin.bukkit.task.ForceLoginTask;
|
||||
import com.github.games647.fastlogin.core.hooks.bedrock.FloodgateService;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent.Result;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.metadata.Metadatable;
|
||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||
|
||||
/**
|
||||
@ -56,14 +50,6 @@ public class ConnectionListener implements Listener {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerLogin(PlayerLoginEvent loginEvent) {
|
||||
removeBlockedStatus(loginEvent.getPlayer());
|
||||
if (loginEvent.getResult() == Result.ALLOWED && !plugin.isServerFullyStarted()) {
|
||||
loginEvent.disallow(Result.KICK_OTHER, plugin.getCore().getMessage("not-started"));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onPlayerJoin(PlayerJoinEvent joinEvent) {
|
||||
Player player = joinEvent.getPlayer();
|
||||
@ -102,21 +88,13 @@ public class ConnectionListener implements Listener {
|
||||
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask);
|
||||
}
|
||||
|
||||
plugin.getBungeeManager().markJoinEventFired(player);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent quitEvent) {
|
||||
Player player = quitEvent.getPlayer();
|
||||
|
||||
removeBlockedStatus(player);
|
||||
plugin.getCore().getPendingConfirms().remove(player.getUniqueId());
|
||||
plugin.getPremiumPlayers().remove(player.getUniqueId());
|
||||
plugin.getBungeeManager().cleanup(player);
|
||||
}
|
||||
|
||||
private void removeBlockedStatus(Metadatable player) {
|
||||
player.removeMetadata(plugin.getName(), plugin);
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.task;
|
||||
package com.github.games647.fastlogin.bukkit.auth;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
@ -23,7 +23,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.task;
|
||||
package com.github.games647.fastlogin.bukkit.auth;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
@ -23,7 +23,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit;
|
||||
package com.github.games647.fastlogin.bukkit.auth;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2024 games647 and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.auth;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.auth.protocollib.SkinApplyListener;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class LocalAuthentication implements AuthenticationBackend {
|
||||
|
||||
protected final FastLoginBukkit plugin;
|
||||
|
||||
protected LocalAuthentication(FastLoginBukkit plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(PluginManager pluginManager) {
|
||||
if (!plugin.getCore().setupDatabase()) {
|
||||
plugin.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// if server is using paper - we need to add one more listener to correct the user cache usage
|
||||
if (isPaper()) {
|
||||
pluginManager.registerEvents(new PaperCacheListener(this), this);
|
||||
} else if (plugin.getConfig().getBoolean("forwardSkin")) {
|
||||
//if server is using paper - we need to set the skin at pre login anyway, so no need for this listener
|
||||
pluginManager.registerEvents(new SkinApplyListener(plugin), plugin);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPaper() {
|
||||
return isClassAvailable("com.destroystokyo.paper.PaperConfig").isPresent()
|
||||
|| isClassAvailable("io.papermc.paper.configuration.Configuration").isPresent();
|
||||
}
|
||||
|
||||
private Optional<Class<?>> isClassAvailable(String clazzName) {
|
||||
try {
|
||||
return Optional.of(Class.forName(clazzName));
|
||||
} catch (ClassNotFoundException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener;
|
||||
package com.github.games647.fastlogin.bukkit.auth;
|
||||
|
||||
import com.destroystokyo.paper.profile.ProfileProperty;
|
||||
import com.github.games647.craftapi.model.skin.Textures;
|
@ -23,10 +23,10 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener.protocollib;
|
||||
package com.github.games647.fastlogin.bukkit.auth.protocollib;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey;
|
||||
import com.google.common.hash.Hasher;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.io.Resources;
|
||||
@ -58,8 +58,8 @@ import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Base64.Encoder;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.random.RandomGenerator;
|
||||
|
||||
/**
|
||||
* Encryption and decryption minecraft util for connection between servers
|
||||
|
@ -23,14 +23,14 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener.protocollib;
|
||||
package com.github.games647.fastlogin.bukkit.auth.protocollib;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.core.shared.JoinManagement;
|
||||
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
|
||||
import com.github.games647.fastlogin.core.storage.StoredProfile;
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2024 games647 and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.auth.protocollib;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.auth.LocalAuthentication;
|
||||
import com.github.games647.fastlogin.core.antibot.AntiBotService;
|
||||
import com.github.games647.fastlogin.core.shared.FastLoginCore;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
public class ProtocolAuthentication extends LocalAuthentication implements Listener {
|
||||
|
||||
public ProtocolAuthentication(FastLoginBukkit plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return plugin.getServer().getPluginManager().isPluginEnabled("ProtocolLib");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(PluginManager pluginManager) {
|
||||
pluginManager.registerEvents(this, plugin);
|
||||
|
||||
FastLoginCore<Player, CommandSender, FastLoginBukkit> core = plugin.getCore();
|
||||
AntiBotService antiBotService = core.getAntiBotService();
|
||||
ProtocolLibListener.register(plugin, antiBotService, core.getConfig().getBoolean("verifyClientKeys"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
ProtocolLibrary.getProtocolManager().getAsynchronousManager().unregisterAsyncHandlers(plugin);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerLogin(PlayerLoginEvent loginEvent) {
|
||||
if (loginEvent.getResult() == PlayerLoginEvent.Result.ALLOWED && !plugin.isInitialized()) {
|
||||
loginEvent.disallow(PlayerLoginEvent.Result.KICK_OTHER, plugin.getCore().getMessage("not-started"));
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener.protocollib;
|
||||
package com.github.games647.fastlogin.bukkit.auth.protocollib;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
@ -42,7 +42,7 @@ import com.comphenix.protocol.wrappers.Converters;
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.core.antibot.AntiBotService;
|
||||
import com.github.games647.fastlogin.core.antibot.AntiBotService.Action;
|
||||
import com.mojang.datafixers.util.Either;
|
@ -23,14 +23,14 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener.protocollib;
|
||||
package com.github.games647.fastlogin.bukkit.auth.protocollib;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.core.shared.LoginSource;
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener.protocollib;
|
||||
package com.github.games647.fastlogin.bukkit.auth.protocollib;
|
||||
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
import com.comphenix.protocol.wrappers.WrappedSignedProperty;
|
@ -23,7 +23,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener.protocollib;
|
||||
package com.github.games647.fastlogin.bukkit.auth.protocollib;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
@ -47,8 +47,8 @@ import com.github.games647.craftapi.model.skin.SkinProperty;
|
||||
import com.github.games647.craftapi.resolver.MojangResolver;
|
||||
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.InetUtils;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.bukkit.auth.InetUtils;
|
||||
import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey;
|
||||
import lombok.val;
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener.protocollib.packet;
|
||||
package com.github.games647.fastlogin.bukkit.auth.protocollib.packet;
|
||||
|
||||
import lombok.Value;
|
||||
import lombok.experimental.Accessors;
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2024 games647 and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.auth.proxy;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.auth.AuthenticationBackend;
|
||||
import com.github.games647.fastlogin.core.message.LoginActionMessage;
|
||||
import com.github.games647.fastlogin.core.message.NamespaceKey;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import static com.github.games647.fastlogin.core.message.ChangePremiumMessage.CHANGE_CHANNEL;
|
||||
import static com.github.games647.fastlogin.core.message.SuccessMessage.SUCCESS_CHANNEL;
|
||||
|
||||
public class ProxyAuthentication implements AuthenticationBackend {
|
||||
|
||||
private final FastLoginBukkit plugin;
|
||||
private ProxyVerifier verifier;
|
||||
|
||||
public ProxyAuthentication(FastLoginBukkit plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return detectProxy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(PluginManager pluginManager) {
|
||||
verifier = new ProxyVerifier(plugin);
|
||||
verifier.loadSecrets();
|
||||
|
||||
registerPluginChannels();
|
||||
|
||||
pluginManager.registerEvents(new ProxyConnectionListener(plugin, verifier), plugin);
|
||||
|
||||
plugin.getLog().info("Found enabled proxy configuration");
|
||||
plugin.getLog().info("Remember to follow the proxy guide to complete your setup");
|
||||
}
|
||||
|
||||
private void registerPluginChannels() {
|
||||
Server server = Bukkit.getServer();
|
||||
|
||||
// check for incoming messages from the bungeecord version of this plugin
|
||||
String groupId = plugin.getName();
|
||||
String forceChannel = NamespaceKey.getCombined(groupId, LoginActionMessage.FORCE_CHANNEL);
|
||||
server.getMessenger().registerIncomingPluginChannel(plugin, forceChannel, new ProxyListener(plugin, verifier));
|
||||
|
||||
// outgoing
|
||||
String successChannel = new NamespaceKey(groupId, SUCCESS_CHANNEL).getCombinedName();
|
||||
String changeChannel = new NamespaceKey(groupId, CHANGE_CHANNEL).getCombinedName();
|
||||
server.getMessenger().registerOutgoingPluginChannel(plugin, successChannel);
|
||||
server.getMessenger().registerOutgoingPluginChannel(plugin, changeChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (verifier != null) {
|
||||
verifier.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean detectProxy() {
|
||||
try {
|
||||
if (isProxySupported("org.spigotmc.SpigotConfig", "bungee")) {
|
||||
return true;
|
||||
}
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
// leave stacktrace for class not found out
|
||||
plugin.getLog().warn("Cannot check for BungeeCord support: {}", classNotFoundException.getMessage());
|
||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||
plugin.getLog().warn("Cannot check for BungeeCord support", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
return isVelocityEnabled();
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
plugin.getLog().warn("Cannot check for Velocity support in Paper: {}", classNotFoundException.getMessage());
|
||||
} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) {
|
||||
plugin.getLog().warn("Cannot check for Velocity support in Paper", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isProxySupported(String className, String fieldName)
|
||||
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
|
||||
return Class.forName(className).getDeclaredField(fieldName).getBoolean(null);
|
||||
}
|
||||
|
||||
private boolean isVelocityEnabled()
|
||||
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, ClassNotFoundException,
|
||||
NoSuchMethodException, InvocationTargetException {
|
||||
try {
|
||||
Class<?> globalConfig = Class.forName("io.papermc.paper.configuration.GlobalConfiguration");
|
||||
Object global = globalConfig.getDeclaredMethod("get").invoke(null);
|
||||
Object proxiesConfiguration = global.getClass().getDeclaredField("proxies").get(global);
|
||||
|
||||
Field velocitySectionField = proxiesConfiguration.getClass().getDeclaredField("velocity");
|
||||
Object velocityConfig = velocitySectionField.get(proxiesConfiguration);
|
||||
|
||||
return velocityConfig.getClass().getDeclaredField("enabled").getBoolean(velocityConfig);
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
// try again using the older Paper configuration, because the old class file still exists in newer versions
|
||||
if (isProxySupported("com.destroystokyo.paper.PaperConfig", "velocitySupport")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2024 games647 and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.auth.proxy;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.auth.FloodgateAuthTask;
|
||||
import com.github.games647.fastlogin.bukkit.auth.ForceLoginTask;
|
||||
import com.github.games647.fastlogin.core.hooks.bedrock.FloodgateService;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.metadata.Metadatable;
|
||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||
|
||||
public class ProxyConnectionListener implements Listener {
|
||||
|
||||
private static final long DELAY_LOGIN = 20L / 2;
|
||||
|
||||
private final FastLoginBukkit plugin;
|
||||
private final ProxyVerifier verifier;
|
||||
|
||||
public ProxyConnectionListener(FastLoginBukkit plugin, ProxyVerifier verifier) {
|
||||
this.plugin = plugin;
|
||||
this.verifier = verifier;
|
||||
}
|
||||
|
||||
private void removeBlockedStatus(Metadatable player) {
|
||||
player.removeMetadata(plugin.getName(), plugin);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerLogin(PlayerLoginEvent loginEvent) {
|
||||
removeBlockedStatus(loginEvent.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onPlayerJoin(PlayerJoinEvent joinEvent) {
|
||||
Player player = joinEvent.getPlayer();
|
||||
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||
delayForceLogin(player);
|
||||
// delay the login process to let auth plugins initialize the player
|
||||
// Magic number however as there is no direct event from those plugins
|
||||
}, DELAY_LOGIN);
|
||||
}
|
||||
|
||||
private void delayForceLogin(Player player) {
|
||||
// session exists so the player is ready for force login
|
||||
// cases: Paper (firing BungeeCord message before PlayerJoinEvent) or not running BungeeCord and already
|
||||
// having the login session from the login process
|
||||
BukkitLoginSession session = plugin.getSession(player.spigot().getRawAddress());
|
||||
|
||||
if (session == null) {
|
||||
// Floodgate players usually don't have a session at this point
|
||||
// exception: if force login by bungee message had been delayed
|
||||
FloodgateService floodgateService = plugin.getFloodgateService();
|
||||
if (floodgateService != null) {
|
||||
FloodgatePlayer floodgatePlayer = floodgateService.getBedrockPlayer(player.getUniqueId());
|
||||
if (floodgatePlayer != null) {
|
||||
Runnable floodgateAuthTask = new FloodgateAuthTask(plugin.getCore(), player, floodgatePlayer);
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, floodgateAuthTask);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String sessionId = plugin.getSessionId(player.spigot().getRawAddress());
|
||||
plugin.getLog().info("No on-going login session for player: {} with ID {}. ", player, sessionId);
|
||||
plugin.getLog().info("Setups using Minecraft proxies will start delayed "
|
||||
+ "when the command from the proxy is received");
|
||||
} else {
|
||||
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, forceLoginTask);
|
||||
}
|
||||
|
||||
verifier.markJoinEventFired(player);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent quitEvent) {
|
||||
Player player = quitEvent.getPlayer();
|
||||
|
||||
removeBlockedStatus(player);
|
||||
verifier.cleanup(player);
|
||||
}
|
||||
}
|
@ -23,11 +23,11 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener;
|
||||
package com.github.games647.fastlogin.bukkit.auth.proxy;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.task.ForceLoginTask;
|
||||
import com.github.games647.fastlogin.bukkit.auth.ForceLoginTask;
|
||||
import com.github.games647.fastlogin.core.PremiumStatus;
|
||||
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
|
||||
import com.github.games647.fastlogin.core.message.LoginActionMessage;
|
||||
@ -47,12 +47,14 @@ import java.util.UUID;
|
||||
* This class also receives the plugin message from the bungeecord version of this plugin in order to get notified if
|
||||
* the connection is in online mode.
|
||||
*/
|
||||
public class BungeeListener implements PluginMessageListener {
|
||||
public class ProxyListener implements PluginMessageListener {
|
||||
|
||||
private final FastLoginBukkit plugin;
|
||||
private final ProxyVerifier verifier;
|
||||
|
||||
public BungeeListener(FastLoginBukkit plugin) {
|
||||
public ProxyListener(FastLoginBukkit plugin, ProxyVerifier verifier) {
|
||||
this.plugin = plugin;
|
||||
this.verifier = verifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -79,7 +81,7 @@ public class BungeeListener implements PluginMessageListener {
|
||||
plugin.getLog().warn("Received message {} from a blocked player {}", loginMessage, targetPlayer);
|
||||
} else {
|
||||
UUID sourceId = loginMessage.getProxyId();
|
||||
if (plugin.getBungeeManager().isProxyAllowed(sourceId)) {
|
||||
if (verifier.isProxyAllowed(sourceId)) {
|
||||
readMessage(targetPlayer, loginMessage);
|
||||
} else {
|
||||
plugin.getLog().warn("Received proxy id: {} that doesn't exist in the proxy file", sourceId);
|
||||
@ -127,7 +129,7 @@ public class BungeeListener implements PluginMessageListener {
|
||||
plugin.putSession(player.spigot().getRawAddress(), session);
|
||||
|
||||
// only start a new login task if the join event fired earlier. This event then didn't
|
||||
boolean result = plugin.getBungeeManager().didJoinEventFired(player);
|
||||
boolean result = verifier.didJoinEventFired(player);
|
||||
plugin.getLog().info("Delaying force login until join event fired?: {}", result);
|
||||
if (result) {
|
||||
Runnable forceLoginTask = new ForceLoginTask(plugin.getCore(), player, session);
|
@ -23,22 +23,18 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit;
|
||||
package com.github.games647.fastlogin.bukkit.auth.proxy;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.listener.BungeeListener;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.core.message.ChannelMessage;
|
||||
import com.github.games647.fastlogin.core.message.LoginActionMessage;
|
||||
import com.github.games647.fastlogin.core.message.NamespaceKey;
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageRecipient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
@ -48,11 +44,9 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.github.games647.fastlogin.core.message.ChangePremiumMessage.CHANGE_CHANNEL;
|
||||
import static com.github.games647.fastlogin.core.message.SuccessMessage.SUCCESS_CHANNEL;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
public class BungeeManager {
|
||||
public class ProxyVerifier {
|
||||
|
||||
private static final String LEGACY_FILE_NAME = "proxy-whitelist.txt";
|
||||
private static final String FILE_NAME = "allowed-proxies.txt";
|
||||
@ -61,11 +55,10 @@ public class BungeeManager {
|
||||
private Set<UUID> proxyIds;
|
||||
|
||||
private final FastLoginBukkit plugin;
|
||||
private boolean enabled;
|
||||
|
||||
private final Collection<UUID> firedJoinEvents = new HashSet<>();
|
||||
|
||||
public BungeeManager(FastLoginBukkit plugin) {
|
||||
public ProxyVerifier(FastLoginBukkit plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@ -84,92 +77,13 @@ public class BungeeManager {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
enabled = detectProxy();
|
||||
|
||||
if (enabled) {
|
||||
proxyIds = loadBungeeCordIds();
|
||||
if (proxyIds.isEmpty()) {
|
||||
plugin.getLog().info("No valid IDs found. Minecraft proxy support cannot work in the current state");
|
||||
}
|
||||
|
||||
registerPluginChannels();
|
||||
plugin.getLog().info("Found enabled proxy configuration");
|
||||
plugin.getLog().info("Remember to follow the proxy guide to complete your setup");
|
||||
} else {
|
||||
plugin.getLog().warn("Disabling Minecraft proxy configuration. Assuming direct connections from now on.");
|
||||
public void loadSecrets() {
|
||||
proxyIds = loadBungeeCordIds();
|
||||
if (proxyIds.isEmpty()) {
|
||||
plugin.getLog().info("No valid IDs found. Minecraft proxy support cannot work in the current state");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isProxySupported(String className, String fieldName)
|
||||
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
|
||||
return Class.forName(className).getDeclaredField(fieldName).getBoolean(null);
|
||||
}
|
||||
|
||||
private boolean isVelocityEnabled()
|
||||
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, ClassNotFoundException,
|
||||
NoSuchMethodException, InvocationTargetException {
|
||||
try {
|
||||
Class<?> globalConfig = Class.forName("io.papermc.paper.configuration.GlobalConfiguration");
|
||||
Object global = globalConfig.getDeclaredMethod("get").invoke(null);
|
||||
Object proxiesConfiguration = global.getClass().getDeclaredField("proxies").get(global);
|
||||
|
||||
Field velocitySectionField = proxiesConfiguration.getClass().getDeclaredField("velocity");
|
||||
Object velocityConfig = velocitySectionField.get(proxiesConfiguration);
|
||||
|
||||
return velocityConfig.getClass().getDeclaredField("enabled").getBoolean(velocityConfig);
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
// try again using the older Paper configuration, because the old class file still exists in newer versions
|
||||
if (isProxySupported("com.destroystokyo.paper.PaperConfig", "velocitySupport")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean detectProxy() {
|
||||
try {
|
||||
if (isProxySupported("org.spigotmc.SpigotConfig", "bungee")) {
|
||||
return true;
|
||||
}
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
// leave stacktrace for class not found out
|
||||
plugin.getLog().warn("Cannot check for BungeeCord support: {}", classNotFoundException.getMessage());
|
||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||
plugin.getLog().warn("Cannot check for BungeeCord support", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
return isVelocityEnabled();
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
plugin.getLog().warn("Cannot check for Velocity support in Paper: {}", classNotFoundException.getMessage());
|
||||
} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) {
|
||||
plugin.getLog().warn("Cannot check for Velocity support in Paper", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void registerPluginChannels() {
|
||||
Server server = Bukkit.getServer();
|
||||
|
||||
// check for incoming messages from the bungeecord version of this plugin
|
||||
String groupId = plugin.getName();
|
||||
String forceChannel = NamespaceKey.getCombined(groupId, LoginActionMessage.FORCE_CHANNEL);
|
||||
server.getMessenger().registerIncomingPluginChannel(plugin, forceChannel, new BungeeListener(plugin));
|
||||
|
||||
// outgoing
|
||||
String successChannel = new NamespaceKey(groupId, SUCCESS_CHANNEL).getCombinedName();
|
||||
String changeChannel = new NamespaceKey(groupId, CHANGE_CHANNEL).getCombinedName();
|
||||
server.getMessenger().registerOutgoingPluginChannel(plugin, successChannel);
|
||||
server.getMessenger().registerOutgoingPluginChannel(plugin, changeChannel);
|
||||
}
|
||||
|
||||
private Set<UUID> loadBungeeCordIds() {
|
||||
Path proxiesFile = plugin.getPluginFolder().resolve(FILE_NAME);
|
||||
Path legacyFile = plugin.getPluginFolder().resolve(LEGACY_FILE_NAME);
|
@ -23,15 +23,9 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.task;
|
||||
package com.github.games647.fastlogin.bukkit.hook;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.hook.AuthMeHook;
|
||||
import com.github.games647.fastlogin.bukkit.hook.CrazyLoginHook;
|
||||
import com.github.games647.fastlogin.bukkit.hook.LogItHook;
|
||||
import com.github.games647.fastlogin.bukkit.hook.LoginSecurityHook;
|
||||
import com.github.games647.fastlogin.bukkit.hook.UltraAuthHook;
|
||||
import com.github.games647.fastlogin.bukkit.hook.XAuthHook;
|
||||
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -51,19 +45,7 @@ public class DelayedAuthHook implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean hookFound = isHookFound();
|
||||
if (plugin.getBungeeManager().isEnabled()) {
|
||||
plugin.getLog().info("BungeeCord setting detected. No auth plugin is required");
|
||||
} else if (!hookFound) {
|
||||
plugin.getLog().warn("No auth plugin were found by this plugin "
|
||||
+ "(other plugins could hook into this after the initialization of this plugin)"
|
||||
+ "and BungeeCord is deactivated. "
|
||||
+ "Either one or both of the checks have to pass in order to use this plugin");
|
||||
}
|
||||
|
||||
if (hookFound) {
|
||||
plugin.markInitialized();
|
||||
}
|
||||
plugin.setInitialized(isHookFound());
|
||||
}
|
||||
|
||||
private boolean isHookFound() {
|
@ -1,139 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2024 games647 and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener.protocolsupport;
|
||||
|
||||
import com.github.games647.craftapi.UUIDAdapter;
|
||||
import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
|
||||
import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
|
||||
import com.github.games647.fastlogin.bukkit.event.BukkitFastLoginPreLoginEvent;
|
||||
import com.github.games647.fastlogin.core.antibot.AntiBotService;
|
||||
import com.github.games647.fastlogin.core.antibot.AntiBotService.Action;
|
||||
import com.github.games647.fastlogin.core.shared.JoinManagement;
|
||||
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
|
||||
import com.github.games647.fastlogin.core.storage.StoredProfile;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import protocolsupport.api.events.ConnectionCloseEvent;
|
||||
import protocolsupport.api.events.PlayerLoginStartEvent;
|
||||
import protocolsupport.api.events.PlayerProfileCompleteEvent;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ProtocolSupportListener extends JoinManagement<Player, CommandSender, ProtocolLoginSource>
|
||||
implements Listener {
|
||||
|
||||
private final FastLoginBukkit plugin;
|
||||
private final AntiBotService antiBotService;
|
||||
|
||||
public ProtocolSupportListener(FastLoginBukkit plugin, AntiBotService antiBotService) {
|
||||
super(plugin.getCore(), plugin.getCore().getAuthPluginHook(), plugin.getBedrockService());
|
||||
|
||||
this.plugin = plugin;
|
||||
this.antiBotService = antiBotService;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onLoginStart(PlayerLoginStartEvent loginStartEvent) {
|
||||
if (loginStartEvent.isLoginDenied() || plugin.getCore().getAuthPluginHook() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String username = loginStartEvent.getConnection().getProfile().getName();
|
||||
InetSocketAddress address = loginStartEvent.getConnection().getRawAddress();
|
||||
plugin.getLog().info("Incoming login request for {} from {}", username, address);
|
||||
|
||||
Action action = antiBotService.onIncomingConnection(address, username);
|
||||
switch (action) {
|
||||
case Ignore:
|
||||
// just ignore
|
||||
return;
|
||||
case Block:
|
||||
String message = plugin.getCore().getMessage("kick-antibot");
|
||||
loginStartEvent.denyLogin(message);
|
||||
break;
|
||||
case Continue:
|
||||
default:
|
||||
//remove old data every time on a new login in order to keep the session only for one person
|
||||
plugin.removeSession(address);
|
||||
|
||||
ProtocolLoginSource source = new ProtocolLoginSource(loginStartEvent);
|
||||
super.onLogin(username, source);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onConnectionClosed(ConnectionCloseEvent closeEvent) {
|
||||
InetSocketAddress address = closeEvent.getConnection().getRawAddress();
|
||||
plugin.removeSession(address);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPropertiesResolve(PlayerProfileCompleteEvent profileCompleteEvent) {
|
||||
InetSocketAddress address = profileCompleteEvent.getConnection().getRawAddress();
|
||||
|
||||
BukkitLoginSession session = plugin.getSession(address);
|
||||
|
||||
if (session != null && profileCompleteEvent.getConnection().getProfile().isOnlineMode()) {
|
||||
session.setVerifiedPremium(true);
|
||||
|
||||
if (!plugin.getConfig().getBoolean("premiumUuid")) {
|
||||
String username = Optional.ofNullable(profileCompleteEvent.getForcedName())
|
||||
.orElse(profileCompleteEvent.getConnection().getProfile().getName());
|
||||
profileCompleteEvent.setForcedUUID(UUIDAdapter.generateOfflineId(username));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastLoginPreLoginEvent callFastLoginPreLoginEvent(String username, ProtocolLoginSource source,
|
||||
StoredProfile profile) {
|
||||
BukkitFastLoginPreLoginEvent event = new BukkitFastLoginPreLoginEvent(username, source, profile);
|
||||
plugin.getServer().getPluginManager().callEvent(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestPremiumLogin(ProtocolLoginSource source, StoredProfile profile, String username,
|
||||
boolean registered) {
|
||||
source.enableOnlinemode();
|
||||
|
||||
String ip = source.getAddress().getAddress().getHostAddress();
|
||||
plugin.getCore().addLoginAttempt(ip, username);
|
||||
|
||||
BukkitLoginSession playerSession = new BukkitLoginSession(username, registered, profile);
|
||||
plugin.putSession(source.getAddress(), playerSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startCrackedSession(ProtocolLoginSource source, StoredProfile profile, String username) {
|
||||
BukkitLoginSession loginSession = new BukkitLoginSession(username, profile);
|
||||
plugin.putSession(source.getAddress(), loginSession);
|
||||
}
|
||||
}
|
@ -25,8 +25,9 @@
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener.protocollib;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.bukkit.auth.protocollib.protocollib.EncryptionUtil;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.SignatureTestData.SignatureData;
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
|
||||
import com.google.common.hash.Hashing;
|
||||
import lombok.val;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -25,7 +25,7 @@
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.listener.protocollib;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.listener.protocollib.packet.ClientPublicKey;
|
||||
import com.github.games647.fastlogin.bukkit.auth.protocollib.packet.ClientPublicKey;
|
||||
import com.google.common.io.Resources;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
package com.github.games647.fastlogin.bukkit.task;
|
||||
|
||||
import com.github.games647.fastlogin.bukkit.hook.DelayedAuthHook;
|
||||
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
|
||||
import lombok.val;
|
||||
import org.bukkit.entity.Player;
|
||||
|
Reference in New Issue
Block a user