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 66b7fa3..2bcdf9b 100644 --- a/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeListener.java +++ b/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeListener.java @@ -57,34 +57,55 @@ public class BungeeListener extends VPNExecutor implements Listener { checkIp(event.getPlayer().getAddress().getAddress().getHostAddress(), AntiVPN.getInstance().getVpnConfig().cachedResults(), result -> { - if(result.isSuccess() && result.isProxy()) { - if(AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) - event.getPlayer().disconnect(TextComponent.fromLegacyText(ChatColor - .translateAlternateColorCodes('&', - AntiVPN.getInstance().getVpnConfig().getKickString()))); - BungeeCord.getInstance().getLogger().info(event.getPlayer().getName() - + " joined on a VPN/Proxy (" + result.getMethod() + ")"); + if(result.isSuccess()) { + if(result.isProxy()) { + if(AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) + event.getPlayer().disconnect(TextComponent.fromLegacyText(ChatColor + .translateAlternateColorCodes('&', + AntiVPN.getInstance().getVpnConfig().getKickString()))); + BungeeCord.getInstance().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()))); + 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()) { - BungeeCord.getInstance().getPluginManager() - .dispatchCommand(BungeeCord.getInstance().getConsole(), - ChatColor.translateAlternateColorCodes('&', - command.replace("%player%", event.getPlayer().getName()))); + //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()) { + BungeeCord.getInstance().getPluginManager() + .dispatchCommand(BungeeCord.getInstance().getConsole(), + ChatColor.translateAlternateColorCodes('&', + command.replace("%player%", event.getPlayer().getName()))); + } + } + AntiVPN.getInstance().detections++; + } + + // If the countryList() size is zero, no need to check. + if(AntiVPN.getInstance().getVpnConfig().countryList().size() > 0 + // 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()) { + 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())); + + BungeeCord.getInstance().getPluginManager().dispatchCommand( + BungeeCord.getInstance().getConsole(), formattedCommand); } } - AntiVPN.getInstance().detections++; - } else if(!result.isSuccess()) { + + } else { BungeeCord.getInstance().getLogger() .log(Level.WARNING, "The API query was not a success! " + diff --git a/Common/src/main/java/dev/brighten/antivpn/api/VPNConfig.java b/Common/src/main/java/dev/brighten/antivpn/api/VPNConfig.java index b6d700a..8f0bd0d 100644 --- a/Common/src/main/java/dev/brighten/antivpn/api/VPNConfig.java +++ b/Common/src/main/java/dev/brighten/antivpn/api/VPNConfig.java @@ -4,6 +4,7 @@ import dev.brighten.antivpn.AntiVPN; import dev.brighten.antivpn.utils.ConfigDefault; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -37,6 +38,8 @@ public class VPNConfig { = new ConfigDefault<>(true, "kickPlayers", AntiVPN.getInstance()), defaultAlertToStaff = new ConfigDefault<>(true, "alerts.enabled", AntiVPN.getInstance()), + defaultWhitelistCountries = new ConfigDefault<>(true, "countries.whitelist", + AntiVPN.getInstance()), defaultMetrics = new ConfigDefault<>(true, "bstats", AntiVPN.getInstance()); private final ConfigDefault defaultPort = new ConfigDefault<>(-1, "database.port", AntiVPN.getInstance()); @@ -44,95 +47,184 @@ public class VPNConfig { "prefixWhitelists", AntiVPN.getInstance()), defaultCommands = new ConfigDefault<>( Collections.singletonList("kick %player% VPNs are not allowed on our server!"), "commands.execute", AntiVPN.getInstance()), - defBlockedCountries = new ConfigDefault<>(new ArrayList<>(), "blockedCountries", - AntiVPN.getInstance()), - defAllowedCountries = new ConfigDefault<>(new ArrayList<>(), "allowedCountries", + defCountryKickCommands = new ConfigDefault<>(Collections.singletonList( + "&cSorry, but our server does not allow connections from\n&f%name%"), + "countries.kickMessage", AntiVPN.getInstance()), + defCountrylist = new ConfigDefault<>(new ArrayList<>(), " countries.list", AntiVPN.getInstance()); private String license, kickMessage, databaseType, databaseName, mongoURL, username, password, ip, alertMsg; - private List prefixWhitelists, commands, allowedCountries, blockedCountries; + private List prefixWhitelists, commands, countryList, countryKickCommands; private int port; - private boolean cacheResults, databaseEnabled, useCredentials, commandsEnabled, kickPlayers, alertToStaff, metrics; + private boolean cacheResults, databaseEnabled, useCredentials, commandsEnabled, kickPlayers, alertToStaff, + metrics, whitelistCountries; + /** + * License from https://funkemunky.cc/shop to be used for more queries. + * @return String + */ public String getLicense() { return license; } + /** + * If true, results will be cached to reduce queries to https://funkemunky.cc + * @return boolean + */ public boolean cachedResults() { return cacheResults; } + /** + * Will be used for vanilla kick message when {@link VPNConfig#runCommands()} is true. + * @return String + */ public String getKickString() { return kickMessage; } - + + /** + * Message to send staff on proxy detection. + * @return String + */ public String alertMessage() { return alertMsg; } - + + /** + * If true, staff will be alerted on proxy detection. + * @return boolean + */ public boolean alertToStaff() { return alertToStaff; } + /** + * If true, will run {@link VPNConfig#commands()} on detect. If not, it will use vanilla kicking methods. + * @return boolean + */ public boolean runCommands() { return commandsEnabled; } - + + /** + * Commands to run on proxy detection. + * @return List + */ public List commands() { return commands; } + /** + * If false, no commands nor kick will be run on proxy detection. + * @return boolean + */ public boolean kickPlayersOnDetect() { return kickPlayers; } - + + /** + * Returns Strings of which are checked against the beginning of player names. Used to + * allow Geyser-connected players to join. + * @return List + */ public List getPrefixWhitelists() { return prefixWhitelists; } - + + /** + * Returns true if we want to use a database + * @return boolean + */ public boolean isDatabaseEnabled() { return databaseEnabled; } + /** + * Whether or not the database we want to connect to requires credentials. + * @return boolean + */ public boolean useDatabaseCreds() { return useCredentials; } + /** + * Only for Mongo only. URL used for connecting to database. Overrides other fields + * @return String + */ public String mongoDatabaseURL() { return mongoURL; } - + + /** + * Database type. Either MySQL and Mongo. + * @return String + */ public String getDatabaseType() { return databaseType; } - + + /** + * Database name + * @return String + */ public String getDatabaseName() { return databaseName; } + /** + * Database username + * @return String + */ public String getUsername() { return username; } - + + /** + * Database Password + * @return String + */ public String getPassword() { return password; } + /** + * Database IP + * @return String + */ public String getIp() { return ip; } - - public List allowedCountries() { - return allowedCountries; + /** + * Returns the list of ISO country codes we need to check. + * @return List + */ + public List countryList() { + return countryList; } - - public List blockedCountries() { - return blockedCountries; + /** + * If true, we only allow the {@link VPNConfig#countryKickCommands()}. If false, we blacklist them. + * @return boolean + */ + public boolean whitelistCountries() { + return whitelistCountries; } - + /** + * Returns our configured commands to run on player country detection. + * @return List + */ + public List countryKickCommands() { + return countryKickCommands; + } + + /** + * Gets the port based on configuration. If {@link VPNConfig#port} is -1, will get default port + * based on {@link VPNConfig#getDatabaseType()} lowerCase(). + * @return int + */ public int getPort() { if(port == -1) { switch (getDatabaseType().toLowerCase()) { @@ -149,11 +241,18 @@ public class VPNConfig { return port; } - + + /** + * If true, https://bstats.org metrics will be collected to improve KauriVPN. + * @return boolean + */ public boolean metrics() { return metrics; } + /** + * Grabs all information from the config.yml + */ public void update() { license = licenseDefault.get(); kickMessage = kickStringDefault.get(); @@ -174,8 +273,9 @@ public class VPNConfig { alertToStaff = defaultAlertToStaff.get(); alertMsg = defaultAlertMsg.get(); metrics = defaultMetrics.get(); - blockedCountries = defBlockedCountries.get(); - allowedCountries = defAllowedCountries.get(); + countryList = defCountrylist.get(); + whitelistCountries = defaultWhitelistCountries.get(); + countryKickCommands = defCountryKickCommands.get(); } } diff --git a/Common/src/main/resources/config.yml b/Common/src/main/resources/config.yml index e02ea71..df1ca32 100644 --- a/Common/src/main/resources/config.yml +++ b/Common/src/main/resources/config.yml @@ -48,6 +48,17 @@ alerts: # %city% (City name). message: '&8[&6KauriVPN&8] &e%player% &7has joined on a VPN/proxy &8(&f%reason%&8) &7in location &8(&f%city%&7, &f%country%&8)' +# Configuration for country gatekeepings +countries: + # You must use ISO codes for country configuration: https://www.iban.com/country-code + # Leave empty to disable this configuration + list: [] + # Set whitelist to true to only allow listed country codes, and false to deny listed country codes. + whitelist: true + # The commands to be run if the player is not allowed on the server with the above configured conditions + # Placeholders: %country% (Country name), %player% (Player name), %code% (Country ISO Code) + commands: + - "kick %player% &cSorry, but our server does not allow connections from\n&f%country%" # This will disable any information being sent to https://bstats.org. We recommend you keep this enabled as it helps # us understand our users and put effort where it is needed. All information sent goes under their privacy as seen # here: https://bstats.org/privacy-policy