Encapsulate floodgate hooks

Related #619
Related #620
This commit is contained in:
games647
2021-10-05 15:35:43 +02:00
parent 11c91e6428
commit a3bf875976
9 changed files with 157 additions and 107 deletions

View File

@@ -27,23 +27,56 @@ package com.github.games647.fastlogin.core.hooks;
import com.github.games647.craftapi.model.Profile;
import com.github.games647.craftapi.resolver.RateLimitException;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.LoginSource;
import java.io.IOException;
import java.util.Locale;
import java.util.Optional;
import java.util.UUID;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
public class FloodgateHook<P extends C, C, S extends LoginSource> {
public class FloodgateService {
private final FastLoginCore<P, C, ?> core;
private final FastLoginCore<?, ?, ?> core;
public FloodgateHook(FastLoginCore<P, C, ?> core) {
public FloodgateService(FastLoginCore<?, ?, ?> core) {
this.core = core;
}
/**
* Checks if a config entry (related to Floodgate) is valid. <br>
* Writes to Log if the value is invalid.
* <p>
* This should be used for:
* <ul>
* <li>allowFloodgateNameConflict
* <li>autoLoginFloodgate
* <li>autoRegisterFloodgate
* </ul>
* </p>
*
* @param key the key of the entry in config.yml
* @return <b>true</b> if the entry's value is "true", "false", or "linked"
*/
public boolean isValidFloodgateConfigString(String key) {
String value = core.getConfig().get(key).toString().toLowerCase(Locale.ENGLISH);
if (!value.equals("true") && !value.equals("linked") && !value.equals("false") && !value.equals("no-conflict")) {
core.getPlugin().getLog().error("Invalid value detected for {} in FastLogin/config.yml.", key);
return false;
}
return true;
}
public boolean isUsernameForbidden(StoredProfile profile) {
String playerPrefix = FloodgateApi.getInstance().getPlayerPrefix();
return profile.getName().startsWith(playerPrefix) && !playerPrefix.isEmpty();
}
/**
* Check if the player's name conflicts an existing Java player's name, and
* kick them if it does
@@ -55,10 +88,10 @@ public class FloodgateHook<P extends C, C, S extends LoginSource> {
String allowConflict = core.getConfig().get("allowFloodgateNameConflict").toString().toLowerCase();
// check if the Bedrock player is linked to a Java account
boolean isLinked = ((FloodgatePlayer) floodgatePlayer).getLinkedPlayer() != null;
boolean isLinked = floodgatePlayer.getLinkedPlayer() != null;
if (allowConflict.equals("false")
|| allowConflict.equals("linked") && !isLinked) {
if ("false".equals(allowConflict)
|| "linked".equals(allowConflict) && !isLinked) {
// check for conflicting Premium Java name
Optional<Profile> premiumUUID = Optional.empty();
@@ -66,13 +99,13 @@ public class FloodgateHook<P extends C, C, S extends LoginSource> {
premiumUUID = core.getResolver().findProfile(username);
} catch (IOException | RateLimitException e) {
core.getPlugin().getLog().error(
"Could not check wether Floodgate Player {}'s name conflicts a premium Java player's name.",
"Could not check whether Floodgate Player {}'s name conflicts a premium Java player's name.",
username);
try {
source.kick("Could not check if your name conflicts an existing premium Java account's name.\n"
+ "This is usually a serverside error.");
} catch (Exception e1) {
core.getPlugin().getLog().error("Could not kick Player {}", username);
} catch (Exception ex) {
core.getPlugin().getLog().error("Could not kick Player {}", username, ex);
}
}
@@ -81,8 +114,8 @@ public class FloodgateHook<P extends C, C, S extends LoginSource> {
username);
try {
source.kick("Your name conflicts an existing premium Java account's name");
} catch (Exception e) {
core.getPlugin().getLog().error("Could not kick Player {}", username);
} catch (Exception ex) {
core.getPlugin().getLog().error("Could not kick Player {}", username, ex);
}
}
} else {
@@ -99,14 +132,25 @@ public class FloodgateHook<P extends C, C, S extends LoginSource> {
* @return FloodgatePlayer if found, null otherwise
*/
public FloodgatePlayer getFloodgatePlayer(String username) {
if (core.getPlugin().isPluginInstalled("floodgate")) {
for (FloodgatePlayer floodgatePlayer : FloodgateApi.getInstance().getPlayers()) {
if (floodgatePlayer.getUsername().equals(username)) {
return floodgatePlayer;
}
for (FloodgatePlayer floodgatePlayer : FloodgateApi.getInstance().getPlayers()) {
if (floodgatePlayer.getUsername().equals(username)) {
return floodgatePlayer;
}
}
return null;
}
public FloodgatePlayer getFloodgatePlayer(UUID uuid) {
return FloodgateApi.getInstance().getPlayer(uuid);
}
public boolean isFloodgatePlayer(UUID uuid) {
return getFloodgatePlayer(uuid) != null;
}
public boolean isFloodgateConnection(String username) {
return getFloodgatePlayer(username) != null;
}
}

View File

@@ -27,13 +27,13 @@ package com.github.games647.fastlogin.core.shared;
import com.github.games647.craftapi.resolver.MojangResolver;
import com.github.games647.craftapi.resolver.http.RotatingProxySelector;
import com.github.games647.fastlogin.core.storage.MySQLStorage;
import com.github.games647.fastlogin.core.storage.SQLStorage;
import com.github.games647.fastlogin.core.CommonUtil;
import com.github.games647.fastlogin.core.RateLimiter;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.hooks.DefaultPasswordGenerator;
import com.github.games647.fastlogin.core.hooks.PasswordGenerator;
import com.github.games647.fastlogin.core.storage.MySQLStorage;
import com.github.games647.fastlogin.core.storage.SQLStorage;
import com.github.games647.fastlogin.core.storage.SQLiteStorage;
import com.google.common.net.HostAndPort;
import com.zaxxer.hikari.HikariConfig;

View File

@@ -29,26 +29,25 @@ import com.github.games647.craftapi.model.Profile;
import com.github.games647.craftapi.resolver.RateLimitException;
import com.github.games647.fastlogin.core.StoredProfile;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.hooks.FloodgateHook;
import com.github.games647.fastlogin.core.hooks.FloodgateService;
import com.github.games647.fastlogin.core.shared.event.FastLoginPreLoginEvent;
import java.util.Optional;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import net.md_5.bungee.config.Configuration;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
protected final FastLoginCore<P, C, ?> core;
protected final AuthPlugin<P> authHook;
private final FloodgateHook<P, C, ?> floodgateHook;
private final FloodgateService floodgateService;
public JoinManagement(FastLoginCore<P, C, ?> core, AuthPlugin<P> authHook) {
public JoinManagement(FastLoginCore<P, C, ?> core, AuthPlugin<P> authHook, FloodgateService floodService) {
this.core = core;
this.authHook = authHook;
this.floodgateHook = new FloodgateHook<>(core);
this.floodgateService = floodService;
}
public void onLogin(String username, S source) {
@@ -59,12 +58,14 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
}
//check if the player is connecting through Floodgate
FloodgatePlayer floodgatePlayer = floodgateHook.getFloodgatePlayer(username);
if (floodgatePlayer != null) {
floodgateHook.checkFloodgateNameConflict(username, source, floodgatePlayer);
return;
if (floodgateService != null) {
if (floodgateService.isFloodgateConnection(username)) {
floodgateService.checkFloodgateNameConflict(username, source, floodgatePlayer);
// skip flow for any floodgate player
return;
}
}
callFastLoginPreLoginEvent(username, source, profile);
Configuration config = core.getConfig();
@@ -77,12 +78,9 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
core.getPlugin().getLog().info("Requesting premium login for registered player: {}", username);
requestPremiumLogin(source, profile, username, true);
} else {
if (profile.getName().startsWith(FloodgateApi.getInstance().getPlayerPrefix())&&!FloodgateApi.getInstance().getPlayerPrefix().isEmpty()) {
core.getPlugin().getLog().info("Floodgate Prefix detected on cracked player");
source.kick("Your username contains illegal characters");
return;
if (isValidUsername(source, profile)) {
startCrackedSession(source, profile, username);
}
startCrackedSession(source, profile, username);
}
} else {
if (core.getPendingLogin().remove(ip + username) != null && config.get("secondAttemptCracked", false)) {
@@ -120,6 +118,16 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
}
}
protected boolean isValidUsername(LoginSource source, StoredProfile profile) throws Exception {
if (floodgateService != null && floodgateService.isUsernameForbidden(profile)) {
core.getPlugin().getLog().info("Floodgate Prefix detected on cracked player");
source.kick("Your username contains illegal characters");
return false;
}
return true;
}
private boolean checkPremiumName(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))) {

View File

@@ -26,6 +26,7 @@
package com.github.games647.fastlogin.core.shared;
import com.github.games647.fastlogin.core.AsyncScheduler;
import com.github.games647.fastlogin.core.hooks.FloodgateService;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.nio.file.Path;
@@ -53,6 +54,8 @@ public interface PlatformPlugin<C> {
}
}
FloodgateService getFloodgateService();
default ThreadFactory getThreadFactory() {
return new ThreadFactoryBuilder()
.setNameFormat(getName() + " Pool Thread #%1$d")