Compare commits

..

28 Commits

Author SHA1 Message Date
Dawson Hessler 5a69e49fb9 Relocating shaded depends to prevent incompatibilities 2022-04-01 11:50:32 -04:00
Dawson fe6d5a3635 Merge pull request #19 from funkemunky/country-banning
Country banning
2022-04-01 11:34:37 -04:00
Dawson Hessler b5caf9604d Adding vanilla kick option 2022-04-01 11:27:56 -04:00
Dawson Hessler 315d4eaa3f Running country checks before running proxy checks 2022-04-01 11:13:21 -04:00
Dawson Hessler f98ab77944 Fixing Bukkit NullPointerException 2022-04-01 11:12:21 -04:00
funkemunky 0fccd9e296 Debugging velocity 2022-03-30 09:47:40 -04:00
funkemunky 0db8b93a7c Updating Bukkit and Velocity 2022-03-30 09:12:59 -04:00
funkemunky ea979cd729 Adding kick command to bungee and adding comments 2022-03-30 08:59:50 -04:00
Dawson Hessler ba72ad2a44 Implementing new configuration system 2022-03-29 16:20:07 -04:00
Dawson Hessler 8edef241e4 Adding universal config API and adding allowed/blocked country config 2022-03-18 10:33:14 -04:00
funkemunky 2fbbe5b3c8 Fixing bukkit prefix not working 2022-03-17 21:41:33 -04:00
Dawson 325e19dca5 Merge pull request #16 from Kek5chen/master
attempted fix of wrong alert state
2022-02-21 09:16:25 -05:00
Dawson 8ad6c3aaa2 Merge pull request #13 from funkemunky/dependabot/maven/Common/com.h2database-h2-2.1.210
Bump h2 from 1.4.200 to 2.1.210 in /Common
2022-02-21 09:16:12 -05:00
Dawson f8765ff95f Merge pull request #17 from funkemunky/fixing-ip-whitelist
Fixing ip whitelist
2022-02-21 09:16:00 -05:00
funkemunky 619b61fe55 Fixed ip whitelisting 2022-02-21 09:15:43 -05:00
funkemunky a6aac8fce7 Using regex to check ipv4 and fixing allowlist ips 2022-02-21 08:19:46 -05:00
funkemunky 2afb31b073 Adding maven compile check 2022-02-21 07:55:06 -05:00
Kekschen 66d193148e Fixed setting values into cache 2022-02-20 22:06:28 +01:00
Kekschen 58b48dceb4 Updated APIPlayer Caching
---Untested Code---

Updated the BukkitPlayer caching objects to use UUIDs instead of Player objects as Player objects generate a new hash when rejoining the server and get out of sync therefore will horde memory and stay unavailable till the programs termination.
2022-02-20 21:59:54 +01:00
Dawson Hessler e03deb6ba6 1.6.1 2022-02-08 14:56:06 -05:00
Dawson Hessler 6142ef603d Merge branch 'master' of https://github.com/funkemunky/AntiVPN 2022-02-08 14:55:39 -05:00
Dawson Hessler 2d82e0c433 Fixing potential memory leak 2022-02-08 14:55:37 -05:00
Dawson 3b629f4796 Merge pull request #15 from unbeproducoes/patch-1
Try to use the new MySQL driver first.
2022-02-06 11:29:28 -05:00
Unbê Produções 23481bd786 Check the new driver before the old one 2022-02-05 02:27:02 -03:00
Unbê Produções 46156c4286 update MySQL Driver
=3
2022-02-05 02:19:22 -03:00
dependabot[bot] 898e32972b Bump h2 from 1.4.200 to 2.1.210 in /Common
Bumps [h2](https://github.com/h2database/h2database) from 1.4.200 to 2.1.210.
- [Release notes](https://github.com/h2database/h2database/releases)
- [Commits](https://github.com/h2database/h2database/compare/version-1.4.200...version-2.1.210)

---
updated-dependencies:
- dependency-name: com.h2database:h2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-21 23:54:53 +00:00
Dawson Hessler cd502b6f34 Adding mongo support and /antivpn clearcache command 2022-01-12 15:37:02 -05:00
Dawson Hessler 7ee04b74ea Fixing config 2021-12-22 09:51:26 -05:00
44 changed files with 1420 additions and 1301 deletions
+20
View File
@@ -0,0 +1,20 @@
on:
push:
branches: ["**"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 17.0.2
uses: actions/setup-java@v1
with:
java-version: 17.0
- name: Compile
run: mvn -B -Pclean install
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+28 -3
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.5.2.1</version>
<version>1.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Assembly</artifactId>
@@ -11,7 +11,7 @@
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
@@ -20,6 +20,32 @@
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<relocations>
<relocation>
<pattern>org.yaml.snakeyaml</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.org.yaml.snakeyaml</shadedPattern>
</relocation>
<relocation>
<pattern>com.mongodb</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.com.mongodb</shadedPattern>
</relocation>
<relocation>
<pattern>org.bson</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.org.bson</shadedPattern>
</relocation>
<relocation>
<pattern>com.mysql</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.com.mysql</shadedPattern>
</relocation>
<relocation>
<pattern>com.google</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.com.google</shadedPattern>
</relocation>
<relocation>
<pattern>com.moandjiezana</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.com.moandjiezana</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
@@ -39,4 +65,3 @@
<maven.compiler.source>8</maven.compiler.source>
</properties>
</project>
+28 -2
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.5.2.1</version>
<version>1.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -21,7 +21,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
@@ -30,6 +30,32 @@
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<relocations>
<relocation>
<pattern>org.yaml.snakeyaml</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.org.yaml.snakeyaml</shadedPattern>
</relocation>
<relocation>
<pattern>com.mongodb</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.com.mongodb</shadedPattern>
</relocation>
<relocation>
<pattern>org.bson</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.org.bson</shadedPattern>
</relocation>
<relocation>
<pattern>com.mysql</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.com.mysql</shadedPattern>
</relocation>
<relocation>
<pattern>com.google</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.com.google</shadedPattern>
</relocation>
<relocation>
<pattern>com.moandjiezana</pattern>
<shadedPattern>dev.brighten.antivpn.utils.shaded.com.moandjiezana</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
+14 -2
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.5.2.1</version>
<version>1.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Bukkit</artifactId>
@@ -56,7 +56,7 @@
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Common</artifactId>
<version>1.5.2.1</version>
<version>1.7</version>
<scope>provided</scope>
<exclusions>
<exclusion>
@@ -67,6 +67,18 @@
<artifactId>mysql-connector-java</artifactId>
<groupId>mysql</groupId>
</exclusion>
<exclusion>
<artifactId>h2</artifactId>
<groupId>com.h2database</groupId>
</exclusion>
<exclusion>
<artifactId>snakeyaml</artifactId>
<groupId>org.yaml</groupId>
</exclusion>
<exclusion>
<artifactId>mongo-java-driver</artifactId>
<groupId>org.mongodb</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
+2 -2
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.5.2.1</version>
<version>1.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -69,7 +69,7 @@
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Common</artifactId>
<version>1.5.2.1</version>
<version>1.7</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -1,168 +0,0 @@
package dev.brighten.antivpn.bukkit;
import dev.brighten.antivpn.api.VPNConfig;
import dev.brighten.antivpn.bukkit.util.ConfigDefault;
import org.bukkit.Bukkit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class BukkitConfig implements VPNConfig {
private final ConfigDefault<String> licenseDefault = new ConfigDefault<>("",
"license", BukkitPlugin.pluginInstance), kickStringDefault =
new ConfigDefault<>("Proxies are not allowed on our server",
"kickMessage", BukkitPlugin.pluginInstance),
defaultDatabaseType = new ConfigDefault<>("MySQL",
"database.type", BukkitPlugin.pluginInstance),
defaultDatabaseName = new ConfigDefault<>("kaurivpn",
"database.database", BukkitPlugin.pluginInstance),
defaultUsername = new ConfigDefault<>("root",
"database.username", BukkitPlugin.pluginInstance),
defaultPassword = new ConfigDefault<>("password",
"database.password", BukkitPlugin.pluginInstance),
defaultAuthDatabase = new ConfigDefault<>("admin",
"database.auth", BukkitPlugin.pluginInstance),
defaultIp = new ConfigDefault<>("localhost", "database.ip", BukkitPlugin.pluginInstance),
defaultAlertMsg = new ConfigDefault<>("&8[&6KauriVPN&8] &e%player% &7has joined on a VPN/proxy" +
" &8(&f%reason%&8) &7in location &8(&f%city%&7, &f%country%&8)", "alerts.message",
BukkitPlugin.pluginInstance);
private final ConfigDefault<Boolean> cacheResultsDefault = new ConfigDefault<>(true,
"cachedResults", BukkitPlugin.pluginInstance),
defaultDatabaseEnabled = new ConfigDefault<>(false, "database.enabled",
BukkitPlugin.pluginInstance), defaultCommandsEnable = new ConfigDefault<>(false,
"commands.enabled", BukkitPlugin.pluginInstance), defaultKickPlayers
= new ConfigDefault<>(true, "kickPlayers", BukkitPlugin.pluginInstance),
defaultAlertToStaff = new ConfigDefault<>(true, "alerts.enabled",
BukkitPlugin.pluginInstance),
defaultMetrics = new ConfigDefault<>(true, "bstats", BukkitPlugin.pluginInstance);
private final ConfigDefault<Integer>
defaultPort = new ConfigDefault<>(-1, "database.port", BukkitPlugin.pluginInstance);
private final ConfigDefault<List<String>> prefixWhitelistsDefault = new ConfigDefault<>(new ArrayList<>(),
"prefixWhitelists", BukkitPlugin.pluginInstance), defaultCommands = new ConfigDefault<>(
Collections.singletonList("kick %player% VPNs are not allowed on our server!"), "commands.execute",
BukkitPlugin.pluginInstance);
private String license, kickMessage, databaseType, databaseName, username, password, ip, alertMsg;
private List<String> prefixWhitelists, commands;
private int port;
private boolean cacheResults, databaseEnabled, commandsEnabled, kickPlayers, alertToStaff, metrics;
@Override
public String getLicense() {
return license;
}
@Override
public boolean cachedResults() {
return cacheResults;
}
@Override
public String getKickString() {
return kickMessage;
}
@Override
public String alertMessage() {
return alertMsg;
}
@Override
public boolean alertToStaff() {
return alertToStaff;
}
@Override
public boolean runCommands() {
return commandsEnabled;
}
@Override
public List<String> commands() {
return commands;
}
@Override
public boolean kickPlayersOnDetect() {
return kickPlayers;
}
@Override
public List<String> getPrefixWhitelists() {
return prefixWhitelists;
}
@Override
public boolean isDatabaseEnabled() {
return databaseEnabled;
}
@Override
public String getDatabaseType() {
return databaseType;
}
@Override
public String getDatabaseName() {
return databaseName;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getIp() {
return ip;
}
@Override
public int getPort() {
if(port == -1) {
switch (getDatabaseType().toLowerCase()) {
case "mongodb":
case "mongo":
case "mongod":
return 27017;
case "sql":
case "mysql":
return 3306;
}
}
return port;
}
@Override
public boolean metrics() {
return metrics;
}
public void update() {
license = licenseDefault.get();
kickMessage = kickStringDefault.get();
cacheResults = cacheResultsDefault.get();
prefixWhitelists = prefixWhitelistsDefault.get();
databaseEnabled = defaultDatabaseEnabled.get();
databaseType = defaultDatabaseType.get();
databaseName = defaultDatabaseName.get();
username = defaultUsername.get();
password = defaultPassword.get();
ip = defaultIp.get();
port = defaultPort.get();
commandsEnabled = defaultCommandsEnable.get();
commands = defaultCommands.get();
kickPlayers = defaultKickPlayers.get();
alertToStaff = defaultAlertToStaff.get();
alertMsg = defaultAlertMsg.get();
metrics = defaultMetrics.get();
}
}
@@ -5,8 +5,9 @@ import dev.brighten.antivpn.api.APIPlayer;
import dev.brighten.antivpn.api.VPNExecutor;
import dev.brighten.antivpn.message.VpnString;
import lombok.val;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
@@ -71,49 +72,88 @@ public class BukkitListener extends VPNExecutor implements Listener {
@EventHandler
public void onListener(final PlayerLoginEvent event) {
//If they're exempt, don't check.
if(AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId())
|| AntiVPN.getInstance().getExecutor().isWhitelisted(event.getAddress().getHostAddress())) return;
checkIp(event.getAddress().getHostAddress(), AntiVPN.getInstance().getConfig().cachedResults(), result -> {
if(result.isSuccess() && result.isProxy()) {
new BukkitRunnable() {
public void run() {
Player player = event.getPlayer();
if(event.getPlayer().hasPermission("antivpn.bypass") //Has bypass permission
|| AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId()) //Is exempt
//Or has a name that starts with a certain prefix. This is for Bedrock exempting.
|| AntiVPN.getInstance().getExecutor().isWhitelisted(event.getAddress().getHostAddress())
|| AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream()
.anyMatch(prefix -> event.getPlayer().getName().startsWith(prefix))) return;
if(!player.hasPermission("antivpn.bypass") //Has bypass permission
//Or has a name that starts with a certain prefix. This is for Bedrock exempting.
|| AntiVPN.getInstance().getConfig().getPrefixWhitelists().stream()
.anyMatch(prefix -> player.getName().startsWith(prefix))) {
if (AntiVPN.getInstance().getConfig().kickPlayersOnDetect())
player.kickPlayer(ChatColor.translateAlternateColorCodes('&',
AntiVPN.getInstance().getConfig().getKickString()));
final Player player = event.getPlayer();
checkIp(event.getAddress().getHostAddress(),
AntiVPN.getInstance().getVpnConfig().cachedResults(), result -> {
if(result.isSuccess()) {
//We need to run on main thread or kicking and running commands will cause errors
new BukkitRunnable() {
public void run() {
// If the countryList() size is zero, no need to check.
// Running country check first
if(AntiVPN.getInstance().getVpnConfig().countryList().size() > 0
// This bit of code will decide whether or not to kick the player
// If it contains the code and it is set to whitelist, it will not kick as they are equal
// and vise versa. However, if the contains does not match the state, it will kick.
&& AntiVPN.getInstance().getVpnConfig().countryList()
.contains(result.getCountryCode())
!= AntiVPN.getInstance().getVpnConfig().whitelistCountries()) {
//Using our built in kicking system if no commands are configured
if(AntiVPN.getInstance().getVpnConfig().countryKickCommands().size() == 0) {
final String kickReason = AntiVPN.getInstance().getVpnConfig()
.countryVanillaKickReason();
// Kicking our player
event.getPlayer().kickPlayer(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()));
//Ensuring the user wishes to alert to staff
if(AntiVPN.getInstance().getConfig().alertToStaff())
AntiVPN.getInstance().getPlayerExecutor().getOnlinePlayers().stream()
.filter(APIPlayer::isAlertsEnabled)
.forEach(pl -> pl.sendMessage(AntiVPN.getInstance().getConfig()
.alertMessage().replace("%player%", event.getPlayer().getName())
.replace("%reason%", result.getMethod())
.replace("%country%", result.getCountryName())
.replace("%city%", result.getCity())));
// Runs our command from console
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), formattedCommand);
}
}
} else if(result.isProxy()) {
if(AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect())
player.kickPlayer(org.bukkit.ChatColor.translateAlternateColorCodes('&',
AntiVPN.getInstance().getVpnConfig().getKickString()));
Bukkit.getLogger().info(event.getPlayer().getName()
+ " joined on a VPN/Proxy (" + result.getMethod() + ")");
//In case the user wants to run their own commands instead of using the built in kicking
if(AntiVPN.getInstance().getConfig().runCommands())
for (String command : AntiVPN.getInstance().getConfig().commands()) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
ChatColor.translateAlternateColorCodes('&',
command.replace("%player%", event.getPlayer().getName())));
//Ensuring the user wishes to alert to staff
if(AntiVPN.getInstance().getVpnConfig().alertToStaff())
AntiVPN.getInstance().getPlayerExecutor().getOnlinePlayers().stream()
.filter(APIPlayer::isAlertsEnabled)
.forEach(pl -> pl.sendMessage(AntiVPN.getInstance().getVpnConfig().alertMessage()
.replace("%player%", event.getPlayer().getName())
.replace("%reason%", result.getMethod())
.replace("%country%", result.getCountryName())
.replace("%city%", result.getCity())));
//In case the user wants to run their own commands instead of using the built in kicking
if(AntiVPN.getInstance().getVpnConfig().runCommands()) {
for (String command : AntiVPN.getInstance().getVpnConfig().commands()) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
ChatColor.translateAlternateColorCodes('&',
command.replace("%player%",
event.getPlayer().getName())));
}
}
AntiVPN.getInstance().detections++;
}
}
Bukkit.getLogger().info(player.getPlayer().getName()
+ " joined on a VPN/Proxy (" + result.getMethod() + ")");
}
}.runTask(BukkitPlugin.pluginInstance);
} else {
Bukkit.getLogger()
.log(Level.WARNING,
"The API query was not a success! " +
"You may need to upgrade your license on https://funkemunky.cc/shop");
}
}.runTask(BukkitPlugin.pluginInstance);
} else if(!result.isSuccess()) {
Bukkit.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++;
});
}
}
@@ -11,7 +11,7 @@ import java.util.stream.Collectors;
public class BukkitPlayerExecutor implements PlayerExecutor {
private final Map<Player, BukkitPlayer> cachedPlayers = new WeakHashMap<>();
private final Map<UUID, BukkitPlayer> cachedPlayers = new WeakHashMap<>();
@Override
public Optional<APIPlayer> getPlayer(String name) {
@@ -21,7 +21,7 @@ public class BukkitPlayerExecutor implements PlayerExecutor {
return Optional.empty();
}
return Optional.of(cachedPlayers.computeIfAbsent(player, BukkitPlayer::new));
return Optional.of(cachedPlayers.computeIfAbsent(player.getUniqueId(), k -> new BukkitPlayer(player)));
}
@Override
@@ -32,14 +32,14 @@ public class BukkitPlayerExecutor implements PlayerExecutor {
return Optional.empty();
}
return Optional.of(cachedPlayers.computeIfAbsent(player, BukkitPlayer::new));
return Optional.of(cachedPlayers.computeIfAbsent(player.getUniqueId(), k -> new BukkitPlayer(player)));
}
@Override
public List<APIPlayer> getOnlinePlayers() {
return Bukkit.getOnlinePlayers().stream()
.map(pl -> cachedPlayers.computeIfAbsent(pl, BukkitPlayer::new))
.map(pl -> cachedPlayers.computeIfAbsent(pl.getUniqueId(), k -> new BukkitPlayer(pl)))
.collect(Collectors.toList());
}
@@ -1,12 +1,13 @@
package dev.brighten.antivpn.bukkit;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.bukkit.util.ConfigDefault;
import dev.brighten.antivpn.command.Command;
import dev.brighten.antivpn.utils.ConfigDefault;
import dev.brighten.antivpn.utils.MiscUtils;
import dev.brighten.antivpn.utils.config.Configuration;
import lombok.val;
import net.md_5.bungee.api.ChatColor;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.MultiLineChart;
import org.bstats.charts.SingleLineChart;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
@@ -16,6 +17,7 @@ import org.bukkit.plugin.SimplePluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
@@ -35,12 +37,17 @@ public class BukkitPlugin extends JavaPlugin {
//Loading config
Bukkit.getLogger().info("Loading config...");
saveDefaultConfig();
Configuration config = new Configuration();
File configFile = new File(getDataFolder(), "config.yml");
if(!configFile.exists()){
configFile.getParentFile().mkdirs();
MiscUtils.copy(getResource( "config.yml"), configFile);
}
Bukkit.getLogger().info("Starting AntiVPN services...");
AntiVPN.start(new BukkitConfig(), new BukkitListener(), new BukkitPlayerExecutor(), getDataFolder());
AntiVPN.start(new BukkitListener(), new BukkitPlayerExecutor(), getDataFolder());
if(AntiVPN.getInstance().getConfig().metrics()) {
if(AntiVPN.getInstance().getVpnConfig().metrics()) {
Bukkit.getLogger().info("Starting bStats metrics...");
Metrics metrics = new Metrics(this, 12615);
metrics.addCustomChart(vpnDetections = new SingleLineChart("vpn_detections",
@@ -128,7 +135,7 @@ public class BukkitPlugin extends JavaPlugin {
}
AntiVPN.getInstance().getMessageHandler().initStrings(vpnString -> new ConfigDefault<>
(vpnString.getDefaultMessage(), "messages." + vpnString.getKey(), BukkitPlugin.pluginInstance)
(vpnString.getDefaultMessage(), "messages." + vpnString.getKey(), AntiVPN.getInstance())
.get());
//TODO Finish system before implementing on startup
/*Bukkit.getLogger().info("Getting strings...");
+14 -2
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.5.2.1</version>
<version>1.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Bungee</artifactId>
@@ -50,7 +50,7 @@
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Common</artifactId>
<version>1.5.2.1</version>
<version>1.7</version>
<scope>provided</scope>
<exclusions>
<exclusion>
@@ -61,6 +61,18 @@
<artifactId>mysql-connector-java</artifactId>
<groupId>mysql</groupId>
</exclusion>
<exclusion>
<artifactId>h2</artifactId>
<groupId>com.h2database</groupId>
</exclusion>
<exclusion>
<artifactId>snakeyaml</artifactId>
<groupId>org.yaml</groupId>
</exclusion>
<exclusion>
<artifactId>mongo-java-driver</artifactId>
<groupId>org.mongodb</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
+2 -2
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.5.2.1</version>
<version>1.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -63,7 +63,7 @@
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Common</artifactId>
<version>1.5.2.1</version>
<version>1.7</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -1,166 +0,0 @@
package dev.brighten.antivpn.bungee;
import dev.brighten.antivpn.api.VPNConfig;
import dev.brighten.antivpn.bungee.util.ConfigDefault;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BungeeConfig implements VPNConfig {
private final ConfigDefault<String> licenseDefault = new ConfigDefault<>("",
"license", BungeePlugin.pluginInstance), kickStringDefault =
new ConfigDefault<>("Proxies are not allowed on our server",
"kickMessage", BungeePlugin.pluginInstance),
defaultDatabaseType = new ConfigDefault<>("MySQL",
"database.type", BungeePlugin.pluginInstance),
defaultDatabaseName = new ConfigDefault<>("kaurivpn",
"database.database", BungeePlugin.pluginInstance),
defaultUsername = new ConfigDefault<>("root",
"database.username", BungeePlugin.pluginInstance),
defaultPassword = new ConfigDefault<>("password",
"database.password", BungeePlugin.pluginInstance),
defaultAuthDatabase = new ConfigDefault<>("admin",
"database.auth", BungeePlugin.pluginInstance),
defaultIp = new ConfigDefault<>("localhost", "database.ip", BungeePlugin.pluginInstance),
defaultAlertMsg = new ConfigDefault<>("&8[&6KauriVPN&8] &e%player% &7has joined on a VPN/proxy" +
" &8(&f%reason%&8) &7in location &8(&f%city%&7, &f%country%&8)", "alerts.message",
BungeePlugin.pluginInstance);
private final ConfigDefault<Boolean> cacheResultsDefault = new ConfigDefault<>(true,
"cachedResults", BungeePlugin.pluginInstance),
defaultDatabaseEnabled = new ConfigDefault<>(false, "database.enabled",
BungeePlugin.pluginInstance), defaultCommandsEnable = new ConfigDefault<>(false,
"commands.enabled", BungeePlugin.pluginInstance), defaultKickPlayers
= new ConfigDefault<>(true, "kickPlayers", BungeePlugin.pluginInstance),
defaultAlertToStaff = new ConfigDefault<>(true, "alerts.enabled",
BungeePlugin.pluginInstance),
defaultMetrics = new ConfigDefault<>(true, "bstats", BungeePlugin.pluginInstance);
private final ConfigDefault<Integer>
defaultPort = new ConfigDefault<>(-1, "database.port", BungeePlugin.pluginInstance);
private final ConfigDefault<List<String>> prefixWhitelistsDefault = new ConfigDefault<>(new ArrayList<>(),
"prefixWhitelists", BungeePlugin.pluginInstance), defaultCommands = new ConfigDefault<>(
Collections.singletonList("kick %player% VPNs are not allowed on our server!"), "commands.execute",
BungeePlugin.pluginInstance);
private String license, kickMessage, databaseType, databaseName, username, password, ip, alertMsg;
private List<String> prefixWhitelists, commands;
private int port;
private boolean cacheResults, databaseEnabled, commandsEnabled, kickPlayers, alertToStaff, metrics;
@Override
public String getLicense() {
return license;
}
@Override
public boolean cachedResults() {
return cacheResults;
}
@Override
public String getKickString() {
return kickMessage;
}
@Override
public String alertMessage() {
return alertMsg;
}
@Override
public boolean alertToStaff() {
return alertToStaff;
}
@Override
public boolean runCommands() {
return commandsEnabled;
}
@Override
public List<String> commands() {
return commands;
}
@Override
public boolean kickPlayersOnDetect() {
return kickPlayers;
}
@Override
public List<String> getPrefixWhitelists() {
return prefixWhitelists;
}
@Override
public boolean isDatabaseEnabled() {
return databaseEnabled;
}
@Override
public String getDatabaseType() {
return databaseType;
}
@Override
public String getDatabaseName() {
return databaseName;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getIp() {
return ip;
}
@Override
public int getPort() {
if(port == -1) {
switch (getDatabaseType().toLowerCase()) {
case "mongodb":
case "mongo":
case "mongod":
return 27017;
case "sql":
case "mysql":
return 3306;
}
}
return port;
}
@Override
public boolean metrics() {
return metrics;
}
public void update() {
license = licenseDefault.get();
kickMessage = kickStringDefault.get();
cacheResults = cacheResultsDefault.get();
prefixWhitelists = prefixWhitelistsDefault.get();
databaseEnabled = defaultDatabaseEnabled.get();
databaseType = defaultDatabaseType.get();
databaseName = defaultDatabaseName.get();
username = defaultUsername.get();
password = defaultPassword.get();
ip = defaultIp.get();
port = defaultPort.get();
commandsEnabled = defaultCommandsEnable.get();
commands = defaultCommands.get();
kickPlayers = defaultKickPlayers.get();
alertToStaff = defaultAlertToStaff.get();
alertMsg = defaultAlertMsg.get();
metrics = defaultMetrics.get();
}
}
@@ -52,39 +52,73 @@ public class BungeeListener extends VPNExecutor implements Listener {
//Or has a name that starts with a certain prefix. This is for Bedrock exempting.
|| AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getAddress().getAddress()
.getHostAddress())
|| AntiVPN.getInstance().getConfig().getPrefixWhitelists().stream()
|| AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream()
.anyMatch(prefix -> event.getPlayer().getName().startsWith(prefix))) return;
checkIp(event.getPlayer().getAddress().getAddress().getHostAddress(),
AntiVPN.getInstance().getConfig().cachedResults(), result -> {
if(result.isSuccess() && result.isProxy()) {
if(AntiVPN.getInstance().getConfig().kickPlayersOnDetect())
event.getPlayer().disconnect(TextComponent.fromLegacyText(ChatColor
.translateAlternateColorCodes('&',
AntiVPN.getInstance().getConfig().getKickString())));
BungeeCord.getInstance().getLogger().info(event.getPlayer().getName()
+ " joined on a VPN/Proxy (" + result.getMethod() + ")");
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().size() > 0
// This bit of code will decide whether or not to kick the player
// If it contains the code and it is set to whitelist, it will not kick as they are equal
// and vise versa. However, if the contains does not match the state, it will kick.
&& AntiVPN.getInstance().getVpnConfig().countryList()
.contains(result.getCountryCode()) != AntiVPN.getInstance().getVpnConfig().whitelistCountries()) {
//Using our built in kicking system if no commands are configured
if(AntiVPN.getInstance().getVpnConfig().countryKickCommands().size() == 0) {
final String kickReason = AntiVPN.getInstance().getVpnConfig()
.countryVanillaKickReason();
// Kicking our player
event.getPlayer().disconnect(TextComponent.fromLegacyText(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()));
if(AntiVPN.getInstance().getConfig().alertToStaff()) //Ensuring the user wishes to alert to staff
AntiVPN.getInstance().getPlayerExecutor().getOnlinePlayers().stream()
.filter(APIPlayer::isAlertsEnabled)
.forEach(pl -> pl.sendMessage(AntiVPN.getInstance().getConfig().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().getConfig().runCommands()) {
for (String command : AntiVPN.getInstance().getConfig().commands()) {
BungeeCord.getInstance().getPluginManager()
.dispatchCommand(BungeeCord.getInstance().getConsole(),
ChatColor.translateAlternateColorCodes('&',
command.replace("%player%", event.getPlayer().getName())));
// Runs our command from console
BungeeCord.getInstance().getPluginManager().dispatchCommand(
BungeeCord.getInstance().getConsole(), formattedCommand);
}
}
} 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++;
}
AntiVPN.getInstance().detections++;
} else if(!result.isSuccess()) {
} else {
BungeeCord.getInstance().getLogger()
.log(Level.WARNING,
"The API query was not a success! " +
@@ -1,10 +1,8 @@
package dev.brighten.antivpn.bungee;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.bungee.util.Config;
import dev.brighten.antivpn.bungee.util.ConfigDefault;
import dev.brighten.antivpn.command.Command;
import lombok.Getter;
import dev.brighten.antivpn.utils.ConfigDefault;
import lombok.val;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatColor;
@@ -24,8 +22,6 @@ public class BungeePlugin extends Plugin {
public static BungeePlugin pluginInstance;
@Getter
private Config config;
private SingleLineChart vpnDetections, ipsChecked;
private static final BaseComponent[] noPermission = new ComponentBuilder("No permission").color(ChatColor.RED)
@@ -37,14 +33,13 @@ public class BungeePlugin extends Plugin {
//Setting up config
BungeeCord.getInstance().getLogger().info("Loading config...");
config = new Config();
//Loading plugin
BungeeCord.getInstance().getLogger().info("Starting AntiVPN services...");
AntiVPN.start(new BungeeConfig(), new BungeeListener(), new BungeePlayerExecutor(), getDataFolder());
AntiVPN.start(new BungeeListener(), new BungeePlayerExecutor(), getDataFolder());
if(AntiVPN.getInstance().getConfig().metrics()) {
if(AntiVPN.getInstance().getVpnConfig().metrics()) {
BungeeCord.getInstance().getLogger().info("Starting bStats metrics...");
Metrics metrics = new Metrics(this, 12616);
metrics.addCustomChart(vpnDetections = new SingleLineChart("vpn_detections",
@@ -103,7 +98,7 @@ public class BungeePlugin extends Plugin {
BungeeCord.getInstance().getLogger().info("Getting strings...");
AntiVPN.getInstance().getMessageHandler().initStrings(vpnString -> new ConfigDefault<>
(vpnString.getDefaultMessage(), "messages." + vpnString.getKey(), BungeePlugin.pluginInstance)
(vpnString.getDefaultMessage(), "messages." + vpnString.getKey(), AntiVPN.getInstance())
.get());
//TODO Finish system before implementing on startup
/*BungeeCord.getInstance().getLogger().info("Getting strings...");
@@ -1,114 +0,0 @@
package dev.brighten.antivpn.bungee.util;
import com.google.common.io.ByteStreams;
import dev.brighten.antivpn.bungee.BungeePlugin;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Author: nitramleo (Martin)
* Date created: 10-Aug-18
*/
public class Config {
private File file;
private Configuration configuration;
public Config() {
this.file = new File(BungeePlugin.pluginInstance.getDataFolder(), "config.yml");
try {
if (!this.file.exists()) {
if (!BungeePlugin.pluginInstance.getDataFolder().exists()) {
BungeePlugin.pluginInstance.getDataFolder().mkdir();
}
this.file.createNewFile();
try (final InputStream is = BungeePlugin.pluginInstance.getResourceAsStream("config.yml");
final OutputStream os = new FileOutputStream(this.file)) {
ByteStreams.copy(is, os);
}
}
this.configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(this.file);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void load() {
this.file = new File(BungeePlugin.pluginInstance.getDataFolder(), "config.yml");
try {
this.configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(this.file);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void save() {
try {
ConfigurationProvider.getProvider( YamlConfiguration.class).save(this.configuration, this.file);
}
catch (IOException e) {
e.printStackTrace();
}
}
public Configuration getConfiguration() {
return this.configuration;
}
public File getFile() {
return this.file;
}
public double getDouble(final String path) {
if (this.configuration.get(path) != null) {
return this.configuration.getDouble(path);
}
return 0.0;
}
public int getInt(final String path) {
if (this.configuration.get(path) != null) {
return this.configuration.getInt(path);
}
return 0;
}
public Object get(final String path) {
return this.configuration.get(path);
}
public void set(final String path, final Object object) {
configuration.set(path, object);
}
public boolean getBoolean(final String path) {
return this.configuration.get(path) != null && this.configuration.getBoolean(path);
}
public String getString(final String path) {
if (this.configuration.get(path) != null) {
return ChatColor.translateAlternateColorCodes('&', this.configuration.getString(path));
}
return "String at path: " + path + " not found!";
}
public List<String> getStringList(final String path) {
if (this.configuration.get(path) != null) {
final ArrayList<String> strings = new ArrayList<String>();
for (final String string : this.configuration.getStringList(path)) {
strings.add(ChatColor.translateAlternateColorCodes('&', string));
}
return strings;
}
return Arrays.asList("String List at path: " + path + " not found!");
}
}
@@ -1,28 +0,0 @@
package dev.brighten.antivpn.bungee.util;
import dev.brighten.antivpn.bungee.BungeePlugin;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class ConfigDefault<A> {
private final A defaultValue;
private final String path;
private final BungeePlugin plugin;
public A get() {
if(plugin.getConfig().get(path) != null)
return (A) plugin.getConfig().get(path);
else {
plugin.getConfig().set(path, defaultValue);
plugin.getConfig().save();
return defaultValue;
}
}
public A set(A value) {
plugin.getConfig().set(path, value);
return value;
}
}
+19 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.5.2.1</version>
<version>1.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -58,6 +58,24 @@
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.210</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.30</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.10</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
@@ -6,9 +6,14 @@ import dev.brighten.antivpn.api.VPNExecutor;
import dev.brighten.antivpn.command.Command;
import dev.brighten.antivpn.command.impl.AntiVPNCommand;
import dev.brighten.antivpn.database.VPNDatabase;
import dev.brighten.antivpn.database.mongo.MongoVPN;
import dev.brighten.antivpn.database.sql.MySqlVPN;
import dev.brighten.antivpn.message.MessageHandler;
import dev.brighten.antivpn.utils.MiscUtils;
import dev.brighten.antivpn.utils.VPNResponse;
import dev.brighten.antivpn.utils.config.Configuration;
import dev.brighten.antivpn.utils.config.ConfigurationProvider;
import dev.brighten.antivpn.utils.config.YamlConfiguration;
import dev.brighten.antivpn.utils.json.JSONException;
import dev.brighten.antivpn.utils.json.JSONObject;
import dev.brighten.antivpn.utils.json.JsonReader;
@@ -18,6 +23,9 @@ import lombok.Setter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
@@ -26,32 +34,46 @@ import java.util.List;
public class AntiVPN {
private static AntiVPN INSTANCE;
private VPNConfig config;
private VPNConfig vpnConfig;
private VPNExecutor executor;
private PlayerExecutor playerExecutor;
private VPNDatabase database;
private MessageHandler messageHandler;
private Configuration config;
private List<Command> commands = new ArrayList<>();
public int detections, checked;
private File pluginFolder;
public static void start(VPNConfig config, VPNExecutor executor, PlayerExecutor playerExecutor, File pluginFolder) {
public static void start(VPNExecutor executor, PlayerExecutor playerExecutor, File pluginFolder) {
//Initializing
INSTANCE = new AntiVPN();
INSTANCE.pluginFolder = pluginFolder;
INSTANCE.config = config;
INSTANCE.executor = executor;
INSTANCE.playerExecutor = playerExecutor;
try {
File configFile = new File(pluginFolder, "config.yml");
if(!configFile.exists()){
configFile.getParentFile().mkdirs();
MiscUtils.copy(INSTANCE.getResource( "config.yml"), configFile);
}
INSTANCE.config = ConfigurationProvider.getProvider(YamlConfiguration.class)
.load(configFile);
} catch (IOException e) {
e.printStackTrace();
}
INSTANCE.vpnConfig = new VPNConfig();
INSTANCE.executor.registerListeners();
INSTANCE.config.update();
INSTANCE.vpnConfig.update();
INSTANCE.messageHandler = new MessageHandler();
switch(INSTANCE.config.getDatabaseType().toLowerCase()) {
switch(INSTANCE.vpnConfig.getDatabaseType().toLowerCase()) {
case "mysql":
case "h2":
case "sql":{
AntiVPN.getInstance().getExecutor().log("Using databaseType MySQL...");
INSTANCE.database = new MySqlVPN();
@@ -61,11 +83,12 @@ public class AntiVPN {
case "mongo":
case "mongodb":
case "mongod": {
AntiVPN.getInstance().getExecutor().log("We currently do not support Mongo, but this is coming in future updates.");
INSTANCE.database = new MongoVPN();
INSTANCE.database.init();
break;
}
default: {
AntiVPN.getInstance().getExecutor().log("Could not find database type \"" + INSTANCE.config.getDatabaseType() + "\". " +
AntiVPN.getInstance().getExecutor().log("Could not find database type \"" + INSTANCE.vpnConfig.getDatabaseType() + "\". " +
"Options: [MySQL]");
break;
}
@@ -85,6 +108,25 @@ public class AntiVPN {
});
}
public InputStream getResource(String filename) {
if (filename == null) {
throw new IllegalArgumentException("Filename cannot be null");
} else {
try {
URL url = executor.getClass().getClassLoader().getResource(filename);
if (url == null) {
return null;
} else {
URLConnection connection = url.openConnection();
connection.setUseCaches(false);
return connection.getInputStream();
}
} catch (IOException var4) {
return null;
}
}
}
public void stop() {
executor.shutdown();
if(database != null) database.shutdown();
@@ -96,6 +138,15 @@ public class AntiVPN {
return INSTANCE;
}
public void saveConfig() {
try {
ConfigurationProvider.getProvider(YamlConfiguration.class)
.save(getConfig(), new File(pluginFolder.getPath() + File.separator + "config.yml"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static VPNResponse getVPNResponse(String ip, String license, boolean cachedResults /* faster if set to true*/)
throws JSONException, IOException {
JSONObject result = JsonReader.readJsonFromUrl(String
@@ -1,43 +1,291 @@
package dev.brighten.antivpn.api;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.utils.ConfigDefault;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public interface VPNConfig {
public class VPNConfig {
private final ConfigDefault<String> licenseDefault = new ConfigDefault<>("",
"license", AntiVPN.getInstance()), kickStringDefault =
new ConfigDefault<>("Proxies are not allowed on our server",
"kickMessage", AntiVPN.getInstance()),
defaultDatabaseType = new ConfigDefault<>("H2",
"database.type", AntiVPN.getInstance()),
defaultDatabaseName = new ConfigDefault<>("kaurivpn",
"database.database", AntiVPN.getInstance()),
defaultMongoURL = new ConfigDefault<>("", "database.mongoURL", AntiVPN.getInstance()),
defaultUsername = new ConfigDefault<>("root",
"database.username", AntiVPN.getInstance()),
defaultPassword = new ConfigDefault<>("password",
"database.password", AntiVPN.getInstance()),
defaultCountryKickReason = new ConfigDefault<>(
"&cSorry, but our server does not allow connections from\n&f%country%",
"countries.vanillaKickReason", AntiVPN.getInstance()),
defaultIp = new ConfigDefault<>("localhost", "database.ip", AntiVPN.getInstance()),
defaultAlertMsg = new ConfigDefault<>("&8[&6KauriVPN&8] &e%player% &7has joined on a VPN/proxy" +
" &8(&f%reason%&8) &7in location &8(&f%city%&7, &f%country%&8)", "alerts.message",
AntiVPN.getInstance());
private final ConfigDefault<Boolean> cacheResultsDefault = new ConfigDefault<>(true,
"cachedResults", AntiVPN.getInstance()),
defaultUseCredentials = new ConfigDefault<>(true,
"database.useCredentials", AntiVPN.getInstance()),
defaultDatabaseEnabled = new ConfigDefault<>(false, "database.enabled",
AntiVPN.getInstance()), defaultCommandsEnable = new ConfigDefault<>(false,
"commands.enabled", AntiVPN.getInstance()), defaultKickPlayers
= new ConfigDefault<>(true, "kickPlayers", AntiVPN.getInstance()),
defaultAlertToStaff = new ConfigDefault<>(true, "alerts.enabled",
AntiVPN.getInstance()),
defaultWhitelistCountries = new ConfigDefault<>(true, "countries.whitelist",
AntiVPN.getInstance()),
defaultMetrics = new ConfigDefault<>(true, "bstats", AntiVPN.getInstance());
private final ConfigDefault<Integer>
defaultPort = new ConfigDefault<>(-1, "database.port", AntiVPN.getInstance());
private final ConfigDefault<List<String>> prefixWhitelistsDefault = new ConfigDefault<>(new ArrayList<>(),
"prefixWhitelists", AntiVPN.getInstance()), defaultCommands = new ConfigDefault<>(
Collections.singletonList("kick %player% VPNs are not allowed on our server!"), "commands.execute",
AntiVPN.getInstance()),
defCountryKickCommands = new ConfigDefault<>(Collections.emptyList(),
"countries.commands", AntiVPN.getInstance()),
defCountrylist = new ConfigDefault<>(new ArrayList<>(), "countries.list",
AntiVPN.getInstance());
String getLicense();
private String license, kickMessage, databaseType, databaseName, mongoURL, username, password, ip, alertMsg,
countryVanillaKickReason;
private List<String> prefixWhitelists, commands, countryList, countryKickCommands;
private int port;
private boolean cacheResults, databaseEnabled, useCredentials, commandsEnabled, kickPlayers, alertToStaff,
metrics, whitelistCountries;
boolean cachedResults();
/**
* License from https://funkemunky.cc/shop to be used for more queries.
* @return String
*/
public String getLicense() {
return license;
}
String getKickString();
/**
* If true, results will be cached to reduce queries to https://funkemunky.cc
* @return boolean
*/
public boolean cachedResults() {
return cacheResults;
}
String alertMessage();
/**
* Will be used for vanilla kick message when {@link VPNConfig#runCommands()} is true.
* @return String
*/
public String getKickString() {
return kickMessage;
}
boolean alertToStaff();
/**
* Message to send staff on proxy detection.
* @return String
*/
public String alertMessage() {
return alertMsg;
}
boolean runCommands();
/**
* If true, staff will be alerted on proxy detection.
* @return boolean
*/
public boolean alertToStaff() {
return alertToStaff;
}
List<String> commands();
/**
* If true, will run {@link VPNConfig#commands()} on detect. If not, it will use vanilla kicking methods.
* @return boolean
*/
public boolean runCommands() {
return commandsEnabled;
}
boolean kickPlayersOnDetect();
/**
* Commands to run on proxy detection.
* @return List
*/
public List<String> commands() {
return commands;
}
List<String> getPrefixWhitelists();
/**
* If false, no commands nor kick will be run on proxy detection.
* @return boolean
*/
public boolean kickPlayersOnDetect() {
return kickPlayers;
}
boolean isDatabaseEnabled();
/**
* Returns Strings of which are checked against the beginning of player names. Used to
* allow Geyser-connected players to join.
* @return List
*/
public List<String> getPrefixWhitelists() {
return prefixWhitelists;
}
String getDatabaseType();
/**
* Returns true if we want to use a database
* @return boolean
*/
public boolean isDatabaseEnabled() {
return databaseEnabled;
}
String getDatabaseName();
/**
* Whether or not the database we want to connect to requires credentials.
* @return boolean
*/
public boolean useDatabaseCreds() {
return useCredentials;
}
String getUsername();
/**
* Only for Mongo only. URL used for connecting to database. Overrides other fields
* @return String
*/
public String mongoDatabaseURL() {
return mongoURL;
}
String getPassword();
/**
* Database type. Either MySQL and Mongo.
* @return String
*/
public String getDatabaseType() {
return databaseType;
}
String getIp();
/**
* Database name
* @return String
*/
public String getDatabaseName() {
return databaseName;
}
int getPort();
/**
* Database username
* @return String
*/
public String getUsername() {
return username;
}
boolean metrics();
/**
* Database Password
* @return String
*/
public String getPassword() {
return password;
}
void update();
/**
* Database IP
* @return String
*/
public String getIp() {
return ip;
}
/**
* Returns the list of ISO country codes we need to check.
* @return List
*/
public List<String> countryList() {
return countryList;
}
/**
* If true, we only allow the {@link VPNConfig#countryKickCommands()}. If false, we blacklist them.
* @return boolean
*/
public boolean whitelistCountries() {
return whitelistCountries;
}
/**
* Returns our configured commands to run on player country detection.
* @return List
*/
public List<String> countryKickCommands() {
return countryKickCommands;
}
/**
* Returns the vanilla kick reason for bad country locations
* @return String
*/
public String countryVanillaKickReason() {
return countryVanillaKickReason;
}
/**
* Gets the port based on configuration. If {@link VPNConfig#port} is -1, will get default port
* based on {@link VPNConfig#getDatabaseType()} lowerCase().
* @return int
*/
public int getPort() {
if(port == -1) {
switch (getDatabaseType().toLowerCase()) {
case "mongodb":
case "mongo":
case "mongod":
return 27017;
case "sql":
case "mysql":
return 3306;
}
}
return port;
}
/**
* If true, https://bstats.org metrics will be collected to improve KauriVPN.
* @return boolean
*/
public boolean metrics() {
return metrics;
}
/**
* Grabs all information from the config.yml
*/
public void update() {
license = licenseDefault.get();
kickMessage = kickStringDefault.get();
cacheResults = cacheResultsDefault.get();
prefixWhitelists = prefixWhitelistsDefault.get();
databaseEnabled = defaultDatabaseEnabled.get();
useCredentials = defaultUseCredentials.get();
databaseType = defaultDatabaseType.get();
databaseName = defaultDatabaseName.get();
mongoURL = defaultMongoURL.get();
username = defaultUsername.get();
password = defaultPassword.get();
ip = defaultIp.get();
port = defaultPort.get();
commandsEnabled = defaultCommandsEnable.get();
commands = defaultCommands.get();
kickPlayers = defaultKickPlayers.get();
alertToStaff = defaultAlertToStaff.get();
alertMsg = defaultAlertMsg.get();
metrics = defaultMetrics.get();
countryList = defCountrylist.get();
whitelistCountries = defaultWhitelistCountries.get();
countryKickCommands = defCountryKickCommands.get();
countryVanillaKickReason = defaultCountryKickReason.get();
}
}
@@ -1,6 +1,7 @@
package dev.brighten.antivpn.api;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.utils.EvictingMap;
import dev.brighten.antivpn.utils.VPNResponse;
import dev.brighten.antivpn.utils.json.JSONException;
import lombok.Getter;
@@ -15,7 +16,7 @@ import java.util.function.Consumer;
public abstract class VPNExecutor {
public static ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
private static final Map<String, VPNResponse> responseCache = new HashMap<>();
public static final Map<String, VPNResponse> responseCache = new EvictingMap<>(5000);
@Getter
private final Set<UUID> whitelisted = Collections.synchronizedSet(new HashSet<>());
@Getter
@@ -50,7 +51,7 @@ public abstract class VPNExecutor {
else {
try {
VPNResponse response = AntiVPN
.getVPNResponse(ip, AntiVPN.getInstance().getConfig().getLicense(), cachedResults);
.getVPNResponse(ip, AntiVPN.getInstance().getVpnConfig().getLicense(), cachedResults);
if(response.isSuccess()) {
AntiVPN.getInstance().getDatabase().cacheResponse(response);
@@ -79,7 +80,7 @@ public abstract class VPNExecutor {
else {
try {
VPNResponse response = AntiVPN
.getVPNResponse(ip, AntiVPN.getInstance().getConfig().getLicense(), cachedResults);
.getVPNResponse(ip, AntiVPN.getInstance().getVpnConfig().getLicense(), cachedResults);
if(response.isSuccess()) {
threadExecutor.execute(() -> AntiVPN.getInstance().getDatabase().cacheResponse(response));
@@ -57,7 +57,7 @@ public class AllowlistCommand extends Command {
if(args.length == 1)
return "&cYou have to provide a player to allow or deny exemption.";
boolean databaseEnabled = AntiVPN.getInstance().getConfig().isDatabaseEnabled();
boolean databaseEnabled = AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled();
if(!databaseEnabled) executor.sendMessage("&cThe database is currently not setup, " +
"so any changes here will disappear after a restart.");
@@ -65,13 +65,16 @@ public class AllowlistCommand extends Command {
if(MiscUtils.isIpv4(args[1])) {
if(!databaseEnabled) {
switch(args[0].toLowerCase()) {
case "add": {
case "add":
case "insert": {
AntiVPN.getInstance().getExecutor().getWhitelistedIps().add(args[1]);
AntiVPN.getInstance().getDatabase().setWhitelisted(args[1], true);
return String.format("&aAdded &6%s &ato the exemption allowlist.", args[1]);
}
case "remove":
case "delete": {
AntiVPN.getInstance().getExecutor().getWhitelistedIps().remove(args[1]);
AntiVPN.getInstance().getDatabase().setWhitelisted(args[1], false);
return String.format("&cRemoved &6%s &cfrom the exemption allowlist.", args[1]);
}
default: {
@@ -80,7 +83,8 @@ public class AllowlistCommand extends Command {
}
} else {
switch(args[0].toLowerCase()) {
case "add": {
case "add":
case "insert": {
AntiVPN.getInstance().getDatabase().setWhitelisted(args[1], true);
return String.format("&aAdded &6%s &a to the exemption allowlist.", args[1]);
}
@@ -41,7 +41,8 @@ public class AntiVPNCommand extends Command {
@Override
public Command[] children() {
return new Command[] {new LookupCommand(), new AllowlistCommand(), new AlertsCommand()};
return new Command[] {new LookupCommand(), new AllowlistCommand(), new AlertsCommand(),
new ClearCacheCommand()};
}
@Override
@@ -0,0 +1,58 @@
package dev.brighten.antivpn.command.impl;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.api.VPNExecutor;
import dev.brighten.antivpn.command.Command;
import dev.brighten.antivpn.command.CommandExecutor;
import java.util.Collections;
import java.util.List;
public class ClearCacheCommand extends Command {
@Override
public String permission() {
return "antivpn.command.clearcache";
}
@Override
public String name() {
return "clearcache";
}
@Override
public String[] aliases() {
return new String[] {"clear", "cc"};
}
@Override
public String description() {
return "Clear the API response cache if you're having problems.";
}
@Override
public String usage() {
return "";
}
@Override
public String parent() {
return "antivpn";
}
@Override
public Command[] children() {
return new Command[0];
}
@Override
public String execute(CommandExecutor executor, String[] args) {
AntiVPN.getInstance().getDatabase().clearResponses();
VPNExecutor.responseCache.clear();
return "&aCleared all cached API response information!";
}
@Override
public List<String> tabComplete(CommandExecutor executor, String alias, String[] args) {
return Collections.emptyList();
}
}
@@ -34,6 +34,8 @@ public interface VPNDatabase {
void updateAlertsState(UUID uuid, boolean state);
void clearResponses();
void init();
void shutdown();
@@ -0,0 +1,208 @@
package dev.brighten.antivpn.database.mongo;
import com.mongodb.*;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Indexes;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.api.VPNExecutor;
import dev.brighten.antivpn.database.VPNDatabase;
import dev.brighten.antivpn.utils.VPNResponse;
import org.bson.Document;
import java.util.*;
import java.util.function.Consumer;
public class MongoVPN implements VPNDatabase {
private MongoCollection<Document> settingsDocument, cacheDocument;
private MongoClient client;
private MongoDatabase antivpnDatabase;
@Override
public Optional<VPNResponse> getStoredResponse(String ip) {
Document rdoc = cacheDocument.find(Filters.eq("ip", ip)).first();
if(rdoc != 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"))
.build());
}
return Optional.empty();
}
@Override
public void cacheResponse(VPNResponse toCache) {
Document rdoc = new Document("ip", toCache.getIp());
rdoc.put("asn", toCache.getAsn());
rdoc.put("countryName", toCache.getCountryName());
rdoc.put("countryCode", toCache.getCountryCode());
rdoc.put("city", toCache.getCity());
rdoc.put("isp", toCache.getIsp());
rdoc.put("method", toCache.getMethod());
rdoc.put("timeZone", toCache.getTimeZone());
rdoc.put("proxy", toCache.isProxy());
rdoc.put("cached", toCache.isCached());
rdoc.put("success", toCache.isSuccess());
rdoc.put("latitude", toCache.getLatitude());
rdoc.put("longitude", toCache.getLongitude());
VPNExecutor.threadExecutor.execute(() -> {
cacheDocument.deleteMany(Filters.eq("ip", toCache.getIp()));
cacheDocument.insertOne(rdoc);
});
}
@Override
public boolean isWhitelisted(UUID uuid) {
return settingsDocument
.find(Filters.and(Filters.eq("setting", "whitelist"),
Filters.eq("uuid", uuid.toString()))).first() != null;
}
@Override
public boolean isWhitelisted(String ip) {
return settingsDocument
.find(Filters.and(Filters.eq("setting", "whitelist"),
Filters.eq("ip", ip))).first() != null;
}
@Override
public void setWhitelisted(UUID uuid, boolean whitelisted) {
if(whitelisted) {
Document wdoc = new Document("setting", "whitelist");
wdoc.put("uuid", uuid.toString());
VPNExecutor.threadExecutor.execute(() -> settingsDocument.insertOne(wdoc));
} else {
VPNExecutor.threadExecutor.execute(() -> settingsDocument.deleteMany(Filters
.and(
Filters.eq("setting", "whitelist"),
Filters.eq("uuid", uuid.toString()))));
}
}
@Override
public void setWhitelisted(String ip, boolean whitelisted) {
if(whitelisted) {
Document wdoc = new Document("setting", "whitelist");
wdoc.put("ip", ip);
VPNExecutor.threadExecutor.execute(() -> settingsDocument.insertOne(wdoc));
} else {
VPNExecutor.threadExecutor.execute(() -> settingsDocument.deleteMany(Filters
.and(
Filters.eq("setting", "whitelist"),
Filters.eq("ip", ip))));
}
}
@Override
public List<UUID> getAllWhitelisted() {
List<UUID> uuids = new ArrayList<>();
settingsDocument.find(Filters.and(Filters.eq("setting", "whitelist"),
Filters.exists("uuid")))
.forEach((Consumer<? super Document>) doc -> uuids.add(UUID.fromString(doc.getString("uuid"))));
return uuids;
}
@Override
public List<String> getAllWhitelistedIps() {
List<String> ips = new ArrayList<>();
settingsDocument.find(Filters.and(Filters.eq("setting", "whitelist"),
Filters.exists("ip")))
.forEach((Consumer<? super Document>) doc -> ips.add(doc.getString("ip")));
return ips;
}
@Override
public void getStoredResponseAsync(String ip, Consumer<Optional<VPNResponse>> result) {
VPNExecutor.threadExecutor.execute(() -> result.accept(getStoredResponse(ip)));
}
@Override
public void isWhitelistedAsync(UUID uuid, Consumer<Boolean> result) {
VPNExecutor.threadExecutor.execute(() -> result.accept(isWhitelisted(uuid)));
}
@Override
public void isWhitelistedAsync(String ip, Consumer<Boolean> result) {
VPNExecutor.threadExecutor.execute(() -> result.accept(isWhitelisted(ip)));
}
@Override
public void alertsState(UUID uuid, Consumer<Boolean> result) {
VPNExecutor.threadExecutor.execute(() -> result.accept(settingsDocument
.find(Filters.and(Filters.eq("setting", "alerts"),
Filters.eq("uuid", uuid.toString()))).first() != null));
}
@Override
public void updateAlertsState(UUID uuid, boolean state) {
VPNExecutor.threadExecutor.execute(() -> {
settingsDocument.deleteMany(Filters.and(Filters.eq("setting", "alerts"),
Filters.eq("uuid", uuid.toString())));
if(state) {
Document adoc = new Document("setting", "alerts");
adoc.put("uuid", uuid.toString());
settingsDocument.insertOne(adoc);
}
});
}
@Override
public void clearResponses() {
cacheDocument.deleteMany(Filters.exists("ip"));
}
@Override
public void init() {
if(AntiVPN.getInstance().getVpnConfig().mongoDatabaseURL().length() > 0) { //URL
ConnectionString cs = new ConnectionString(AntiVPN.getInstance().getVpnConfig().mongoDatabaseURL());
MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(cs).build();
client = MongoClients.create(settings);
} else {
MongoClientSettings.Builder settingsBld = MongoClientSettings.builder().readPreference(ReadPreference.nearest())
.applyToClusterSettings(builder -> {
builder.hosts(Collections.singletonList(new ServerAddress(AntiVPN.getInstance().getVpnConfig().getIp(),
AntiVPN.getInstance().getVpnConfig().getPort())));
});
if(AntiVPN.getInstance().getVpnConfig().useDatabaseCreds()) {
settingsBld = settingsBld.credential(MongoCredential
.createCredential(AntiVPN.getInstance().getVpnConfig().getUsername(),
AntiVPN.getInstance().getVpnConfig().getDatabaseName(),
AntiVPN.getInstance().getVpnConfig().getPassword().toCharArray()));
}
client = MongoClients.create(settingsBld.build());
}
antivpnDatabase = client.getDatabase(AntiVPN.getInstance().getVpnConfig().getDatabaseName());
settingsDocument = antivpnDatabase.getCollection("settings");
if(settingsDocument.listIndexes().first() == null) {
AntiVPN.getInstance().getExecutor().log("Created index for settings collection!");
settingsDocument.createIndex(Indexes.ascending("ip"));
}
cacheDocument = antivpnDatabase.getCollection("cache");
}
@Override
public void shutdown() {
settingsDocument = null;
cacheDocument = null;
client.close();
}
}
@@ -26,7 +26,7 @@ public class MySqlVPN implements VPNDatabase {
}
while (true) {
// Updating from database
if (AntiVPN.getInstance().getConfig().isDatabaseEnabled()) {
if (AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()) {
AntiVPN.getInstance().getExecutor().getWhitelisted().clear();
AntiVPN.getInstance().getExecutor().getWhitelisted()
.addAll(AntiVPN.getInstance().getDatabase().getAllWhitelisted());
@@ -47,7 +47,7 @@ public class MySqlVPN implements VPNDatabase {
@Override
public Optional<VPNResponse> getStoredResponse(String ip) {
if (!AntiVPN.getInstance().getConfig().isDatabaseEnabled()|| MySQL.isClosed())
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()|| MySQL.isClosed())
return Optional.empty();
ResultSet rs = Query.prepare("select * from `responses` where `ip` = ? limit 1").append(ip).executeQuery();
@@ -81,7 +81,7 @@ public class MySqlVPN implements VPNDatabase {
*/
@Override
public void cacheResponse(VPNResponse toCache) {
if (!AntiVPN.getInstance().getConfig().isDatabaseEnabled() || MySQL.isClosed())
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
return;
Query.prepare("insert into `responses` (`ip`,`asn`,`countryName`,`countryCode`,`city`,`timeZone`,"
@@ -96,7 +96,7 @@ public class MySqlVPN implements VPNDatabase {
@SneakyThrows
@Override
public boolean isWhitelisted(UUID uuid) {
if (!AntiVPN.getInstance().getConfig().isDatabaseEnabled() || MySQL.isClosed())
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
return false;
ResultSet set = Query.prepare("select uuid from `whitelisted` where `uuid` = ? limit 1")
.append(uuid.toString()).executeQuery();
@@ -107,7 +107,7 @@ public class MySqlVPN implements VPNDatabase {
@SneakyThrows
@Override
public boolean isWhitelisted(String ip) {
if (!AntiVPN.getInstance().getConfig().isDatabaseEnabled() || MySQL.isClosed())
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
return false;
ResultSet set = Query.prepare("select `ip` from `whitelisted-ips` where `ip` = ? limit 1")
.append(ip).executeQuery();
@@ -118,7 +118,7 @@ public class MySqlVPN implements VPNDatabase {
@Override
public void setWhitelisted(UUID uuid, boolean whitelisted) {
if (!AntiVPN.getInstance().getConfig().isDatabaseEnabled() || MySQL.isClosed())
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
return;
if (whitelisted) {
@@ -134,7 +134,7 @@ public class MySqlVPN implements VPNDatabase {
@Override
public void setWhitelisted(String ip, boolean whitelisted) {
if (!AntiVPN.getInstance().getConfig().isDatabaseEnabled() || MySQL.isClosed())
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
return;
if(whitelisted) {
@@ -225,12 +225,21 @@ public class MySqlVPN implements VPNDatabase {
.execute());
}
@Override
public void clearResponses() {
if(MySQL.isClosed()) return;
VPNExecutor.threadExecutor.execute(() -> Query.prepare("delete from `responses`").execute());
}
@Override
public void init() {
if (!AntiVPN.getInstance().getConfig().isDatabaseEnabled())
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled())
return;
AntiVPN.getInstance().getExecutor().log("Initializing MySQL...");
MySQL.init();
if(AntiVPN.getInstance().getVpnConfig().getDatabaseType().contains("sql")) {
MySQL.init();
} else MySQL.initH2();
AntiVPN.getInstance().getExecutor().log("Creating tables...");
@@ -324,7 +333,7 @@ public class MySqlVPN implements VPNDatabase {
@Override
public void shutdown() {
if (!AntiVPN.getInstance().getConfig().isDatabaseEnabled())
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled())
return;
MySQL.shutdown();
}
@@ -1,10 +1,13 @@
package dev.brighten.antivpn.database.sql.utils;
import org.h2.jdbc.JdbcConnection;
import dev.brighten.antivpn.AntiVPN;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class MySQL {
private static Connection conn;
@@ -12,17 +15,21 @@ public class MySQL {
public static void init() {
try {
if (conn == null || conn.isClosed()) {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://" + AntiVPN.getInstance().getConfig().getIp()
+ ":" + AntiVPN.getInstance().getConfig().getPort()
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
Class.forName("com.mysql.jdbc.Driver");
}
conn = DriverManager.getConnection("jdbc:mysql://" + AntiVPN.getInstance().getVpnConfig().getIp()
+ ":" + AntiVPN.getInstance().getVpnConfig().getPort()
+ "/?useSSL=true&autoReconnect=true",
AntiVPN.getInstance().getConfig().getUsername(),
AntiVPN.getInstance().getConfig().getPassword());
AntiVPN.getInstance().getVpnConfig().getUsername(),
AntiVPN.getInstance().getVpnConfig().getPassword());
conn.setAutoCommit(true);
Query.use(conn);
Query.prepare("CREATE DATABASE IF NOT EXISTS `"
+ AntiVPN.getInstance().getConfig().getDatabaseName() + "`").execute();
Query.prepare("USE `" + AntiVPN.getInstance().getConfig().getDatabaseName() + "`").execute();
+ AntiVPN.getInstance().getVpnConfig().getDatabaseName() + "`").execute();
Query.prepare("USE `" + AntiVPN.getInstance().getVpnConfig().getDatabaseName() + "`").execute();
AntiVPN.getInstance().getExecutor().log("Connection to MySQL has been established.");
}
} catch (Exception e) {
@@ -31,12 +38,13 @@ public class MySQL {
}
}
/*public static void initH2() {
public static void initH2() {
File dataFolder = new File(AntiVPN.getInstance().getPluginFolder(), "databases" + File.separator + "database");
try {
Class.forName("org.h2.Driver");
conn = new NonClosableConnection(new JdbcConnection("jdbc:h2:file:" +
dataFolder.getAbsolutePath(), new Properties()));
conn = new NonClosableConnection(DriverManager.getConnection ("jdbc:h2:file:" +
dataFolder.getAbsolutePath(),
AntiVPN.getInstance().getVpnConfig().getUsername(),AntiVPN.getInstance().getVpnConfig().getPassword()));
conn.setAutoCommit(true);
Query.use(conn);
AntiVPN.getInstance().getExecutor().log("Connection to SQlLite has been established.");
@@ -46,7 +54,7 @@ public class MySQL {
} catch (ClassNotFoundException ex) {
AntiVPN.getInstance().getExecutor().log("No H2 library found!");
}
}*/
}
public static void use() {
try {
@@ -1,14 +1,14 @@
package dev.brighten.antivpn.bukkit.util;
package dev.brighten.antivpn.utils;
import dev.brighten.antivpn.AntiVPN;
import lombok.AllArgsConstructor;
import org.bukkit.plugin.Plugin;
@AllArgsConstructor
public class ConfigDefault<A> {
private final A defaultValue;
private final String path;
private final Plugin plugin;
private final AntiVPN plugin;
public A get() {
if(plugin.getConfig().get(path) != null)
@@ -0,0 +1,19 @@
package dev.brighten.antivpn.utils;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.LinkedHashMap;
import java.util.Map;
@RequiredArgsConstructor
public class EvictingMap<K, V> extends LinkedHashMap<K, V> {
@Getter
private final int size;
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() >= size;
}
}
@@ -1,9 +1,6 @@
package dev.brighten.antivpn.utils;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.*;
import java.lang.reflect.Method;
import java.net.Inet4Address;
import java.net.InetAddress;
@@ -11,9 +8,12 @@ import java.net.URL;
import java.net.URLClassLoader;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.regex.Pattern;
public class MiscUtils {
private static final Pattern ipv4 = Pattern.compile("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");
public static void close(Closeable... closeables) {
try {
for (Closeable closeable : closeables) if (closeable != null) closeable.close();
@@ -30,44 +30,26 @@ public class MiscUtils {
}
}
public static void copy(InputStream in, File file) {
try {
OutputStream out = new FileOutputStream(file);
int lenght;
byte[] buf = new byte[1024];
while ((lenght = in.read(buf)) > 0)
{
out.write(buf, 0, lenght);
}
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static boolean isIpv4(String ip)
{
try {
InetAddress address = InetAddress.getByName(ip);
return address instanceof Inet4Address;
} catch(Exception e) {
return false;
}
}
/* Borrowed from FireFlyx ngxdev */
public static void download(File file, String from) throws Exception {
URL url = new URL(from);
InputStream stream = url.openStream();
ReadableByteChannel channel = Channels.newChannel(stream);
FileOutputStream out = new FileOutputStream(file);
out.getChannel().transferFrom(channel, 0L, Long.MAX_VALUE);
}
/* Borrowed from FireFlyx ngxdev */
public static ClassLoader injectorClassLoader = MiscUtils.class.getClassLoader();
/* Borrowed from FireFlyx ngxdev */
public static void injectURL(URL url) {
try {
URLClassLoader systemClassLoader = (URLClassLoader) injectorClassLoader;
Class<URLClassLoader> classLoaderClass = URLClassLoader.class;
try {
Method method = classLoaderClass.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(systemClassLoader, url);
} catch (Throwable t) {
t.printStackTrace();
}
} catch (Exception e) {
}
return ipv4.matcher(ip).matches();
}
}
@@ -2,15 +2,13 @@ package dev.brighten.antivpn.utils;
import dev.brighten.antivpn.utils.json.JSONException;
import dev.brighten.antivpn.utils.json.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.*;
@Getter
@Setter
@AllArgsConstructor
@RequiredArgsConstructor
@Builder
public class VPNResponse {
private String asn, ip, countryName, countryCode, city, timeZone, method, isp, failureReason = "N/A";
private boolean proxy, cached;
@@ -1,18 +1,13 @@
package dev.brighten.antivpn.velocity.config;
package dev.brighten.antivpn.utils.config;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.*;
public final class Configuration
{
private static final char SEPARATOR = '.';
final Map<String, Object> self;
final Map<String, List<String>> comments;
private final Configuration defaults;
public Configuration()
@@ -29,6 +24,7 @@ public final class Configuration
{
this.self = new LinkedHashMap<>();
this.defaults = defaults;
comments = new HashMap<>();
for ( Map.Entry<?, ?> entry : map.entrySet() )
{
@@ -44,6 +40,103 @@ public final class Configuration
}
}
public void loadFromString(String contents) {
List<String> list = new ArrayList<>();
Collections.addAll(list, contents.split("\n"));
int currentLayer = 0;
String currentPath = "";
int lineNumber = 0;
for(Iterator<String> iterator = list.iterator(); iterator.hasNext(); lineNumber++) {
String line = iterator.next();
String trimmed = line.trim();
if(trimmed.startsWith("#") || trimmed.isEmpty()) {
addCommentLine(currentPath, line);
continue;
}
if(!line.isEmpty()) {
if(line.contains(":")) {
int layerFromLine = getLayerFromLine(line, lineNumber);
if(layerFromLine < currentLayer) {
currentPath = regressPathBy(currentLayer - layerFromLine, currentPath);
}
String key = getKeyFromLine(line);
if(currentLayer == 0) {
currentPath = key;
}
else {
currentPath += "." + key;
}
}
}
}
}
private void addCommentLine(String currentPath, String line) {
List<String> list = comments.get(currentPath);
if(list == null) {
list = new ArrayList<>();
}
list.add(line);
comments.put(currentPath, list);
}
String getKeyFromLine(String line) {
String key = null;
for(int i = 0; i < line.length(); i++) {
if(line.charAt(i) == ':') {
key = line.substring(0, i);
break;
}
}
return key == null ? null : key.trim();
}
String regressPathBy(int i, String currentPath) {
if(i <= 0) {
return currentPath;
}
String[] split = currentPath.split("\\.");
String rebuild = "";
for(int j = 0; j < split.length - i; j++) {
rebuild += split[j];
if(j <= (split.length - j)) {
rebuild += ".";
}
}
return rebuild;
}
int getLayerFromLine(String line, int lineNumber) {
double d = 0;
for(int i = 0; i < line.length(); i++) {
if(line.charAt(i) == ' ') {
d += 0.5;
}
else {
break;
}
}
return (int) d;
}
private Configuration getSectionFor(String path)
{
int index = path.indexOf( SEPARATOR );
@@ -1,17 +1,13 @@
package dev.brighten.antivpn.velocity.config;
package dev.brighten.antivpn.utils.config;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.Writer;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public abstract class ConfigurationProvider
{
private static final Map<Class<? extends ConfigurationProvider>, ConfigurationProvider> providers = new HashMap<>();
public static final Map<Class<? extends ConfigurationProvider>, ConfigurationProvider> providers = new HashMap<>();
static
{
@@ -20,16 +16,9 @@ public abstract class ConfigurationProvider
providers.put( YamlConfiguration.class, new YamlConfiguration() );
} catch ( NoClassDefFoundError ex )
{
ex.printStackTrace();
// Ignore, no SnakeYAML
}
try
{
providers.put( JsonConfiguration.class, new JsonConfiguration() );
} catch ( NoClassDefFoundError ex )
{
// Ignore, no Gson
}
}
public static ConfigurationProvider getProvider(Class<? extends ConfigurationProvider> provider)
@@ -0,0 +1,181 @@
package dev.brighten.antivpn.utils.config;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.representer.Representer;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
@NoArgsConstructor(access = AccessLevel.PACKAGE)
public class YamlConfiguration extends ConfigurationProvider
{
private final ThreadLocal<Yaml> yaml = new ThreadLocal<Yaml>()
{
@Override
protected Yaml initialValue()
{
Representer representer = new Representer()
{
{
representers.put( Configuration.class, data -> represent( ( (Configuration) data ).self ));
}
};
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK );
representer.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
return new Yaml( new Constructor(), representer, options );
}
};
@Override
public void save(Configuration config, File file) throws IOException
{
try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), StandardCharsets.UTF_8 ) )
{
save( config, writer );
}
}
@Override
public void save(Configuration config, Writer writer)
{
String contents = this.yaml.get().dump(config.self);
if (contents.equals("{}\n")) {
contents = "";
}
List<String> list = new ArrayList<>();
Collections.addAll(list, contents.split("\n"));
int currentLayer = 0;
StringBuilder currentPath = new StringBuilder();
StringBuilder sb = new StringBuilder();
int lineNumber = 0;
for(Iterator<String> iterator = list.iterator(); iterator.hasNext(); lineNumber++) {
String line = iterator.next();
sb.append(line);
sb.append('\n');
if (!line.isEmpty()) {
if (line.contains(":")) {
int layerFromLine = config.getLayerFromLine(line, lineNumber);
if (layerFromLine < currentLayer) {
currentPath = new StringBuilder(config.regressPathBy(currentLayer - layerFromLine, currentPath.toString()));
}
String key = config.getKeyFromLine(line);
if (currentLayer == 0) {
currentPath = new StringBuilder(key);
} else {
currentPath.append("." + key);
}
String path = currentPath.toString();
if (config.comments.containsKey(path)) {
config.comments.get(path).forEach(string -> {
sb.append(string);
sb.append('\n');
});
}
}
}
}
try {
writer.write(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public Configuration load(File file) throws IOException
{
return load( file, null );
}
@Override
public Configuration load(File file, Configuration defaults) throws IOException
{
try ( FileInputStream is = new FileInputStream( file ) )
{
return load( is, defaults );
}
}
@Override
public Configuration load(Reader reader)
{
return load( reader, null );
}
@SneakyThrows
@Override
public Configuration load(Reader reader, Configuration defaults)
{
BufferedReader input = reader instanceof BufferedReader ? (BufferedReader)reader : new BufferedReader(reader);
StringBuilder builder = new StringBuilder();
String line;
try {
while((line = input.readLine()) != null) {
builder.append(line);
builder.append('\n');
}
} finally {
input.close();
}
return load(builder.toString(), defaults);
}
@Override
public Configuration load(InputStream is)
{
return this.load(new InputStreamReader(is, Charset.defaultCharset()));
}
@Override
public Configuration load(InputStream is, Configuration defaults)
{
return this.load(new InputStreamReader(is, Charset.defaultCharset()), defaults);
}
@Override
public Configuration load(String string)
{
return load( string, null );
}
@Override
@SuppressWarnings("unchecked")
public Configuration load(String contents, Configuration defaults)
{
Map<String, Object> map;
LoaderOptions loaderOptions = new LoaderOptions();
loaderOptions.setMaxAliasesForCollections(2147483647);
map = this.yaml.get().loadAs(contents, LinkedHashMap.class);
Configuration config = new Configuration( map, defaults );
config.loadFromString(contents);
return config;
}
}
+68
View File
@@ -0,0 +1,68 @@
#####################################################
# KauriVPN Config #
# by Brighten Development #
#####################################################
# If you find that you run out of your free 20,000 queries, you may purchase a license on https://funkemunky.cc/shop
license: ''
# Message only sent with commands disabled below. Supports color codes ('&')
kickMessage: Proxies are not allowed on our server
# Caching results will lower your query usage, but results may be out of date.
cachedResults: true
# All players with any of the following characters in the beginning of their name will be whitelisted
# This is a useful feature for servers that allow players through Geyser and their IPs are not forwarded, causing
# players to be removed falsely for use of proxy.
prefixWhitelists: []
# Configure your database here.
database:
# Enable to cache queries and save alerts state beyond restarts
enabled: false
useCredentials: true
#Options Mongo, MySQL, or H2
type: H2
# The database name you would like to use
database: kaurivpn
# Can be used if you prefer to authenticate via Mongo URL
mongoURL: ''
# Your database username
username: root
# Your database password
password: password
# The IP of your database goes here
ip: localhost
# -1 will use default port of databases (MySQL:3306, Mongo:27017). Otherwise, enter alternative ports here.
port: -1
commands:
# Enable this to override the default kick function of the plugin with your own commands
enabled: false
# List of commands to run when a player is detected to be using a proxy. Supports color codes ('&')
execute:
- kick %player% VPNs are not allowed on our server!
# Enable/disable the default kicking feature of KauriVPN.
kickPlayers: true
# Configure all alerting functionality
alerts:
# You may set to 'false' to disable all alerts functionality
enabled: true
# Message to send to users with alerts enabled
# Placeholders: %country% (Country name), %player% (Player name), %reason% (Proxy detection method),
# %city% (City name).
message: '&8[&6KauriVPN&8] &e%player% &7has joined on a VPN/proxy &8(&f%reason%&8)
&7in location &8(&f%city%&7, &f%country%&8)'
# Configuration for country gatekeepings
countries:
# You must use ISO codes for country configuration: https://www.iban.com/country-code
# Leave empty to disable this configuration
list: []
# Set whitelist to true to only allow listed country codes, and false to deny listed country codes.
whitelist: true
# The commands to be run if the player is not allowed on the server with the above configured conditions
# Placeholders: %country% (Country name), %player% (Player name), %code% (Country ISO Code)
# Keep this empty with "[]" if you want to use the built in kicking system.
commands: []
# The kick message that will be used if commands are configured to use the built-in kicking sytem.
# PlaceHolders: %country% (Country name), %player% (Player name), %code% (Country ISO Code)
vanillaKickReason: "&cSorry, but our server does not allow connections from\n&f%country%"
# This will disable any information being sent to https://bstats.org. We recommend you keep this enabled as it helps
# us understand our users and put effort where it is needed. All information sent goes under their privacy as seen
# here: https://bstats.org/privacy-policy
bstats: true
+2 -2
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.5.2.1</version>
<version>1.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -33,7 +33,7 @@
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Common</artifactId>
<version>1.5.2.1</version>
<version>1.7</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -1,166 +0,0 @@
package dev.brighten.antivpn.velocity;
import dev.brighten.antivpn.api.VPNConfig;
import dev.brighten.antivpn.velocity.util.ConfigDefault;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class VelocityConfig implements VPNConfig {
private final ConfigDefault<String> licenseDefault = new ConfigDefault<>("",
"license", VelocityPlugin.INSTANCE), kickStringDefault =
new ConfigDefault<>("Proxies are not allowed on our server",
"kickMessage", VelocityPlugin.INSTANCE),
defaultDatabaseType = new ConfigDefault<>("MySQL",
"database.type", VelocityPlugin.INSTANCE),
defaultDatabaseName = new ConfigDefault<>("kaurivpn",
"database.database", VelocityPlugin.INSTANCE),
defaultUsername = new ConfigDefault<>("root",
"database.username", VelocityPlugin.INSTANCE),
defaultPassword = new ConfigDefault<>("password",
"database.password", VelocityPlugin.INSTANCE),
defaultAuthDatabase = new ConfigDefault<>("admin",
"database.auth", VelocityPlugin.INSTANCE),
defaultIp = new ConfigDefault<>("localhost", "database.ip", VelocityPlugin.INSTANCE),
defaultAlertMsg = new ConfigDefault<>("&8[&6KauriVPN&8] &e%player% &7has joined on a VPN/proxy" +
" &8(&f%reason%&8) &7in location &8(&f%city%&7, &f%country%&8)", "alerts.message",
VelocityPlugin.INSTANCE);
private final ConfigDefault<Boolean> cacheResultsDefault = new ConfigDefault<>(true,
"cachedResults", VelocityPlugin.INSTANCE),
defaultDatabaseEnabled = new ConfigDefault<>(false, "database.enabled",
VelocityPlugin.INSTANCE), defaultCommandsEnable = new ConfigDefault<>(false,
"commands.enabled", VelocityPlugin.INSTANCE), defaultKickPlayers
= new ConfigDefault<>(true, "kickPlayers", VelocityPlugin.INSTANCE),
defaultAlertToStaff = new ConfigDefault<>(true, "alerts.enabled",
VelocityPlugin.INSTANCE),
defaultMetrics = new ConfigDefault<>(true, "bstats", VelocityPlugin.INSTANCE);
private final ConfigDefault<Integer>
defaultPort = new ConfigDefault<>(-1, "database.port", VelocityPlugin.INSTANCE);
private final ConfigDefault<List<String>> prefixWhitelistsDefault = new ConfigDefault<>(new ArrayList<>(),
"prefixWhitelists", VelocityPlugin.INSTANCE), defaultCommands = new ConfigDefault<>(
Collections.singletonList("kick %player% VPNs are not allowed on our server!"), "commands.execute",
VelocityPlugin.INSTANCE);
private String license, kickMessage, databaseType, databaseName, username, password, ip, alertMsg;
private List<String> prefixWhitelists, commands;
private int port;
private boolean cacheResults, databaseEnabled, commandsEnabled, kickPlayers, alertToStaff, metrics;
@Override
public String getLicense() {
return license;
}
@Override
public boolean cachedResults() {
return cacheResults;
}
@Override
public String getKickString() {
return kickMessage;
}
@Override
public String alertMessage() {
return alertMsg;
}
@Override
public boolean alertToStaff() {
return alertToStaff;
}
@Override
public boolean runCommands() {
return commandsEnabled;
}
@Override
public List<String> commands() {
return commands;
}
@Override
public boolean kickPlayersOnDetect() {
return kickPlayers;
}
@Override
public List<String> getPrefixWhitelists() {
return prefixWhitelists;
}
@Override
public boolean isDatabaseEnabled() {
return databaseEnabled;
}
@Override
public String getDatabaseType() {
return databaseType;
}
@Override
public String getDatabaseName() {
return databaseName;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getIp() {
return ip;
}
@Override
public int getPort() {
if(port == -1) {
switch (getDatabaseType().toLowerCase()) {
case "mongodb":
case "mongo":
case "mongod":
return 27017;
case "sql":
case "mysql":
return 3306;
}
}
return port;
}
@Override
public boolean metrics() {
return metrics;
}
public void update() {
license = licenseDefault.get();
kickMessage = kickStringDefault.get();
cacheResults = cacheResultsDefault.get();
prefixWhitelists = prefixWhitelistsDefault.get();
databaseEnabled = defaultDatabaseEnabled.get();
databaseType = defaultDatabaseType.get();
databaseName = defaultDatabaseName.get();
username = defaultUsername.get();
password = defaultPassword.get();
ip = defaultIp.get();
port = defaultPort.get();
commandsEnabled = defaultCommandsEnable.get();
commands = defaultCommands.get();
kickPlayers = defaultKickPlayers.get();
alertToStaff = defaultAlertToStaff.get();
alertMsg = defaultAlertMsg.get();
metrics = defaultMetrics.get();
}
}
@@ -4,6 +4,7 @@ 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.VPNConfig;
import dev.brighten.antivpn.api.VPNExecutor;
import dev.brighten.antivpn.velocity.util.StringUtils;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
@@ -24,48 +25,96 @@ public class VelocityListener extends VPNExecutor {
event -> {
if(event.getResult().isAllowed()) {
if(event.getPlayer().hasPermission("antivpn.bypass") //Has bypass permission
|| AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId()) //Is exempt
//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().getConfig().getPrefixWhitelists().stream()
.getAddress().getHostAddress())
|| AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream()
.anyMatch(prefix -> event.getPlayer().getUsername().startsWith(prefix))) return;
checkIp(event.getPlayer().getRemoteAddress().getAddress().getHostAddress(),
AntiVPN.getInstance().getConfig().cachedResults(), result -> {
if(result.isSuccess() && result.isProxy()) {
if(AntiVPN.getInstance().getConfig().kickPlayersOnDetect())
event.getPlayer().disconnect(LegacyComponentSerializer.builder().character('&')
.build().deserialize(AntiVPN.getInstance().getConfig().getKickString()));
VelocityPlugin.INSTANCE.getLogger().info(event.getPlayer().getUsername()
+ " joined on a VPN/Proxy (" + result.getMethod() + ")");
if(AntiVPN.getInstance().getConfig().alertToStaff()) //Ensuring the user wishes to alert to staff
AntiVPN.getInstance().getPlayerExecutor().getOnlinePlayers().stream()
.filter(APIPlayer::isAlertsEnabled)
.forEach(pl -> pl.sendMessage(AntiVPN.getInstance().getConfig().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().getConfig().runCommands()) {
for (String command : AntiVPN.getInstance().getConfig().commands()) {
VelocityPlugin.INSTANCE.getServer().getCommandManager()
.executeAsync(VelocityPlugin.INSTANCE.getServer()
.getConsoleCommandSource(),
StringUtils.translateAlternateColorCodes('&',
command.replace("%player%",
event.getPlayer().getUsername())));
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().size() > 0
// This bit of code will decide whether or not to kick the player
// If it contains the code and it is set to whitelist, it will not kick
// as they are equal and vise versa. However, if the contains does not match
// the state, it will kick.
&& AntiVPN.getInstance().getVpnConfig().countryList()
.contains(result.getCountryCode())
!= AntiVPN.getInstance().getVpnConfig().whitelistCountries()) {
//Using our built in kicking system if no commands are configured
if(AntiVPN.getInstance().getVpnConfig().countryKickCommands().size() == 0) {
final String kickReason = AntiVPN.getInstance().getVpnConfig()
.countryVanillaKickReason();
// Kicking our player
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())
event.getPlayer().disconnect(LegacyComponentSerializer.builder().character('&')
.build().deserialize(AntiVPN.getInstance().getVpnConfig()
.getKickString()));
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().detections++;
} else if(!result.isSuccess()) {
} 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");
"You may need to upgrade your license on " +
"https://funkemunky.cc/shop");
}
AntiVPN.getInstance().checked++;
});
@@ -10,7 +10,6 @@ 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.velocity.util.Config;
import lombok.Getter;
import lombok.val;
import net.kyori.adventure.text.Component;
@@ -37,8 +36,6 @@ public class VelocityPlugin {
@DataDirectory
private Path configDir;
private Config config;
@Inject
public VelocityPlugin(ProxyServer server, Logger logger, Metrics.Factory metricsFactory) {
this.server = server;
@@ -50,13 +47,12 @@ public class VelocityPlugin {
public void onInit(ProxyInitializeEvent event) {
INSTANCE = this;
logger.info("Loading config...");
config = new Config();
//Loading plugin
logger.info("Starting AntiVPN services...");
AntiVPN.start(new VelocityConfig(), new VelocityListener(), new VelocityPlayerExecutor(), configDir.toFile());
AntiVPN.start(new VelocityListener(), new VelocityPlayerExecutor(), configDir.toFile());
if(AntiVPN.getInstance().getConfig().metrics()) {
if(AntiVPN.getInstance().getVpnConfig().metrics()) {
logger.info("Starting metrics...");
Metrics metrics = metricsFactory.make(this, 12791);
}
@@ -1,114 +0,0 @@
package dev.brighten.antivpn.velocity.config;
import com.google.common.base.Charsets;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PACKAGE)
public class JsonConfiguration extends ConfigurationProvider
{
private final Gson json = new GsonBuilder().serializeNulls().setPrettyPrinting().registerTypeAdapter( Configuration.class, new JsonSerializer<Configuration>()
{
@Override
public JsonElement serialize(Configuration src, Type typeOfSrc, JsonSerializationContext context)
{
return context.serialize( ( (Configuration) src ).self );
}
} ).create();
@Override
public void save(Configuration config, File file) throws IOException
{
try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), Charsets.UTF_8 ) )
{
save( config, writer );
}
}
@Override
public void save(Configuration config, Writer writer)
{
json.toJson( config.self, writer );
}
@Override
public Configuration load(File file) throws IOException
{
return load( file, null );
}
@Override
public Configuration load(File file, Configuration defaults) throws IOException
{
try ( FileInputStream is = new FileInputStream( file ) )
{
return load( is, defaults );
}
}
@Override
public Configuration load(Reader reader)
{
return load( reader, null );
}
@Override
@SuppressWarnings("unchecked")
public Configuration load(Reader reader, Configuration defaults)
{
Map<String, Object> map = json.fromJson( reader, LinkedHashMap.class );
if ( map == null )
{
map = new LinkedHashMap<>();
}
return new Configuration( map, defaults );
}
@Override
public Configuration load(InputStream is)
{
return load( is, null );
}
@Override
public Configuration load(InputStream is, Configuration defaults)
{
return load( new InputStreamReader( is, Charsets.UTF_8 ), defaults );
}
@Override
public Configuration load(String string)
{
return load( string, null );
}
@Override
@SuppressWarnings("unchecked")
public Configuration load(String string, Configuration defaults)
{
Map<String, Object> map = json.fromJson( string, LinkedHashMap.class );
if ( map == null )
{
map = new LinkedHashMap<>();
}
return new Configuration( map, defaults );
}
}
@@ -1,136 +0,0 @@
package dev.brighten.antivpn.velocity.config;
import com.google.common.base.Charsets;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.representer.Represent;
import org.yaml.snakeyaml.representer.Representer;
@NoArgsConstructor(access = AccessLevel.PACKAGE)
public class YamlConfiguration extends ConfigurationProvider
{
private final ThreadLocal<Yaml> yaml = new ThreadLocal<Yaml>()
{
@Override
protected Yaml initialValue()
{
Representer representer = new Representer()
{
{
representers.put( Configuration.class, new Represent()
{
@Override
public Node representData(Object data)
{
return represent( ( (Configuration) data ).self );
}
} );
}
};
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK );
return new Yaml( new Constructor(), representer, options );
}
};
@Override
public void save(Configuration config, File file) throws IOException
{
try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), Charsets.UTF_8 ) )
{
save( config, writer );
}
}
@Override
public void save(Configuration config, Writer writer)
{
yaml.get().dump( config.self, writer );
}
@Override
public Configuration load(File file) throws IOException
{
return load( file, null );
}
@Override
public Configuration load(File file, Configuration defaults) throws IOException
{
try ( FileInputStream is = new FileInputStream( file ) )
{
return load( is, defaults );
}
}
@Override
public Configuration load(Reader reader)
{
return load( reader, null );
}
@Override
@SuppressWarnings("unchecked")
public Configuration load(Reader reader, Configuration defaults)
{
Map<String, Object> map = yaml.get().loadAs( reader, LinkedHashMap.class );
if ( map == null )
{
map = new LinkedHashMap<>();
}
return new Configuration( map, defaults );
}
@Override
public Configuration load(InputStream is)
{
return load( is, null );
}
@Override
@SuppressWarnings("unchecked")
public Configuration load(InputStream is, Configuration defaults)
{
Map<String, Object> map = yaml.get().loadAs( is, LinkedHashMap.class );
if ( map == null )
{
map = new LinkedHashMap<>();
}
return new Configuration( map, defaults );
}
@Override
public Configuration load(String string)
{
return load( string, null );
}
@Override
@SuppressWarnings("unchecked")
public Configuration load(String string, Configuration defaults)
{
Map<String, Object> map = yaml.get().loadAs( string, LinkedHashMap.class );
if ( map == null )
{
map = new LinkedHashMap<>();
}
return new Configuration( map, defaults );
}
}
@@ -1,115 +0,0 @@
package dev.brighten.antivpn.velocity.util;
import com.google.common.io.ByteStreams;
import dev.brighten.antivpn.velocity.VelocityPlugin;
import dev.brighten.antivpn.velocity.config.Configuration;
import dev.brighten.antivpn.velocity.config.ConfigurationProvider;
import dev.brighten.antivpn.velocity.config.YamlConfiguration;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Author: nitramleo (Martin)
* Date created: 10-Aug-18
*/
public class Config {
private File file;
private Configuration configuration;
public Config() {
File dataFolder = VelocityPlugin.INSTANCE.getConfigDir().toFile();
this.file = new File(dataFolder, "config.yml");
try {
if (!this.file.exists()) {
if (!dataFolder.exists()) {
dataFolder.mkdir();
}
this.file.createNewFile();
try (final InputStream is =VelocityPlugin.INSTANCE.getClass().getResourceAsStream("config.yml");
final OutputStream os = new FileOutputStream(this.file)) {
ByteStreams.copy(is, os);
}
}
this.configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(this.file);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void load() {
File dataFolder = VelocityPlugin.INSTANCE.getConfigDir().toFile();
this.file = new File(dataFolder, "config.yml");
try {
this.configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(this.file);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void save() {
try {
ConfigurationProvider.getProvider( YamlConfiguration.class).save(this.configuration, this.file);
}
catch (IOException e) {
e.printStackTrace();
}
}
public Configuration getConfiguration() {
return this.configuration;
}
public File getFile() {
return this.file;
}
public double getDouble(final String path) {
if (this.configuration.get(path) != null) {
return this.configuration.getDouble(path);
}
return 0.0;
}
public int getInt(final String path) {
if (this.configuration.get(path) != null) {
return this.configuration.getInt(path);
}
return 0;
}
public Object get(final String path) {
return this.configuration.get(path);
}
public void set(final String path, final Object object) {
configuration.set(path, object);
}
public boolean getBoolean(final String path) {
return this.configuration.get(path) != null && this.configuration.getBoolean(path);
}
public String getString(final String path) {
if (this.configuration.get(path) != null) {
return StringUtils.translateAlternateColorCodes('&', this.configuration.getString(path));
}
return "String at path: " + path + " not found!";
}
public List<String> getStringList(final String path) {
if (this.configuration.get(path) != null) {
final ArrayList<String> strings = new ArrayList<String>();
for (final String string : this.configuration.getStringList(path)) {
strings.add(StringUtils.translateAlternateColorCodes('&', string));
}
return strings;
}
return Arrays.asList("String List at path: " + path + " not found!");
}
}
@@ -1,28 +0,0 @@
package dev.brighten.antivpn.velocity.util;
import dev.brighten.antivpn.velocity.VelocityPlugin;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class ConfigDefault<A> {
private final A defaultValue;
private final String path;
private final VelocityPlugin plugin;
public A get() {
if(plugin.getConfig().get(path) != null)
return (A) plugin.getConfig().get(path);
else {
plugin.getConfig().set(path, defaultValue);
plugin.getConfig().save();
return defaultValue;
}
}
public A set(A value) {
plugin.getConfig().set(path, value);
return value;
}
}
+1 -1
View File
@@ -7,7 +7,7 @@
<groupId>dev.brighten.antivpn</groupId>
<artifactId>AntiVPN</artifactId>
<packaging>pom</packaging>
<version>1.5.2.1</version>
<version>1.7</version>
<modules>
<module>Common</module>