diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 640dd04..f4dd1cb 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -7,16 +7,21 @@ on:
jobs:
build:
+ name: Build and Test
runs-on: ubuntu-latest
-
+
steps:
- uses: actions/checkout@v4
- - name: Set up JDK 17.0.2
+ - name: Set up JDK 17
uses: actions/setup-java@v4
with:
- java-version: 17.0
+ java-version: '17'
distribution: 'zulu'
- cache: 'maven'
+ cache: maven
+ - name: Set up Maven
+ uses: stCarolas/setup-maven@v5
+ with:
+ maven-version: 3.9.6
- name: Compile
run: mvn -B package --file pom.xml
env:
@@ -25,4 +30,4 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: AntiVPN
- path: Assembly/target/Assembly-*.jar
+ path: Universal/target/AntiVPN-*.jar
diff --git a/Bukkit/pom.xml b/Bukkit/pom.xml
index 0cc59d1..cda1424 100644
--- a/Bukkit/pom.xml
+++ b/Bukkit/pom.xml
@@ -16,17 +16,17 @@
org.apache.maven.pluginsmaven-compiler-plugin
- 3.7.0
+ 3.13.0
- 8
- 8
+ 17
+ 17-XDignore.symbol.fileorg.apache.maven.pluginsmaven-shade-plugin
- 3.2.4
+ 3.6.0package
@@ -45,10 +45,6 @@
org.yaml.snakeyamldev.brighten.antivpn.shaded.org.yaml.snakeyaml
-
- com.google.common
- dev.brighten.antivpn.shaded.com.google.common
-
@@ -64,10 +60,17 @@
- 8
- 8
+ 17
+ 17
+
+
+ spigot-repo
+ https://hub.spigotmc.org/nexus/content/repositories/snapshots/
+
+
+
org.spigotmc
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 8736537..1ded919 100644
--- a/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitListener.java
+++ b/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitListener.java
@@ -1,7 +1,7 @@
package dev.brighten.antivpn.bukkit;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
+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;
@@ -24,7 +24,7 @@ import java.util.logging.Level;
@SuppressWarnings("unchecked")
public class BukkitListener extends VPNExecutor implements Listener {
- private final Cache responseCache = CacheBuilder.newBuilder()
+ private final Cache responseCache = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.maximumSize(2000)
.build();
@@ -35,11 +35,6 @@ public class BukkitListener extends VPNExecutor implements Listener {
.registerEvents(this, BukkitPlugin.pluginInstance);
}
- @Override
- public void onShutdown() {
-
- }
-
@Override
public void log(Level level, String log, Object... objects) {
Bukkit.getLogger().log(level, String.format(log, objects));
@@ -51,7 +46,7 @@ public class BukkitListener extends VPNExecutor implements Listener {
}
@Override
- public void logException(String message, Exception ex) {
+ public void logException(String message, Throwable ex) {
Bukkit.getLogger().log(Level.SEVERE, message, ex);
}
@@ -99,43 +94,42 @@ public class BukkitListener extends VPNExecutor implements Listener {
}
final Player player = event.getPlayer();
- 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());
- return;
- }
+ 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 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++;
- });
+ // 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) {
diff --git a/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitPlugin.java b/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitPlugin.java
index 2b67350..fcd48a0 100644
--- a/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitPlugin.java
+++ b/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitPlugin.java
@@ -3,9 +3,13 @@ package dev.brighten.antivpn.bukkit;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.bukkit.command.BukkitCommand;
import dev.brighten.antivpn.command.Command;
+import dev.brighten.antivpn.database.VPNDatabase;
+import dev.brighten.antivpn.database.local.H2VPN;
+import dev.brighten.antivpn.database.mongo.MongoVPN;
+import dev.brighten.antivpn.database.sql.MySqlVPN;
import lombok.Getter;
import org.bstats.bukkit.Metrics;
-import org.bstats.charts.SingleLineChart;
+import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit;
import org.bukkit.command.SimpleCommandMap;
import org.bukkit.event.HandlerList;
@@ -24,8 +28,6 @@ public class BukkitPlugin extends JavaPlugin {
private SimpleCommandMap commandMap;
private final List registeredCommands = new ArrayList<>();
- @Getter
- private SingleLineChart vpnDetections, ipsChecked;
@Getter
private PlayerCommandRunner playerCommandRunner;
@@ -42,10 +44,7 @@ public class BukkitPlugin extends JavaPlugin {
if(AntiVPN.getInstance().getVpnConfig().metrics()) {
Bukkit.getLogger().info("Starting bStats metrics...");
Metrics metrics = new Metrics(this, 12615);
- metrics.addCustomChart(vpnDetections = new SingleLineChart("vpn_detections",
- () -> AntiVPN.getInstance().detections));
- metrics.addCustomChart(ipsChecked = new SingleLineChart("ips_checked",
- () -> AntiVPN.getInstance().checked));
+ metrics.addCustomChart(new SimplePie("database_used", this::getDatabaseType));
new BukkitRunnable() {
public void run() {
AntiVPN.getInstance().checked = AntiVPN.getInstance().detections = 0;
@@ -55,14 +54,13 @@ public class BukkitPlugin extends JavaPlugin {
Bukkit.getLogger().info("Setting up and registering commands...");
// We need access to the commandMap to register our commands without using the "proper" method
- if (pluginInstance.getServer().getPluginManager() instanceof SimplePluginManager) {
- SimplePluginManager manager = (SimplePluginManager) pluginInstance.getServer().getPluginManager();
+ if (pluginInstance.getServer().getPluginManager() instanceof SimplePluginManager manager) {
try {
Field field = SimplePluginManager.class.getDeclaredField("commandMap");
field.setAccessible(true);
commandMap = (SimpleCommandMap) field.get(manager);
} catch (IllegalArgumentException | SecurityException | NoSuchFieldException | IllegalAccessException e) {
- e.printStackTrace();
+ AntiVPN.getInstance().getExecutor().logException(e);
}
}
@@ -89,6 +87,7 @@ public class BukkitPlugin extends JavaPlugin {
}
@Override
+ @SuppressWarnings("unchecked")
public void onDisable() {
Bukkit.getLogger().info("Stopping plugin services...");
AntiVPN.getInstance().stop();
@@ -98,13 +97,15 @@ public class BukkitPlugin extends JavaPlugin {
try {
Field field = SimpleCommandMap.class.getDeclaredField("knownCommands");
field.setAccessible(true);
- Map knownCommands =
- (Map) field.get(commandMap);
- knownCommands.values().removeAll(registeredCommands);
- registeredCommands.clear();
+ if(field.get(commandMap) instanceof Map, ?> knownCommands) {
+ Map casted = (Map) knownCommands;
+ casted.values().removeAll(registeredCommands);
+ registeredCommands.clear();
+ }
+
} catch (IllegalAccessException | NoSuchFieldException e) {
- e.printStackTrace();
+ AntiVPN.getInstance().getExecutor().logException(e);
}
Bukkit.getLogger().info("Unregistering listeners...");
@@ -113,4 +114,18 @@ public class BukkitPlugin extends JavaPlugin {
Bukkit.getLogger().info("Cancelling any running tasks...");
Bukkit.getScheduler().cancelTasks(this);
}
+
+ private String getDatabaseType() {
+ VPNDatabase database = AntiVPN.getInstance().getDatabase();
+
+ if(database instanceof H2VPN) {
+ return "H2";
+ } else if(database instanceof MySqlVPN) {
+ return "MySQL";
+ } else if(database instanceof MongoVPN) {
+ return "MongoDB";
+ } else {
+ return "No-Database";
+ }
+ }
}
diff --git a/Bungee/pom.xml b/Bungee/pom.xml
index 06e4cff..9135c8d 100644
--- a/Bungee/pom.xml
+++ b/Bungee/pom.xml
@@ -16,17 +16,17 @@
org.apache.maven.pluginsmaven-compiler-plugin
- 3.7.0
+ 3.13.0
- 8
- 8
+ 17
+ 17-XDignore.symbol.fileorg.apache.maven.pluginsmaven-shade-plugin
- 3.1.0
+ 3.6.0
@@ -38,10 +38,6 @@
org.yaml.snakeyamldev.brighten.antivpn.shaded.org.yaml.snakeyaml
-
- com.google
- dev.brighten.antivpn.shaded.com.google
-
@@ -63,8 +59,8 @@
- 8
- 8
+ 17
+ 17
@@ -75,9 +71,10 @@
provided
- org.github.bungee
- BungeeCord-1.8
- 1.8
+ net.md-5
+ bungeecord-api
+ 1.21-R0.2
+ jarprovided
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 30d6250..ea8344b 100644
--- a/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeListener.java
+++ b/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeListener.java
@@ -1,12 +1,11 @@
package dev.brighten.antivpn.bungee;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
+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 net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
@@ -25,7 +24,7 @@ public class BungeeListener extends VPNExecutor implements Listener {
private ScheduledTask cacheResetTask;
- private final Cache responseCache = CacheBuilder.newBuilder()
+ private final Cache responseCache = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.maximumSize(2000)
.build();
@@ -36,18 +35,9 @@ public class BungeeListener extends VPNExecutor implements Listener {
.registerListener(BungeePlugin.pluginInstance, this);
}
- @Override
- public void onShutdown() {
- if(cacheResetTask != null) {
- cacheResetTask.cancel();
- cacheResetTask = null;
- }
- BungeePlugin.pluginInstance.getProxy().getPluginManager().unregisterListener(this);
- }
-
@Override
public void log(Level level, String log, Object... objects) {
- BungeeCord.getInstance().getLogger().log(Level.INFO, String.format(log, objects));
+ BungeePlugin.pluginInstance.getProxy().getLogger().log(Level.INFO, String.format(log, objects));
}
@Override
@@ -56,18 +46,18 @@ public class BungeeListener extends VPNExecutor implements Listener {
}
@Override
- public void logException(String message, Exception ex) {
- BungeeCord.getInstance().getLogger().log(Level.SEVERE, message, ex);
+ public void logException(String message, Throwable ex) {
+ BungeePlugin.pluginInstance.getProxy().getLogger().log(Level.SEVERE, message, ex);
}
@Override
public void disablePlugin() {
- BungeeCord.getInstance().getPluginManager().unregisterListeners(BungeePlugin.pluginInstance);
+ BungeePlugin.pluginInstance.getProxy().getPluginManager().unregisterListeners(BungeePlugin.pluginInstance);
if(cacheResetTask != null) {
cacheResetTask.cancel();
cacheResetTask = null;
}
- BungeeCord.getInstance().getPluginManager().unregisterCommands(BungeePlugin.pluginInstance);
+ BungeePlugin.pluginInstance.getProxy().getPluginManager().unregisterCommands(BungeePlugin.pluginInstance);
BungeePlugin.pluginInstance.onDisable();
}
@@ -79,7 +69,7 @@ public class BungeeListener extends VPNExecutor implements Listener {
if(cached != null && cached.isProxy()) {
event.setCancelled(true);
- event.setCancelReason(TextComponent.fromLegacyText(ChatColor
+ event.setReason(TextComponent.fromLegacy(ChatColor
.translateAlternateColorCodes('&',
AntiVPN.getInstance().getVpnConfig().getKickString())));
AntiVPN.getInstance().getExecutor().log(Level.INFO,
@@ -94,92 +84,92 @@ public class BungeeListener extends VPNExecutor implements Listener {
|| AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream()
.anyMatch(prefix -> event.getPlayer().getName().startsWith(prefix))) return;
- checkIp(event.getPlayer().getAddress().getAddress().getHostAddress(),
- AntiVPN.getInstance().getVpnConfig().cachedResults(), result -> {
- if(result.isSuccess()) {
- //If the player is whitelisted, we don't want to kick them
- if(AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId())) {
- AntiVPN.getInstance().getExecutor().log("UUID is whitelisted: %s",
- event.getPlayer().getUniqueId().toString());
- return;
- }
+ String address = event.getPlayer().getSocketAddress().toString();
- //If the IP is whitelisted, we don't want to kick them
- if(AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getAddress().getAddress()
- .getHostAddress())) {
- AntiVPN.getInstance().getExecutor().log("IP is whitelisted: %s",
- event.getPlayer().getAddress().getAddress().getHostAddress());
- return;
- }
+ if(AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId())) {
+ AntiVPN.getInstance().getExecutor().log("UUID is whitelisted: %s",
+ event.getPlayer().getUniqueId().toString());
+ return;
+ }
- responseCache.put(event.getPlayer().getUniqueId(), result);
+ //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;
+ }
- 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.fromLegacyText(ChatColor
- .translateAlternateColorCodes('&',
- kickReason
+ 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("%code%", result.getCountryCode()))));
+ .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 {
- 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
- BungeeCord.getInstance().getPluginManager().dispatchCommand(
- BungeeCord.getInstance().getConsole(), formattedCommand);
- }
+ 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");
}
- } else 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())));
-
- //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++;
- }
-
- } else {
- BungeeCord.getInstance().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++;
- });
+ AntiVPN.getInstance().checked++;
+ });
}
@EventHandler
diff --git a/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeePlayerExecutor.java b/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeePlayerExecutor.java
index b5e41fb..ab77f95 100644
--- a/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeePlayerExecutor.java
+++ b/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeePlayerExecutor.java
@@ -2,7 +2,6 @@ package dev.brighten.antivpn.bungee;
import dev.brighten.antivpn.api.APIPlayer;
import dev.brighten.antivpn.api.PlayerExecutor;
-import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.*;
@@ -14,7 +13,7 @@ public class BungeePlayerExecutor implements PlayerExecutor {
@Override
public Optional getPlayer(String name) {
- ProxiedPlayer player = BungeeCord.getInstance().getPlayer(name);
+ ProxiedPlayer player = BungeePlugin.pluginInstance.getProxy().getPlayer(name);
if(player == null) return Optional.empty();
@@ -23,7 +22,7 @@ public class BungeePlayerExecutor implements PlayerExecutor {
@Override
public Optional getPlayer(UUID uuid) {
- ProxiedPlayer player = BungeeCord.getInstance().getPlayer(uuid);
+ ProxiedPlayer player = BungeePlugin.pluginInstance.getProxy().getPlayer(uuid);
if(player == null) return Optional.empty();
@@ -37,7 +36,7 @@ public class BungeePlayerExecutor implements PlayerExecutor {
@Override
public List getOnlinePlayers() {
- return BungeeCord.getInstance().getPlayers().stream()
+ return BungeePlugin.pluginInstance.getProxy().getPlayers().stream()
.map(pl -> cachedPlayers.computeIfAbsent(pl.getUniqueId(), key -> new BungeePlayer(pl)))
.collect(Collectors.toList());
}
diff --git a/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeePlugin.java b/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeePlugin.java
index bb54d83..15e29bc 100644
--- a/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeePlugin.java
+++ b/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeePlugin.java
@@ -3,10 +3,13 @@ package dev.brighten.antivpn.bungee;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.bungee.command.BungeeCommand;
import dev.brighten.antivpn.command.Command;
-import net.md_5.bungee.BungeeCord;
+import dev.brighten.antivpn.database.VPNDatabase;
+import dev.brighten.antivpn.database.local.H2VPN;
+import dev.brighten.antivpn.database.mongo.MongoVPN;
+import dev.brighten.antivpn.database.sql.MySqlVPN;
import net.md_5.bungee.api.plugin.Plugin;
import org.bstats.bungeecord.Metrics;
-import org.bstats.charts.SingleLineChart;
+import org.bstats.charts.SimplePie;
import java.util.concurrent.TimeUnit;
@@ -14,34 +17,29 @@ public class BungeePlugin extends Plugin {
public static BungeePlugin pluginInstance;
- private SingleLineChart vpnDetections, ipsChecked;
-
@Override
public void onEnable() {
pluginInstance = this;
//Setting up config
- BungeeCord.getInstance().getLogger().info("Loading config...");
+ getProxy().getLogger().info("Loading config...");
//Loading plugin
- BungeeCord.getInstance().getLogger().info("Starting AntiVPN services...");
+ getProxy().getLogger().info("Starting AntiVPN services...");
AntiVPN.start(new BungeeListener(), new BungeePlayerExecutor(), getDataFolder());
if(AntiVPN.getInstance().getVpnConfig().metrics()) {
- BungeeCord.getInstance().getLogger().info("Starting bStats metrics...");
+ getProxy().getLogger().info("Starting bStats metrics...");
Metrics metrics = new Metrics(this, 12616);
- metrics.addCustomChart(vpnDetections = new SingleLineChart("vpn_detections",
- () -> AntiVPN.getInstance().detections));
- metrics.addCustomChart(ipsChecked = new SingleLineChart("ips_checked",
- () -> AntiVPN.getInstance().checked));
- BungeeCord.getInstance().getScheduler().schedule(this,
+ metrics.addCustomChart(new SimplePie("database_used", this::getDatabaseType));
+ getProxy().getScheduler().schedule(this,
() -> AntiVPN.getInstance().checked = AntiVPN.getInstance().detections = 0,
10, 10, TimeUnit.MINUTES);
}
for (Command command : AntiVPN.getInstance().getCommands()) {
- BungeeCord.getInstance().getPluginManager().registerCommand(pluginInstance, new BungeeCommand(command));
+ getProxy().getPluginManager().registerCommand(pluginInstance, new BungeeCommand(command));
}
}
@@ -49,4 +47,18 @@ public class BungeePlugin extends Plugin {
public void onDisable() {
AntiVPN.getInstance().stop();
}
+
+ private String getDatabaseType() {
+ VPNDatabase database = AntiVPN.getInstance().getDatabase();
+
+ if(database instanceof H2VPN) {
+ return "H2";
+ } else if(database instanceof MySqlVPN) {
+ return "MySQL";
+ } else if(database instanceof MongoVPN) {
+ return "MongoDB";
+ } else {
+ return "No-Database";
+ }
+ }
}
diff --git a/Common/pom.xml b/Common/pom.xml
index 82f313f..230cf7d 100644
--- a/Common/pom.xml
+++ b/Common/pom.xml
@@ -12,8 +12,8 @@
Common
- 8
- 8
+ 17
+ 17
@@ -21,10 +21,10 @@
org.apache.maven.pluginsmaven-compiler-plugin
- 3.10.1
+ 3.13.0
- 8
- 8
+ 17
+ 17-XDignore.symbol.file
@@ -38,7 +38,7 @@
org.apache.maven.pluginsmaven-shade-plugin
- 3.4.1
+ 3.6.0package
@@ -51,14 +51,65 @@
org.yaml.snakeyamldev.brighten.antivpn.shaded.org.yaml.snakeyaml
+
+
+ dev.brighten.antivpn.depends.Relocate
+ dev.brighten.antivpn.depends.MavenLibraries
+
- com.google.common
- dev.brighten.antivpn.shaded.com.google.common
+ com.google
+ dev.brighten.antivpn.shaded.com.google
+
+
+ dev.brighten.antivpn.depends.Relocate
+ dev.brighten.antivpn.depends.MavenLibraries
+ org.h2dev.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
+
@@ -87,12 +138,24 @@
mysql-connector-j9.1.0jar
- compile
+ providedcom.h2databaseh22.2.220
+ provided
+
+
+ org.ow2.asm
+ asm
+ 9.8
+ compile
+
+
+ org.ow2.asm
+ asm-commons
+ 9.8compile
@@ -102,15 +165,17 @@
compile
- com.google.guava
- guava
- 32.1.3-jre
+ com.github.ben-manes.caffeine
+ caffeine
+ 3.1.8
+ compile
+
org.mongodbmongo-java-driver3.12.14
- 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 9446bf8..3a24d96 100644
--- a/Common/src/main/java/dev/brighten/antivpn/AntiVPN.java
+++ b/Common/src/main/java/dev/brighten/antivpn/AntiVPN.java
@@ -9,6 +9,9 @@ import dev.brighten.antivpn.database.VPNDatabase;
import dev.brighten.antivpn.database.local.H2VPN;
import dev.brighten.antivpn.database.mongo.MongoVPN;
import dev.brighten.antivpn.database.sql.MySqlVPN;
+import dev.brighten.antivpn.depends.LibraryLoader;
+import dev.brighten.antivpn.depends.MavenLibrary;
+import dev.brighten.antivpn.depends.Relocate;
import dev.brighten.antivpn.message.MessageHandler;
import dev.brighten.antivpn.utils.ConfigDefault;
import dev.brighten.antivpn.utils.MiscUtils;
@@ -29,6 +32,21 @@ import java.util.List;
@Getter
@Setter(AccessLevel.PRIVATE)
+@MavenLibrary(groupId = "com.h2database", artifactId ="h2", version = "2.2.220", relocations = {
+ @Relocate(from ="org" + ".\\h2", to ="dev.brighten.antivpn.shaded.org.h2")})
+@MavenLibrary(groupId = "org.mongodb", artifactId = "mongo-java-driver", version = "3.12.14", relocations = {
+ @Relocate(from = "com." + "\\mongodb", to = "dev.brighten.antivpn.shaded.com.mongodb"),
+ @Relocate(from = "org" + "\\.bson", to = "dev.brighten.antivpn.shaded.org.bson")
+})
+@MavenLibrary(
+ groupId = "com.mysql",
+ artifactId = "mysql-connector-j",
+ version = "9.1.0",
+ relocations = {
+ @Relocate(from = "com.my\\" + "sql.cj", to = "dev.brighten.antivpn.shaded.com.mysql.cj"),
+ @Relocate(from = "com.my\\" + "sql.jdbc", to = "dev.brighten.antivpn.shaded.com.mysql.jdbc")
+ }
+)
public class AntiVPN {
private static AntiVPN INSTANCE;
@@ -51,6 +69,8 @@ public class AntiVPN {
INSTANCE.executor = executor;
INSTANCE.playerExecutor = playerExecutor;
+ LibraryLoader.loadAll(INSTANCE);
+
try {
File configFile = new File(pluginFolder, "config.yml");
if(!configFile.exists()){
@@ -143,7 +163,20 @@ public class AntiVPN {
}
public void stop() {
- executor.onShutdown();
+ if (database instanceof H2VPN) {
+ database.shutdown();
+
+ // Try to deregister driver
+ try {
+ java.sql.Driver driver = java.sql.DriverManager.getDriver("jdbc:h2:");
+ if (driver != null) {
+ java.sql.DriverManager.deregisterDriver(driver);
+ }
+ } catch (Exception e) {
+ // Log but don't throw
+ executor.log("Failed to deregister H2 driver: " + e.getMessage());
+ }
+ }
VPNExecutor.threadExecutor.shutdown();
if(database != null) database.shutdown();
}
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 1ae8cd7..838e6d8 100644
--- a/Common/src/main/java/dev/brighten/antivpn/api/VPNExecutor.java
+++ b/Common/src/main/java/dev/brighten/antivpn/api/VPNExecutor.java
@@ -1,7 +1,5 @@
package dev.brighten.antivpn.api;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.utils.json.JSONException;
import dev.brighten.antivpn.web.FunkemunkyAPI;
@@ -10,11 +8,9 @@ import lombok.Getter;
import java.io.IOException;
import java.util.*;
-import java.util.concurrent.ExecutionException;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
import java.util.logging.Level;
public abstract class VPNExecutor {
@@ -24,23 +20,15 @@ public abstract class VPNExecutor {
private final Set whitelisted = Collections.synchronizedSet(new HashSet<>());
@Getter
private final Set whitelistedIps = Collections.synchronizedSet(new HashSet<>());
-
- private final Cache responseCache = CacheBuilder.newBuilder()
- .expireAfterWrite(20, TimeUnit.MINUTES)
- .maximumSize(4000)
- .build();
-
public abstract void registerListeners();
- public abstract void onShutdown();
-
public abstract void log(Level level, String log, Object... objects);
public abstract void log(String log, Object... objects);
- public abstract void logException(String message, Exception ex);
+ public abstract void logException(String message, Throwable ex);
- public void logException(Exception ex) {
+ public void logException(Throwable ex) {
logException("An exception occurred: " + ex.getMessage(), ex);
}
@@ -58,44 +46,31 @@ public abstract class VPNExecutor {
return whitelistedIps.contains(ip);
}
- public void checkIp(String ip, boolean cachedResults, Consumer result) {
- threadExecutor.execute(() -> {
- if(cachedResults) {
+ public CompletableFuture checkIp(String ip) {
+ return CompletableFuture.supplyAsync(() -> {
+ Optional cachedRes = AntiVPN.getInstance().getDatabase().getStoredResponse(ip);
+
+ if(cachedRes.isPresent()) {
+ return cachedRes.get();
+ }
+ else {
try {
- result.accept(responseCache.get(ip, () -> checkIp(ip)));
- } catch (ExecutionException e) {
- log("Failed to process checkIp() method! Reason: " + e.getMessage());
- result.accept(VPNResponse.FAILED_RESPONSE);
+ VPNResponse response = FunkemunkyAPI
+ .getVPNResponse(ip, AntiVPN.getInstance().getVpnConfig().getLicense(), true);
+
+ if (response.isSuccess()) {
+ AntiVPN.getInstance().getDatabase().cacheResponse(response);
+ } else {
+ log("Query to VPN API failed! Reason: " + response.getFailureReason());
+ }
+
+ return response;
+ } catch (JSONException | IOException e) {
+ log("Query to VPN API failed! Reason: " + e.getMessage());
+ return VPNResponse.FAILED_RESPONSE;
}
- } else {
- result.accept(checkIp(ip));
}
- });
- }
-
- public VPNResponse checkIp(String ip) {
- Optional cachedRes = AntiVPN.getInstance().getDatabase().getStoredResponse(ip);
-
- if(cachedRes.isPresent()) {
- return cachedRes.get();
- }
- else {
- try {
- VPNResponse response = FunkemunkyAPI
- .getVPNResponse(ip, AntiVPN.getInstance().getVpnConfig().getLicense(), true);
-
- if (response.isSuccess()) {
- AntiVPN.getInstance().getDatabase().cacheResponse(response);
- } else {
- log("Query to VPN API failed! Reason: " + response.getFailureReason());
- }
-
- return response;
- } catch (JSONException | IOException e) {
- log("Query to VPN API failed! Reason: " + e.getMessage());
- return VPNResponse.FAILED_RESPONSE;
- }
- }
+ }, threadExecutor);
}
public abstract void disablePlugin();
diff --git a/Common/src/main/java/dev/brighten/antivpn/command/impl/LookupCommand.java b/Common/src/main/java/dev/brighten/antivpn/command/impl/LookupCommand.java
index cd2ba12..9949d40 100644
--- a/Common/src/main/java/dev/brighten/antivpn/command/impl/LookupCommand.java
+++ b/Common/src/main/java/dev/brighten/antivpn/command/impl/LookupCommand.java
@@ -55,28 +55,31 @@ public class LookupCommand extends Command {
Optional player = AntiVPN.getInstance().getPlayerExecutor().getPlayer(args[0]);
- if(!player.isPresent()) {
+ if(player.isEmpty()) {
return String.format("&cNo player found with the name \"%s\"", args[0]);
}
- AntiVPN.getInstance().getExecutor().checkIp(player.get().getIp().getHostAddress(),
- false, result -> {
- if(!result.isSuccess()) {
- executor.sendMessage("&cThere was an error trying to find the information of this player.");
- } else {
- executor.sendMessage(StringUtil.line("&8"));
- executor.sendMessage("&6&l" + player.get().getName() + "&7&l's Connection Information");
- executor.sendMessage("");
- executor.sendMessage("&e%s&8: &f%s", "Proxy", result.isProxy()
- ? "&a" + result.getMethod() : "&cNo");
- executor.sendMessage("&e%s&8: &f%s", "ISP", result.getIsp());
- executor.sendMessage("&e%s&8: &f%s", "Country", result.getCountryName());
- executor.sendMessage("&e%s&8: &f%s", "City", result.getCity());
- executor.sendMessage("&e%s&8: &f%s", "Coordinates", result.getLatitude()
- + "&7/&f" + result.getLongitude());
- executor.sendMessage(StringUtil.line("&8"));
- }
- });
+ AntiVPN.getInstance().getExecutor()
+ .checkIp(player.get().getIp().getHostAddress())
+ .thenAccept(result -> {
+ if(!result.isSuccess()) {
+ executor.sendMessage("&cThere was an error trying to find the " +
+ "information of this player.");
+ return;
+ }
+
+ executor.sendMessage(StringUtil.line("&8"));
+ executor.sendMessage("&6&l" + player.get().getName() + "&7&l's Connection Information");
+ executor.sendMessage("");
+ executor.sendMessage("&e%s&8: &f%s", "Proxy", result.isProxy()
+ ? "&a" + result.getMethod() : "&cNo");
+ executor.sendMessage("&e%s&8: &f%s", "ISP", result.getIsp());
+ executor.sendMessage("&e%s&8: &f%s", "Country", result.getCountryName());
+ executor.sendMessage("&e%s&8: &f%s", "City", result.getCity());
+ executor.sendMessage("&e%s&8: &f%s", "Coordinates", result.getLatitude()
+ + "&7/&f" + result.getLongitude());
+ executor.sendMessage(StringUtil.line("&8"));
+ });
return "&7Looking up the IP information for player " + player.get().getName() + "...";
diff --git a/Common/src/main/java/dev/brighten/antivpn/database/local/H2VPN.java b/Common/src/main/java/dev/brighten/antivpn/database/local/H2VPN.java
index c2cd904..4dfcdf9 100644
--- a/Common/src/main/java/dev/brighten/antivpn/database/local/H2VPN.java
+++ b/Common/src/main/java/dev/brighten/antivpn/database/local/H2VPN.java
@@ -1,5 +1,7 @@
package dev.brighten.antivpn.database.local;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.api.VPNExecutor;
import dev.brighten.antivpn.database.VPNDatabase;
@@ -20,6 +22,12 @@ import java.util.function.Consumer;
public class H2VPN implements VPNDatabase {
+ private final Cache cachedResponses = Caffeine.newBuilder()
+ .expireAfterWrite(20, TimeUnit.MINUTES)
+ .maximumSize(4000)
+ .build();
+
+
public H2VPN() {
VPNExecutor.threadExecutor.scheduleAtFixedRate(() -> {
if(!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed()) return;
@@ -41,29 +49,26 @@ public class H2VPN implements VPNDatabase {
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()|| MySQL.isClosed())
return Optional.empty();
- ResultSet rs = Query.prepare("select * from `responses` where `ip` = ? limit 1").append(ip).executeQuery();
-
- try {
- if (rs != null && rs.next()) {
- VPNResponse response = new VPNResponse(rs.getString("asn"), rs.getString("ip"),
- rs.getString("countryName"), rs.getString("countryCode"),
- rs.getString("city"), rs.getString("timeZone"),
- rs.getString("method"), rs.getString("isp"), "N/A",
- rs.getBoolean("proxy"), rs.getBoolean("cached"), true,
- rs.getDouble("latitude"), rs.getDouble("longitude"),
- rs.getTimestamp("inserted").getTime(), -1);
-
- if(System.currentTimeMillis() - response.getLastAccess() > TimeUnit.HOURS.toMillis(1)) {
- VPNExecutor.threadExecutor.execute(() -> deleteResponse(ip));
- return Optional.empty();
+ VPNResponse response = cachedResponses.get(ip, ip2 -> {
+ try(ResultSet rs = Query.prepare("select * from `responses` where `ip` = ? limit 1").append(ip).
+ executeQuery()) {
+ if (rs != null && rs.next()) {
+ return new VPNResponse(rs.getString("asn"), rs.getString("ip"),
+ rs.getString("countryName"), rs.getString("countryCode"),
+ rs.getString("city"), rs.getString("timeZone"),
+ rs.getString("method"), rs.getString("isp"), "N/A",
+ rs.getBoolean("proxy"), rs.getBoolean("cached"), true,
+ rs.getDouble("latitude"), rs.getDouble("longitude"),
+ rs.getTimestamp("inserted").getTime(), -1);
}
- return Optional.of(response);
+ } catch (SQLException e) {
+ AntiVPN.getInstance().getExecutor().logException("There was a problem getting a response for "
+ + ip, e);
}
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- }
+ return null;
+ });
- return Optional.empty();
+ return Optional.ofNullable(response);
}
/*
@@ -80,6 +85,8 @@ public class H2VPN implements VPNDatabase {
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
return;
+ cachedResponses.put(toCache.getIp(), toCache);
+
Query.prepare("insert into `responses` (`ip`,`asn`,`countryName`,`countryCode`,`city`,`timeZone`,"
+ "`method`,`isp`,`proxy`,`cached`,`inserted`,`latitude`,`longitude`) values (?,?,?,?,?,?,?,?,?,?,?,?,?)")
.append(toCache.getIp()).append(toCache.getAsn()).append(toCache.getCountryName())
@@ -198,13 +205,12 @@ public class H2VPN implements VPNDatabase {
if(MySQL.isClosed()) return;
VPNExecutor.threadExecutor.execute(() -> {
- ResultSet set = Query.prepare("select * from `alerts` where `uuid` = ? limit 1")
- .append(uuid.toString()).executeQuery();
- try {
+ try(ResultSet set = Query.prepare("select * from `alerts` where `uuid` = ? limit 1")
+ .append(uuid.toString()).executeQuery()) {
result.accept(set != null && set.next() && set.getString("uuid") != null);
} catch (SQLException e) {
- e.printStackTrace();
+ AntiVPN.getInstance().getExecutor().logException("There was a problem getting alerts state for " + uuid, e);
result.accept(false);
}
});
@@ -271,6 +277,7 @@ public class H2VPN implements VPNDatabase {
public void shutdown() {
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled())
return;
+
MySQL.shutdown();
}
}
diff --git a/Common/src/main/java/dev/brighten/antivpn/database/mongo/MongoVPN.java b/Common/src/main/java/dev/brighten/antivpn/database/mongo/MongoVPN.java
index 900abd4..2e7c4eb 100644
--- a/Common/src/main/java/dev/brighten/antivpn/database/mongo/MongoVPN.java
+++ b/Common/src/main/java/dev/brighten/antivpn/database/mongo/MongoVPN.java
@@ -1,5 +1,7 @@
package dev.brighten.antivpn.database.mongo;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
import com.mongodb.*;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
@@ -24,6 +26,11 @@ public class MongoVPN implements VPNDatabase {
private MongoCollection settingsDocument, cacheDocument;
private MongoClient client;
+ private final Cache cachedResponses = Caffeine.newBuilder()
+ .expireAfterWrite(20, TimeUnit.MINUTES)
+ .maximumSize(4000)
+ .build();
+
public MongoVPN() {
VPNExecutor.threadExecutor.scheduleAtFixedRate(() -> {
if(!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()) return;
@@ -41,32 +48,37 @@ public class MongoVPN implements VPNDatabase {
}
@Override
public Optional getStoredResponse(String ip) {
- Document rdoc = cacheDocument.find(Filters.eq("ip", ip)).first();
+ VPNResponse response = cachedResponses.get(ip, ip2 -> {
+ Document rdoc = cacheDocument.find(Filters.eq("ip", ip)).first();
- if(rdoc != null) {
- long lastUpdate = rdoc.get("lastAccess", 0L);
+ if(rdoc != null) {
+ long lastUpdate = rdoc.get("lastAccess", 0L);
- if(System.currentTimeMillis() - lastUpdate > TimeUnit.HOURS.toMillis(1)) {
- VPNExecutor.threadExecutor.execute(() -> deleteResponse(ip));
- return Optional.empty();
+ if(System.currentTimeMillis() - lastUpdate > TimeUnit.HOURS.toMillis(1)) {
+ VPNExecutor.threadExecutor.execute(() -> deleteResponse(ip));
+ return null;
+ }
+
+ return VPNResponse.builder().asn(rdoc.getString("asn")).ip(ip)
+ .countryName(rdoc.getString("countryName"))
+ .countryCode(rdoc.getString("countryCode"))
+ .city(rdoc.getString("city"))
+ .isp(rdoc.getString("isp"))
+ .method(rdoc.getString("method"))
+ .timeZone(rdoc.getString("timeZone"))
+ .proxy(rdoc.getBoolean("proxy"))
+ .cached(rdoc.getBoolean("cached"))
+ .success(true)
+ .latitude(rdoc.getDouble("latitude"))
+ .longitude(rdoc.getDouble("longitude"))
+ .lastAccess(rdoc.get("lastAccess", 0L))
+ .build();
}
+ return null;
+ });
- return Optional.of(VPNResponse.builder().asn(rdoc.getString("asn")).ip(ip)
- .countryName(rdoc.getString("countryName"))
- .countryCode(rdoc.getString("countryCode"))
- .city(rdoc.getString("city"))
- .isp(rdoc.getString("isp"))
- .method(rdoc.getString("method"))
- .timeZone(rdoc.getString("timeZone"))
- .proxy(rdoc.getBoolean("proxy"))
- .cached(rdoc.getBoolean("cached"))
- .success(true)
- .latitude(rdoc.getDouble("latitude"))
- .longitude(rdoc.getDouble("longitude"))
- .lastAccess(rdoc.get("lastAccess", 0L))
- .build());
- }
- return Optional.empty();
+
+ return Optional.ofNullable(response);
}
@Override
@@ -87,6 +99,8 @@ public class MongoVPN implements VPNDatabase {
rdoc.put("longitude", toCache.getLongitude());
rdoc.put("lastAccess", System.currentTimeMillis());
+ cachedResponses.put(toCache.getIp(), toCache);
+
VPNExecutor.threadExecutor.execute(() -> {
Bson update = new Document("$set", rdoc);
cacheDocument.updateOne(Filters.eq("ip", toCache.getIp()), update,
diff --git a/Common/src/main/java/dev/brighten/antivpn/database/sql/MySqlVPN.java b/Common/src/main/java/dev/brighten/antivpn/database/sql/MySqlVPN.java
index 1b3babd..39a9cea 100644
--- a/Common/src/main/java/dev/brighten/antivpn/database/sql/MySqlVPN.java
+++ b/Common/src/main/java/dev/brighten/antivpn/database/sql/MySqlVPN.java
@@ -1,5 +1,7 @@
package dev.brighten.antivpn.database.sql;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.api.VPNExecutor;
import dev.brighten.antivpn.database.VPNDatabase;
@@ -20,6 +22,12 @@ import java.util.function.Consumer;
public class MySqlVPN implements VPNDatabase {
+ private final Cache cachedResponses = Caffeine.newBuilder()
+ .expireAfterWrite(20, TimeUnit.MINUTES)
+ .maximumSize(4000)
+ .build();
+
+
public MySqlVPN() {
VPNExecutor.threadExecutor.scheduleAtFixedRate(() -> {
if(!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed()) return;
@@ -41,30 +49,34 @@ public class MySqlVPN implements VPNDatabase {
if (isDisabled())
return Optional.empty();
- ResultSet rs = Query.prepare("select * from `responses` where `ip` = ? limit 1").append(ip).executeQuery();
+ VPNResponse response = cachedResponses.get(ip, ip2 -> {
+ try(ResultSet rs = Query.prepare("select * from `responses` where `ip` = ? limit 1").append(ip)
+ .executeQuery()) {
+ if (rs != null && rs.next()) {
+ VPNResponse responseFromDoc = new VPNResponse(rs.getString("asn"),
+ rs.getString("ip"),
+ rs.getString("countryName"), rs.getString("countryCode"),
+ rs.getString("city"), rs.getString("timeZone"),
+ rs.getString("method"), rs.getString("isp"), "N/A",
+ rs.getBoolean("proxy"), rs.getBoolean("cached"), true,
+ rs.getDouble("latitude"), rs.getDouble("longitude"),
+ rs.getTimestamp("inserted").getTime(), -1);
- try {
- if (rs != null && rs.next()) {
- VPNResponse response = new VPNResponse(rs.getString("asn"), rs.getString("ip"),
- rs.getString("countryName"), rs.getString("countryCode"),
- rs.getString("city"), rs.getString("timeZone"),
- rs.getString("method"), rs.getString("isp"), "N/A",
- rs.getBoolean("proxy"), rs.getBoolean("cached"), true,
- rs.getDouble("latitude"), rs.getDouble("longitude"),
- rs.getTimestamp("inserted").getTime(), -1);
+ if(System.currentTimeMillis() - responseFromDoc.getLastAccess() > TimeUnit.HOURS.toMillis(1)) {
+ VPNExecutor.threadExecutor.execute(() -> deleteResponse(ip));
+ return null;
+ }
- if(System.currentTimeMillis() - response.getLastAccess() > TimeUnit.HOURS.toMillis(1)) {
- VPNExecutor.threadExecutor.execute(() -> deleteResponse(ip));
- return Optional.empty();
+ return responseFromDoc;
}
-
- return Optional.of(response);
+ } catch (SQLException e) {
+ AntiVPN.getInstance().getExecutor()
+ .logException("Failed to get response from cache due to SQL error for: " + ip, e);
}
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- }
+ return null;
+ });
- return Optional.empty();
+ return Optional.ofNullable(response);
}
/*
@@ -81,6 +93,8 @@ public class MySqlVPN implements VPNDatabase {
if (isDisabled())
return;
+ cachedResponses.put(toCache.getIp(), toCache);
+
Query.prepare("insert into `responses` (`ip`,`asn`,`countryName`,`countryCode`,`city`,`timeZone`,"
+ "`method`,`isp`,`proxy`,`cached`,`inserted`,`latitude`,`longitude`) values (?,?,?,?,?,?,?,?,?,?,?,?,?)")
.append(toCache.getIp()).append(toCache.getAsn()).append(toCache.getCountryName())
@@ -103,10 +117,10 @@ public class MySqlVPN implements VPNDatabase {
public boolean isWhitelisted(UUID uuid) {
if (isDisabled())
return false;
- ResultSet set = Query.prepare("select uuid from `whitelisted` where `uuid` = ? limit 1")
- .append(uuid.toString()).executeQuery();
-
- return set != null && set.next() && set.getString("uuid") != null;
+ try(ResultSet set = Query.prepare("select uuid from `whitelisted` where `uuid` = ? limit 1")
+ .append(uuid.toString()).executeQuery()) {
+ return set != null && set.next() && set.getString("uuid") != null;
+ }
}
@SneakyThrows
@@ -114,11 +128,10 @@ public class MySqlVPN implements VPNDatabase {
public boolean isWhitelisted(String ip) {
if (isDisabled())
return false;
- ResultSet set = Query.prepare("select `ip` from `whitelisted-ips` where `ip` = ? limit 1")
- .append(ip).executeQuery();
-
-
- return set != null && set.next() && set.getString("ip") != null;
+ try(ResultSet set = Query.prepare("select `ip` from `whitelisted-ips` where `ip` = ? limit 1")
+ .append(ip).executeQuery()) {
+ return set != null && set.next() && set.getString("ip") != null;
+ }
}
@Override
@@ -199,13 +212,13 @@ public class MySqlVPN implements VPNDatabase {
if(MySQL.isClosed()) return;
VPNExecutor.threadExecutor.execute(() -> {
- ResultSet set = Query.prepare("select * from `alerts` where `uuid` = ? limit 1")
- .append(uuid.toString()).executeQuery();
- try {
+ try(ResultSet set = Query.prepare("select * from `alerts` where `uuid` = ? limit 1")
+ .append(uuid.toString()).executeQuery()) {
result.accept(set != null && set.next() && set.getString("uuid") != null);
} catch (SQLException e) {
- e.printStackTrace();
+ AntiVPN.getInstance().getExecutor()
+ .logException("Failed to get alerts state from database for: " + uuid, e);
result.accept(false);
}
});
@@ -247,18 +260,16 @@ public class MySqlVPN implements VPNDatabase {
AntiVPN.getInstance().getExecutor().log("Creating tables...");
//Running check for old table types to update
- oldTableCheck: {
- Query.prepare("select `DATA_TYPE` from INFORMATION_SCHEMA.COLUMNS " +
- "WHERE table_name = 'responses' AND COLUMN_NAME = 'isp';").execute(set -> {
- if(set.getObject("DATA_TYPE").toString().contains("varchar")) {
- AntiVPN.getInstance().getExecutor().log("Using old database format for storing responses! " +
- "Dropping table and creating a new one...");
- if(Query.prepare("drop table `responses`").execute() > 0) {
- AntiVPN.getInstance().getExecutor().log("Successfully dropped table!");
- }
- }
- });
- }
+ Query.prepare("select `DATA_TYPE` from INFORMATION_SCHEMA.COLUMNS " +
+ "WHERE table_name = 'responses' AND COLUMN_NAME = 'isp';").execute(set -> {
+ if(set.getObject("DATA_TYPE").toString().contains("varchar")) {
+ AntiVPN.getInstance().getExecutor().log("Using old database format for storing responses! " +
+ "Dropping table and creating a new one...");
+ if(Query.prepare("drop table `responses`").execute() > 0) {
+ AntiVPN.getInstance().getExecutor().log("Successfully dropped table!");
+ }
+ }
+ });
Query.prepare("create table if not exists `whitelisted` (`uuid` varchar(36) not null)").execute();
Query.prepare("create table if not exists `whitelisted-ips` (`ip` varchar(45) not null)").execute();
@@ -277,15 +288,13 @@ public class MySqlVPN implements VPNDatabase {
" AND table_name='whitelisted' AND index_name='uuid_1';";
ResultSet rs = Query.prepare(query).executeQuery();
int id = 0;
- whitelistedIndex: {
- while (rs.next()) {
- id = rs.getInt("IndexExists");
- }
- if (id == 0) {
- Query.prepare("create index `uuid_1` on `whitelisted` (`uuid`)").execute();
- }
- id = 0;
+ while (rs.next()) {
+ id = rs.getInt("IndexExists");
}
+ if (id == 0) {
+ Query.prepare("create index `uuid_1` on `whitelisted` (`uuid`)").execute();
+ }
+ id = 0;
responsesIndex: {
query = "SELECT COUNT(1) IndexExists FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema=DATABASE() " +
"AND table_name='responses' AND index_name='ip_1';";
diff --git a/Common/src/main/java/dev/brighten/antivpn/depends/LibraryLoader.java b/Common/src/main/java/dev/brighten/antivpn/depends/LibraryLoader.java
new file mode 100644
index 0000000..2ef3bca
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/depends/LibraryLoader.java
@@ -0,0 +1,365 @@
+/*
+ * This file is part of helper, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package dev.brighten.antivpn.depends;
+
+import dev.brighten.antivpn.AntiVPN;
+import dev.brighten.antivpn.utils.NonnullByDefault;
+import dev.brighten.antivpn.utils.Supplier;
+import dev.brighten.antivpn.utils.Suppliers;
+import lombok.Getter;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.commons.ClassRemapper;
+import org.objectweb.asm.commons.Remapper;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.util.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+
+/**
+ * Resolves {@link MavenLibrary} annotations for a class, and loads the dependency
+ * into the classloader.
+ */
+@SuppressWarnings("CallToPrintStackTrace")
+@NonnullByDefault
+public final class LibraryLoader {
+
+ @SuppressWarnings("Guava")
+ private static final Supplier URL_INJECTOR = Suppliers.memoize(() ->
+ URLClassLoaderAccess.create((URLClassLoader) AntiVPN.getInstance().getClass().getClassLoader()));
+
+ public static void loadAll(Object object) {
+ loadAll(object.getClass());
+ }
+
+ public static void loadAll(Class> clazz) {
+ MavenLibrary[] libs = clazz.getDeclaredAnnotationsByType(MavenLibrary.class);
+
+ for (MavenLibrary lib : libs) {
+ // Create relocations map if any are defined
+ Map relocations = new HashMap<>();
+ for (Relocate relocate : lib.relocations()) {
+ relocations.put(relocate.from().replace("\\", ""), relocate.to());
+ }
+
+ load(lib.groupId().replace("\\", ""), lib.artifactId(), lib.version(), lib.repo().url(), relocations);
+ }
+ }
+
+ public static void load(String groupId, String artifactId, String version, String repoUrl,
+ Map relocations) {
+ load(new Dependency(groupId, artifactId, version, repoUrl), relocations);
+ }
+
+ public static void load(Dependency d, Map relocations) {
+ System.out.printf("Loading dependency %s:%s:%s from %s%n",
+ d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getRepoUrl());
+ String name = d.getArtifactId() + "-" + d.getVersion();
+
+ // If we have relocations, add a suffix to identify the relocated version
+ String fileName = name + ".jar";
+ if (!relocations.isEmpty()) {
+ fileName = name + "-relocated.jar";
+ }
+
+ File saveLocation = new File(getLibFolder(), fileName);
+ File originalJar = new File(getLibFolder(), name + ".jar");
+
+ // Download the original jar if it doesn't exist
+ if (!originalJar.exists()) {
+ try {
+ System.out.println("Dependency '" + name +
+ "' is not already in the libraries folder. Attempting to download...");
+ URL url = d.getUrl();
+
+ try (InputStream is = url.openStream()) {
+ Files.copy(is, originalJar.toPath());
+ }
+ System.out.println("Dependency '" + name + "' successfully downloaded.");
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Unable to download dependency: " + d, e);
+ }
+ }
+
+ // If we have relocations, create a relocated jar
+ if (!relocations.isEmpty() && !saveLocation.exists()) {
+ try {
+ System.out.println("Relocating packages for " + name + "...");
+ relocateJar(originalJar, saveLocation, relocations);
+ System.out.println("Successfully relocated packages for " + name);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Failed to relocate packages for dependency: " + d, e);
+ }
+ }
+
+ // Load the appropriate jar (original or relocated)
+ File jarToLoad = relocations.isEmpty() ? originalJar : saveLocation;
+
+ if (!jarToLoad.exists()) {
+ throw new RuntimeException("Unable to find dependency jar: " + jarToLoad.getAbsolutePath());
+ }
+
+ try {
+ URL_INJECTOR.get().addURL(jarToLoad.toURI().toURL());
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to load dependency: " + jarToLoad, e);
+ }
+
+ System.out.println("Loaded dependency '" + name + "' successfully.");
+ }
+
+ private static void relocateJar(File sourceJar, File targetJar, Map relocations)
+ throws IOException {
+ // Track service files to avoid duplicates
+ Map serviceFiles = new HashMap<>();
+
+ try (JarFile jar = new JarFile(sourceJar);
+ JarOutputStream jos = new JarOutputStream(Files.newOutputStream(targetJar.toPath()))) {
+
+ Enumeration entries = jar.entries();
+
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ String name = entry.getName();
+
+ // Skip directories
+ if (entry.isDirectory()) {
+ continue;
+ }
+
+ try (InputStream is = jar.getInputStream(entry)) {
+ if (name.startsWith("META-INF/services/")) {
+ // Process service files but don't write yet
+ processServiceFile(name, is, serviceFiles, relocations);
+ } else if (name.endsWith(".class")) {
+ // Relocate class file path as well as content
+ String relocatedPath = relocateClassPath(name, relocations);
+
+ JarEntry newEntry = new JarEntry(relocatedPath);
+ jos.putNextEntry(newEntry);
+
+ byte[] classBytes = readAllBytes(is);
+ byte[] relocatedBytes = relocateClass(classBytes, relocations);
+ jos.write(relocatedBytes);
+ jos.closeEntry();
+ } else {
+ // Copy other files as-is
+ JarEntry newEntry = new JarEntry(name);
+ jos.putNextEntry(newEntry);
+ copyStream(is, jos);
+ jos.closeEntry();
+ }
+ }
+ }
+
+ // Now write all service files after processing
+ for (Map.Entry entry : serviceFiles.entrySet()) {
+ try {
+ JarEntry serviceEntry = new JarEntry(entry.getKey());
+ jos.putNextEntry(serviceEntry);
+ jos.write(entry.getValue().toString().getBytes());
+ jos.closeEntry();
+ } catch (Exception e) {
+ // Log but continue with other service files
+ System.out.println("Warning: Could not write service file " +
+ entry.getKey() + ": " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ private static void processServiceFile(String name, InputStream is,
+ Map serviceFiles,
+ Map relocations) throws IOException {
+ // Read service file content
+ String content = new String(readAllBytes(is));
+ StringBuilder contentBuilder = serviceFiles.computeIfAbsent(name, k -> new StringBuilder());
+
+ // Process and relocate service implementations
+ for (String line : content.split("\n")) {
+ String trimmed = line.trim();
+ if (!trimmed.isEmpty() && !trimmed.startsWith("#")) {
+ for (Map.Entry relocation : relocations.entrySet()) {
+ if (trimmed.startsWith(relocation.getKey())) {
+ trimmed = relocation.getValue() +
+ trimmed.substring(relocation.getKey().length());
+ break;
+ }
+ }
+ }
+ contentBuilder.append(trimmed).append("\n");
+ }
+ }
+
+ private static byte[] relocateClass(byte[] classBytes, Map relocations) {
+ try {
+ // Convert to slash notation for ASM
+ Remapper prefixRemapper = getPrefixRemapper(relocations);
+
+ // Create custom ClassWriter to handle missing classes
+ ClassReader reader = new ClassReader(classBytes);
+ ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS) {
+ @Override
+ protected String getCommonSuperClass(String type1, String type2) {
+ try {
+ return super.getCommonSuperClass(type1, type2);
+ } catch (RuntimeException e) {
+ // Fall back to Object when classes can't be loaded
+ return "java/lang/Object";
+ }
+ }
+ };
+
+ ClassVisitor visitor = new ClassRemapper(writer, prefixRemapper);
+
+ // Process class with remapper
+ reader.accept(visitor, ClassReader.EXPAND_FRAMES);
+
+ return writer.toByteArray();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return classBytes;
+ }
+ }
+
+ private static Remapper getPrefixRemapper(Map relocations) {
+ Map slashMappings = new HashMap<>();
+ for (Map.Entry entry : relocations.entrySet()) {
+ String fromSlash = entry.getKey().replace('.', '/');
+ String toSlash = entry.getValue().replace('.', '/');
+ slashMappings.put(fromSlash, toSlash);
+ }
+
+ // Create customized remapper for package prefixes
+ return new Remapper() {
+ @Override
+ public String map(String typeName) {
+ if (typeName == null) return null;
+
+ for (Map.Entry entry : slashMappings.entrySet()) {
+ String from = entry.getKey();
+ String to = entry.getValue();
+
+ if (typeName.startsWith(from)) {
+ return to + typeName.substring(from.length());
+ }
+ }
+ return typeName;
+ }
+ };
+ }
+
+ private static String relocateClassPath(String path, Map relocations) {
+ // Convert path to package format (replacing / with .)
+ String packagePath = path.substring(0, path.length() - 6).replace('/', '.');
+
+ // Apply relocations
+ for (Map.Entry relocation : relocations.entrySet()) {
+ if (packagePath.startsWith(relocation.getKey())) {
+ packagePath = relocation.getValue() + packagePath.substring(relocation.getKey().length());
+ break;
+ }
+ }
+
+ // Convert back to path format
+ return packagePath.replace('.', '/') + ".class";
+ }
+
+ private static byte[] readAllBytes(InputStream is) throws IOException {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ int bytesRead;
+ byte[] data = new byte[1024];
+ while ((bytesRead = is.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, bytesRead);
+ }
+ return buffer.toByteArray();
+ }
+
+ private static void copyStream(InputStream is, OutputStream os) throws IOException {
+ byte[] buffer = new byte[1024];
+ int bytesRead;
+ while ((bytesRead = is.read(buffer)) != -1) {
+ os.write(buffer, 0, bytesRead);
+ }
+ }
+
+ private static File getLibFolder() {
+ File pluginDataFolder = AntiVPN.getInstance().getPluginFolder();
+ File libs = new File(pluginDataFolder, "libraries");
+ if(libs.mkdirs()) {
+ System.out.println("Created libraries folder!");
+ }
+ return libs;
+ }
+
+ @Getter
+ @NonnullByDefault
+// Fix the Dependency class to preserve original groupId for downloading
+ public static final class Dependency {
+ private final String groupId;
+ private final String artifactId;
+ private final String version;
+ private final String repoUrl;
+ // Keep the original groupId/artifactId for Maven downloads
+ private final String originalGroupId;
+ private final String originalArtifactId;
+
+ public Dependency(String groupId, String artifactId, String version, String repoUrl) {
+ this.originalGroupId = Objects.requireNonNull(groupId, "groupId");
+ this.originalArtifactId = Objects.requireNonNull(artifactId, "artifactId");
+ this.groupId = this.originalGroupId;
+ this.artifactId = this.originalArtifactId;
+ this.version = Objects.requireNonNull(version, "version");
+ this.repoUrl = Objects.requireNonNull(repoUrl, "repoUrl");
+ }
+
+ public URL getUrl() throws MalformedURLException {
+ String repo = this.repoUrl;
+ if (!repo.endsWith("/")) {
+ repo += "/";
+ }
+ repo += "%s/%s/%s/%s-%s.jar";
+
+ // Always use original groupId for Maven repository URL
+ String url = String.format(repo, this.originalGroupId.replace(".", "/"),
+ this.originalArtifactId, this.version, this.originalArtifactId, this.version);
+ return new URL(url);
+ }
+
+ // Rest of the class unchanged
+ }
+
+
+}
diff --git a/Common/src/main/java/dev/brighten/antivpn/depends/MavenLibraries.java b/Common/src/main/java/dev/brighten/antivpn/depends/MavenLibraries.java
new file mode 100644
index 0000000..189f737
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/depends/MavenLibraries.java
@@ -0,0 +1,40 @@
+/*
+ * This file is part of helper, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package dev.brighten.antivpn.depends;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation to indicate the required libraries for a class.
+ */
+@Documented
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MavenLibraries {
+
+ MavenLibrary[] value() default {};
+
+}
diff --git a/Common/src/main/java/dev/brighten/antivpn/depends/MavenLibrary.java b/Common/src/main/java/dev/brighten/antivpn/depends/MavenLibrary.java
new file mode 100644
index 0000000..eed8117
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/depends/MavenLibrary.java
@@ -0,0 +1,69 @@
+/*
+ * This file is part of helper, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package dev.brighten.antivpn.depends;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotation to indicate a required library for a class.
+ */
+@Documented
+@Repeatable(MavenLibraries.class)
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MavenLibrary {
+
+ /**
+ * The group id of the library
+ *
+ * @return the group id of the library
+ */
+ String groupId();
+
+ /**
+ * The artifact id of the library
+ *
+ * @return the artifact id of the library
+ */
+ String artifactId();
+
+ /**
+ * The version of the library
+ *
+ * @return the version of the library
+ */
+ String version();
+
+ /**
+ * The repo where the library can be obtained from
+ *
+ * @return the repo where the library can be obtained from
+ */
+ Repository repo() default @Repository(url = "https://repo1.maven.org/maven2");
+
+ Relocate[] relocations() default {}; // Add this line
+
+}
diff --git a/Common/src/main/java/dev/brighten/antivpn/depends/Relocate.java b/Common/src/main/java/dev/brighten/antivpn/depends/Relocate.java
new file mode 100644
index 0000000..32b8af5
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/depends/Relocate.java
@@ -0,0 +1,14 @@
+package dev.brighten.antivpn.depends;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({})
+public @interface Relocate {
+ String from();
+ String to();
+}
\ No newline at end of file
diff --git a/Common/src/main/java/dev/brighten/antivpn/depends/Repository.java b/Common/src/main/java/dev/brighten/antivpn/depends/Repository.java
new file mode 100644
index 0000000..4381225
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/depends/Repository.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of helper, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package dev.brighten.antivpn.depends;
+
+import java.lang.annotation.*;
+
+/**
+ * Represents a maven repository.
+ */
+@Documented
+@Target(ElementType.LOCAL_VARIABLE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Repository {
+
+ /**
+ * Gets the base url of the repository.
+ *
+ * @return the base url of the repository
+ */
+ String url();
+
+}
diff --git a/Common/src/main/java/dev/brighten/antivpn/depends/URLClassLoaderAccess.java b/Common/src/main/java/dev/brighten/antivpn/depends/URLClassLoaderAccess.java
new file mode 100644
index 0000000..a0159f0
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/depends/URLClassLoaderAccess.java
@@ -0,0 +1,175 @@
+/*
+ * This file is part of helper, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package dev.brighten.antivpn.depends;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collection;
+
+/**
+ * Provides access to {@link URLClassLoader}#addURL.
+ */
+public abstract class URLClassLoaderAccess {
+
+ /**
+ * Creates a {@link URLClassLoaderAccess} for the given class loader.
+ *
+ * @param classLoader the class loader
+ * @return the access object
+ */
+ static URLClassLoaderAccess create(URLClassLoader classLoader) {
+ if (Reflection.isSupported()) {
+ return new Reflection(classLoader);
+ } else if (Unsafe.isSupported()) {
+ return new Unsafe(classLoader);
+ } else {
+ return Noop.INSTANCE;
+ }
+ }
+
+ private final URLClassLoader classLoader;
+
+ protected URLClassLoaderAccess(URLClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+
+ /**
+ * Adds the given URL to the class loader.
+ *
+ * @param url the URL to add
+ */
+ public abstract void addURL(URL url);
+
+ /**
+ * Accesses using reflection, not supported on Java 9+.
+ */
+ private static class Reflection extends URLClassLoaderAccess {
+ private static final Method ADD_URL_METHOD;
+
+ static {
+ Method addUrlMethod;
+ try {
+ addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
+ addUrlMethod.setAccessible(true);
+ } catch (Exception e) {
+ addUrlMethod = null;
+ }
+ ADD_URL_METHOD = addUrlMethod;
+ }
+
+ private static boolean isSupported() {
+ return ADD_URL_METHOD != null;
+ }
+
+ Reflection(URLClassLoader classLoader) {
+ super(classLoader);
+ }
+
+ @Override
+ public void addURL(URL url) {
+ try {
+ ADD_URL_METHOD.invoke(super.classLoader, url);
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Accesses using sun.misc.Unsafe, supported on Java 9+.
+ *
+ * @author Vaishnav Anil (...)
+ */
+ private static class Unsafe extends URLClassLoaderAccess {
+ private static final sun.misc.Unsafe UNSAFE;
+
+ static {
+ sun.misc.Unsafe unsafe;
+ try {
+ Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
+ unsafeField.setAccessible(true);
+ unsafe = (sun.misc.Unsafe) unsafeField.get(null);
+ } catch (Throwable t) {
+ unsafe = null;
+ }
+ UNSAFE = unsafe;
+ }
+
+ private static boolean isSupported() {
+ return UNSAFE != null;
+ }
+
+ private final Collection unopenedURLs;
+ private final Collection pathURLs;
+
+ @SuppressWarnings("unchecked")
+ Unsafe(URLClassLoader classLoader) {
+ super(classLoader);
+
+ Collection unopenedURLs;
+ Collection pathURLs;
+ try {
+ Object ucp = fetchField(URLClassLoader.class, classLoader, "ucp");
+ unopenedURLs = (Collection) fetchField(ucp.getClass(), ucp, "unopenedUrls");
+ pathURLs = (Collection) fetchField(ucp.getClass(), ucp, "path");
+ } catch (Throwable e) {
+ unopenedURLs = null;
+ pathURLs = null;
+ }
+ this.unopenedURLs = unopenedURLs;
+ this.pathURLs = pathURLs;
+ }
+
+ private static Object fetchField(final Class> clazz, final Object object, final String name) throws NoSuchFieldException {
+ Field field = clazz.getDeclaredField(name);
+ long offset = UNSAFE.objectFieldOffset(field);
+ return UNSAFE.getObject(object, offset);
+ }
+
+ @Override
+ public void addURL(URL url) {
+ this.unopenedURLs.add(url);
+ this.pathURLs.add(url);
+ }
+ }
+
+ private static class Noop extends URLClassLoaderAccess {
+ private static final Noop INSTANCE = new Noop();
+
+ private Noop() {
+ super(null);
+ }
+
+ @Override
+ public void addURL(URL url) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+}
diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/ExtraObjectsMethodsForWeb.java b/Common/src/main/java/dev/brighten/antivpn/utils/ExtraObjectsMethodsForWeb.java
new file mode 100644
index 0000000..484f35e
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/utils/ExtraObjectsMethodsForWeb.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package dev.brighten.antivpn.utils;
+
+/**
+ * Holder for extra methods of {@code Objects} only in web. Intended to be empty for regular
+ * version.
+ */
+abstract class ExtraObjectsMethodsForWeb {}
diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/NonnullByDefault.java b/Common/src/main/java/dev/brighten/antivpn/utils/NonnullByDefault.java
new file mode 100644
index 0000000..48a1f73
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/utils/NonnullByDefault.java
@@ -0,0 +1,36 @@
+/*
+ * This file is part of helper, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package dev.brighten.antivpn.utils;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NonnullByDefault {
+
+}
diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/NullnessCasts.java b/Common/src/main/java/dev/brighten/antivpn/utils/NullnessCasts.java
new file mode 100644
index 0000000..24d68c9
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/utils/NullnessCasts.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package dev.brighten.antivpn.utils;
+
+/** A utility method to perform unchecked casts to suppress errors produced by nullness analyses. */
+final class NullnessCasts {
+ /**
+ * Accepts a {@code @Nullable T} and returns a plain {@code T}, without performing any check that
+ * that conversion is safe.
+ *
+ *
This method is intended to help with usages of type parameters that have {
+ * ParametricNullness parametric nullness}. If a type parameter instead ranges over only non-null
+ * types (or if the type is a non-variable type, like {@code String}), then code should almost
+ * never use this method, preferring instead to call {@code requireNonNull} so as to benefit from
+ * its runtime check.
+ *
+ *
An example use case for this method is in implementing an {@code Iterator} whose {@code
+ * next} field is lazily initialized. The type of that field would be {@code @Nullable T}, and the
+ * code would be responsible for populating a "real" {@code T} (which might still be the value
+ * {@code null}!) before returning it to callers. Depending on how the code is structured, a
+ * nullness analysis might not understand that the field has been populated. To avoid that problem
+ * without having to add {@code @SuppressWarnings}, the code can call this method.
+ *
+ *
Why not just add {@code SuppressWarnings}? The problem is that this method is
+ * typically useful for {@code return} statements. That leaves the code with two options: Either
+ * add the suppression to the whole method (which turns off checking for a large section of code),
+ * or extract a variable, and put the suppression on that. However, a local variable typically
+ * doesn't work: Because nullness analyses typically infer the nullness of local variables,
+ * there's no way to assign a {@code @Nullable T} to a field {@code T foo;} and instruct the
+ * analysis that that means "plain {@code T}" rather than the inferred type {@code @Nullable T}.
+ * (Even if supported added {@code @NonNull}, that would not help, since the problem case
+ * addressed by this method is the case in which {@code T} has parametric nullness -- and thus its
+ * value may be legitimately {@code null}.)
+ */
+ @SuppressWarnings("nullness")
+ static T uncheckedCastNullableTToT(T t) {
+ return t;
+ }
+
+ private NullnessCasts() {}
+}
diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/Preconditions.java b/Common/src/main/java/dev/brighten/antivpn/utils/Preconditions.java
new file mode 100644
index 0000000..7d24918
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/utils/Preconditions.java
@@ -0,0 +1,244 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package dev.brighten.antivpn.utils;
+
+public final class Preconditions {
+ private Preconditions() {
+ }
+
+ public static T checkNotNull(T reference) {
+ if (reference == null) {
+ throw new NullPointerException();
+ } else {
+ return reference;
+ }
+ }
+
+ public static T checkNotNull(T reference, Object errorMessage) {
+ if (reference == null) {
+ throw new NullPointerException(String.valueOf(errorMessage));
+ } else {
+ return reference;
+ }
+ }
+
+ public static T checkNotNull(T reference, String errorMessageTemplate, Object... errorMessageArgs) {
+ if (reference == null) {
+ throw new NullPointerException(format(errorMessageTemplate, errorMessageArgs));
+ } else {
+ return reference;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, char p1) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, int p1) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, long p1) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, Object p1) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, char p1, char p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, char p1, int p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, char p1, long p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, char p1, Object p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, int p1, char p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, int p1, int p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, int p1, long p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, int p1, Object p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, long p1, char p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, long p1, int p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, long p1, long p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, long p1, Object p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, Object p1, char p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, Object p1, int p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, Object p1, long p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, Object p1, Object p2) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, Object p1, Object p2, Object p3) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2, p3));
+ } else {
+ return obj;
+ }
+ }
+
+ public static T checkNotNull(T obj, String errorMessageTemplate, Object p1, Object p2, Object p3, Object p4) {
+ if (obj == null) {
+ throw new NullPointerException(format(errorMessageTemplate, p1, p2, p3, p4));
+ } else {
+ return obj;
+ }
+ }
+
+ static String format(String template, Object... args) {
+ template = String.valueOf(template);
+ StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
+ int templateStart = 0;
+
+ int i;
+ int placeholderStart;
+ for(i = 0; i < args.length; templateStart = placeholderStart + 2) {
+ placeholderStart = template.indexOf("%s", templateStart);
+ if (placeholderStart == -1) {
+ break;
+ }
+
+ builder.append(template, templateStart, placeholderStart);
+ builder.append(args[i++]);
+ }
+
+ builder.append(template, templateStart, template.length());
+ if (i < args.length) {
+ builder.append(" [");
+ builder.append(args[i++]);
+
+ while(i < args.length) {
+ builder.append(", ");
+ builder.append(args[i++]);
+ }
+
+ builder.append(']');
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/Supplier.java b/Common/src/main/java/dev/brighten/antivpn/utils/Supplier.java
new file mode 100644
index 0000000..c1f7365
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/utils/Supplier.java
@@ -0,0 +1,11 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package dev.brighten.antivpn.utils;
+
+@FunctionalInterface
+public interface Supplier extends java.util.function.Supplier {
+ T get();
+}
diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/Suppliers.java b/Common/src/main/java/dev/brighten/antivpn/utils/Suppliers.java
new file mode 100644
index 0000000..d380307
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/utils/Suppliers.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2007 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package dev.brighten.antivpn.utils;
+
+import java.io.Serializable;
+
+import static dev.brighten.antivpn.utils.NullnessCasts.uncheckedCastNullableTToT;
+import static dev.brighten.antivpn.utils.Preconditions.checkNotNull;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Useful suppliers.
+ *
+ *
All methods return serializable suppliers as long as they're given serializable parameters.
+ *
+ * @author Laurence Gonsalves
+ * @author Harry Heymann
+ * @since 2.0
+ */
+public final class Suppliers {
+ private Suppliers() {}
+
+ /**
+ * Returns a supplier which caches the instance retrieved during the first call to {@code get()}
+ * and returns that value on subsequent calls to {@code get()}. See: memoization
+ *
+ *
The returned supplier is thread-safe. The delegate's {@code get()} method will be invoked at
+ * most once unless the underlying {@code get()} throws an exception. The supplier's serialized
+ * form does not contain the cached value, which will be recalculated when {@code get()} is called
+ * on the reserialized instance.
+ *
+ *
When the underlying delegate throws an exception then this memoizing supplier will keep
+ * delegating calls until it returns valid data.
+ *
+ *
If {@code delegate} is an instance created by an earlier call to {@code memoize}, it is
+ * returned directly.
+ */
+ public static Supplier memoize(Supplier delegate) {
+ if (delegate instanceof NonSerializableMemoizingSupplier
+ || delegate instanceof MemoizingSupplier) {
+ return delegate;
+ }
+ return delegate instanceof Serializable
+ ? new MemoizingSupplier<>(delegate)
+ : new NonSerializableMemoizingSupplier<>(delegate);
+ }
+
+ static class MemoizingSupplier implements Supplier, Serializable {
+ final Supplier delegate;
+ transient volatile boolean initialized;
+ // "value" does not need to be volatile; visibility piggy-backs
+ // on volatile read of "initialized".
+ transient T value;
+
+ MemoizingSupplier(Supplier delegate) {
+ this.delegate = checkNotNull(delegate);
+ }
+
+ @Override
+ public T get() {
+ // A 2-field variant of Double Checked Locking.
+ if (!initialized) {
+ synchronized (this) {
+ if (!initialized) {
+ T t = delegate.get();
+ value = t;
+ initialized = true;
+ return t;
+ }
+ }
+ }
+ // This is safe because we checked `initialized.`
+ return uncheckedCastNullableTToT(value);
+ }
+
+ @Override
+ public String toString() {
+ return "Suppliers.memoize("
+ + (initialized ? "" : delegate)
+ + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ static class NonSerializableMemoizingSupplier implements Supplier {
+ volatile Supplier delegate;
+ volatile boolean initialized;
+ // "value" does not need to be volatile; visibility piggy-backs
+ // on volatile read of "initialized".
+ T value;
+
+ NonSerializableMemoizingSupplier(Supplier delegate) {
+ this.delegate = checkNotNull(delegate);
+ }
+
+ @Override
+ public T get() {
+ // A 2-field variant of Double Checked Locking.
+ if (!initialized) {
+ synchronized (this) {
+ if (!initialized) {
+ /*
+ * requireNonNull is safe because we read and write `delegate` under synchronization.
+ *
+ * TODO(cpovirk): To avoid having to check for null, replace `delegate` with a singleton
+ * `Supplier` that always throws an exception.
+ */
+ T t = requireNonNull(delegate).get();
+ value = t;
+ initialized = true;
+ // Release the delegate to GC.
+ delegate = null;
+ return t;
+ }
+ }
+ }
+ // This is safe because we checked `initialized.`
+ return uncheckedCastNullableTToT(value);
+ }
+
+ @Override
+ public String toString() {
+ Supplier delegate = this.delegate;
+ return "Suppliers.memoize("
+ + (delegate == null ? "" : delegate)
+ + ")";
+ }
+ }
+}
diff --git a/Assembly/pom.xml b/Universal/pom.xml
similarity index 58%
rename from Assembly/pom.xml
rename to Universal/pom.xml
index a118190..ebe5ca1 100644
--- a/Assembly/pom.xml
+++ b/Universal/pom.xml
@@ -2,26 +2,56 @@
+ 4.0.0
- AntiVPNdev.brighten.antivpn
+ AntiVPN1.9.4-DEV
- 4.0.0
- Assembly
+ Universal
- 8
- 8
+ 17
+ 17
+ UTF-8
+
+
+ dev.brighten.antivpn
+ Common
+ ${project.version}
+
+
+ dev.brighten.antivpn
+ Bukkit
+ ${project.version}
+
+
+ dev.brighten.antivpn
+ Bungee
+ ${project.version}
+
+
+ dev.brighten.antivpn
+ Velocity
+ ${project.version}
+
+
+
+
+
org.apache.maven.pluginsmaven-shade-plugin
- 3.2.4
+ 3.6.0package
@@ -29,15 +59,25 @@
shade
+ AntiVPN-${project.version}-universal
+ false
+
+
+ org.yaml.snakeyamldev.brighten.antivpn.shaded.org.yaml.snakeyaml
- com.google.common
- dev.brighten.antivpn.shaded.com.google.common
+ org.bstats
+ dev.brighten.antivpn.shaded.org.bstats
+
+ com.google
+ dev.brighten.antivpn.shaded.com.google
+
+
@@ -46,37 +86,4 @@
-
-
- dev.brighten.antivpn
- Bungee
- ${version}
- compile
-
-
- dev.brighten.antivpn
- Velocity
- ${version}
- compile
-
-
- dev.brighten.antivpn
- Common
- ${version}
- compile
-
-
- org.xerial
- sqlite-jdbc
- 3.41.2.2
- compile
-
-
- dev.brighten.antivpn
- Bukkit
- ${version}
- compile
-
-
-
\ No newline at end of file
diff --git a/Velocity/pom.xml b/Velocity/pom.xml
index 045296f..f7dc4b3 100644
--- a/Velocity/pom.xml
+++ b/Velocity/pom.xml
@@ -12,8 +12,8 @@
Velocity
- 8
- 8
+ 17
+ 17
@@ -49,17 +49,17 @@
org.apache.maven.pluginsmaven-compiler-plugin
- 3.7.0
+ 3.13.0
- 8
- 8
+ 17
+ 17-XDignore.symbol.fileorg.apache.maven.pluginsmaven-shade-plugin
- 3.1.0
+ 3.6.0
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 04ab467..8c6a437 100644
--- a/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityListener.java
+++ b/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityListener.java
@@ -1,192 +1,155 @@
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;
-import com.velocitypowered.api.scheduler.ScheduledTask;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.api.APIPlayer;
import dev.brighten.antivpn.api.VPNExecutor;
import dev.brighten.antivpn.velocity.util.StringUtils;
-import dev.brighten.antivpn.web.objects.VPNResponse;
-import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
public class VelocityListener extends VPNExecutor {
- private ScheduledTask cacheResetTask;
- private final Cache responseCache = CacheBuilder.newBuilder()
- .expireAfterWrite(5, TimeUnit.MINUTES)
- .maximumSize(2000)
- .build();
-
- private final EventHandler 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() {
VelocityPlugin.INSTANCE.getServer().getEventManager()
.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,
- 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;
+ 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()))));
- @Override
- public void onShutdown() {
- if (cacheResetTask != null) {
- cacheResetTask.cancel();
- cacheResetTask = null;
- }
- VelocityPlugin.INSTANCE.getServer().getEventManager().unregisterListener(VelocityPlugin.INSTANCE, this);
+ 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++;
+ }
+ AntiVPN.getInstance().checked++;
+ });
+ }
+ });
}
@Override
@@ -200,7 +163,7 @@ public class VelocityListener extends VPNExecutor {
}
@Override
- public void logException(String message, Exception ex) {
+ public void logException(String message, Throwable ex) {
VelocityPlugin.INSTANCE.getLogger().log(Level.SEVERE, message, ex);
}
diff --git a/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityPlugin.java b/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityPlugin.java
index 33e8e89..da0de33 100644
--- a/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityPlugin.java
+++ b/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityPlugin.java
@@ -9,8 +9,13 @@ import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.command.Command;
+import dev.brighten.antivpn.database.VPNDatabase;
+import dev.brighten.antivpn.database.local.H2VPN;
+import dev.brighten.antivpn.database.mongo.MongoVPN;
+import dev.brighten.antivpn.database.sql.MySqlVPN;
import dev.brighten.antivpn.velocity.command.VelocityCommand;
import lombok.Getter;
+import org.bstats.charts.SimplePie;
import org.bstats.velocity.Metrics;
import javax.annotation.Nullable;
@@ -29,6 +34,7 @@ public class VelocityPlugin {
@Nullable
private Metrics metrics;
+
public static VelocityPlugin INSTANCE;
@Inject
@@ -51,6 +57,8 @@ public class VelocityPlugin {
if(AntiVPN.getInstance().getVpnConfig().metrics()) {
logger.info("Starting metrics...");
metrics = metricsFactory.make(this, 12791);
+
+ metrics.addCustomChart(new SimplePie("database_used", this::getDatabaseType));
}
logger.info("Registering commands...");
@@ -61,8 +69,33 @@ public class VelocityPlugin {
}
@Subscribe
- public void onShutdown(ProxyShutdownEvent event) {
- AntiVPN.getInstance().stop();
+ public void onDisable(ProxyShutdownEvent event) {
+ logger.info("Disabling AntiVPN...");
+ AntiVPN.getInstance().getExecutor().log("Disabling AntiVPN...");
+
+ if (AntiVPN.getInstance().getDatabase() != null) {
+ AntiVPN.getInstance().stop();
+ }
+
+ if (metrics != null) {
+ metrics = null;
+ }
+
INSTANCE = null;
+ logger.info("Disabled AntiVPN.");
+ }
+
+ private String getDatabaseType() {
+ VPNDatabase database = AntiVPN.getInstance().getDatabase();
+
+ if(database instanceof H2VPN) {
+ return "H2";
+ } else if(database instanceof MySqlVPN) {
+ return "MySQL";
+ } else if(database instanceof MongoVPN) {
+ return "MongoDB";
+ } else {
+ return "No-Database";
+ }
}
}
diff --git a/pom.xml b/pom.xml
index 1bab415..05cf495 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,14 +13,14 @@
CommonBungeeBukkit
- AssemblyVelocitySponge
+ Universal
- 8
- 8
+ 17
+ 17
@@ -30,8 +30,8 @@
maven-compiler-plugin3.7.0
- 8
- 8
+ 17
+ 17-XDignore.symbol.filefalse
@@ -53,10 +53,6 @@
-
- spigot-repo
- https://hub.spigotmc.org/nexus/content/repositories/snapshots/
- funkemunky-releaseshttps://nexus.funkemunky.cc/content/repositories/releases/