Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,3 @@ updates:
# Plugin require special evaluation about their compatibility
- "com.lenis0012.bukkit:loginsecurity"
- "com.comphenix.protocol:ProtocolLib"

ignore:
# HikariCP dropped Java 8 support with 5.0
- dependency-name: "com.zaxxer:HikariCP"
update-types: ["version-update:semver-major"]
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
if: ${{ github.event.workflow_run.conclusion == 'success' }}

permissions:
# Only allow write for security, then all others default to read only
# Only allow 'write' permission for security, then all others default to read only
security-events: write

strategy:
Expand Down
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
# 2.0

## Major changes

* Bumped minimum Java version to 11 make use of modern Java performance features
* Report back if really still need the old versions
* Then we could make use of versioned code, but that requires more coding effort

## Added

* Support for HTTP/2 for contacting Mojang

## Changed

* Updated many dependencies

## 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
* Dropped support for ProtocolSupport seems to unsupported

[...] A lot of changes

### 1.11

* TODO: Replace reflection with methodhandles
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -55,6 +53,8 @@
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
Expand All @@ -71,18 +71,30 @@ 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 final Collection<UUID> pendingConfirms = new HashSet<>();

@Getter
private FastLoginCore<Player, CommandSender, FastLoginBukkit> core;

@Getter
private FloodgateService floodgateService;
private GeyserService geyserService;

private PremiumPlaceholder premiumPlaceholder;

@Getter
private AuthenticationBackend backend;

@Getter
private boolean initialized;

public FastLoginBukkit() {
this.logger = CommonUtil.initializeLoggerService(getLogger());
this.scheduler = new BukkitScheduler(this, logger);
Expand All @@ -104,51 +116,42 @@ public void onEnable() {
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() {
Expand Down Expand Up @@ -182,27 +185,15 @@ public void onDisable() {
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);
}
}

if (getServer().getPluginManager().isPluginEnabled("ProtocolLib")) {
ProtocolLibrary.getProtocolManager().getAsynchronousManager().unregisterAsyncHandlers(this);
premiumPlaceholder.unregister();
}
}

public FastLoginCore<Player, CommandSender, FastLoginBukkit> getCore() {
return core;
}

/**
* Gets a thread-safe map about players which are connecting to the server are being checked to be premium (paid
* account)
Expand Down Expand Up @@ -232,10 +223,6 @@ public void removeSession(InetSocketAddress address) {
loginSession.remove(id);
}

public Map<UUID, PremiumStatus> getPremiumPlayers() {
return premiumPlayers;
}

/**
* Fetches the premium status of an online player.
* {@snippet :
Expand Down Expand Up @@ -263,24 +250,6 @@ public Map<UUID, PremiumStatus> getPremiumPlayers() {
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();
Expand Down Expand Up @@ -313,32 +282,29 @@ public boolean isPluginInstalled(String name) {
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");
}

initialized = true;
}

public GeyserService getGeyserService() {
return geyserService;
public ProxyAuthentication getBungeeManager() {
return (ProxyAuthentication) backend;
}

@Override
public BedrockService<?> getBedrockService() {
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();
}
return geyserService;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Loading