Compare commits

..

10 Commits

Author SHA1 Message Date
funkemunky 3a0419cbac Merge branch 'bugfix/h2-load' 2025-04-22 12:09:04 -04:00
funkemunky 24257e4f42 Merge branch 'bugfix/bukkit-kick'
# Conflicts:
#	Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitListener.java
2025-04-22 12:08:53 -04:00
Dawson 2b7f043eb9 Improving shutdown and error handling (#63)
Co-authored-by: Dawson <dawson@funkemunky.cc>
2025-04-22 12:07:30 -04:00
Dawson 2dbe465b9e Fixing Bukkit player kicking not functioning properly (#62)
* Fixing bug where player is not kicked when using proxy on Bukkit servers

* Removing from PlayerLoginEvent and doing PlayerJoinEvent only instead.

---------

Co-authored-by: Dawson <dawson@funkemunky.cc>
2025-04-22 09:58:46 -04:00
funkemunky ac628811cc Merge branch 'master' into bugfix/bukkit-kick 2025-04-22 09:55:08 -04:00
Dawson 3aae8d8f49 Backing up and resetting database on versioning compatibility (#61)
Co-authored-by: Dawson <dawson@funkemunky.cc>
2025-04-22 09:54:43 -04:00
funkemunky f0c37c6ff0 Merge branch 'master' into bugfix/bukkit-kick
# Conflicts:
#	Assembly/pom.xml
#	Bukkit/pom.xml
#	Bungee/pom.xml
#	Common/pom.xml
#	Sponge/pom.xml
#	Velocity/pom.xml
#	pom.xml
2025-04-22 09:53:47 -04:00
funkemunky 311f1e198b Backing up and resetting database on versioning compatibility 2025-04-21 13:20:13 -04:00
funkemunky 6453898ca4 Removing from PlayerLoginEvent and doing PlayerJoinEvent only instead. 2025-03-20 10:29:21 -04:00
funkemunky 6243727ebf Fixing bug where player is not kicked when using proxy on Bukkit servers 2025-03-17 11:24:56 -04:00
15 changed files with 385 additions and 295 deletions
+8 -2
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.9.3.1</version>
<version>1.9.4-DEV</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -21,7 +21,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.2</version>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
@@ -65,6 +65,12 @@
<version>${version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.41.2.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Bukkit</artifactId>
+5 -4
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.9.3.1</version>
<version>1.9.4-DEV</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -16,7 +16,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<version>3.7.0</version>
<configuration>
<source>8</source>
<target>8</target>
@@ -26,7 +26,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.2</version>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
@@ -34,6 +34,7 @@
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
@@ -77,7 +78,7 @@
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Common</artifactId>
<version>1.9.3.1</version>
<version>1.9.4-DEV</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -11,14 +11,13 @@ 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.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
@@ -37,7 +36,7 @@ public class BukkitListener extends VPNExecutor implements Listener {
}
@Override
public void shutdown() {
public void onShutdown() {
}
@@ -56,7 +55,13 @@ public class BukkitListener extends VPNExecutor implements Listener {
Bukkit.getLogger().log(Level.SEVERE, message, ex);
}
@EventHandler
@Override
public void disablePlugin() {
HandlerList.unregisterAll(this);
BukkitPlugin.pluginInstance.getServer().getPluginManager().disablePlugin(BukkitPlugin.pluginInstance);
}
@EventHandler(priority = EventPriority.HIGH)
public void onJoin(final PlayerJoinEvent event) {
AntiVPN.getInstance().getPlayerExecutor().getPlayer(event.getPlayer().getUniqueId())
.ifPresent(player -> AntiVPN.getInstance().getDatabase().alertsState(player.getUuid(), enabled -> {
@@ -67,15 +72,20 @@ public class BukkitListener extends VPNExecutor implements Listener {
.getFormattedMessage(new VpnString.Var<>("state", true)));
}
}));
}
@EventHandler
public void onListener(final PlayerLoginEvent event) {
//If they're exempt, don't check.
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(event.getAddress().getHostAddress())
|| AntiVPN.getInstance().getExecutor().isWhitelisted(address)
|| AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream()
.anyMatch(prefix -> event.getPlayer().getName().startsWith(prefix))) return;
@@ -83,147 +93,124 @@ public class BukkitListener extends VPNExecutor implements Listener {
VPNResponse cached = responseCache.getIfPresent(event.getPlayer().getUniqueId());
if (cached != null && cached.isProxy()) {
event.setResult(PlayerLoginEvent.Result.KICK_BANNED);
event.setKickMessage(org.bukkit.ChatColor.translateAlternateColorCodes('&',
AntiVPN.getInstance().getVpnConfig().getKickString()));
proxyKick(event.getPlayer(), cached);
return;
}
}
final Player player = event.getPlayer();
checkIp(event.getAddress().getHostAddress(),
checkIp(address,
AntiVPN.getInstance().getVpnConfig().cachedResults(), 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());
log("UUID is whitelisted: %s", event.getPlayer().getUniqueId().toString());
return;
}
//If the IP is whitelisted, we don't want to kick them
InetSocketAddress address = event.getPlayer().getAddress();
if (address != null){
InetAddress address1 = address.getAddress();
if (address1 != null && AntiVPN.getInstance().getExecutor()
.isWhitelisted(address1.getHostAddress())) {
log("IP is whitelisted: %s",
address1.getHostAddress());
return;
}
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 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
// 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()) {
final String kickReason = AntiVPN.getInstance().getVpnConfig()
.countryVanillaKickReason();
// Start "online" fix
// In case the response was so fast from API the player wouldn't be "online".
event.setResult(PlayerLoginEvent.Result.KICK_BANNED);
event.setKickMessage(ChatColor
.translateAlternateColorCodes('&',
kickReason
.replace("%player%", event.getPlayer().getName())
.replace("%country%", result.getCountryName())
.replace("%code%", result.getCountryCode())));
// End "online" fix
//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() {
event.getPlayer().kickPlayer(ChatColor
.translateAlternateColorCodes('&',
kickReason
.replace("%player%", event.getPlayer().getName())
.replace("%country%", result.getCountryName())
.replace("%code%", result.getCountryCode())));
}
}.runTask(BukkitPlugin.pluginInstance);
} else {
final String playerName = event.getPlayer().getName();
BukkitPlugin.pluginInstance.getPlayerCommandRunner()
.addAction(event.getPlayer().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);
}
});
}
countryKick(player, result);
} else if(result.isProxy()) {
// Start "online" fix
// In case the response was so fast from API the player wouldn't be "online".
event.setResult(PlayerLoginEvent.Result.KICK_BANNED);
event.setKickMessage(ChatColor
.translateAlternateColorCodes('&',
AntiVPN.getInstance().getVpnConfig().getKickString()
.replace("%player%", event.getPlayer().getName())
.replace("%country%", result.getCountryName())
.replace("%code%", result.getCountryCode())));
// End "online" fix
if(AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) {
new BukkitRunnable() {
public void run() {
player.kickPlayer(org.bukkit.ChatColor.translateAlternateColorCodes('&',
AntiVPN.getInstance().getVpnConfig().getKickString()));
}
}.runTask(BukkitPlugin.pluginInstance);
}
log(Level.INFO, event.getPlayer().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%", 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()) {
String playerName = event.getPlayer().getName();
BukkitPlugin.pluginInstance.getPlayerCommandRunner()
.addAction(event.getPlayer().getUniqueId(), () -> {
for (String command : AntiVPN.getInstance().getVpnConfig().commands()) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
ChatColor.translateAlternateColorCodes('&',
command.replace("%player%",
playerName)));
}
});
}
AntiVPN.getInstance().detections++;
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");
"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
public void onQuit(PlayerQuitEvent event) {
AntiVPN.getInstance().getPlayerExecutor().unloadPlayer(event.getPlayer().getUniqueId());
+4 -4
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.9.3.1</version>
<version>1.9.4-DEV</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -16,7 +16,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<version>3.7.0</version>
<configuration>
<source>8</source>
<target>8</target>
@@ -26,7 +26,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.2</version>
<version>3.1.0</version>
<configuration>
<relocations>
<relocation>
@@ -71,7 +71,7 @@
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Common</artifactId>
<version>1.9.3.1</version>
<version>1.9.4-DEV</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -37,12 +37,11 @@ public class BungeeListener extends VPNExecutor implements Listener {
}
@Override
public void shutdown() {
public void onShutdown() {
if(cacheResetTask != null) {
cacheResetTask.cancel();
cacheResetTask = null;
}
threadExecutor.shutdown();
BungeePlugin.pluginInstance.getProxy().getPluginManager().unregisterListener(this);
}
@@ -61,6 +60,17 @@ public class BungeeListener extends VPNExecutor implements Listener {
BungeeCord.getInstance().getLogger().log(Level.SEVERE, message, ex);
}
@Override
public void disablePlugin() {
BungeeCord.getInstance().getPluginManager().unregisterListeners(BungeePlugin.pluginInstance);
if(cacheResetTask != null) {
cacheResetTask.cancel();
cacheResetTask = null;
}
BungeeCord.getInstance().getPluginManager().unregisterCommands(BungeePlugin.pluginInstance);
BungeePlugin.pluginInstance.onDisable();
}
@EventHandler(priority = EventPriority.LOWEST)
public void onListener(final PreLoginEvent event) {
if(!responseCache.asMap().containsKey(event.getConnection().getUniqueId())) return;
+7 -5
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.9.3.1</version>
<version>1.9.4-DEV</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -21,7 +21,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<version>3.10.1</version>
<configuration>
<source>8</source>
<target>8</target>
@@ -38,7 +38,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.2</version>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>
@@ -46,7 +46,7 @@
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<minimizeJar>true</minimizeJar>
<relocations>
<relocation>
<pattern>org.yaml.snakeyaml</pattern>
@@ -86,11 +86,13 @@
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.1.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.224</version>
<version>2.2.220</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -54,13 +54,17 @@ public class AntiVPN {
try {
File configFile = new File(pluginFolder, "config.yml");
if(!configFile.exists()){
configFile.getParentFile().mkdirs();
if(configFile.getParentFile().mkdirs()) {
AntiVPN.getInstance().getExecutor().log("Created plugin folder!");
}
MiscUtils.copy(INSTANCE.getResource( "config.yml"), configFile);
}
INSTANCE.config = ConfigurationProvider.getProvider(YamlConfiguration.class)
.load(configFile);
} catch (IOException e) {
e.printStackTrace();
AntiVPN.getInstance().getExecutor().logException("Could not load config.yml, plugin disabling...", e);
executor.disablePlugin();
return;
}
INSTANCE.vpnConfig = new VPNConfig();
@@ -139,7 +143,8 @@ public class AntiVPN {
}
public void stop() {
executor.shutdown();
executor.onShutdown();
VPNExecutor.threadExecutor.shutdown();
if(database != null) database.shutdown();
}
@@ -188,7 +193,7 @@ public class AntiVPN {
ConfigurationProvider.getProvider(YamlConfiguration.class)
.save(getConfig(), new File(pluginFolder.getPath() + File.separator + "config.yml"));
} catch (IOException e) {
e.printStackTrace();
AntiVPN.getInstance().getExecutor().logException(e);
}
}
@@ -32,7 +32,7 @@ public abstract class VPNExecutor {
public abstract void registerListeners();
public abstract void shutdown();
public abstract void onShutdown();
public abstract void log(Level level, String log, Object... objects);
@@ -97,4 +97,6 @@ public abstract class VPNExecutor {
}
}
}
public abstract void disablePlugin();
}
@@ -2,12 +2,17 @@ package dev.brighten.antivpn.database.sql.utils;
import com.mysql.cj.jdbc.Driver;
import dev.brighten.antivpn.AntiVPN;
import org.h2.jdbc.JdbcSQLFeatureNotSupportedException;
import org.h2.jdbc.JdbcSQLNonTransientConnectionException;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import java.util.logging.Level;
public class MySQL {
private static Connection conn;
@@ -33,12 +38,25 @@ public class MySQL {
}
}
private static boolean didRetry = false;
public static void initH2() {
if(didRetry) {
AntiVPN.getInstance().getExecutor().log(Level.WARNING,
"Already attempted to retry H2 connection, skipping.");
return;
}
File dataFolder = new File(AntiVPN.getInstance().getPluginFolder(), "databases");
if (!dataFolder.exists() && dataFolder.mkdirs()) {
AntiVPN.getInstance().getExecutor().log("Created database directory");
}
File dbFile = new File(dataFolder, "database.mv.db");
File databaseFile = new File(dataFolder, "database");
try {
conn = new NonClosableConnection(new org.h2.jdbc.JdbcConnection("jdbc:h2:file:" +
databaseFile.getAbsolutePath(),
databaseFile.getAbsolutePath(),
new Properties(), AntiVPN.getInstance().getVpnConfig().getUsername(),
AntiVPN.getInstance().getVpnConfig().getPassword(), false));
conn.setAutoCommit(true);
@@ -46,6 +64,44 @@ public class MySQL {
AntiVPN.getInstance().getExecutor().log("Connection to H2 has been established.");
} catch (SQLException ex) {
AntiVPN.getInstance().getExecutor().logException("H2 exception on initialize", ex);
if(ex instanceof JdbcSQLFeatureNotSupportedException
|| ex instanceof JdbcSQLNonTransientConnectionException) {
AntiVPN.getInstance().getExecutor()
.log("H2 database file is incompatible with this version of AntiVPN. " +
"Backing up old database file...");
backupOldDB(dbFile, dataFolder);
initH2();
didRetry = true;
} else {
AntiVPN.getInstance().getExecutor().logException("Failed to load H2 database: " + ex.getCause().toString(), ex);
}
}
}
private static void backupOldDB(File dbFile, File dataFolder) {
if (dbFile.exists()) {
try {
// Optional: Make backup first
File backupDir = new File(dataFolder, "backups");
if(backupDir.mkdirs()) {
AntiVPN.getInstance().getExecutor().log("Created backup directory");
} else {
AntiVPN.getInstance().getExecutor().log("Backup directory already exists");
}
File backupFile = new File(backupDir, "database.mv.db.backup_" + System.currentTimeMillis());
Files.copy(dbFile.toPath(), backupFile.toPath());
// Actually delete the file
if (!dbFile.delete()) {
// If normal delete fails, try force delete on JVM exit
dbFile.deleteOnExit();
AntiVPN.getInstance().getExecutor().log("Could not delete database file - will try again on shutdown");
} else {
AntiVPN.getInstance().getExecutor().log("Successfully deleted incompatible database file");
}
} catch (IOException ex) {
AntiVPN.getInstance().getExecutor().logException("Failed to handle database file", ex);
}
}
}
+2 -1
View File
@@ -11,7 +11,8 @@ cachedResults: true
# All players with any of the following characters in the beginning of their name will be whitelisted
# This is a useful feature for servers that allow players through Geyser and their IPs are not forwarded, causing
# players to be removed falsely for use of proxy.
prefixWhitelists: []
prefixWhitelists:
- "*"
# Configure your database here.
database:
# Enable to cache queries and save alerts state beyond restarts
+4 -4
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.9.3.1</version>
<version>1.9.4-DEV</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -28,14 +28,14 @@
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Common</artifactId>
<version>1.9.3.1</version>
<version>1.9.4-DEV</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
</project>
+4 -4
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.9.3.1</version>
<version>1.9.4-DEV</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -33,7 +33,7 @@
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Common</artifactId>
<version>1.9.3.1</version>
<version>1.9.4-DEV</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -49,7 +49,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<version>3.7.0</version>
<configuration>
<source>8</source>
<target>8</target>
@@ -59,7 +59,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.2</version>
<version>3.1.0</version>
<configuration>
<relocations>
<relocation>
@@ -2,6 +2,7 @@ package dev.brighten.antivpn.velocity;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.velocitypowered.api.event.EventHandler;
import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.connection.LoginEvent;
@@ -26,6 +27,145 @@ public class VelocityListener extends VPNExecutor {
.maximumSize(2000)
.build();
private final EventHandler<LoginEvent> loginEvent = 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;
if(responseCache.asMap().containsKey(event.getPlayer().getUniqueId())) {
VPNResponse cached = responseCache.getIfPresent(event.getPlayer().getUniqueId());
if (cached != null && cached.isProxy()) {
event.setResult(ResultedEvent.ComponentResult.denied(Component.text("No")));
return;
}
}
checkIp(event.getPlayer().getRemoteAddress().getAddress().getHostAddress(),
AntiVPN.getInstance().getVpnConfig().cachedResults(), result -> {
if (result.isSuccess()) {
// 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()))));
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())));
//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++;
}
} else {
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");
}
AntiVPN.getInstance().checked++;
});
}
};
@Override
public void registerListeners() {
@@ -33,156 +173,19 @@ 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;
if(responseCache.asMap().containsKey(event.getPlayer().getUniqueId())) {
VPNResponse cached = responseCache.getIfPresent(event.getPlayer().getUniqueId());
if (cached != null && cached.isProxy()) {
event.setResult(ResultedEvent.ComponentResult.denied(Component.text("No")));
return;
}
}
checkIp(event.getPlayer().getRemoteAddress().getAddress().getHostAddress(),
AntiVPN.getInstance().getVpnConfig().cachedResults(), result -> {
if (result.isSuccess()) {
// 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()))));
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())));
//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++;
}
} else {
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");
}
AntiVPN.getInstance().checked++;
});
}
});
loginEvent);
}
@Override
public void shutdown() {
public void onShutdown() {
if (cacheResetTask != null) {
cacheResetTask.cancel();
cacheResetTask = null;
}
threadExecutor.shutdown();
VelocityPlugin.INSTANCE.getServer().getEventManager().unregisterListener(VelocityPlugin.INSTANCE, this);
}
@@ -200,4 +203,10 @@ public class VelocityListener extends VPNExecutor {
public void logException(String message, Exception ex) {
VelocityPlugin.INSTANCE.getLogger().log(Level.SEVERE, message, ex);
}
@Override
public void disablePlugin() {
VelocityPlugin.INSTANCE.getServer().getEventManager().unregisterListener(VelocityPlugin.INSTANCE, this);
VelocityPlugin.INSTANCE.getServer().getCommandManager().unregister("antivpn");
}
}
@@ -3,6 +3,7 @@ package dev.brighten.antivpn.velocity;
import com.google.inject.Inject;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
@@ -12,6 +13,7 @@ import dev.brighten.antivpn.velocity.command.VelocityCommand;
import lombok.Getter;
import org.bstats.velocity.Metrics;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.util.logging.Logger;
@@ -24,6 +26,9 @@ public class VelocityPlugin {
private final Metrics.Factory metricsFactory;
private final Path configDir;
@Nullable
private Metrics metrics;
public static VelocityPlugin INSTANCE;
@Inject
@@ -45,7 +50,7 @@ public class VelocityPlugin {
if(AntiVPN.getInstance().getVpnConfig().metrics()) {
logger.info("Starting metrics...");
Metrics metrics = metricsFactory.make(this, 12791);
metrics = metricsFactory.make(this, 12791);
}
logger.info("Registering commands...");
@@ -54,4 +59,10 @@ public class VelocityPlugin {
.aliases(command.aliases()).build(), new VelocityCommand(command));
}
}
@Subscribe
public void onShutdown(ProxyShutdownEvent event) {
AntiVPN.getInstance().stop();
INSTANCE = null;
}
}
+2 -2
View File
@@ -7,7 +7,7 @@
<groupId>dev.brighten.antivpn</groupId>
<artifactId>AntiVPN</artifactId>
<packaging>pom</packaging>
<version>1.9.3.1</version>
<version>1.9.4-DEV</version>
<modules>
<module>Common</module>
@@ -28,7 +28,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<version>3.7.0</version>
<configuration>
<source>8</source>
<target>8</target>