diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index f4dd1cb..ad0d183 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -12,12 +12,13 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'zulu' - cache: maven + cache: 'maven' + cache-dependency-path: '**/pom.xml' # Add this line - name: Set up Maven uses: stCarolas/setup-maven@v5 with: @@ -29,5 +30,10 @@ jobs: - name: Upload AntiVPN uses: actions/upload-artifact@v4 with: - name: AntiVPN + name: AntiVPN-Universal path: Universal/target/AntiVPN-*.jar + - name: Upload Sponge plugin + uses: actions/upload-artifact@v4 + with: + name: AntiVPN-Sponge + path: Sponge/target/Sponge-*.jar diff --git a/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitListener.java b/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitListener.java index 1ded919..9c51ef6 100644 --- a/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitListener.java +++ b/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitListener.java @@ -1,33 +1,27 @@ package dev.brighten.antivpn.bukkit; -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; import dev.brighten.antivpn.AntiVPN; import dev.brighten.antivpn.api.APIPlayer; +import dev.brighten.antivpn.api.CheckResult; +import dev.brighten.antivpn.api.OfflinePlayer; import dev.brighten.antivpn.api.VPNExecutor; import dev.brighten.antivpn.message.VpnString; -import dev.brighten.antivpn.web.objects.VPNResponse; +import dev.brighten.antivpn.utils.StringUtil; +import dev.brighten.antivpn.utils.Tuple; import net.md_5.bungee.api.ChatColor; import org.bukkit.Bukkit; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; 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.scheduler.BukkitRunnable; -import java.util.UUID; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; @SuppressWarnings("unchecked") public class BukkitListener extends VPNExecutor implements Listener { - private final Cache responseCache = Caffeine.newBuilder() - .expireAfterWrite(5, TimeUnit.MINUTES) - .maximumSize(2000) - .build(); @Override public void registerListeners() { @@ -50,6 +44,12 @@ public class BukkitListener extends VPNExecutor implements Listener { Bukkit.getLogger().log(Level.SEVERE, message, ex); } + @Override + public void runCommand(String command) { + Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), + ChatColor.translateAlternateColorCodes('&', command)); + } + @Override public void disablePlugin() { HandlerList.unregisterAll(this); @@ -57,6 +57,63 @@ public class BukkitListener extends VPNExecutor implements Listener { } @EventHandler(priority = EventPriority.HIGH) + public void onLogin(final PlayerLoginEvent event) { + APIPlayer player = AntiVPN.getInstance().getPlayerExecutor().getPlayer(event.getPlayer().getUniqueId()) + .orElse(new OfflinePlayer( + event.getPlayer().getUniqueId(), + event.getPlayer().getName(), + event.getAddress() + )); + + CheckResult instantResult = player.checkPlayer(result -> { + if(!result.resultType().isShouldBlock()) return; + + AntiVPN.getInstance().getExecutor().log(Level.INFO, "Adding %s to kick", event.getPlayer().getName()); + AntiVPN.getInstance().getExecutor().getToKick().add(new Tuple<>(result, event.getPlayer().getUniqueId())); + }); + + if(!instantResult.resultType().isShouldBlock()) return; + + AntiVPN.getInstance().getExecutor().getToKick() + .add(new Tuple<>(instantResult, event.getPlayer().getUniqueId())); + + if(!AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) { + return; + } + + AntiVPN.getInstance().getExecutor().log(Level.INFO, "%s was kicked from pre-login cache with IP %s", event.getPlayer().getName(), instantResult.response().getIp()); + + event.setResult(PlayerLoginEvent.Result.KICK_BANNED); + switch (instantResult.resultType()) { + case DENIED_COUNTRY -> event.setKickMessage(StringUtil.translateAlternateColorCodes('&', + StringUtil.varReplace( + AntiVPN.getInstance().getVpnConfig().countryVanillaKickReason(), + player, + instantResult.response() + ))); + case DENIED_PROXY -> { + if(AntiVPN.getInstance().getVpnConfig().alertToStaff()) { + AntiVPN.getInstance().getPlayerExecutor().getOnlinePlayers().stream() + .filter(APIPlayer::isAlertsEnabled) + .forEach(pl -> + pl.sendMessage(StringUtil.varReplace( + ChatColor.translateAlternateColorCodes( + '&', + AntiVPN.getInstance().getVpnConfig().alertMessage()), + player, + instantResult.response()))); + } + event.setKickMessage(StringUtil.translateAlternateColorCodes('&', + StringUtil.varReplace( + AntiVPN.getInstance().getVpnConfig().getKickString(), + player, + instantResult.response() + ))); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR) public void onJoin(final PlayerJoinEvent event) { AntiVPN.getInstance().getPlayerExecutor().getPlayer(event.getPlayer().getUniqueId()) .ifPresent(player -> AntiVPN.getInstance().getDatabase().alertsState(player.getUuid(), enabled -> { @@ -67,142 +124,6 @@ public class BukkitListener extends VPNExecutor implements Listener { .getFormattedMessage(new VpnString.Var<>("state", true))); } })); - - String address; - - if(event.getPlayer().getAddress() != null) { - address = event.getPlayer().getAddress().getAddress().getHostAddress(); - } else { - log(Level.WARNING, "Player %s address is null! This is a bug and should be reported!", event.getPlayer().getName()); - return; - } - - if(event.getPlayer().hasPermission("antivpn.bypass") //Has bypass permission - || AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId()) //Is exempt - //Or has a name that starts with a certain prefix. This is for Bedrock exempting. - || AntiVPN.getInstance().getExecutor().isWhitelisted(address) - || AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream() - .anyMatch(prefix -> event.getPlayer().getName().startsWith(prefix))) return; - - if(responseCache.asMap().containsKey(event.getPlayer().getUniqueId())) { - VPNResponse cached = responseCache.getIfPresent(event.getPlayer().getUniqueId()); - - if (cached != null && cached.isProxy()) { - proxyKick(event.getPlayer(), cached); - return; - } - } - - final Player player = event.getPlayer(); - checkIp(address).thenAccept(result -> { - if(result.isSuccess()) { - //We need to run on main thread or kicking and running commands will cause errors - //If the player is whitelisted, we don't want to kick them - if(AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId())) { - log("UUID is whitelisted: %s", event.getPlayer().getUniqueId().toString()); - return; - } - - //If the IP is whitelisted, we don't want to kick them - if (AntiVPN.getInstance().getExecutor().isWhitelisted(address)) { - log("IP is whitelisted: %s", - address); - return; - } - - // If the countryList() size is zero, no need to check. - // Running country check first - if(!AntiVPN.getInstance().getVpnConfig().countryList().isEmpty() - // This bit of code will decide whether to kick the player - // If contains the code, and set to whitelist, it will not kick as they are equal - // and vise versa. However, if the contains does not match the state, it will kick. - && AntiVPN.getInstance().getVpnConfig().countryList() - .contains(result.getCountryCode()) - != AntiVPN.getInstance().getVpnConfig().whitelistCountries()) { - countryKick(player, result); - } else if(result.isProxy()) { - proxyKick(player, result); - } - } else { - log(Level.WARNING, - "The API query was not a success! " + - "You may need to upgrade your license on https://funkemunky.cc/shop"); - } - AntiVPN.getInstance().checked++; - }); - } - - private void countryKick(Player player, VPNResponse result) { - final String kickReason = AntiVPN.getInstance().getVpnConfig() - .countryVanillaKickReason(); - //Using our built-in kicking system if no commands are configured - if(AntiVPN.getInstance().getVpnConfig().countryKickCommands().isEmpty()) { - // Kicking our player - new BukkitRunnable() { - public void run() { - player.kickPlayer(ChatColor - .translateAlternateColorCodes('&', - kickReason - .replace("%player%", player.getName()) - .replace("%country%", result.getCountryName()) - .replace("%code%", result.getCountryCode()))); - } - }.runTask(BukkitPlugin.pluginInstance); - } else { - final String playerName = player.getName(); - - BukkitPlugin.pluginInstance.getPlayerCommandRunner() - .addAction(player.getUniqueId(), () -> { - for (String cmd : AntiVPN.getInstance().getVpnConfig().countryKickCommands()) { - final String formattedCommand = ChatColor.translateAlternateColorCodes('&', - cmd.replace("%player%", playerName) - .replace("%country%", result.getCountryName()) - .replace("%code%", result.getCountryCode())); - - // Runs our command from console - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), formattedCommand); - } - }); - } - } - - private void proxyKick(Player player, VPNResponse result) { - log(Level.INFO, player.getName() - + " joined on a VPN/Proxy (" + result.getMethod() + ")"); - - //Ensuring the user wishes to alert to staff - if(AntiVPN.getInstance().getVpnConfig().alertToStaff()) - AntiVPN.getInstance().getPlayerExecutor().getOnlinePlayers().stream() - .filter(APIPlayer::isAlertsEnabled) - .forEach(pl -> pl.sendMessage(AntiVPN.getInstance().getVpnConfig().alertMessage() - .replace("%player%", player.getName()) - .replace("%reason%", result.getMethod()) - .replace("%country%", result.getCountryName()) - .replace("%city%", result.getCity()))); - - if(AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) { - new BukkitRunnable() { - public void run() { - player.kickPlayer(org.bukkit.ChatColor.translateAlternateColorCodes('&', - AntiVPN.getInstance().getVpnConfig().getKickString())); - } - }.runTask(BukkitPlugin.pluginInstance); - } else { - //In case the user wants to run their own commands instead of using the built-in kicking - if(AntiVPN.getInstance().getVpnConfig().runCommands()) { - String playerName = player.getName(); - BukkitPlugin.pluginInstance.getPlayerCommandRunner() - .addAction(player.getUniqueId(), () -> { - for (String command : AntiVPN.getInstance().getVpnConfig().commands()) { - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), - ChatColor.translateAlternateColorCodes('&', - command.replace("%player%", - playerName))); - } - }); - } - AntiVPN.getInstance().detections++; - } } @EventHandler diff --git a/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeListener.java b/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeListener.java index ea8344b..ae5c12e 100644 --- a/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeListener.java +++ b/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeListener.java @@ -1,34 +1,27 @@ package dev.brighten.antivpn.bungee; -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; import dev.brighten.antivpn.AntiVPN; -import dev.brighten.antivpn.api.APIPlayer; -import dev.brighten.antivpn.api.VPNExecutor; -import dev.brighten.antivpn.web.objects.VPNResponse; +import dev.brighten.antivpn.api.*; +import dev.brighten.antivpn.utils.MiscUtils; +import dev.brighten.antivpn.utils.StringUtil; +import dev.brighten.antivpn.utils.Tuple; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.event.PlayerDisconnectEvent; -import net.md_5.bungee.api.event.PostLoginEvent; import net.md_5.bungee.api.event.PreLoginEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.scheduler.ScheduledTask; import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventPriority; +import java.net.InetSocketAddress; import java.util.UUID; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; public class BungeeListener extends VPNExecutor implements Listener { private ScheduledTask cacheResetTask; - private final Cache responseCache = Caffeine.newBuilder() - .expireAfterWrite(5, TimeUnit.MINUTES) - .maximumSize(2000) - .build(); - @Override public void registerListeners() { BungeePlugin.pluginInstance.getProxy().getPluginManager() @@ -50,10 +43,16 @@ public class BungeeListener extends VPNExecutor implements Listener { BungeePlugin.pluginInstance.getProxy().getLogger().log(Level.SEVERE, message, ex); } + @Override + public void runCommand(String command) { + BungeePlugin.pluginInstance.getProxy().getPluginManager() + .dispatchCommand(BungeePlugin.pluginInstance.getProxy().getConsole(), command); + } + @Override public void disablePlugin() { BungeePlugin.pluginInstance.getProxy().getPluginManager().unregisterListeners(BungeePlugin.pluginInstance); - if(cacheResetTask != null) { + if (cacheResetTask != null) { cacheResetTask.cancel(); cacheResetTask = null; } @@ -61,115 +60,56 @@ public class BungeeListener extends VPNExecutor implements Listener { BungeePlugin.pluginInstance.onDisable(); } - @EventHandler(priority = EventPriority.LOWEST) + @EventHandler(priority = EventPriority.HIGH) public void onListener(final PreLoginEvent event) { - if(!responseCache.asMap().containsKey(event.getConnection().getUniqueId())) return; - VPNResponse cached = responseCache.getIfPresent(event.getConnection().getUniqueId()); + APIPlayer player = AntiVPN.getInstance().getPlayerExecutor().getPlayer(event.getConnection().getUniqueId()) + .orElseGet(() -> { + UUID uuid = MiscUtils.lookupUUID(event.getConnection().getName()); + AntiVPN.getInstance().getExecutor().log(Level.INFO, "Getting offline player for %s with name %s", + event.getConnection().getUniqueId(), uuid); - if(cached != null && cached.isProxy()) { - event.setCancelled(true); - event.setReason(TextComponent.fromLegacy(ChatColor - .translateAlternateColorCodes('&', - AntiVPN.getInstance().getVpnConfig().getKickString()))); - AntiVPN.getInstance().getExecutor().log(Level.INFO, - "%s was kicked from pre-login proxy cache.", - event.getConnection().getName()); - } - } - - @EventHandler(priority = EventPriority.LOWEST) - public void onListener(final PostLoginEvent event) { - if(event.getPlayer().hasPermission("antivpn.bypass") //Has bypass permission - || AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream() - .anyMatch(prefix -> event.getPlayer().getName().startsWith(prefix))) return; - - String address = event.getPlayer().getSocketAddress().toString(); - - if(AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId())) { - AntiVPN.getInstance().getExecutor().log("UUID is whitelisted: %s", - event.getPlayer().getUniqueId().toString()); - return; - } - - //If the IP is whitelisted, we don't want to kick them - if(AntiVPN.getInstance().getExecutor().isWhitelisted(address)) { - AntiVPN.getInstance().getExecutor().log("IP is whitelisted: %s", address); - return; - } - - checkIp(address) - .thenAccept(result -> { - if(result.isSuccess()) { - //If the player is whitelisted, we don't want to kick them - responseCache.put(event.getPlayer().getUniqueId(), result); - if(!AntiVPN.getInstance().getVpnConfig().countryList().isEmpty() - // This bit of code will decide whether or not to kick the player - // If it contains the code and it is set to whitelist, it will not kick as they are equal - // and vise versa. However, if the contains does not match the state, it will kick. - && AntiVPN.getInstance().getVpnConfig().countryList() - .contains(result.getCountryCode()) != AntiVPN.getInstance().getVpnConfig().whitelistCountries()) { - //Using our built in kicking system if no commands are configured - if(AntiVPN.getInstance().getVpnConfig().countryKickCommands().isEmpty()) { - final String kickReason = AntiVPN.getInstance().getVpnConfig() - .countryVanillaKickReason(); - // Kicking our player - event.getPlayer().disconnect(TextComponent.fromLegacy(ChatColor - .translateAlternateColorCodes('&', - kickReason - .replace("%player%", event.getPlayer().getName()) - .replace("%country%", result.getCountryName()) - .replace("%code%", result.getCountryCode())))); - } else { - for (String cmd : AntiVPN.getInstance().getVpnConfig().countryKickCommands()) { - final String formattedCommand = ChatColor.translateAlternateColorCodes('&', - cmd.replace("%player%", event.getPlayer().getName()) - .replace("%country%", result.getCountryName()) - .replace("%code%", result.getCountryCode())); - - // Runs our command from console - BungeePlugin.pluginInstance.getProxy().getPluginManager().dispatchCommand( - BungeePlugin.pluginInstance.getProxy().getConsole(), formattedCommand); - } - } - } else if(result.isProxy()) { - if(AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) - event.getPlayer().disconnect(TextComponent.fromLegacy(ChatColor - .translateAlternateColorCodes('&', - AntiVPN.getInstance().getVpnConfig().getKickString()))); - BungeePlugin.pluginInstance.getProxy().getLogger().info(event.getPlayer().getName() - + " joined on a VPN/Proxy (" + result.getMethod() + ")"); - - if(AntiVPN.getInstance().getVpnConfig().alertToStaff()) //Ensuring the user wishes to alert to staff - AntiVPN.getInstance().getPlayerExecutor().getOnlinePlayers().stream() - .filter(APIPlayer::isAlertsEnabled) - .forEach(pl -> pl.sendMessage(AntiVPN.getInstance().getVpnConfig() - .alertMessage() - .replace("%player%", event.getPlayer().getName()) - .replace("%reason%", result.getMethod()) - .replace("%country%", result.getCountryName()) - .replace("%city%", result.getCity()))); - - //In case the user wants to run their own commands instead of using the built in kicking - if(AntiVPN.getInstance().getVpnConfig().runCommands()) { - for (String command : AntiVPN.getInstance().getVpnConfig().commands()) { - BungeePlugin.pluginInstance.getProxy().getPluginManager() - .dispatchCommand(BungeePlugin.pluginInstance.getProxy().getConsole(), - ChatColor.translateAlternateColorCodes('&', - command.replace("%player%", event.getPlayer().getName()))); - } - } - AntiVPN.getInstance().detections++; - } - - } else { - BungeePlugin.pluginInstance.getProxy().getLogger() - .log(Level.WARNING, - "The API query was not a success! " + - "You may need to upgrade your license on https://funkemunky.cc/shop"); - } - AntiVPN.getInstance().checked++; + return new OfflinePlayer(uuid, event.getConnection().getName(), + ((InetSocketAddress) event.getConnection().getSocketAddress()).getAddress()); }); + + CheckResult instantResult = player.checkPlayer(result -> { + if (!result.resultType().isShouldBlock()) return; + AntiVPN.getInstance().getExecutor().getToKick() + .add(new Tuple<>(result, player.getUuid())); + }); + + if (!instantResult.resultType().isShouldBlock()) { + return; + } + + AntiVPN.getInstance().getExecutor().getToKick() + .add(new Tuple<>(instantResult, player.getUuid())); + + if (!AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) { + return; + } + + event.setCancelled(true); + AntiVPN.getInstance().getExecutor().log(Level.INFO, + "%s was kicked from pre-login proxy cache.", + event.getConnection().getName()); + + + switch (instantResult.resultType()) { + case DENIED_PROXY -> event.setReason(TextComponent.fromLegacy(ChatColor + .translateAlternateColorCodes('&', + StringUtil.varReplace( + AntiVPN.getInstance().getVpnConfig().getKickString(), + player, + instantResult.response())))); + case DENIED_COUNTRY -> event.setReason(TextComponent.fromLegacy(ChatColor + .translateAlternateColorCodes('&', + StringUtil.varReplace( + AntiVPN.getInstance().getVpnConfig().countryVanillaKickReason(), + player, + instantResult.response())))); + } } @EventHandler diff --git a/Common/pom.xml b/Common/pom.xml index 0854ccd..dec5693 100644 --- a/Common/pom.xml +++ b/Common/pom.xml @@ -57,6 +57,10 @@ dev.brighten.antivpn.depends.MavenLibraries + + com.github.benmanes.caffeine + dev.brighten.antivpn.shaded.com.github.benmanes.caffeine + org.h2 dev.brighten.antivpn.shaded.org.h2 @@ -159,7 +163,7 @@ com.github.ben-manes.caffeine caffeine 3.1.8 - compile + provided diff --git a/Common/src/main/java/dev/brighten/antivpn/AntiVPN.java b/Common/src/main/java/dev/brighten/antivpn/AntiVPN.java index 3a24d96..e89821a 100644 --- a/Common/src/main/java/dev/brighten/antivpn/AntiVPN.java +++ b/Common/src/main/java/dev/brighten/antivpn/AntiVPN.java @@ -47,6 +47,10 @@ import java.util.List; @Relocate(from = "com.my\\" + "sql.jdbc", to = "dev.brighten.antivpn.shaded.com.mysql.jdbc") } ) +@MavenLibrary(groupId = "com.\\github\\.ben-manes\\.caffeine", artifactId = "caffeine", version = "3.1.8", + relocations = { + @Relocate(from = "com\\.github\\.benmanes\\.caffeine", to = "dev.brighten.antivpn.shaded.com.github.benmanes.caffeine"), + }) public class AntiVPN { private static AntiVPN INSTANCE; @@ -94,34 +98,40 @@ public class AntiVPN { INSTANCE.messageHandler = new MessageHandler(); - switch(INSTANCE.vpnConfig.getDatabaseType().toLowerCase()) { - case "h2": - case "local": - case "flatfile": { - AntiVPN.getInstance().getExecutor().log("Using databaseType H2..."); - INSTANCE.database = new H2VPN(); - INSTANCE.database.init(); - break; - } - case "mysql": - case "sql":{ - AntiVPN.getInstance().getExecutor().log("Using databaseType MySQL..."); - INSTANCE.database = new MySqlVPN(); - INSTANCE.database.init(); - break; - } - case "mongo": - case "mongodb": - case "mongod": { - INSTANCE.database = new MongoVPN(); - INSTANCE.database.init(); - break; - } - default: { - AntiVPN.getInstance().getExecutor().log("Could not find database type \"" + INSTANCE.vpnConfig.getDatabaseType() + "\". " + - "Options: [MySQL]"); - break; + try { + switch(INSTANCE.vpnConfig.getDatabaseType().toLowerCase()) { + case "h2": + case "local": + case "flatfile": { + AntiVPN.getInstance().getExecutor().log("Using databaseType H2..."); + INSTANCE.database = new H2VPN(); + INSTANCE.database.init(); + break; + } + case "mysql": + case "sql":{ + AntiVPN.getInstance().getExecutor().log("Using databaseType MySQL..."); + INSTANCE.database = new MySqlVPN(); + INSTANCE.database.init(); + break; + } + case "mongo": + case "mongodb": + case "mongod": { + INSTANCE.database = new MongoVPN(); + INSTANCE.database.init(); + break; + } + default: { + AntiVPN.getInstance().getExecutor().log("Could not find database type \"" + INSTANCE.vpnConfig.getDatabaseType() + "\". " + + "Options: [MySQL]"); + break; + } } + } catch (Exception e) { + AntiVPN.getInstance().getExecutor().logException("Could not initialize database, plugin disabling...", e); + executor.disablePlugin(); + return; } //Registering commands @@ -141,6 +151,9 @@ public class AntiVPN { (vpnString.getDefaultMessage(), "messages." + vpnString.getKey(), AntiVPN.getInstance()) .get()); AntiVPN.getInstance().getMessageHandler().reloadStrings(); + + // Starting kick checks + AntiVPN.getInstance().getExecutor().startKickChecks(); } public InputStream getResource(String filename) { diff --git a/Common/src/main/java/dev/brighten/antivpn/api/APIPlayer.java b/Common/src/main/java/dev/brighten/antivpn/api/APIPlayer.java index 72fa742..1c0f2bc 100644 --- a/Common/src/main/java/dev/brighten/antivpn/api/APIPlayer.java +++ b/Common/src/main/java/dev/brighten/antivpn/api/APIPlayer.java @@ -1,18 +1,30 @@ package dev.brighten.antivpn.api; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import dev.brighten.antivpn.AntiVPN; import lombok.Getter; +import lombok.Setter; import java.net.InetAddress; import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.logging.Level; @Getter public abstract class APIPlayer { private final UUID uuid; private final String name; private final InetAddress ip; + @Setter private boolean alertsEnabled; + private static final Cache checkResultCache = Caffeine.newBuilder() + .expireAfterWrite(5, TimeUnit.MINUTES) + .maximumSize(2000) + .build(); + public APIPlayer(UUID uuid, String name, InetAddress ip) { this.uuid = uuid; this.name = name; @@ -25,12 +37,65 @@ public abstract class APIPlayer { public abstract boolean hasPermission(String permission); - public void setAlertsEnabled(boolean alertsEnabled) { - this.alertsEnabled = alertsEnabled; - } - public void updateAlertsState() { //Updating into database so its synced across servers and saved on logout. AntiVPN.getInstance().getDatabase().updateAlertsState(uuid, alertsEnabled); } + + public CheckResult checkPlayer(Consumer onKick) { + if (hasPermission("antivpn.bypass") //Has bypass permission + //Is exempt + || (uuid != null && AntiVPN.getInstance().getExecutor().isWhitelisted(uuid)) + //Or has a name that starts with a certain prefix. This is for Bedrock exempting. + || AntiVPN.getInstance().getExecutor().isWhitelisted(ip.getHostAddress()) + || AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream() + .anyMatch(name::startsWith)) return new CheckResult(null, ResultType.WHITELISTED); + + CheckResult cachedResult = checkResultCache.getIfPresent(ip.getHostAddress()); + + if(cachedResult != null) { + if(cachedResult.response().getIp().equals(ip.getHostAddress())) { + AntiVPN.getInstance().getExecutor().log(Level.FINE, "Cached result for " + ip.getHostAddress() + " is " + cachedResult.resultType()); + return cachedResult; + } + } + + AntiVPN.getInstance().getExecutor().checkIp(ip.getHostAddress()) + .thenAccept(result -> { + if(!result.isSuccess()) { + AntiVPN.getInstance().getExecutor().log(Level.WARNING, "The API query was not a success! " + + "You may need to upgrade your license on " + + "https://funkemunky.cc/shop"); + } + // If the countryList() size is zero, no need to check. + // Running country check first + CheckResult checkResult; + if (!AntiVPN.getInstance().getVpnConfig().countryList().isEmpty() + && !((uuid != null && AntiVPN.getInstance().getExecutor() + .isWhitelisted(uuid)) + //Or has a name that starts with a certain prefix. This is for Bedrock exempting. + || AntiVPN.getInstance().getExecutor().isWhitelisted(ip.getHostAddress())) + // This bit of code will decide whether or not to kick the player + // If it contains the code and it is set to whitelist, it will not kick + // as they are equal and vise versa. However, if the contains does not match + // the state, it will kick. + && AntiVPN.getInstance().getVpnConfig().countryList() + .contains(result.getCountryCode()) + != AntiVPN.getInstance().getVpnConfig().whitelistCountries()) { + //Using our built in kicking system if no commands are configured + checkResult = new CheckResult(result, ResultType.DENIED_COUNTRY); + } else if (result.isProxy()) { + checkResult = new CheckResult(result, ResultType.DENIED_PROXY); + } else { + checkResult = new CheckResult(result, ResultType.ALLOWED); + } + + AntiVPN.getInstance().getExecutor().log(Level.FINE, "Result for " + ip.getHostAddress() + " is " + checkResult.resultType()); + + checkResultCache.put(ip.getHostAddress(), checkResult); + onKick.accept(checkResult); + AntiVPN.getInstance().checked++; + }); + return new CheckResult(null, ResultType.UNKNOWN); + } } diff --git a/Common/src/main/java/dev/brighten/antivpn/api/CheckResult.java b/Common/src/main/java/dev/brighten/antivpn/api/CheckResult.java new file mode 100644 index 0000000..c331961 --- /dev/null +++ b/Common/src/main/java/dev/brighten/antivpn/api/CheckResult.java @@ -0,0 +1,6 @@ +package dev.brighten.antivpn.api; + +import dev.brighten.antivpn.web.objects.VPNResponse; + +public record CheckResult(VPNResponse response, ResultType resultType) { +} diff --git a/Common/src/main/java/dev/brighten/antivpn/api/OfflinePlayer.java b/Common/src/main/java/dev/brighten/antivpn/api/OfflinePlayer.java new file mode 100644 index 0000000..27ce5f7 --- /dev/null +++ b/Common/src/main/java/dev/brighten/antivpn/api/OfflinePlayer.java @@ -0,0 +1,26 @@ +package dev.brighten.antivpn.api; + +import java.net.InetAddress; +import java.util.UUID; + +public class OfflinePlayer extends APIPlayer { + + public OfflinePlayer(UUID uuid, String name, InetAddress ip) { + super(uuid, name, ip); + } + + @Override + public void sendMessage(String message) { + + } + + @Override + public void kickPlayer(String reason) { + + } + + @Override + public boolean hasPermission(String permission) { + return false; + } +} diff --git a/Common/src/main/java/dev/brighten/antivpn/api/ResultType.java b/Common/src/main/java/dev/brighten/antivpn/api/ResultType.java new file mode 100644 index 0000000..e8dfea4 --- /dev/null +++ b/Common/src/main/java/dev/brighten/antivpn/api/ResultType.java @@ -0,0 +1,18 @@ +package dev.brighten.antivpn.api; + +import lombok.Getter; + +public enum ResultType { + ALLOWED(false), + WHITELISTED(false), + DENIED_COUNTRY(true), + DENIED_PROXY(true), + UNKNOWN(false); + + @Getter + private final boolean shouldBlock; + + ResultType(boolean shouldBlock) { + this.shouldBlock = shouldBlock; + } +} diff --git a/Common/src/main/java/dev/brighten/antivpn/api/VPNExecutor.java b/Common/src/main/java/dev/brighten/antivpn/api/VPNExecutor.java index 838e6d8..6635f94 100644 --- a/Common/src/main/java/dev/brighten/antivpn/api/VPNExecutor.java +++ b/Common/src/main/java/dev/brighten/antivpn/api/VPNExecutor.java @@ -1,6 +1,8 @@ package dev.brighten.antivpn.api; import dev.brighten.antivpn.AntiVPN; +import dev.brighten.antivpn.utils.StringUtil; +import dev.brighten.antivpn.utils.Tuple; import dev.brighten.antivpn.utils.json.JSONException; import dev.brighten.antivpn.web.FunkemunkyAPI; import dev.brighten.antivpn.web.objects.VPNResponse; @@ -11,6 +13,7 @@ import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; public abstract class VPNExecutor { @@ -20,6 +23,10 @@ public abstract class VPNExecutor { private final Set whitelisted = Collections.synchronizedSet(new HashSet<>()); @Getter private final Set whitelistedIps = Collections.synchronizedSet(new HashSet<>()); + + @Getter + private final List> toKick = Collections.synchronizedList(new LinkedList<>()); + public abstract void registerListeners(); public abstract void log(Level level, String log, Object... objects); @@ -28,10 +35,73 @@ public abstract class VPNExecutor { public abstract void logException(String message, Throwable ex); + public abstract void runCommand(String command); + public void logException(Throwable ex) { logException("An exception occurred: " + ex.getMessage(), ex); } + public void startKickChecks() { + threadExecutor.scheduleAtFixedRate(() -> { + synchronized (toKick) { + if(toKick.isEmpty()) return; + + Iterator> i = toKick.iterator(); + + while(i.hasNext()) { + var toCheck = i.next(); + + Optional player = AntiVPN.getInstance().getPlayerExecutor().getPlayer(toCheck.second()); + + if(player.isEmpty()) { + continue; + } + + handleKickingOfPlayer(toCheck.first(), player.get()); + + i.remove(); + } + } + }, 8, 2, TimeUnit.SECONDS); + } + + public void handleKickingOfPlayer(CheckResult result, APIPlayer player) { + if (AntiVPN.getInstance().getVpnConfig().alertToStaff()) AntiVPN.getInstance().getPlayerExecutor() + .getOnlinePlayers() + .stream() + .filter(APIPlayer::isAlertsEnabled) + .forEach(pl -> + pl.sendMessage(StringUtil.translateAlternateColorCodes('&', + StringUtil.varReplace(dev.brighten.antivpn.AntiVPN.getInstance().getVpnConfig() + .alertMessage(), player, result.response())))); + + if(AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) { + switch (result.resultType()) { + case DENIED_PROXY -> player.kickPlayer(StringUtil.varReplace(AntiVPN.getInstance().getVpnConfig() + .getKickString(), player, result.response())); + case DENIED_COUNTRY -> player.kickPlayer(StringUtil.varReplace(AntiVPN.getInstance().getVpnConfig() + .countryVanillaKickReason(), player, result.response())); + } + } + + if(!AntiVPN.getInstance().getVpnConfig().runCommands()) return; + + switch (result.resultType()) { + case DENIED_PROXY -> { + for (String command : AntiVPN.getInstance().getVpnConfig().commands()) { + runCommand(StringUtil.translateAlternateColorCodes('&', + StringUtil.varReplace(command, player, result.response()))); + } + } + case DENIED_COUNTRY -> { + for (String command : AntiVPN.getInstance().getVpnConfig().countryKickCommands()) { + runCommand(StringUtil.translateAlternateColorCodes('&', + StringUtil.varReplace(command, player, result.response()))); + } + } + } + } + public boolean isWhitelisted(UUID uuid) { if(AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()) { return AntiVPN.getInstance().getDatabase().isWhitelisted(uuid); diff --git a/Common/src/main/java/dev/brighten/antivpn/database/sql/utils/MySQL.java b/Common/src/main/java/dev/brighten/antivpn/database/sql/utils/MySQL.java index 8355e2a..e8a1530 100644 --- a/Common/src/main/java/dev/brighten/antivpn/database/sql/utils/MySQL.java +++ b/Common/src/main/java/dev/brighten/antivpn/database/sql/utils/MySQL.java @@ -75,6 +75,9 @@ public class MySQL { } else { AntiVPN.getInstance().getExecutor().logException("Failed to load H2 database: " + ex.getCause().toString(), ex); } + } catch (Exception e) { + AntiVPN.getInstance().getExecutor().logException("Failed to load H2 database: " + e.getMessage(), e); + AntiVPN.getInstance().getExecutor().log(Level.INFO, "TIP: Try deleting the plugin folder and restarting your server!"); } } diff --git a/Common/src/main/java/dev/brighten/antivpn/depends/LibraryLoader.java b/Common/src/main/java/dev/brighten/antivpn/depends/LibraryLoader.java index 2ef3bca..8f16b26 100644 --- a/Common/src/main/java/dev/brighten/antivpn/depends/LibraryLoader.java +++ b/Common/src/main/java/dev/brighten/antivpn/depends/LibraryLoader.java @@ -55,14 +55,20 @@ import java.util.jar.JarOutputStream; public final class LibraryLoader { @SuppressWarnings("Guava") - private static final Supplier URL_INJECTOR = Suppliers.memoize(() -> - URLClassLoaderAccess.create((URLClassLoader) AntiVPN.getInstance().getClass().getClassLoader())); + private static final Supplier URL_INJECTOR = AntiVPN.getInstance().getClass().getClassLoader() instanceof URLClassLoader ? + Suppliers.memoize(() -> + URLClassLoaderAccess.create((URLClassLoader) AntiVPN.getInstance().getClass().getClassLoader())) + : null; public static void loadAll(Object object) { + if(URL_INJECTOR == null) + return; loadAll(object.getClass()); } public static void loadAll(Class clazz) { + if(URL_INJECTOR == null) + return; MavenLibrary[] libs = clazz.getDeclaredAnnotationsByType(MavenLibrary.class); for (MavenLibrary lib : libs) { diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/MiscUtils.java b/Common/src/main/java/dev/brighten/antivpn/utils/MiscUtils.java index 41c1856..77cde0b 100644 --- a/Common/src/main/java/dev/brighten/antivpn/utils/MiscUtils.java +++ b/Common/src/main/java/dev/brighten/antivpn/utils/MiscUtils.java @@ -1,6 +1,12 @@ package dev.brighten.antivpn.utils; +import dev.brighten.antivpn.AntiVPN; +import dev.brighten.antivpn.utils.json.JSONException; +import dev.brighten.antivpn.utils.json.JSONObject; +import dev.brighten.antivpn.utils.json.JsonReader; + import java.io.*; +import java.util.UUID; import java.util.concurrent.ThreadFactory; import java.util.regex.Pattern; @@ -12,7 +18,7 @@ public class MiscUtils { try { for (Closeable closeable : closeables) if (closeable != null) closeable.close(); } catch (Exception e) { - e.printStackTrace(); + AntiVPN.getInstance().getExecutor().logException(e); } } @@ -20,7 +26,7 @@ public class MiscUtils { try { for (AutoCloseable closeable : closeables) if (closeable != null) closeable.close(); } catch (Exception e) { - e.printStackTrace(); + AntiVPN.getInstance().getExecutor().logException(e); } } @@ -38,7 +44,7 @@ public class MiscUtils { out.close(); in.close(); } catch (Exception e) { - e.printStackTrace(); + AntiVPN.getInstance().getExecutor().logException(e); } } @@ -50,6 +56,33 @@ public class MiscUtils { }; } + public static UUID formatFromMojangUUID(String mojangUUID) { + StringBuilder uuid = new StringBuilder(); + for(int i = 0; i <= 31; i++) { + uuid.append(mojangUUID.charAt(i)); + if(i == 7 || i == 11 || i == 15 || i == 19) { + uuid.append("-"); + } + } + + return UUID.fromString(uuid.toString()); + } + + public static UUID lookupUUID(String playername) { + try { + JSONObject object = JsonReader + .readJsonFromUrl("https://funkemunky.cc/mojang/uuid?name=" + playername); + + if(object.has("uuid")) { + return UUID.fromString(object.getString("uuid")); + } + } catch (IOException | JSONException e) { + AntiVPN.getInstance().getExecutor().logException("Error while looking up UUID for " + playername, e); + } + + return null; + } + public static boolean isIpv4(String ip) { return ipv4.matcher(ip).matches(); diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/StringUtil.java b/Common/src/main/java/dev/brighten/antivpn/utils/StringUtil.java index 53ba8af..5081aa3 100644 --- a/Common/src/main/java/dev/brighten/antivpn/utils/StringUtil.java +++ b/Common/src/main/java/dev/brighten/antivpn/utils/StringUtil.java @@ -1,5 +1,8 @@ package dev.brighten.antivpn.utils; +import dev.brighten.antivpn.api.APIPlayer; +import dev.brighten.antivpn.web.objects.VPNResponse; + public class StringUtil { public static String line(String color) { return color + "&m-----------------------------------------------------"; @@ -12,4 +15,24 @@ public class StringUtil { public static String lineNoStrike(String color) { return color + "-----------------------------------------------------"; } + + public static String varReplace(String input, APIPlayer player, VPNResponse result) { + return input.replace("%player%", player.getName()) + .replace("%reason%", result.getMethod()) + .replace("%country%", result.getCountryName()) + .replace("%city%", result.getCity()); + } + + public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) { + char[] b = textToTranslate.toCharArray(); + + for(int i = 0; i < b.length - 1; ++i) { + if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i + 1]) > -1) { + b[i] = 167; + b[i + 1] = Character.toLowerCase(b[i + 1]); + } + } + + return new String(b); + } } diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/Tuple.java b/Common/src/main/java/dev/brighten/antivpn/utils/Tuple.java new file mode 100644 index 0000000..0e54854 --- /dev/null +++ b/Common/src/main/java/dev/brighten/antivpn/utils/Tuple.java @@ -0,0 +1,5 @@ +package dev.brighten.antivpn.utils; + +public record Tuple(F first, S second) { + +} diff --git a/Sponge/pom.xml b/Sponge/pom.xml index de32988..468cf97 100644 --- a/Sponge/pom.xml +++ b/Sponge/pom.xml @@ -13,8 +13,12 @@ - sponge - https://repo.spongepowered.org/repository/maven-public/ + spongepowered-repo + https://repo.spongepowered.org/maven/ + + + funkemunky-releases + https://nexus.funkemunky.cc/content/repositories/releases/ @@ -22,14 +26,39 @@ org.spongepowered spongeapi - 8.1.0 + 11.0.0 provided dev.brighten.antivpn Common 1.9.4-DEV - provided + compile + + + com.github.ben-manes.caffeine + caffeine + 3.1.8 + compile + + + org.mongodb + mongo-java-driver + 3.12.14 + compile + + + com.mysql + mysql-connector-j + 9.1.0 + jar + compile + + + com.h2database + h2 + 2.2.220 + compile @@ -38,4 +67,111 @@ 17 + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + 17 + 17 + -XDignore.symbol.file + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + + package + + shade + + + + + *:* + + com/google/** + org/objectweb/** + org/checkerframework/** + + + + + + + org.yaml.snakeyaml + dev.brighten.antivpn.shaded.org.yaml.snakeyaml + + + dev.brighten.antivpn.depends.Relocate + dev.brighten.antivpn.depends.MavenLibraries + + + + com.github.benmanes.caffeine + dev.brighten.antivpn.shaded.com.github.benmanes.caffeine + + + org.h2 + dev.brighten.antivpn.shaded.org.h2 + + + dev.brighten.antivpn.depends.Relocate + dev.brighten.antivpn.depends.MavenLibraries + + + + org.bson + dev.brighten.antivpn.shaded.org.bson + + + dev.brighten.antivpn.depends.Relocate + dev.brighten.antivpn.depends.MavenLibraries + + + + com.mongodb + dev.brighten.antivpn.shaded.com.mongodb + + + dev.brighten.antivpn.depends.Relocate + dev.brighten.antivpn.depends.MavenLibraries + + + + com.mysql.cj + dev.brighten.antivpn.shaded.com.mysql.cj + + + dev.brighten.antivpn.depends.Relocate + dev.brighten.antivpn.depends.MavenLibraries + + + + com.mysql.jdbc + dev.brighten.antivpn.shaded.com.mysql.jdbc + + + dev.brighten.antivpn.depends.Relocate + dev.brighten.antivpn.depends.MavenLibraries + + + + + + + + + + + src/main/resources + true + + + + \ No newline at end of file diff --git a/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongeListener.java b/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongeListener.java new file mode 100644 index 0000000..47b6664 --- /dev/null +++ b/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongeListener.java @@ -0,0 +1,114 @@ +package dev.brighten.antivpn.sponge; + +import dev.brighten.antivpn.AntiVPN; +import dev.brighten.antivpn.api.*; +import dev.brighten.antivpn.sponge.util.StringUtil; +import dev.brighten.antivpn.utils.Tuple; +import net.kyori.adventure.text.Component; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.command.exception.CommandException; +import org.spongepowered.api.event.Listener; +import org.spongepowered.api.event.Order; +import org.spongepowered.api.event.network.ServerSideConnectionEvent; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.Level; + +public class SpongeListener extends VPNExecutor { + + @Listener(order = Order.EARLY) + public void onJoin(ServerSideConnectionEvent.Login event) { + AtomicReference player = new AtomicReference<>(AntiVPN.getInstance().getPlayerExecutor() + .getPlayer(event.profile().uuid()) + .orElse(new OfflinePlayer( + event.profile().uuid(), + event.profile().name().orElse("Unknown"), + event.connection().address().getAddress() + ))); + + CheckResult instantResult = player.get().checkPlayer(result -> { + if(result.resultType().isShouldBlock()) { + AntiVPN.getInstance().getExecutor().getToKick().add(new Tuple<>(result, player.get().getUuid())); + } + }); + + if(!instantResult.resultType().isShouldBlock()) { + return; + } + + AntiVPN.getInstance().getExecutor().getToKick().add(new Tuple<>(instantResult, player.get().getUuid())); + + if(!AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) { + return; + } + + AntiVPN.getInstance().getExecutor().log(Level.INFO, "%s was kicked from cache with IP %s", player.get().getName(), instantResult.response().getIp()); + + event.setCancelled(true); + switch (instantResult.resultType()) { + case DENIED_PROXY -> { + AntiVPN.getInstance().getExecutor().log(Level.INFO, player.get().getName() + + " joined on a VPN/Proxy (" + instantResult.response().getMethod() + ")"); + event.setMessage(Component.text(StringUtil + .translateColorCodes('&', AntiVPN.getInstance().getVpnConfig() + .getKickString() + .replace("%player%", player.get().getName()) + .replace("%country%", instantResult.response().getCountryName()) + .replace("%code%", instantResult.response().getCountryCode())))); + } + case DENIED_COUNTRY -> + event.setMessage(Component.text(StringUtil + .translateColorCodes('&', AntiVPN.getInstance().getVpnConfig() + .countryVanillaKickReason() + .replace("%player%", player.get().getName()) + .replace("%country%", instantResult.response().getCountryName()) + .replace("%code%", instantResult.response().getCountryCode())))); + } + } + + @Listener + public void onPlayerDisconnect(ServerSideConnectionEvent.Disconnect event) { + event.profile().ifPresent(profile -> + AntiVPN.getInstance().getPlayerExecutor().unloadPlayer(profile.uuid())); + } + + @Override + public void registerListeners() { + Sponge.eventManager().registerListeners(SpongePlugin.getInstance().getContainer(), this); + } + + @Override + public void log(Level level, String log, Object... objects) { + if (level.equals(Level.SEVERE)) { + SpongePlugin.getInstance().getLogger().error(String.format(log, objects)); + } else if (level.equals(Level.WARNING)) { + SpongePlugin.getInstance().getLogger().warn(String.format(log, objects)); + } else { + SpongePlugin.getInstance().getLogger().info(String.format(log, objects)); + } + } + + @Override + public void log(String log, Object... objects) { + log(Level.INFO, String.format(log, objects)); + } + + @Override + public void logException(String message, Throwable ex) { + SpongePlugin.getInstance().getLogger().error(message, ex); + } + + @Override + public void runCommand(String command) { + try { + Sponge.server().commandManager().process(Sponge.systemSubject(), command); + } catch (CommandException e) { + logException(e); + } + } + + @Override + public void disablePlugin() { + AntiVPN.getInstance().getExecutor().log(Level.INFO, "Disabling listeners for plugin..."); + } +} diff --git a/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlayer.java b/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlayer.java index 9ce17f9..2052eea 100644 --- a/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlayer.java +++ b/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlayer.java @@ -16,7 +16,7 @@ public class SpongePlayer extends APIPlayer { @Override public void sendMessage(String message) { - //player.sendMessage(StringUtil.translateColorCodes('&', message)); + player.sendMessage(Component.text(StringUtil.translateColorCodes('&', message))); } @Override diff --git a/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlayerExecutor.java b/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlayerExecutor.java index 414d7b3..3904633 100644 --- a/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlayerExecutor.java +++ b/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlayerExecutor.java @@ -1,31 +1,70 @@ package dev.brighten.antivpn.sponge; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import dev.brighten.antivpn.api.APIPlayer; import dev.brighten.antivpn.api.PlayerExecutor; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.TimeUnit; public class SpongePlayerExecutor implements PlayerExecutor { + + private final Cache playerCache = Caffeine.newBuilder().maximumSize(10000) + .expireAfterAccess(30, TimeUnit.MINUTES) + .build(); + @Override public Optional getPlayer(String name) { + Optional serverPlayer = Sponge.server().player(name); - return Optional.empty(); + return serverPlayer.map(SpongePlayer::new); } @Override public Optional getPlayer(UUID uuid) { - return Optional.empty(); + SpongePlayer cachedPlayer = playerCache.getIfPresent(uuid); + + if(cachedPlayer != null) { + return Optional.of(cachedPlayer); + } + + Optional serverPlayer = Sponge.server().player(uuid); + + Optional player = serverPlayer.map(SpongePlayer::new); + + player.ifPresent(value -> playerCache.put(uuid, (SpongePlayer) value)); + + return player; } @Override public void unloadPlayer(UUID uuid) { - + playerCache.invalidate(uuid); } @Override public List getOnlinePlayers() { - return null; + if(!Sponge.game().isServerAvailable()) return Collections.emptyList(); + return Sponge.server().onlinePlayers() + .stream() + .map(pl -> { + SpongePlayer cachedPlayer = playerCache.getIfPresent(pl.uniqueId()); + + if(cachedPlayer != null) { + return cachedPlayer; + } + + SpongePlayer player = new SpongePlayer(pl); + playerCache.put(pl.uniqueId(), player); + + return (APIPlayer) player; + }) + .toList(); } } diff --git a/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlugin.java b/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlugin.java index 39d9c50..1aa11f2 100644 --- a/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlugin.java +++ b/Sponge/src/main/java/dev/brighten/antivpn/sponge/SpongePlugin.java @@ -1,28 +1,60 @@ package dev.brighten.antivpn.sponge; import com.google.inject.Inject; +import dev.brighten.antivpn.AntiVPN; +import dev.brighten.antivpn.sponge.command.SpongeCommand; +import lombok.Getter; import org.spongepowered.api.Server; +import org.apache.logging.log4j.Logger; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.command.Command; +import org.spongepowered.api.config.ConfigManager; import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.lifecycle.StartedEngineEvent; +import org.spongepowered.api.event.lifecycle.*; +import org.spongepowered.plugin.PluginContainer; import org.spongepowered.plugin.builtin.jvm.Plugin; -import java.util.logging.Logger; - @Plugin("kaurivpn") +@Getter public class SpongePlugin { - public static SpongePlugin INSTANCE; //Plugin init - + @Inject + private PluginContainer container; @Inject private Logger logger; + @Getter + private static SpongePlugin instance; @Listener - public void onServerStart(final StartedEngineEvent event) { - INSTANCE = this; + public void onConstruct(final ConstructPluginEvent event) { + instance = this; - logger.info("Starting AntiVPN services..."); - //Start AntiVPN + ConfigManager configManager = Sponge.configManager(); + SpongeListener spongeListener = new SpongeListener(); + + var path = configManager.sharedConfig(container).directory(); + + logger.info("Fucking path: " + path); + + AntiVPN.start(spongeListener, new SpongePlayerExecutor(), path.toFile()); } + @Listener + public void onServer(final StoppingEngineEvent event) { + AntiVPN.getInstance().getExecutor().disablePlugin(); + } + + @Listener + public void onRegisterRawCommands(final RegisterCommandEvent event){ + if(AntiVPN.getInstance() == null) { + for(int i = 0 ; i < 5 ; i++) System.out.println("FUCKING NULL"); + return; + } + AntiVPN.getInstance().getExecutor().log("Registering commands..."); + for (dev.brighten.antivpn.command.Command command : AntiVPN.getInstance().getCommands()) { + AntiVPN.getInstance().getExecutor().log("Registering command %s...", command.name()); + event.register(this.container, new SpongeCommand(command), command.name(), command.aliases()); + } + } } diff --git a/Sponge/src/main/java/dev/brighten/antivpn/sponge/command/SpongeCommand.java b/Sponge/src/main/java/dev/brighten/antivpn/sponge/command/SpongeCommand.java new file mode 100644 index 0000000..3bccdc2 --- /dev/null +++ b/Sponge/src/main/java/dev/brighten/antivpn/sponge/command/SpongeCommand.java @@ -0,0 +1,111 @@ +package dev.brighten.antivpn.sponge.command; + +import dev.brighten.antivpn.AntiVPN; +import dev.brighten.antivpn.command.Command; +import dev.brighten.antivpn.command.CommandExecutor; +import dev.brighten.antivpn.utils.StringUtil; +import lombok.val; +import net.kyori.adventure.text.Component; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.command.CommandCompletion; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.parameter.ArgumentReader; + +import java.util.*; +import java.util.stream.IntStream; + +public class SpongeCommand implements org.spongepowered.api.command.Command.Raw { + + private final Command command; + + public SpongeCommand(Command command) { + this.command = command; + } + + @Override + public CommandResult process(CommandCause sender, ArgumentReader.Mutable arguments) { + + String[] args = arguments.input().split(" "); + + CommandExecutor commandExecutor = new SpongeCommandExecutor(sender); + + val children = command.children(); + + if(children.length > 0 && args.length > 0) { + for (dev.brighten.antivpn.command.Command child : children) { + if(child.name().equalsIgnoreCase(args[0]) || Arrays.stream(child.aliases()) + .anyMatch(alias -> alias.equalsIgnoreCase(args[0]))) { + if(!sender.hasPermission("antivpn.command.*") + && !sender.hasPermission(child.permission())) { + return CommandResult.error(Component.text(StringUtil.translateAlternateColorCodes('&', + AntiVPN.getInstance().getMessageHandler().getString("no-permission").getMessage()))); + } + + commandExecutor.sendMessage(StringUtil + .translateAlternateColorCodes('&', + child.execute(commandExecutor, IntStream + .range(0, args.length - 1) + .mapToObj(i -> args[i + 1]).toArray(String[]::new)))); + return CommandResult.success(); + } + } + } + + commandExecutor.sendMessage(StringUtil + .translateAlternateColorCodes('&', + command.execute(new SpongeCommandExecutor(sender), args))); + + command.execute(new SpongeCommandExecutor(sender), args); + return CommandResult.success(); + } + + @Override + public List complete(CommandCause sender, ArgumentReader.Mutable arguments) { + val children = command.children(); + String[] args = arguments.input().split(" "); + if(children.length > 0 && args.length > 0) { + for (dev.brighten.antivpn.command.Command child : children) { + if(child.name().equalsIgnoreCase(args[0]) || Arrays.stream(child.aliases()) + .anyMatch(alias2 -> alias2.equalsIgnoreCase(args[0]))) { + return child.tabComplete(new SpongeCommandExecutor(sender), "alias", IntStream + .range(0, args.length - 1) + .mapToObj(i -> args[i + 1]).toArray(String[]::new)) + .stream() + .map(CommandCompletion::of) + .toList(); + } + } + } + return command.tabComplete(new SpongeCommandExecutor(sender), "alias", args) + .stream() + .map(CommandCompletion::of) + .toList(); + } + + @Override + public boolean canExecute(CommandCause cause) { + return cause.hasPermission(command.permission()); + } + + @Override + public Optional shortDescription(CommandCause cause) { + return command.description() != null ? Optional.of(Component.text(command.description())) : Optional.empty(); + } + + @Override + public Optional extendedDescription(CommandCause cause) { + return Optional.empty(); + } + + @Override + public Optional help(@NonNull CommandCause cause) { + return Optional.of(Component.text(StringUtil.translateAlternateColorCodes('&', + command.execute(new SpongeCommandExecutor(cause), new String[0])))); + } + + @Override + public Component usage(CommandCause cause) { + return command.usage() != null ? Component.text(command.usage()) : Component.empty(); + } +} diff --git a/Sponge/src/main/java/dev/brighten/antivpn/sponge/command/SpongeCommandExecutor.java b/Sponge/src/main/java/dev/brighten/antivpn/sponge/command/SpongeCommandExecutor.java new file mode 100644 index 0000000..de96dd5 --- /dev/null +++ b/Sponge/src/main/java/dev/brighten/antivpn/sponge/command/SpongeCommandExecutor.java @@ -0,0 +1,42 @@ +package dev.brighten.antivpn.sponge.command; + +import dev.brighten.antivpn.AntiVPN; +import dev.brighten.antivpn.api.APIPlayer; +import dev.brighten.antivpn.command.CommandExecutor; +import dev.brighten.antivpn.sponge.util.StringUtil; +import lombok.RequiredArgsConstructor; +import net.kyori.adventure.text.Component; +import org.spongepowered.api.command.CommandCause; +import org.spongepowered.api.entity.living.player.server.ServerPlayer; + +import java.util.Optional; + +@RequiredArgsConstructor +public class SpongeCommandExecutor implements CommandExecutor { + + private final CommandCause cause; + + @Override + public void sendMessage(String message, Object... objects) { + cause.sendMessage(Component.text(StringUtil.translateColorCodes('&', + String.format(message, objects)))); + } + + @Override + public boolean hasPermission(String permission) { + return cause.hasPermission(permission); + } + + @Override + public Optional getPlayer() { + if(cause.subject() instanceof ServerPlayer serverPlayer) { + return AntiVPN.getInstance().getPlayerExecutor().getPlayer(serverPlayer.uniqueId()); + } + return Optional.empty(); + } + + @Override + public boolean isPlayer() { + return cause.subject() instanceof ServerPlayer; + } +} diff --git a/Sponge/src/main/resources/META-INF/sponge_plugins.json b/Sponge/src/main/resources/META-INF/sponge_plugins.json new file mode 100644 index 0000000..be21d3b --- /dev/null +++ b/Sponge/src/main/resources/META-INF/sponge_plugins.json @@ -0,0 +1,29 @@ +{ + "loader": { + "name": "java_plain", + "version": "1.0" + }, + "license": "All-Rights-Reserved", + "plugins": [ + { + "id": "kaurivpn", + "name": "Kauri VPN", + "version": "${version}", + "entrypoint": "dev.brighten.antivpn.sponge.SpongePlugin", + "description": "A simple and fast antivpn plugin.", + "branding": {}, + "links": { + }, + "contributors": [ + ], + "dependencies": [ + { + "id": "spongeapi", + "version": "11.0.0", + "load-order": "after", + "optional": false + } + ] + } + ] +} diff --git a/Universal/pom.xml b/Universal/pom.xml index fe9424e..b036049 100644 --- a/Universal/pom.xml +++ b/Universal/pom.xml @@ -42,12 +42,6 @@ ${project.version} compile - - @@ -77,6 +71,10 @@ org.bstats dev.brighten.antivpn.shaded.org.bstats + + org.objectweb + dev.brighten.antivpn.shaded.org.objectweb + diff --git a/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityListener.java b/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityListener.java index 8c6a437..8f79deb 100644 --- a/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityListener.java +++ b/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityListener.java @@ -5,8 +5,11 @@ import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.LoginEvent; import dev.brighten.antivpn.AntiVPN; import dev.brighten.antivpn.api.APIPlayer; +import dev.brighten.antivpn.api.CheckResult; +import dev.brighten.antivpn.api.OfflinePlayer; import dev.brighten.antivpn.api.VPNExecutor; -import dev.brighten.antivpn.velocity.util.StringUtils; +import dev.brighten.antivpn.utils.StringUtil; +import dev.brighten.antivpn.web.objects.VPNResponse; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import java.util.concurrent.TimeUnit; @@ -20,136 +23,146 @@ public class VelocityListener extends VPNExecutor { .register(VelocityPlugin.INSTANCE, this); VelocityPlugin.INSTANCE.getServer().getEventManager().register(VelocityPlugin.INSTANCE, DisconnectEvent.class, - event -> AntiVPN.getInstance().getPlayerExecutor().unloadPlayer(event.getPlayer().getUniqueId())); + event -> AntiVPN.getInstance() + .getPlayerExecutor() + .unloadPlayer(event.getPlayer().getUniqueId())); VelocityPlugin.INSTANCE.getServer().getEventManager().register(VelocityPlugin.INSTANCE, LoginEvent.class, event -> { - if (event.getResult().isAllowed()) { - if (event.getPlayer().hasPermission("antivpn.bypass") //Has bypass permission - //Is exempt - || AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId()) - //Or has a name that starts with a certain prefix. This is for Bedrock exempting. - || AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getRemoteAddress() - .getAddress().getHostAddress()) - || AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream() - .anyMatch(prefix -> event.getPlayer().getUsername().startsWith(prefix))) return; - checkIp(event.getPlayer().getRemoteAddress().getAddress().getHostAddress()) - .thenAccept(result -> { - if(!result.isSuccess()) { - VelocityPlugin.INSTANCE.getLogger() - .log(Level.WARNING, - "The API query was not a success! " + - "You may need to upgrade your license on " + - "https://funkemunky.cc/shop"); - } - // If the countryList() size is zero, no need to check. - // Running country check first - if (!AntiVPN.getInstance().getVpnConfig().countryList().isEmpty() - && !(AntiVPN.getInstance().getExecutor() - .isWhitelisted(event.getPlayer().getUniqueId()) //Is exempt - //Or has a name that starts with a certain prefix. This is for Bedrock exempting. - || AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer() - .getRemoteAddress().getAddress().getHostAddress())) - // This bit of code will decide whether or not to kick the player - // If it contains the code and it is set to whitelist, it will not kick - // as they are equal and vise versa. However, if the contains does not match - // the state, it will kick. - && AntiVPN.getInstance().getVpnConfig().countryList() - .contains(result.getCountryCode()) - != AntiVPN.getInstance().getVpnConfig().whitelistCountries()) { - //Using our built in kicking system if no commands are configured - if (AntiVPN.getInstance().getVpnConfig().countryKickCommands().isEmpty()) { - final String kickReason = AntiVPN.getInstance().getVpnConfig() - .countryVanillaKickReason(); - // Kicking our player - event.setResult(ResultedEvent.ComponentResult.denied(LegacyComponentSerializer.builder() - .character('&') - .build().deserialize(kickReason - .replace("%player%", event.getPlayer().getUsername()) - .replace("%country%", result.getCountryName()) - .replace("%code%", result.getCountryCode())))); - VelocityPlugin.INSTANCE.getServer().getScheduler() - .buildTask(VelocityPlugin.INSTANCE, () -> - event.getPlayer().disconnect(LegacyComponentSerializer.builder() - .character('&') - .build().deserialize(kickReason - .replace("%player%", event.getPlayer().getUsername()) - .replace("%country%", result.getCountryName()) - .replace("%code%", result.getCountryCode())))); - } else { - for (String cmd : AntiVPN.getInstance().getVpnConfig().countryKickCommands()) { - final String formattedCommand = StringUtils - .translateAlternateColorCodes('&', - cmd.replace("%player%", - event.getPlayer().getUsername()) - .replace("%country%", result.getCountryName()) - .replace("%code%", result.getCountryCode())); - // Running the command from console - VelocityPlugin.INSTANCE.getServer().getCommandManager() - .executeAsync(VelocityPlugin.INSTANCE.getServer() - .getConsoleCommandSource(), - StringUtils.translateAlternateColorCodes('&', - formattedCommand)); - } - } - } else if (result.isProxy()) { - if (AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) { - // Delay code execution - event.setResult(ResultedEvent.ComponentResult.denied(LegacyComponentSerializer.builder() - .character('&') - .build().deserialize(AntiVPN.getInstance().getVpnConfig() - .getKickString() - .replace("%player%", event.getPlayer().getUsername()) - .replace("%country%", result.getCountryName()) - .replace("%code%", result.getCountryCode())))); + APIPlayer player = AntiVPN.getInstance().getPlayerExecutor().getPlayer(event.getPlayer().getUniqueId()) + .orElse(new OfflinePlayer( + event.getPlayer().getUniqueId(), + event.getPlayer().getUsername(), + event.getPlayer().getRemoteAddress().getAddress() + )); - VelocityPlugin.INSTANCE.getServer().getScheduler() - .buildTask(VelocityPlugin.INSTANCE, () -> - event.getPlayer().disconnect(LegacyComponentSerializer.builder() - .character('&') - .build().deserialize(AntiVPN.getInstance().getVpnConfig() - .getKickString() - .replace("%player%", event.getPlayer().getUsername()) - .replace("%country%", result.getCountryName()) - .replace("%code%", result.getCountryCode())))) - .delay(1, TimeUnit.SECONDS).schedule(); - } - VelocityPlugin.INSTANCE.getLogger().info(event.getPlayer().getUsername() - + " joined on a VPN/Proxy (" + result.getMethod() + ")"); - //Ensuring the user wishes to alert to staff - if (AntiVPN.getInstance().getVpnConfig().alertToStaff()) - AntiVPN.getInstance().getPlayerExecutor().getOnlinePlayers().stream() - .filter(APIPlayer::isAlertsEnabled) - .forEach(pl -> - pl.sendMessage(AntiVPN.getInstance().getVpnConfig() - .alertMessage() - .replace("%player%", - event.getPlayer().getUsername()) - .replace("%reason%", - result.getMethod()) - .replace("%country%", - result.getCountryName()) - .replace("%city%", - result.getCity()))); + CheckResult instantResult = player.checkPlayer(result -> { + if(!result.resultType().isShouldBlock()) return; + + handleDeniedTasks(event, result); + }); + + if(!instantResult.resultType().isShouldBlock()) return; + + switch (instantResult.resultType()) { + case DENIED_COUNTRY -> event.setResult(ResultedEvent.ComponentResult.denied( + LegacyComponentSerializer.builder() + .character('&') + .build().deserialize(AntiVPN.getInstance().getVpnConfig() + .countryVanillaKickReason() + .replace("%player%", event.getPlayer().getUsername()) + .replace("%country%", instantResult.response().getCountryName()) + .replace("%code%", instantResult.response().getCountryCode())))); + case DENIED_PROXY -> { + VelocityPlugin.INSTANCE.getLogger().info(event.getPlayer().getUsername() + + " joined on a VPN/Proxy (" + instantResult.response().getMethod() + ")"); + event.setResult(ResultedEvent.ComponentResult.denied(LegacyComponentSerializer.builder() + .character('&') + .build().deserialize(AntiVPN.getInstance().getVpnConfig() + .getKickString() + .replace("%player%", event.getPlayer().getUsername()) + .replace("%country%", instantResult.response().getCountryName()) + .replace("%code%", instantResult.response().getCountryCode())))); + } + } + + handleDeniedTasks(event, instantResult, true); + }); + } + + private void handleDeniedTasks(LoginEvent event, CheckResult result) { + handleDeniedTasks(event, result, false); + } + + private void handleDeniedTasks(LoginEvent event, CheckResult checkResult, boolean deniedOnLogin) { + VPNResponse result = checkResult.response(); + //Ensuring the user wishes to alert to staff + if (AntiVPN.getInstance().getVpnConfig().alertToStaff()) + AntiVPN.getInstance().getPlayerExecutor().getOnlinePlayers().stream() + .filter(APIPlayer::isAlertsEnabled) + .forEach(pl -> + pl.sendMessage(dev.brighten.antivpn.AntiVPN.getInstance().getVpnConfig() + .alertMessage() + .replace("%player%", + event.getPlayer().getUsername()) + .replace("%reason%", + result.getMethod()) + .replace("%country%", + result.getCountryName()) + .replace("%city%", + result.getCity()))); + + if(deniedOnLogin) return; + + //In case the user wants to run their own commands instead of using the + // built in kicking + + if(AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) { + switch (checkResult.resultType()) { + case DENIED_PROXY -> VelocityPlugin.INSTANCE.getServer().getScheduler() + .buildTask(VelocityPlugin.INSTANCE, () -> + event.getPlayer().disconnect(LegacyComponentSerializer.builder() + .character('&') + .build().deserialize(AntiVPN.getInstance().getVpnConfig() + .getKickString() + .replace("%player%", event.getPlayer().getUsername()) + .replace("%country%", result.getCountryName()) + .replace("%code%", result.getCountryCode())))) + .delay(1, TimeUnit.SECONDS).schedule(); + case DENIED_COUNTRY -> VelocityPlugin.INSTANCE.getServer().getScheduler() + .buildTask(VelocityPlugin.INSTANCE, () -> + event.getPlayer().disconnect(LegacyComponentSerializer.builder() + .character('&') + .build().deserialize(AntiVPN.getInstance().getVpnConfig() + .countryVanillaKickReason() + .replace("%player%", event.getPlayer().getUsername()) + .replace("%country%", result.getCountryName()) + .replace("%code%", result.getCountryCode())))) + .delay(1, TimeUnit.SECONDS).schedule(); + } + } + + if(!AntiVPN.getInstance().getVpnConfig().runCommands()) return; + + switch (checkResult.resultType()) { + case DENIED_PROXY -> { + for (String command : AntiVPN.getInstance().getVpnConfig().commands()) { + VelocityPlugin.INSTANCE.getServer().getCommandManager() + .executeAsync(VelocityPlugin.INSTANCE.getServer() + .getConsoleCommandSource(), + StringUtil.translateAlternateColorCodes('&', + StringUtil.varReplace( + command, + AntiVPN.getInstance().getPlayerExecutor() + .getPlayer(event.getPlayer().getUniqueId()) + .orElse(new OfflinePlayer( + event.getPlayer().getUniqueId(), + event.getPlayer().getUsername(), + event.getPlayer().getRemoteAddress().getAddress()) + ), + result))); + } + } + case DENIED_COUNTRY -> { + for (String cmd : AntiVPN.getInstance().getVpnConfig().countryKickCommands()) { + final String formattedCommand = StringUtil + .translateAlternateColorCodes('&', + StringUtil.varReplace( + cmd, + AntiVPN.getInstance().getPlayerExecutor() + .getPlayer(event.getPlayer().getUniqueId()) + .orElse(new OfflinePlayer( + event.getPlayer().getUniqueId(), + event.getPlayer().getUsername(), + event.getPlayer().getRemoteAddress().getAddress()) + ), + result)); + // Running the command from console + runCommand(formattedCommand); + } + } + } - //In case the user wants to run their own commands instead of using the - // built in kicking - if (AntiVPN.getInstance().getVpnConfig().runCommands()) { - for (String command : AntiVPN.getInstance().getVpnConfig().commands()) { - VelocityPlugin.INSTANCE.getServer().getCommandManager() - .executeAsync(VelocityPlugin.INSTANCE.getServer() - .getConsoleCommandSource(), - StringUtils.translateAlternateColorCodes('&', - command.replace("%player%", - event.getPlayer().getUsername()))); - } - } - AntiVPN.getInstance().detections++; - } - AntiVPN.getInstance().checked++; - }); - } - }); } @Override @@ -167,6 +180,15 @@ public class VelocityListener extends VPNExecutor { VelocityPlugin.INSTANCE.getLogger().log(Level.SEVERE, message, ex); } + @Override + public void runCommand(String command) { + VelocityPlugin.INSTANCE.getServer().getCommandManager() + .executeAsync(VelocityPlugin.INSTANCE.getServer() + .getConsoleCommandSource(), + StringUtil.translateAlternateColorCodes('&', + command)); + } + @Override public void disablePlugin() { VelocityPlugin.INSTANCE.getServer().getEventManager().unregisterListener(VelocityPlugin.INSTANCE, this); diff --git a/Velocity/src/main/java/dev/brighten/antivpn/velocity/util/StringUtils.java b/Velocity/src/main/java/dev/brighten/antivpn/velocity/util/StringUtils.java deleted file mode 100644 index a4f02fe..0000000 --- a/Velocity/src/main/java/dev/brighten/antivpn/velocity/util/StringUtils.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.brighten.antivpn.velocity.util; - -public class StringUtils { - - public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) { - char[] b = textToTranslate.toCharArray(); - - for(int i = 0; i < b.length - 1; ++i) { - if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i + 1]) > -1) { - b[i] = 167; - b[i + 1] = Character.toLowerCase(b[i + 1]); - } - } - - return new String(b); - } -}