diff --git a/Assembly/dependency-reduced-pom.xml b/Assembly/dependency-reduced-pom.xml
index 14a0aeb..df32d86 100644
--- a/Assembly/dependency-reduced-pom.xml
+++ b/Assembly/dependency-reduced-pom.xml
@@ -3,7 +3,7 @@
AntiVPN
dev.brighten.antivpn
- 1.6.1
+ 1.7
4.0.0
Assembly
diff --git a/Assembly/pom.xml b/Assembly/pom.xml
index 3a9ef52..3894153 100644
--- a/Assembly/pom.xml
+++ b/Assembly/pom.xml
@@ -5,7 +5,7 @@
AntiVPN
dev.brighten.antivpn
- 1.6.1
+ 1.7
4.0.0
diff --git a/Bukkit/dependency-reduced-pom.xml b/Bukkit/dependency-reduced-pom.xml
index 0f4c4bb..94d1665 100644
--- a/Bukkit/dependency-reduced-pom.xml
+++ b/Bukkit/dependency-reduced-pom.xml
@@ -3,7 +3,7 @@
AntiVPN
dev.brighten.antivpn
- 1.6.1
+ 1.7
4.0.0
Bukkit
@@ -56,7 +56,7 @@
dev.brighten.antivpn
Common
- 1.6.1
+ 1.7
provided
@@ -71,6 +71,10 @@
h2
com.h2database
+
+ snakeyaml
+ org.yaml
+
mongo-java-driver
org.mongodb
diff --git a/Bukkit/pom.xml b/Bukkit/pom.xml
index 76a044d..df0dca9 100644
--- a/Bukkit/pom.xml
+++ b/Bukkit/pom.xml
@@ -5,7 +5,7 @@
AntiVPN
dev.brighten.antivpn
- 1.6.1
+ 1.7
4.0.0
@@ -69,7 +69,7 @@
dev.brighten.antivpn
Common
- 1.6.1
+ 1.7
provided
diff --git a/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitConfig.java b/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitConfig.java
index 03e010d..d4daec3 100644
--- a/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitConfig.java
+++ b/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitConfig.java
@@ -23,6 +23,8 @@ public class BukkitConfig implements VPNConfig {
"database.username", BukkitPlugin.pluginInstance),
defaultPassword = new ConfigDefault<>("password",
"database.password", 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",
@@ -43,10 +45,14 @@ public class BukkitConfig implements VPNConfig {
private final ConfigDefault> 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),
+ defBlockedCountries = new ConfigDefault<>(new ArrayList<>(), "blockedCountries",
+ BukkitPlugin.pluginInstance),
+ defAllowedCountries = new ConfigDefault<>(new ArrayList<>(), "allowedCountries",
BukkitPlugin.pluginInstance);
private String license, kickMessage, databaseType, databaseName, mongoURL, username, password, ip, alertMsg;
- private List prefixWhitelists, commands;
+ private List prefixWhitelists, commands, allowedCountries, blockedCountries;
private int port;
private boolean cacheResults, databaseEnabled, useCredentials, commandsEnabled, kickPlayers, alertToStaff, metrics;
@@ -135,6 +141,16 @@ public class BukkitConfig implements VPNConfig {
return ip;
}
+ @Override
+ public List allowedCountries() {
+ return allowedCountries;
+ }
+
+ @Override
+ public List blockedCountries() {
+ return blockedCountries;
+ }
+
@Override
public int getPort() {
if(port == -1) {
@@ -177,5 +193,7 @@ public class BukkitConfig implements VPNConfig {
alertToStaff = defaultAlertToStaff.get();
alertMsg = defaultAlertMsg.get();
metrics = defaultMetrics.get();
+ blockedCountries = defBlockedCountries.get();
+ allowedCountries = defAllowedCountries.get();
}
}
diff --git a/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitPlugin.java b/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitPlugin.java
index b0da53a..8282a13 100644
--- a/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitPlugin.java
+++ b/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/BukkitPlugin.java
@@ -3,6 +3,8 @@ 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.MiscUtils;
+import dev.brighten.antivpn.utils.config.Configuration;
import lombok.val;
import net.md_5.bungee.api.ChatColor;
import org.bstats.bukkit.Metrics;
@@ -16,6 +18,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,7 +38,12 @@ 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());
diff --git a/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/util/ConfigDefault.java b/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/util/ConfigDefault.java
index 8fd0d8f..d5c2477 100644
--- a/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/util/ConfigDefault.java
+++ b/Bukkit/src/main/java/dev/brighten/antivpn/bukkit/util/ConfigDefault.java
@@ -1,8 +1,12 @@
package dev.brighten.antivpn.bukkit.util;
+import dev.brighten.antivpn.utils.MiscUtils;
+import dev.brighten.antivpn.utils.config.Configuration;
import lombok.AllArgsConstructor;
import org.bukkit.plugin.Plugin;
+import java.io.File;
+
@AllArgsConstructor
public class ConfigDefault {
diff --git a/Bukkit/src/main/resources/config.yml b/Bukkit/src/main/resources/config.yml
new file mode 100644
index 0000000..2f61a3f
--- /dev/null
+++ b/Bukkit/src/main/resources/config.yml
@@ -0,0 +1,46 @@
+#####################################################
+# 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:
+ enabled: false # Enable to cache queries and save alerts state beyond restarts
+ useCredentials: true
+ type: MySQL #Options Mongo and MySQL
+ database: kaurivpn # The database name you would like to use
+ mongoURL: '' # Can be used if you prefer to authenticate via Mongo URL
+ username: root # Your database username
+ password: password # Your database password
+ ip: localhost #The IP of your database goes here
+ port: -1 #-1 will use default port of databases (MySQL:3306, Mongo:27017). Otherwise, enter alternative ports here.
+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)'
+# 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
diff --git a/Bungee/dependency-reduced-pom.xml b/Bungee/dependency-reduced-pom.xml
index 7a673e6..4d9ac21 100644
--- a/Bungee/dependency-reduced-pom.xml
+++ b/Bungee/dependency-reduced-pom.xml
@@ -3,7 +3,7 @@
AntiVPN
dev.brighten.antivpn
- 1.6.1
+ 1.7
4.0.0
Bungee
@@ -50,7 +50,7 @@
dev.brighten.antivpn
Common
- 1.6.1
+ 1.7
provided
@@ -65,6 +65,10 @@
h2
com.h2database
+
+ snakeyaml
+ org.yaml
+
mongo-java-driver
org.mongodb
diff --git a/Bungee/pom.xml b/Bungee/pom.xml
index dd4a350..baa19f5 100644
--- a/Bungee/pom.xml
+++ b/Bungee/pom.xml
@@ -5,7 +5,7 @@
AntiVPN
dev.brighten.antivpn
- 1.6.1
+ 1.7
4.0.0
@@ -63,7 +63,7 @@
dev.brighten.antivpn
Common
- 1.6.1
+ 1.7
provided
diff --git a/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeConfig.java b/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeConfig.java
index 2d3f0a5..9e0598a 100644
--- a/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeConfig.java
+++ b/Bungee/src/main/java/dev/brighten/antivpn/bungee/BungeeConfig.java
@@ -41,10 +41,14 @@ public class BungeeConfig implements VPNConfig {
private final ConfigDefault> 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);
+ BungeePlugin.pluginInstance),
+ defBlockedCountries = new ConfigDefault<>(new ArrayList<>(), "blockedCountries",
+ BungeePlugin.pluginInstance),
+ defAllowedCountries = new ConfigDefault<>(new ArrayList<>(), "allowedCountries",
+ BungeePlugin.pluginInstance);
private String license, kickMessage, databaseType, databaseName, mongoURL, username, password, ip, alertMsg;
- private List prefixWhitelists, commands;
+ private List prefixWhitelists, commands, allowedCountries, blockedCountries;
private int port;
private boolean cacheResults, useCredentials, databaseEnabled, commandsEnabled, kickPlayers, alertToStaff, metrics;
@@ -133,6 +137,16 @@ public class BungeeConfig implements VPNConfig {
return ip;
}
+ @Override
+ public List allowedCountries() {
+ return allowedCountries;
+ }
+
+ @Override
+ public List blockedCountries() {
+ return blockedCountries;
+ }
+
@Override
public int getPort() {
if(port == -1) {
@@ -175,5 +189,7 @@ public class BungeeConfig implements VPNConfig {
alertToStaff = defaultAlertToStaff.get();
alertMsg = defaultAlertMsg.get();
metrics = defaultMetrics.get();
+ blockedCountries = defBlockedCountries.get();
+ allowedCountries = defAllowedCountries.get();
}
}
diff --git a/Common/pom.xml b/Common/pom.xml
index c543a95..8bef495 100644
--- a/Common/pom.xml
+++ b/Common/pom.xml
@@ -5,7 +5,7 @@
AntiVPN
dev.brighten.antivpn
- 1.6.1
+ 1.7
4.0.0
@@ -64,6 +64,12 @@
2.1.210
compile
+
+ org.yaml
+ snakeyaml
+ 1.15
+ compile
+
org.mongodb
mongo-java-driver
diff --git a/Common/src/main/java/dev/brighten/antivpn/api/VPNConfig.java b/Common/src/main/java/dev/brighten/antivpn/api/VPNConfig.java
index 1a53d85..3927507 100644
--- a/Common/src/main/java/dev/brighten/antivpn/api/VPNConfig.java
+++ b/Common/src/main/java/dev/brighten/antivpn/api/VPNConfig.java
@@ -38,6 +38,10 @@ public interface VPNConfig {
String getIp();
+ List allowedCountries();
+
+ List blockedCountries();
+
int getPort();
boolean metrics();
diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/MiscUtils.java b/Common/src/main/java/dev/brighten/antivpn/utils/MiscUtils.java
index 7e6bc9a..1496970 100644
--- a/Common/src/main/java/dev/brighten/antivpn/utils/MiscUtils.java
+++ b/Common/src/main/java/dev/brighten/antivpn/utils/MiscUtils.java
@@ -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;
@@ -33,6 +30,24 @@ 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)
{
return ipv4.matcher(ip).matches();
diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/config/Configuration.java b/Common/src/main/java/dev/brighten/antivpn/utils/config/Configuration.java
new file mode 100644
index 0000000..b9408cf
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/utils/config/Configuration.java
@@ -0,0 +1,507 @@
+package dev.brighten.antivpn.utils.config;
+
+import java.util.*;
+
+public final class Configuration
+{
+
+ private static final char SEPARATOR = '.';
+ final Map self;
+ final Map> comments;
+ private final Configuration defaults;
+
+ public Configuration()
+ {
+ this( null );
+ }
+
+ public Configuration(Configuration defaults)
+ {
+ this( new LinkedHashMap(), defaults );
+ }
+
+ Configuration(Map, ?> map, Configuration defaults)
+ {
+ this.self = new LinkedHashMap<>();
+ this.defaults = defaults;
+ comments = new HashMap<>();
+
+ for ( Map.Entry, ?> entry : map.entrySet() )
+ {
+ String key = ( entry.getKey() == null ) ? "null" : entry.getKey().toString();
+
+ if ( entry.getValue() instanceof Map )
+ {
+ this.self.put( key, new Configuration( (Map) entry.getValue(), ( defaults == null ) ? null : defaults.getSection( key ) ) );
+ } else
+ {
+ this.self.put( key, entry.getValue() );
+ }
+ }
+ }
+
+ public void loadFromString(String contents) {
+
+ List list = new ArrayList<>();
+ Collections.addAll(list, contents.split("\n"));
+
+ int currentLayer = 0;
+ String currentPath = "";
+
+ int lineNumber = 0;
+ for(Iterator 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 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 );
+ if ( index == -1 )
+ {
+ return this;
+ }
+
+ String root = path.substring( 0, index );
+ Object section = self.get( root );
+ if ( section == null )
+ {
+ section = new Configuration( ( defaults == null ) ? null : defaults.getSection( root ) );
+ self.put( root, section );
+ }
+
+ return (Configuration) section;
+ }
+
+ private String getChild(String path)
+ {
+ int index = path.indexOf( SEPARATOR );
+ return ( index == -1 ) ? path : path.substring( index + 1 );
+ }
+
+ /*------------------------------------------------------------------------*/
+ @SuppressWarnings("unchecked")
+ public T get(String path, T def)
+ {
+ Configuration section = getSectionFor( path );
+ Object val;
+ if ( section == this )
+ {
+ val = self.get( path );
+ } else
+ {
+ val = section.get( getChild( path ), def );
+ }
+
+ if ( val == null && def instanceof Configuration )
+ {
+ self.put( path, def );
+ }
+
+ return ( val != null ) ? (T) val : def;
+ }
+
+ public boolean contains(String path)
+ {
+ return get( path, null ) != null;
+ }
+
+ public Object get(String path)
+ {
+ return get( path, getDefault( path ) );
+ }
+
+ public Object getDefault(String path)
+ {
+ return ( defaults == null ) ? null : defaults.get( path );
+ }
+
+ public void set(String path, Object value)
+ {
+ if ( value instanceof Map )
+ {
+ value = new Configuration( (Map) value, ( defaults == null ) ? null : defaults.getSection( path ) );
+ }
+
+ Configuration section = getSectionFor( path );
+ if ( section == this )
+ {
+ if ( value == null )
+ {
+ self.remove( path );
+ } else
+ {
+ self.put( path, value );
+ }
+ } else
+ {
+ section.set( getChild( path ), value );
+ }
+ }
+
+ /*------------------------------------------------------------------------*/
+ public Configuration getSection(String path)
+ {
+ Object def = getDefault( path );
+ return (Configuration) get( path, ( def instanceof Configuration ) ? def : new Configuration( ( defaults == null ) ? null : defaults.getSection( path ) ) );
+ }
+
+ /**
+ * Gets keys, not deep by default.
+ *
+ * @return top level keys for this section
+ */
+ public Collection getKeys()
+ {
+ return new LinkedHashSet<>( self.keySet() );
+ }
+
+ /*------------------------------------------------------------------------*/
+ public byte getByte(String path)
+ {
+ Object def = getDefault( path );
+ return getByte( path, ( def instanceof Number ) ? ( (Number) def ).byteValue() : 0 );
+ }
+
+ public byte getByte(String path, byte def)
+ {
+ Object val = get( path, def );
+ return ( val instanceof Number ) ? ( (Number) val ).byteValue() : def;
+ }
+
+ public List getByteList(String path)
+ {
+ List> list = getList( path );
+ List result = new ArrayList<>();
+
+ for ( Object object : list )
+ {
+ if ( object instanceof Number )
+ {
+ result.add( ( (Number) object ).byteValue() );
+ }
+ }
+
+ return result;
+ }
+
+ public short getShort(String path)
+ {
+ Object def = getDefault( path );
+ return getShort( path, ( def instanceof Number ) ? ( (Number) def ).shortValue() : 0 );
+ }
+
+ public short getShort(String path, short def)
+ {
+ Object val = get( path, def );
+ return ( val instanceof Number ) ? ( (Number) val ).shortValue() : def;
+ }
+
+ public List getShortList(String path)
+ {
+ List> list = getList( path );
+ List result = new ArrayList<>();
+
+ for ( Object object : list )
+ {
+ if ( object instanceof Number )
+ {
+ result.add( ( (Number) object ).shortValue() );
+ }
+ }
+
+ return result;
+ }
+
+ public int getInt(String path)
+ {
+ Object def = getDefault( path );
+ return getInt( path, ( def instanceof Number ) ? ( (Number) def ).intValue() : 0 );
+ }
+
+ public int getInt(String path, int def)
+ {
+ Object val = get( path, def );
+ return ( val instanceof Number ) ? ( (Number) val ).intValue() : def;
+ }
+
+ public List getIntList(String path)
+ {
+ List> list = getList( path );
+ List result = new ArrayList<>();
+
+ for ( Object object : list )
+ {
+ if ( object instanceof Number )
+ {
+ result.add( ( (Number) object ).intValue() );
+ }
+ }
+
+ return result;
+ }
+
+ public long getLong(String path)
+ {
+ Object def = getDefault( path );
+ return getLong( path, ( def instanceof Number ) ? ( (Number) def ).longValue() : 0 );
+ }
+
+ public long getLong(String path, long def)
+ {
+ Object val = get( path, def );
+ return ( val instanceof Number ) ? ( (Number) val ).longValue() : def;
+ }
+
+ public List getLongList(String path)
+ {
+ List> list = getList( path );
+ List result = new ArrayList<>();
+
+ for ( Object object : list )
+ {
+ if ( object instanceof Number )
+ {
+ result.add( ( (Number) object ).longValue() );
+ }
+ }
+
+ return result;
+ }
+
+ public float getFloat(String path)
+ {
+ Object def = getDefault( path );
+ return getFloat( path, ( def instanceof Number ) ? ( (Number) def ).floatValue() : 0 );
+ }
+
+ public float getFloat(String path, float def)
+ {
+ Object val = get( path, def );
+ return ( val instanceof Number ) ? ( (Number) val ).floatValue() : def;
+ }
+
+ public List getFloatList(String path)
+ {
+ List> list = getList( path );
+ List result = new ArrayList<>();
+
+ for ( Object object : list )
+ {
+ if ( object instanceof Number )
+ {
+ result.add( ( (Number) object ).floatValue() );
+ }
+ }
+
+ return result;
+ }
+
+ public double getDouble(String path)
+ {
+ Object def = getDefault( path );
+ return getDouble( path, ( def instanceof Number ) ? ( (Number) def ).doubleValue() : 0 );
+ }
+
+ public double getDouble(String path, double def)
+ {
+ Object val = get( path, def );
+ return ( val instanceof Number ) ? ( (Number) val ).doubleValue() : def;
+ }
+
+ public List getDoubleList(String path)
+ {
+ List> list = getList( path );
+ List result = new ArrayList<>();
+
+ for ( Object object : list )
+ {
+ if ( object instanceof Number )
+ {
+ result.add( ( (Number) object ).doubleValue() );
+ }
+ }
+
+ return result;
+ }
+
+ public boolean getBoolean(String path)
+ {
+ Object def = getDefault( path );
+ return getBoolean( path, ( def instanceof Boolean ) ? (Boolean) def : false );
+ }
+
+ public boolean getBoolean(String path, boolean def)
+ {
+ Object val = get( path, def );
+ return ( val instanceof Boolean ) ? (Boolean) val : def;
+ }
+
+ public List getBooleanList(String path)
+ {
+ List> list = getList( path );
+ List result = new ArrayList<>();
+
+ for ( Object object : list )
+ {
+ if ( object instanceof Boolean )
+ {
+ result.add( (Boolean) object );
+ }
+ }
+
+ return result;
+ }
+
+ public char getChar(String path)
+ {
+ Object def = getDefault( path );
+ return getChar( path, ( def instanceof Character ) ? (Character) def : '\u0000' );
+ }
+
+ public char getChar(String path, char def)
+ {
+ Object val = get( path, def );
+ return ( val instanceof Character ) ? (Character) val : def;
+ }
+
+ public List getCharList(String path)
+ {
+ List> list = getList( path );
+ List result = new ArrayList<>();
+
+ for ( Object object : list )
+ {
+ if ( object instanceof Character )
+ {
+ result.add( (Character) object );
+ }
+ }
+
+ return result;
+ }
+
+ public String getString(String path)
+ {
+ Object def = getDefault( path );
+ return getString( path, ( def instanceof String ) ? (String) def : "" );
+ }
+
+ public String getString(String path, String def)
+ {
+ Object val = get( path, def );
+ return ( val instanceof String ) ? (String) val : def;
+ }
+
+ public List getStringList(String path)
+ {
+ List> list = getList( path );
+ List result = new ArrayList<>();
+
+ for ( Object object : list )
+ {
+ if ( object instanceof String )
+ {
+ result.add( (String) object );
+ }
+ }
+
+ return result;
+ }
+
+ /*------------------------------------------------------------------------*/
+ public List> getList(String path)
+ {
+ Object def = getDefault( path );
+ return getList( path, ( def instanceof List> ) ? (List>) def : Collections.EMPTY_LIST );
+ }
+
+ public List> getList(String path, List> def)
+ {
+ Object val = get( path, def );
+ return ( val instanceof List> ) ? (List>) val : def;
+ }
+}
\ No newline at end of file
diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/config/ConfigurationProvider.java b/Common/src/main/java/dev/brighten/antivpn/utils/config/ConfigurationProvider.java
new file mode 100644
index 0000000..47f8a48
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/utils/config/ConfigurationProvider.java
@@ -0,0 +1,49 @@
+package dev.brighten.antivpn.utils.config;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class ConfigurationProvider
+{
+
+ public static final Map, ConfigurationProvider> providers = new HashMap<>();
+
+ static
+ {
+ try
+ {
+ providers.put( YamlConfiguration.class, new YamlConfiguration() );
+ } catch ( NoClassDefFoundError ex )
+ {
+ ex.printStackTrace();
+ // Ignore, no SnakeYAML
+ }
+ }
+
+ public static ConfigurationProvider getProvider(Class extends ConfigurationProvider> provider)
+ {
+ return providers.get( provider );
+ }
+
+ /*------------------------------------------------------------------------*/
+ public abstract void save(Configuration config, File file) throws IOException;
+
+ public abstract void save(Configuration config, Writer writer);
+
+ public abstract Configuration load(File file) throws IOException;
+
+ public abstract Configuration load(File file, Configuration defaults) throws IOException;
+
+ public abstract Configuration load(Reader reader);
+
+ public abstract Configuration load(Reader reader, Configuration defaults);
+
+ public abstract Configuration load(InputStream is);
+
+ public abstract Configuration load(InputStream is, Configuration defaults);
+
+ public abstract Configuration load(String string);
+
+ public abstract Configuration load(String string, Configuration defaults);
+}
\ No newline at end of file
diff --git a/Common/src/main/java/dev/brighten/antivpn/utils/config/YamlConfiguration.java b/Common/src/main/java/dev/brighten/antivpn/utils/config/YamlConfiguration.java
new file mode 100644
index 0000000..81bdf33
--- /dev/null
+++ b/Common/src/main/java/dev/brighten/antivpn/utils/config/YamlConfiguration.java
@@ -0,0 +1,161 @@
+package dev.brighten.antivpn.utils.config;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.*;
+
+@NoArgsConstructor(access = AccessLevel.PACKAGE)
+public class YamlConfiguration extends ConfigurationProvider
+{
+
+ private final ThreadLocal yaml = new ThreadLocal()
+ {
+ @Override
+ protected Yaml initialValue()
+ {
+
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK );
+
+ return new Yaml(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);
+
+ List 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 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(contents);
+ } 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 );
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Configuration load(Reader reader, Configuration defaults)
+ {
+ Map 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 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 map = yaml.get().loadAs( string, LinkedHashMap.class );
+ if ( map == null )
+ {
+ map = new LinkedHashMap<>();
+ }
+ return new Configuration( map, defaults );
+ }
+}
\ No newline at end of file
diff --git a/Velocity/pom.xml b/Velocity/pom.xml
index 0132b68..5178e79 100644
--- a/Velocity/pom.xml
+++ b/Velocity/pom.xml
@@ -5,7 +5,7 @@
AntiVPN
dev.brighten.antivpn
- 1.6.1
+ 1.7
4.0.0
@@ -33,7 +33,7 @@
dev.brighten.antivpn
Common
- 1.6.1
+ 1.7
provided
diff --git a/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityConfig.java b/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityConfig.java
index 94fe0ea..32f21a7 100644
--- a/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityConfig.java
+++ b/Velocity/src/main/java/dev/brighten/antivpn/velocity/VelocityConfig.java
@@ -41,10 +41,14 @@ public class VelocityConfig implements VPNConfig {
private final ConfigDefault> 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);
+ VelocityPlugin.INSTANCE),
+ defBlockedCountries = new ConfigDefault<>(new ArrayList<>(), "blockedCountries",
+ VelocityPlugin.INSTANCE),
+ defAllowedCountries = new ConfigDefault<>(new ArrayList<>(), "allowedCountries",
+ VelocityPlugin.INSTANCE);
private String license, kickMessage, databaseType, databaseName, mongoURL, username, password, ip, alertMsg;
- private List prefixWhitelists, commands;
+ private List prefixWhitelists, commands, allowedCountries, blockedCountries;
private int port;
private boolean cacheResults, useCredentials, databaseEnabled, commandsEnabled, kickPlayers, alertToStaff, metrics;
@@ -133,6 +137,16 @@ public class VelocityConfig implements VPNConfig {
return ip;
}
+ @Override
+ public List allowedCountries() {
+ return allowedCountries;
+ }
+
+ @Override
+ public List blockedCountries() {
+ return blockedCountries;
+ }
+
@Override
public int getPort() {
if(port == -1) {
@@ -175,5 +189,7 @@ public class VelocityConfig implements VPNConfig {
alertToStaff = defaultAlertToStaff.get();
alertMsg = defaultAlertMsg.get();
metrics = defaultMetrics.get();
+ blockedCountries = defBlockedCountries.get();
+ allowedCountries = defAllowedCountries.get();
}
}
diff --git a/pom.xml b/pom.xml
index 228c66d..2b45b4a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
dev.brighten.antivpn
AntiVPN
pom
- 1.6.1
+ 1.7
Common