mirror of
https://github.com/funkemunky/AntiVPN.git
synced 2026-05-31 17:31:55 +00:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2bdd7d2c34 | |||
| 31a9412c0a | |||
| 7f96c49ce8 | |||
| 7b3f9fc6ae | |||
| edd08b27ce | |||
| 158045217e | |||
| 63bdb0a4da | |||
| b9e23ba34e | |||
| 9f6b0f8b27 | |||
| fec1dcdef1 | |||
| c062e3d910 | |||
| a79fb1fe9a | |||
| d224efce3c | |||
| a2554c2bba | |||
| 70bfb4e83d | |||
| bc666447c5 | |||
| 26cfc3e3f8 | |||
| 7974b24271 | |||
| 87cdd57383 | |||
| 6fe928ca14 | |||
| dae9111a34 | |||
| f4d6fc2b4b | |||
| d461b5945b | |||
| c6303ec1b2 | |||
| ca8fb24134 | |||
| 5e37d2c371 | |||
| 48c6dd63ee | |||
| 50e7059597 | |||
| 464b02f416 | |||
| db1cdad4e1 | |||
| 9f66570088 | |||
| 5f0b2796b3 | |||
| be5eb4e953 | |||
| dde81b0495 | |||
| cbc00b79e2 | |||
| 3b2a463e58 | |||
| 96e48594d8 | |||
| c1ab71c7ed | |||
| 4bda24f10c | |||
| 259cff4402 | |||
| c54e90dca1 | |||
| 4f1e3848de | |||
| 1606ad192e | |||
| 40308869c0 | |||
| 6959f35d0c | |||
| 21b6924cce | |||
| 9c843cd061 | |||
| 91a09f6940 | |||
| 36b44200c4 | |||
| 903dd8e73e | |||
| e6bc601372 | |||
| 9dbf0e8635 | |||
| dd1b6afbb7 | |||
| 14e266b978 | |||
| cc289f41ff | |||
| bf5b81b750 | |||
| a480f13302 | |||
| 4a95b51350 | |||
| 9dc312186b | |||
| 3f9a2100a9 | |||
| 4c82755935 | |||
| 0048cf6b8c | |||
| 795c869fc0 | |||
| 95a00a4d0a | |||
| a6f26d4ba7 | |||
| 7a0786e29f | |||
| df4a14086b | |||
| f55fa88c2b | |||
| 4f79522010 | |||
| 7654cca651 | |||
| e01cbf95f2 | |||
| db49d400a0 | |||
| b39cc3e19c | |||
| ff25c75055 | |||
| 733e797a17 | |||
| 0c903794e5 | |||
| bddf26359d | |||
| 4424b2b9a5 |
@@ -1,6 +1,8 @@
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -13,8 +15,17 @@ jobs:
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 17.0
|
||||
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
- name: Compile
|
||||
run: mvn -B -Pclean install
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload AntiVPN
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: AntiVPN
|
||||
path: Assembly/target/Assembly-*.jar
|
||||
|
||||
@@ -13,6 +13,9 @@ local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
.recommenders
|
||||
*.iml
|
||||
|
||||
.idea/
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.7.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>Assembly</artifactId>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</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.moandjiezana</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.utils.shaded.com.moandjiezana</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cc.funkemunky.utils</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
</properties>
|
||||
</project>
|
||||
+4
-17
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.7.1</version>
|
||||
<version>1.9.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -29,27 +29,14 @@
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<minimizeJar>false</minimizeJar>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.yaml.snakeyaml</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.utils.shaded.org.yaml.snakeyaml</shadedPattern>
|
||||
<shadedPattern>dev.brighten.antivpn.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.moandjiezana</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.utils.shaded.com.moandjiezana</shadedPattern>
|
||||
<pattern>com.google.common</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.shaded.com.google.common</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.7.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>Bukkit</artifactId>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
<compilerArgument>-XDignore.symbol.file</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.bukkit.org.bstats</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.github.spigot</groupId>
|
||||
<artifactId>1.13.2</artifactId>
|
||||
<version>1.13.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>Common</artifactId>
|
||||
<version>1.7.1</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>toml4j</artifactId>
|
||||
<groupId>com.moandjiezana.toml</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<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>
|
||||
<groupId>cc.funkemunky.utils</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
</properties>
|
||||
</project>
|
||||
|
||||
+21
-12
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.7.1</version>
|
||||
<version>1.9.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -26,22 +26,31 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.bstats</pattern>
|
||||
<!-- Replace this with your package! -->
|
||||
<shadedPattern>dev.brighten.antivpn.bukkit.org.bstats</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.bstats</pattern>
|
||||
<!-- Replace this with your package! -->
|
||||
<shadedPattern>dev.brighten.antivpn.bukkit.org.bstats</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.yaml.snakeyaml</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.shaded.org.yaml.snakeyaml</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.google.common</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.shaded.com.google.common</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
@@ -69,7 +78,7 @@
|
||||
<dependency>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>Common</artifactId>
|
||||
<version>1.7.1</version>
|
||||
<version>1.9.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -16,8 +16,9 @@ public class BukkitCommandExecutor implements CommandExecutor {
|
||||
private final CommandSender sender;
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', message));
|
||||
public void sendMessage(String message, Object... objects) {
|
||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&',
|
||||
String.format(message, objects)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,25 +1,34 @@
|
||||
package dev.brighten.antivpn.bukkit;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.api.APIPlayer;
|
||||
import dev.brighten.antivpn.api.VPNExecutor;
|
||||
import dev.brighten.antivpn.message.VpnString;
|
||||
import dev.brighten.antivpn.web.objects.VPNResponse;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class BukkitListener extends VPNExecutor implements Listener {
|
||||
private final Cache<UUID, VPNResponse> responseCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.maximumSize(2000)
|
||||
.build();
|
||||
|
||||
private BukkitTask cacheResetTask;
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
BukkitPlugin.pluginInstance.getServer().getPluginManager()
|
||||
@@ -27,25 +36,18 @@ public class BukkitListener extends VPNExecutor implements Listener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runCacheReset() {
|
||||
cacheResetTask = new BukkitRunnable() {
|
||||
public void run() {
|
||||
resetCache();
|
||||
}
|
||||
}.runTaskTimerAsynchronously(BukkitPlugin.pluginInstance, 24000, 24000); //Reset cache every 20 minutes
|
||||
public void shutdown() {
|
||||
|
||||
HandlerList.unregisterAll(this);
|
||||
threadExecutor.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if(cacheResetTask != null && !cacheResetTask.isCancelled()) cacheResetTask.cancel();
|
||||
public void log(Level level, String log, Object... objects) {
|
||||
Bukkit.getLogger().log(level, String.format(log, objects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String log, Object... objects) {
|
||||
Bukkit.getLogger().log(Level.INFO, String.format(log, objects));
|
||||
log(Level.INFO, String.format(log, objects));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -74,6 +76,18 @@ public class BukkitListener extends VPNExecutor implements Listener {
|
||||
|| AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream()
|
||||
.anyMatch(prefix -> event.getPlayer().getName().startsWith(prefix))) return;
|
||||
|
||||
|
||||
if(responseCache.asMap().containsKey(event.getPlayer().getUniqueId())) {
|
||||
VPNResponse cached = responseCache.getIfPresent(event.getPlayer().getUniqueId());
|
||||
|
||||
if (cached != null && cached.isProxy()) {
|
||||
event.setResult(PlayerLoginEvent.Result.KICK_BANNED);
|
||||
event.setKickMessage(org.bukkit.ChatColor.translateAlternateColorCodes('&',
|
||||
AntiVPN.getInstance().getVpnConfig().getKickString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final Player player = event.getPlayer();
|
||||
checkIp(event.getAddress().getHostAddress(),
|
||||
AntiVPN.getInstance().getVpnConfig().cachedResults(), result -> {
|
||||
@@ -81,9 +95,28 @@ public class BukkitListener extends VPNExecutor implements Listener {
|
||||
//We need to run on main thread or kicking and running commands will cause errors
|
||||
new BukkitRunnable() {
|
||||
public void run() {
|
||||
//If the player is whitelisted, we don't want to kick them
|
||||
if(AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId())) {
|
||||
log("UUID is whitelisted: %s",
|
||||
event.getPlayer().getUniqueId().toString());
|
||||
return;
|
||||
}
|
||||
{
|
||||
//If the IP is whitelisted, we don't want to kick them
|
||||
InetSocketAddress address = event.getPlayer().getAddress();
|
||||
if (address != null){
|
||||
InetAddress address1 = address.getAddress();
|
||||
if (address1 != null && AntiVPN.getInstance().getExecutor().isWhitelisted(address1.getHostAddress())) {
|
||||
log("IP is whitelisted: %s",
|
||||
address1.getHostAddress());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the countryList() size is zero, no need to check.
|
||||
// Running country check first
|
||||
if(AntiVPN.getInstance().getVpnConfig().countryList().size() > 0
|
||||
if(!AntiVPN.getInstance().getVpnConfig().countryList().isEmpty()
|
||||
// This bit of code will decide whether or not to kick the player
|
||||
// If it contains the code and it is set to whitelist, it will not kick as they are equal
|
||||
// and vise versa. However, if the contains does not match the state, it will kick.
|
||||
@@ -91,7 +124,7 @@ public class BukkitListener extends VPNExecutor implements Listener {
|
||||
.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) {
|
||||
if(AntiVPN.getInstance().getVpnConfig().countryKickCommands().isEmpty()) {
|
||||
final String kickReason = AntiVPN.getInstance().getVpnConfig()
|
||||
.countryVanillaKickReason();
|
||||
// Kicking our player
|
||||
@@ -116,7 +149,7 @@ public class BukkitListener extends VPNExecutor implements Listener {
|
||||
if(AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect())
|
||||
player.kickPlayer(org.bukkit.ChatColor.translateAlternateColorCodes('&',
|
||||
AntiVPN.getInstance().getVpnConfig().getKickString()));
|
||||
Bukkit.getLogger().info(event.getPlayer().getName()
|
||||
log(Level.INFO, event.getPlayer().getName()
|
||||
+ " joined on a VPN/Proxy (" + result.getMethod() + ")");
|
||||
|
||||
//Ensuring the user wishes to alert to staff
|
||||
@@ -143,12 +176,16 @@ public class BukkitListener extends VPNExecutor implements Listener {
|
||||
}
|
||||
}.runTask(BukkitPlugin.pluginInstance);
|
||||
} else {
|
||||
Bukkit.getLogger()
|
||||
.log(Level.WARNING,
|
||||
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++;
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event) {
|
||||
AntiVPN.getInstance().getPlayerExecutor().unloadPlayer(event.getPlayer().getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class BukkitPlayerExecutor implements PlayerExecutor {
|
||||
|
||||
private final Map<UUID, BukkitPlayer> cachedPlayers = new WeakHashMap<>();
|
||||
private final Map<UUID, BukkitPlayer> cachedPlayers = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Optional<APIPlayer> getPlayer(String name) {
|
||||
@@ -34,6 +34,11 @@ public class BukkitPlayerExecutor implements PlayerExecutor {
|
||||
return Optional.of(cachedPlayers.computeIfAbsent(player.getUniqueId(), k -> new BukkitPlayer(player)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadPlayer(UUID uuid) {
|
||||
cachedPlayers.remove(uuid);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<APIPlayer> getOnlinePlayers() {
|
||||
|
||||
@@ -3,7 +3,6 @@ package dev.brighten.antivpn.bukkit;
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.bukkit.command.BukkitCommand;
|
||||
import dev.brighten.antivpn.command.Command;
|
||||
import dev.brighten.antivpn.utils.ConfigDefault;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -71,15 +70,14 @@ public class BukkitPlugin extends JavaPlugin {
|
||||
commandMap.register(pluginInstance.getName(), newCommand);
|
||||
}
|
||||
|
||||
AntiVPN.getInstance().getMessageHandler().initStrings(vpnString -> new ConfigDefault<>
|
||||
(vpnString.getDefaultMessage(), "messages." + vpnString.getKey(), AntiVPN.getInstance())
|
||||
.get());
|
||||
//TODO Finish system before implementing on startup
|
||||
/*Bukkit.getLogger().info("Getting strings...");
|
||||
AntiVPN.getInstance().getMessageHandler().initStrings(vpnString -> new ConfigDefault<>
|
||||
(vpnString.getDefaultMessage(), "messages." + vpnString.getKey(), BukkitPlugin.pluginInstance)
|
||||
.get());
|
||||
AntiVPN.getInstance().getMessageHandler().reloadStrings();*/
|
||||
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.brighten.antivpn.bukkit.command;
|
||||
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.bukkit.BukkitCommandExecutor;
|
||||
import dev.brighten.antivpn.command.Command;
|
||||
import lombok.val;
|
||||
@@ -41,7 +42,8 @@ public class BukkitCommand extends org.bukkit.command.Command {
|
||||
public boolean execute(CommandSender sender, String s, String[] args) {
|
||||
if(!sender.hasPermission("antivpn.command.*")
|
||||
&& !sender.hasPermission(command.permission())) {
|
||||
sender.sendMessage(ChatColor.RED + "No permission.");
|
||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&',
|
||||
AntiVPN.getInstance().getMessageHandler().getString("no-permission").getMessage()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -53,7 +55,8 @@ public class BukkitCommand extends org.bukkit.command.Command {
|
||||
.anyMatch(alias -> alias.equalsIgnoreCase(args[0]))) {
|
||||
if(!sender.hasPermission("antivpn.command.*")
|
||||
&& !sender.hasPermission(child.permission())) {
|
||||
sender.sendMessage(ChatColor.RED + "No permission.");
|
||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&',
|
||||
AntiVPN.getInstance().getMessageHandler().getString("no-permission").getMessage()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.7.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>Bungee</artifactId>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
<compilerArgument>-XDignore.symbol.file</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.bungee.org.bstats</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>Common</artifactId>
|
||||
<version>1.7.1</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>toml4j</artifactId>
|
||||
<groupId>com.moandjiezana.toml</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<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>
|
||||
<groupId>org.github.bungee</groupId>
|
||||
<artifactId>BungeeCord-1.8</artifactId>
|
||||
<version>1.8</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cc.funkemunky.utils</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
</properties>
|
||||
</project>
|
||||
|
||||
+10
-2
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.7.1</version>
|
||||
<version>1.9.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -34,6 +34,14 @@
|
||||
<!-- Replace this with your package! -->
|
||||
<shadedPattern>dev.brighten.antivpn.bungee.org.bstats</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.yaml.snakeyaml</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.shaded.org.yaml.snakeyaml</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.google</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.shaded.com.google</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<executions>
|
||||
@@ -63,7 +71,7 @@
|
||||
<dependency>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>Common</artifactId>
|
||||
<version>1.7.1</version>
|
||||
<version>1.9.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
package dev.brighten.antivpn.bungee;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.api.APIPlayer;
|
||||
import dev.brighten.antivpn.api.VPNExecutor;
|
||||
import dev.brighten.antivpn.web.objects.VPNResponse;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.api.event.PreLoginEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@@ -18,18 +24,17 @@ public class BungeeListener extends VPNExecutor implements Listener {
|
||||
|
||||
private ScheduledTask cacheResetTask;
|
||||
|
||||
private final Cache<UUID, VPNResponse> responseCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.maximumSize(2000)
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
BungeePlugin.pluginInstance.getProxy().getPluginManager()
|
||||
.registerListener(BungeePlugin.pluginInstance, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runCacheReset() {
|
||||
cacheResetTask = BungeePlugin.pluginInstance.getProxy().getScheduler().schedule(BungeePlugin.pluginInstance,
|
||||
this::resetCache, 20, 20, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if(cacheResetTask != null) {
|
||||
@@ -41,25 +46,58 @@ public class BungeeListener extends VPNExecutor implements Listener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String log, Object... objects) {
|
||||
public void log(Level level, String log, Object... objects) {
|
||||
BungeeCord.getInstance().getLogger().log(Level.INFO, String.format(log, objects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String log, Object... objects) {
|
||||
log(Level.INFO, String.format(log, objects));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onListener(final PreLoginEvent event) {
|
||||
if(!responseCache.asMap().containsKey(event.getConnection().getUniqueId())) return;
|
||||
|
||||
VPNResponse cached = responseCache.getIfPresent(event.getConnection().getUniqueId());
|
||||
|
||||
if(cached != null && cached.isProxy()) {
|
||||
event.setCancelled(true);
|
||||
event.setCancelReason(TextComponent.fromLegacyText(ChatColor
|
||||
.translateAlternateColorCodes('&',
|
||||
AntiVPN.getInstance().getVpnConfig().getKickString())));
|
||||
AntiVPN.getInstance().getExecutor().log(Level.INFO,
|
||||
"%s was kicked from pre-login proxy cache.",
|
||||
event.getConnection().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onListener(final PostLoginEvent event) {
|
||||
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.getPlayer().getAddress().getAddress()
|
||||
.getHostAddress())
|
||||
|| AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream()
|
||||
.anyMatch(prefix -> event.getPlayer().getName().startsWith(prefix))) return;
|
||||
|
||||
checkIp(event.getPlayer().getAddress().getAddress().getHostAddress(),
|
||||
AntiVPN.getInstance().getVpnConfig().cachedResults(), result -> {
|
||||
if(result.isSuccess()) {
|
||||
// If the countryList() size is zero, no need to check.
|
||||
// Running country check first
|
||||
//If the player is whitelisted, we don't want to kick them
|
||||
if(AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId())) {
|
||||
AntiVPN.getInstance().getExecutor().log("UUID is whitelisted: %s",
|
||||
event.getPlayer().getUniqueId().toString());
|
||||
return;
|
||||
}
|
||||
|
||||
//If the IP is whitelisted, we don't want to kick them
|
||||
if(AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getAddress().getAddress()
|
||||
.getHostAddress())) {
|
||||
AntiVPN.getInstance().getExecutor().log("IP is whitelisted: %s",
|
||||
event.getPlayer().getAddress().getAddress().getHostAddress());
|
||||
return;
|
||||
}
|
||||
|
||||
responseCache.put(event.getPlayer().getUniqueId(), result);
|
||||
|
||||
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
|
||||
@@ -127,4 +165,9 @@ public class BungeeListener extends VPNExecutor implements Listener {
|
||||
AntiVPN.getInstance().checked++;
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onLeave(PlayerDisconnectEvent event) {
|
||||
AntiVPN.getInstance().getPlayerExecutor().unloadPlayer(event.getPlayer().getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class BungeePlayerExecutor implements PlayerExecutor {
|
||||
|
||||
private final Map<ProxiedPlayer, BungeePlayer> cachedPlayers = new WeakHashMap<>();
|
||||
private final Map<UUID, BungeePlayer> cachedPlayers = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Optional<APIPlayer> getPlayer(String name) {
|
||||
@@ -18,7 +18,7 @@ public class BungeePlayerExecutor implements PlayerExecutor {
|
||||
|
||||
if(player == null) return Optional.empty();
|
||||
|
||||
return Optional.of(cachedPlayers.computeIfAbsent(player, BungeePlayer::new));
|
||||
return Optional.of(cachedPlayers.computeIfAbsent(player.getUniqueId(), key -> new BungeePlayer(player)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -27,13 +27,18 @@ public class BungeePlayerExecutor implements PlayerExecutor {
|
||||
|
||||
if(player == null) return Optional.empty();
|
||||
|
||||
return Optional.of(cachedPlayers.computeIfAbsent(player, BungeePlayer::new));
|
||||
return Optional.of(cachedPlayers.computeIfAbsent(uuid, key -> new BungeePlayer(player)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadPlayer(UUID uuid) {
|
||||
this.cachedPlayers.remove(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<APIPlayer> getOnlinePlayers() {
|
||||
return BungeeCord.getInstance().getPlayers().stream()
|
||||
.map(pl -> cachedPlayers.computeIfAbsent(pl, BungeePlayer::new))
|
||||
.map(pl -> cachedPlayers.computeIfAbsent(pl.getUniqueId(), key -> new BungeePlayer(pl)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package dev.brighten.antivpn.bungee;
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.bungee.command.BungeeCommand;
|
||||
import dev.brighten.antivpn.command.Command;
|
||||
import dev.brighten.antivpn.utils.ConfigDefault;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import org.bstats.bungeecord.Metrics;
|
||||
@@ -44,17 +43,6 @@ public class BungeePlugin extends Plugin {
|
||||
for (Command command : AntiVPN.getInstance().getCommands()) {
|
||||
BungeeCord.getInstance().getPluginManager().registerCommand(pluginInstance, new BungeeCommand(command));
|
||||
}
|
||||
|
||||
BungeeCord.getInstance().getLogger().info("Getting strings...");
|
||||
AntiVPN.getInstance().getMessageHandler().initStrings(vpnString -> new ConfigDefault<>
|
||||
(vpnString.getDefaultMessage(), "messages." + vpnString.getKey(), AntiVPN.getInstance())
|
||||
.get());
|
||||
//TODO Finish system before implementing on startup
|
||||
/*BungeeCord.getInstance().getLogger().info("Getting strings...");
|
||||
AntiVPN.getInstance().getMessageHandler().initStrings(vpnString -> new ConfigDefault<>
|
||||
(vpnString.getDefaultMessage(), "messages." + vpnString.getKey(), BungeePlugin.pluginInstance)
|
||||
.get());
|
||||
AntiVPN.getInstance().getMessageHandler().reloadStrings();*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package dev.brighten.antivpn.bungee.command;
|
||||
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import lombok.val;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.api.plugin.TabExecutor;
|
||||
@@ -14,9 +13,6 @@ import java.util.stream.IntStream;
|
||||
|
||||
public class BungeeCommand extends Command implements TabExecutor {
|
||||
|
||||
private static final BaseComponent[] noPermission = new ComponentBuilder("No permission").color(ChatColor.RED)
|
||||
.create();
|
||||
|
||||
private final dev.brighten.antivpn.command.Command command;
|
||||
public BungeeCommand(dev.brighten.antivpn.command.Command command) {
|
||||
super(command.name(), command.permission(), command.aliases());
|
||||
@@ -28,7 +24,8 @@ public class BungeeCommand extends Command implements TabExecutor {
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if(!sender.hasPermission("antivpn.command.*")
|
||||
&& !sender.hasPermission(command.permission())) {
|
||||
sender.sendMessage(noPermission);
|
||||
sender.sendMessage(TextComponent.fromLegacyText(ChatColor.translateAlternateColorCodes('&',
|
||||
AntiVPN.getInstance().getMessageHandler().getString("no-permission").getMessage())));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -40,7 +37,8 @@ public class BungeeCommand extends Command implements TabExecutor {
|
||||
.anyMatch(alias -> alias.equalsIgnoreCase(args[0]))) {
|
||||
if(!sender.hasPermission("antivpn.command.*")
|
||||
&& !sender.hasPermission(child.permission())) {
|
||||
sender.sendMessage(noPermission);
|
||||
sender.sendMessage(TextComponent.fromLegacyText(ChatColor.translateAlternateColorCodes('&',
|
||||
AntiVPN.getInstance().getMessageHandler().getString("no-permission").getMessage())));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ public class BungeeCommandExecutor implements CommandExecutor {
|
||||
private final CommandSender sender;
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
public void sendMessage(String message, Object... objects) {
|
||||
sender.sendMessage(TextComponent.fromLegacyText(ChatColor
|
||||
.translateAlternateColorCodes('&', message)));
|
||||
.translateAlternateColorCodes('&', String.format(message, objects))));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+41
-16
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.7.1</version>
|
||||
<version>1.9.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -28,6 +28,32 @@
|
||||
<compilerArgument>-XDignore.symbol.file</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.yaml.snakeyaml</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.shaded.org.yaml.snakeyaml</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.google.common</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.shaded.com.google.common</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
@@ -46,35 +72,34 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.moandjiezana.toml</groupId>
|
||||
<artifactId>toml4j</artifactId>
|
||||
<version>0.7.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.27</version>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>8.2.0</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>2.1.210</version>
|
||||
<scope>compile</scope>
|
||||
<version>2.2.224</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>1.30</version>
|
||||
<version>2.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>32.1.3-jre</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<version>3.12.10</version>
|
||||
<scope>compile</scope>
|
||||
<version>3.12.14</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -6,17 +6,17 @@ 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.local.H2VPN;
|
||||
import dev.brighten.antivpn.database.mongo.MongoVPN;
|
||||
import dev.brighten.antivpn.database.sql.MySqlVPN;
|
||||
import dev.brighten.antivpn.depends.LibraryLoader;
|
||||
import dev.brighten.antivpn.depends.MavenLibrary;
|
||||
import dev.brighten.antivpn.message.MessageHandler;
|
||||
import dev.brighten.antivpn.utils.ConfigDefault;
|
||||
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;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -31,6 +31,9 @@ import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter(AccessLevel.PRIVATE)
|
||||
@MavenLibrary(groupId = "com.h2database", artifactId ="h2", version = "2.2.224")
|
||||
@MavenLibrary(groupId = "org.mongodb", artifactId = "mongo-java-driver", version = "3.12.14")
|
||||
@MavenLibrary(groupId = "com.mysql", artifactId = "mysql-connector-j", version = "8.2.0")
|
||||
public class AntiVPN {
|
||||
|
||||
private static AntiVPN INSTANCE;
|
||||
@@ -52,6 +55,9 @@ public class AntiVPN {
|
||||
INSTANCE.pluginFolder = pluginFolder;
|
||||
INSTANCE.executor = executor;
|
||||
INSTANCE.playerExecutor = playerExecutor;
|
||||
|
||||
LibraryLoader.loadAll(INSTANCE);
|
||||
|
||||
try {
|
||||
File configFile = new File(pluginFolder, "config.yml");
|
||||
if(!configFile.exists()){
|
||||
@@ -72,8 +78,15 @@ public class AntiVPN {
|
||||
INSTANCE.messageHandler = new MessageHandler();
|
||||
|
||||
switch(INSTANCE.vpnConfig.getDatabaseType().toLowerCase()) {
|
||||
case "mysql":
|
||||
case "h2":
|
||||
case "local":
|
||||
case "flatfile": {
|
||||
AntiVPN.getInstance().getExecutor().log("Using databaseType H2...");
|
||||
INSTANCE.database = new H2VPN();
|
||||
INSTANCE.database.init();
|
||||
break;
|
||||
}
|
||||
case "mysql":
|
||||
case "sql":{
|
||||
AntiVPN.getInstance().getExecutor().log("Using databaseType MySQL...");
|
||||
INSTANCE.database = new MySqlVPN();
|
||||
@@ -106,6 +119,11 @@ public class AntiVPN {
|
||||
INSTANCE.database.alertsState(player.getUuid(), player::setAlertsEnabled);
|
||||
}
|
||||
});
|
||||
|
||||
AntiVPN.getInstance().getMessageHandler().initStrings(vpnString -> new ConfigDefault<>
|
||||
(vpnString.getDefaultMessage(), "messages." + vpnString.getKey(), AntiVPN.getInstance())
|
||||
.get());
|
||||
AntiVPN.getInstance().getMessageHandler().reloadStrings();
|
||||
}
|
||||
|
||||
public InputStream getResource(String filename) {
|
||||
@@ -132,6 +150,40 @@ public class AntiVPN {
|
||||
if(database != null) database.shutdown();
|
||||
}
|
||||
|
||||
public void reloadDatabase() {
|
||||
database.shutdown();
|
||||
|
||||
switch(AntiVPN.getInstance().getVpnConfig().getDatabaseType().toLowerCase()) {
|
||||
case "h2":
|
||||
case "local":
|
||||
case "flatfile": {
|
||||
AntiVPN.getInstance().getExecutor().log("Using databaseType H2...");
|
||||
INSTANCE.database = new H2VPN();
|
||||
INSTANCE.database.init();
|
||||
break;
|
||||
}
|
||||
case "mysql":
|
||||
case "sql":{
|
||||
AntiVPN.getInstance().getExecutor().log("Using databaseType MySQL...");
|
||||
INSTANCE.database = new MySqlVPN();
|
||||
INSTANCE.database.init();
|
||||
break;
|
||||
}
|
||||
case "mongo":
|
||||
case "mongodb":
|
||||
case "mongod": {
|
||||
INSTANCE.database = new MongoVPN();
|
||||
INSTANCE.database.init();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
AntiVPN.getInstance().getExecutor().log("Could not find database type \"" + INSTANCE.vpnConfig.getDatabaseType() + "\". " +
|
||||
"Options: [MySQL]");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static AntiVPN getInstance() {
|
||||
assert INSTANCE != null: "AntiVPN has not been initialized!";
|
||||
|
||||
@@ -147,13 +199,14 @@ public class AntiVPN {
|
||||
}
|
||||
}
|
||||
|
||||
public static VPNResponse getVPNResponse(String ip, String license, boolean cachedResults /* faster if set to true*/)
|
||||
throws JSONException, IOException {
|
||||
JSONObject result = JsonReader.readJsonFromUrl(String
|
||||
.format("https://funkemunky.cc/vpn?ip=%s&license=%s&cache=%s",
|
||||
ip, license.length() == 0 ? "none" : license, cachedResults));
|
||||
public void reloadConfig() {
|
||||
try {
|
||||
|
||||
return VPNResponse.fromJson(result);
|
||||
config = ConfigurationProvider.getProvider(YamlConfiguration.class)
|
||||
.load(new File(pluginFolder.getPath() + File.separator + "config.yml"));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerCommands() {
|
||||
|
||||
@@ -10,5 +10,7 @@ public interface PlayerExecutor {
|
||||
|
||||
Optional<APIPlayer> getPlayer(UUID uuid);
|
||||
|
||||
void unloadPlayer(UUID uuid);
|
||||
|
||||
List<APIPlayer> getOnlinePlayers();
|
||||
}
|
||||
|
||||
@@ -1,101 +1,94 @@
|
||||
package dev.brighten.antivpn.api;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.utils.EvictingMap;
|
||||
import dev.brighten.antivpn.utils.VPNResponse;
|
||||
import dev.brighten.antivpn.utils.json.JSONException;
|
||||
import dev.brighten.antivpn.web.FunkemunkyAPI;
|
||||
import dev.brighten.antivpn.web.objects.VPNResponse;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public abstract class VPNExecutor {
|
||||
public static ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
|
||||
public static ScheduledExecutorService threadExecutor = Executors.newScheduledThreadPool(2);
|
||||
|
||||
public static final Map<String, VPNResponse> responseCache = new EvictingMap<>(5000);
|
||||
@Getter
|
||||
private final Set<UUID> whitelisted = Collections.synchronizedSet(new HashSet<>());
|
||||
@Getter
|
||||
private final Set<String> whitelistedIps = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
private final Cache<String, VPNResponse> responseCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(20, TimeUnit.MINUTES)
|
||||
.maximumSize(4000)
|
||||
.build();
|
||||
|
||||
public abstract void registerListeners();
|
||||
|
||||
public abstract void runCacheReset();
|
||||
|
||||
public void resetCache() {
|
||||
responseCache.clear();
|
||||
}
|
||||
|
||||
public abstract void shutdown();
|
||||
|
||||
public abstract void log(Level level, String log, Object... objects);
|
||||
|
||||
public abstract void log(String log, Object... objects);
|
||||
|
||||
public boolean isWhitelisted(UUID uuid) {
|
||||
if(AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()) {
|
||||
return AntiVPN.getInstance().getDatabase().isWhitelisted(uuid);
|
||||
}
|
||||
return whitelisted.contains(uuid);
|
||||
}
|
||||
|
||||
public boolean isWhitelisted(String ip) {
|
||||
if(AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()) {
|
||||
return AntiVPN.getInstance().getDatabase().isWhitelisted(ip);
|
||||
}
|
||||
return whitelistedIps.contains(ip);
|
||||
}
|
||||
|
||||
public void checkIp(String ip, boolean cachedResults, Consumer<VPNResponse> result) {
|
||||
threadExecutor.execute(() -> result.accept(responseCache.compute(ip, (key, val) -> {
|
||||
if(val == null) {
|
||||
Optional<VPNResponse> cachedRes = AntiVPN.getInstance().getDatabase().getStoredResponse(ip);
|
||||
|
||||
if(cachedRes.isPresent()) return cachedRes.get();
|
||||
else {
|
||||
try {
|
||||
VPNResponse response = AntiVPN
|
||||
.getVPNResponse(ip, AntiVPN.getInstance().getVpnConfig().getLicense(), cachedResults);
|
||||
|
||||
if(response.isSuccess()) {
|
||||
AntiVPN.getInstance().getDatabase().cacheResponse(response);
|
||||
} else {
|
||||
log("Query to VPN API failed! Reason: " + response.getFailureReason());
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (JSONException | IOException e) {
|
||||
log("Query to VPN API failed! Reason: Java Exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
threadExecutor.execute(() -> {
|
||||
if(cachedResults) {
|
||||
try {
|
||||
result.accept(responseCache.get(ip, () -> checkIp(ip)));
|
||||
} catch (ExecutionException e) {
|
||||
log("Failed to process checkIp() method! Reason: " + e.getMessage());
|
||||
result.accept(VPNResponse.FAILED_RESPONSE);
|
||||
}
|
||||
} else {
|
||||
result.accept(checkIp(ip));
|
||||
}
|
||||
|
||||
return val;
|
||||
})));
|
||||
}
|
||||
|
||||
public VPNResponse checkIp(String ip, boolean cachedResults) {
|
||||
return responseCache.compute(ip, (key, val) -> {
|
||||
if(val == null) {
|
||||
Optional<VPNResponse> cachedRes = AntiVPN.getInstance().getDatabase().getStoredResponse(ip);
|
||||
|
||||
if(cachedRes.isPresent()) return cachedRes.get();
|
||||
else {
|
||||
try {
|
||||
VPNResponse response = AntiVPN
|
||||
.getVPNResponse(ip, AntiVPN.getInstance().getVpnConfig().getLicense(), cachedResults);
|
||||
|
||||
if(response.isSuccess()) {
|
||||
threadExecutor.execute(() -> AntiVPN.getInstance().getDatabase().cacheResponse(response));
|
||||
} else {
|
||||
log("Query to VPN API failed! Reason: " + response.getFailureReason());
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (JSONException | IOException e) {
|
||||
log("Query to VPN API failed! Reason: Java Exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
});
|
||||
}
|
||||
|
||||
public VPNResponse checkIp(String ip) {
|
||||
Optional<VPNResponse> cachedRes = AntiVPN.getInstance().getDatabase().getStoredResponse(ip);
|
||||
|
||||
if(cachedRes.isPresent()) {
|
||||
return cachedRes.get();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
VPNResponse response = FunkemunkyAPI
|
||||
.getVPNResponse(ip, AntiVPN.getInstance().getVpnConfig().getLicense(), true);
|
||||
|
||||
if (response.isSuccess()) {
|
||||
AntiVPN.getInstance().getDatabase().cacheResponse(response);
|
||||
} else {
|
||||
log("Query to VPN API failed! Reason: " + response.getFailureReason());
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (JSONException | IOException e) {
|
||||
log("Query to VPN API failed! Reason: " + e.getMessage());
|
||||
return VPNResponse.FAILED_RESPONSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.util.Optional;
|
||||
|
||||
public interface CommandExecutor {
|
||||
|
||||
void sendMessage(String message);
|
||||
void sendMessage(String message, Object... objects);
|
||||
boolean hasPermission(String permission);
|
||||
Optional<APIPlayer> getPlayer();
|
||||
boolean isPlayer();
|
||||
|
||||
@@ -45,7 +45,7 @@ public class AntiVPNCommand extends Command {
|
||||
@Override
|
||||
public Command[] children() {
|
||||
return new Command[] {new LookupCommand(), new AllowlistCommand(), new AlertsCommand(),
|
||||
new ClearCacheCommand()};
|
||||
new ClearCacheCommand(), new PlanCommand(), new ReloadCommand()};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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;
|
||||
|
||||
@@ -47,7 +46,6 @@ public class ClearCacheCommand extends Command {
|
||||
@Override
|
||||
public String execute(CommandExecutor executor, String[] args) {
|
||||
AntiVPN.getInstance().getDatabase().clearResponses();
|
||||
VPNExecutor.responseCache.clear();
|
||||
return "&aCleared all cached API response information!";
|
||||
}
|
||||
|
||||
|
||||
@@ -67,13 +67,13 @@ public class LookupCommand extends Command {
|
||||
executor.sendMessage(StringUtil.line("&8"));
|
||||
executor.sendMessage("&6&l" + player.get().getName() + "&7&l's Connection Information");
|
||||
executor.sendMessage("");
|
||||
executor.sendMessage(String.format("&e%s&8: &f%s", "Proxy", result.isProxy()
|
||||
? "&a" + result.getMethod() : "&cNo"));
|
||||
executor.sendMessage(String.format("&e%s&8: &f%s", "ISP", result.getIsp()));
|
||||
executor.sendMessage(String.format("&e%s&8: &f%s", "Country", result.getCountryName()));
|
||||
executor.sendMessage(String.format("&e%s&8: &f%s", "City", result.getCity()));
|
||||
executor.sendMessage(String.format("&e%s&8: &f%s", "Coordinates", result.getLatitude()
|
||||
+ "&7/&f" + result.getLongitude()));
|
||||
executor.sendMessage("&e%s&8: &f%s", "Proxy", result.isProxy()
|
||||
? "&a" + result.getMethod() : "&cNo");
|
||||
executor.sendMessage("&e%s&8: &f%s", "ISP", result.getIsp());
|
||||
executor.sendMessage("&e%s&8: &f%s", "Country", result.getCountryName());
|
||||
executor.sendMessage("&e%s&8: &f%s", "City", result.getCity());
|
||||
executor.sendMessage("&e%s&8: &f%s", "Coordinates", result.getLatitude()
|
||||
+ "&7/&f" + result.getLongitude());
|
||||
executor.sendMessage(StringUtil.line("&8"));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
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 dev.brighten.antivpn.utils.StringUtil;
|
||||
import dev.brighten.antivpn.utils.json.JSONException;
|
||||
import dev.brighten.antivpn.web.FunkemunkyAPI;
|
||||
import dev.brighten.antivpn.web.objects.QueryResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class PlanCommand extends Command {
|
||||
@Override
|
||||
public String permission() {
|
||||
return "antivpn.command.plan";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "plan";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] aliases() {
|
||||
return new String[] {"queries", "query"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Info related to KauriVPN Plan";
|
||||
}
|
||||
|
||||
@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) {
|
||||
VPNExecutor.threadExecutor.execute(() -> {
|
||||
QueryResponse result;
|
||||
try {
|
||||
if(AntiVPN.getInstance().getVpnConfig().getLicense().equals("")) {
|
||||
result = FunkemunkyAPI.getQueryResponse();
|
||||
} else {
|
||||
result = FunkemunkyAPI.getQueryResponse(AntiVPN.getInstance().getVpnConfig().getLicense());
|
||||
|
||||
if(!result.isValidPlan()) {
|
||||
executor.sendMessage("&cThe license &f%s &cis not a valid license, " +
|
||||
"checking your Free plan information...",
|
||||
AntiVPN.getInstance().getVpnConfig().getLicense());
|
||||
|
||||
result = FunkemunkyAPI.getQueryResponse();
|
||||
}
|
||||
}
|
||||
|
||||
String plan = result.getPlanType();
|
||||
if(plan.equals("IP")) plan+= " (Free)";
|
||||
|
||||
String queryMax = result.getQueriesMax() == Long.MAX_VALUE
|
||||
? "Unlimited" : String.valueOf(result.getQueriesMax());
|
||||
|
||||
executor.sendMessage(StringUtil.line("&8"));
|
||||
executor.sendMessage("&6&lKauriVPN Plan Information");
|
||||
executor.sendMessage("");
|
||||
executor.sendMessage("&e%s&8: &f%s", "Plan", plan);
|
||||
executor.sendMessage("&e%s&8: &f%s&7/&f%s", "Queries Used",
|
||||
result.getQueries(), queryMax);
|
||||
executor.sendMessage(StringUtil.line("&8"));
|
||||
} catch(JSONException e) {
|
||||
e.printStackTrace();
|
||||
executor.sendMessage("&cThere was a JSONException thrown while looking up your query " +
|
||||
"information. Check console for more details.");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
executor.sendMessage("&cThere was a IOException thrown while looking up your query " +
|
||||
"information. Check console for more details.");
|
||||
}
|
||||
});
|
||||
return "&7Looking up your query information...";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> tabComplete(CommandExecutor executor, String alias, String[] args) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package dev.brighten.antivpn.command.impl;
|
||||
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.command.Command;
|
||||
import dev.brighten.antivpn.command.CommandExecutor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ReloadCommand extends Command {
|
||||
@Override
|
||||
public String permission() {
|
||||
return "antivpn.command.reload";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "reload";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] aliases() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Reload the plugin";
|
||||
}
|
||||
|
||||
@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) {
|
||||
// Loading changes from the config.yml
|
||||
AntiVPN.getInstance().reloadConfig();
|
||||
|
||||
// Updating the cache of these values in VPNConfig
|
||||
AntiVPN.getInstance().getVpnConfig().update();
|
||||
|
||||
AntiVPN.getInstance().getMessageHandler().reloadStrings();
|
||||
|
||||
AntiVPN.getInstance().reloadDatabase();
|
||||
|
||||
return AntiVPN.getInstance().getMessageHandler().getString("command-reload-complete").getMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> tabComplete(CommandExecutor executor, String alias, String[] args) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package dev.brighten.antivpn.database;
|
||||
|
||||
import dev.brighten.antivpn.utils.VPNResponse;
|
||||
import dev.brighten.antivpn.web.objects.VPNResponse;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -12,6 +12,8 @@ public interface VPNDatabase {
|
||||
|
||||
void cacheResponse(VPNResponse toCache);
|
||||
|
||||
void deleteResponse(String ip);
|
||||
|
||||
boolean isWhitelisted(UUID uuid);
|
||||
|
||||
boolean isWhitelisted(String ip);
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
package dev.brighten.antivpn.database.local;
|
||||
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.api.VPNExecutor;
|
||||
import dev.brighten.antivpn.database.VPNDatabase;
|
||||
import dev.brighten.antivpn.database.sql.utils.MySQL;
|
||||
import dev.brighten.antivpn.database.sql.utils.Query;
|
||||
import dev.brighten.antivpn.web.objects.VPNResponse;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class H2VPN implements VPNDatabase {
|
||||
|
||||
public H2VPN() {
|
||||
VPNExecutor.threadExecutor.scheduleAtFixedRate(() -> {
|
||||
if(!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed()) return;
|
||||
|
||||
//Refreshing whitelisted players
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted().clear();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted()
|
||||
.addAll(AntiVPN.getInstance().getDatabase().getAllWhitelisted());
|
||||
|
||||
//Refreshing whitlisted IPs
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps().clear();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps()
|
||||
.addAll(AntiVPN.getInstance().getDatabase().getAllWhitelistedIps());
|
||||
}, 2, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VPNResponse> getStoredResponse(String ip) {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()|| MySQL.isClosed())
|
||||
return Optional.empty();
|
||||
|
||||
ResultSet rs = Query.prepare("select * from `responses` where `ip` = ? limit 1").append(ip).executeQuery();
|
||||
|
||||
try {
|
||||
if (rs != null && rs.next()) {
|
||||
VPNResponse response = new VPNResponse(rs.getString("asn"), rs.getString("ip"),
|
||||
rs.getString("countryName"), rs.getString("countryCode"),
|
||||
rs.getString("city"), rs.getString("timeZone"),
|
||||
rs.getString("method"), rs.getString("isp"), "N/A",
|
||||
rs.getBoolean("proxy"), rs.getBoolean("cached"), true,
|
||||
rs.getDouble("latitude"), rs.getDouble("longitude"),
|
||||
rs.getTimestamp("inserted").getTime(), -1);
|
||||
|
||||
if(System.currentTimeMillis() - response.getLastAccess() > TimeUnit.HOURS.toMillis(1)) {
|
||||
VPNExecutor.threadExecutor.execute(() -> deleteResponse(ip));
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(response);
|
||||
}
|
||||
} catch (SQLException throwables) {
|
||||
throwables.printStackTrace();
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/*
|
||||
* Query.
|
||||
* prepare("create table if not exists `responses` (`ip` varchar(45) not null, "
|
||||
* +
|
||||
* "`countryName` varchar(64), `countryCode` varchar(10), `city` varchar(64), `timeZone` varchar(64), "
|
||||
* +
|
||||
* "`method` varchar(32), `isp` varchar(32), `proxy` boolean, `cached` boolean "
|
||||
* + "`latitude` double, `longitude` double)");
|
||||
*/
|
||||
@Override
|
||||
public void cacheResponse(VPNResponse toCache) {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
|
||||
return;
|
||||
|
||||
Query.prepare("insert into `responses` (`ip`,`asn`,`countryName`,`countryCode`,`city`,`timeZone`,"
|
||||
+ "`method`,`isp`,`proxy`,`cached`,`inserted`,`latitude`,`longitude`) values (?,?,?,?,?,?,?,?,?,?,?,?,?)")
|
||||
.append(toCache.getIp()).append(toCache.getAsn()).append(toCache.getCountryName())
|
||||
.append(toCache.getCountryCode()).append(toCache.getCity()).append(toCache.getTimeZone())
|
||||
.append(toCache.getMethod()).append(toCache.getIsp()).append(toCache.isProxy())
|
||||
.append(toCache.isCached()).append(new Timestamp(System.currentTimeMillis()))
|
||||
.append(toCache.getLatitude()).append(toCache.getLongitude()).execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteResponse(String ip) {
|
||||
if(!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
|
||||
return;
|
||||
|
||||
Query.prepare("delete from `responses` where `ip` = ?").append(ip).execute();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean isWhitelisted(UUID uuid) {
|
||||
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();
|
||||
|
||||
return set != null && set.next() && set.getString("uuid") != null;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean isWhitelisted(String ip) {
|
||||
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();
|
||||
|
||||
|
||||
return set != null && set.next() && set.getString("ip") != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWhitelisted(UUID uuid, boolean whitelisted) {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
|
||||
return;
|
||||
|
||||
if (whitelisted) {
|
||||
if (!isWhitelisted(uuid)) {
|
||||
Query.prepare("insert into `whitelisted` (`uuid`) values (?)").append(uuid.toString()).execute();
|
||||
}
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted().add(uuid);
|
||||
} else {
|
||||
Query.prepare("delete from `whitelisted` where `uuid` = ?").append(uuid.toString()).execute();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted().remove(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWhitelisted(String ip, boolean whitelisted) {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
|
||||
return;
|
||||
|
||||
if(whitelisted) {
|
||||
if(!isWhitelisted(ip)) {
|
||||
Query.prepare("insert into `whitelisted-ips` (`ip`) values (?)").append(ip).execute();
|
||||
}
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps().add(ip);
|
||||
} else {
|
||||
Query.prepare("delete from `whitelisted-ips` where `ip` = ?").append(ip).execute();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps().remove(ip);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UUID> getAllWhitelisted() {
|
||||
List<UUID> uuids = new ArrayList<>();
|
||||
|
||||
if(!MySQL.isClosed()) Query.prepare("select uuid from `whitelisted`")
|
||||
.execute(set -> uuids.add(UUID.fromString(set.getString("uuid"))));
|
||||
|
||||
return uuids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAllWhitelistedIps() {
|
||||
List<String> ips = new ArrayList<>();
|
||||
|
||||
if(!MySQL.isClosed()) Query.prepare("select `ip` from `whitelisted-ips`")
|
||||
.execute(set -> ips.add(set.getString("ip")));
|
||||
|
||||
return ips;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getStoredResponseAsync(String ip, Consumer<Optional<VPNResponse>> result) {
|
||||
if(MySQL.isClosed()) return;
|
||||
|
||||
VPNExecutor.threadExecutor.execute(() -> result.accept(getStoredResponse(ip)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isWhitelistedAsync(UUID uuid, Consumer<Boolean> result) {
|
||||
if(MySQL.isClosed()) return;
|
||||
|
||||
VPNExecutor.threadExecutor.execute(() -> result.accept(isWhitelisted(uuid)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isWhitelistedAsync(String ip, Consumer<Boolean> result) {
|
||||
if(MySQL.isClosed()) return;
|
||||
|
||||
VPNExecutor.threadExecutor.execute(() -> result.accept(isWhitelisted(ip)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alertsState(UUID uuid, Consumer<Boolean> result) {
|
||||
if(MySQL.isClosed()) return;
|
||||
|
||||
VPNExecutor.threadExecutor.execute(() -> {
|
||||
ResultSet set = Query.prepare("select * from `alerts` where `uuid` = ? limit 1")
|
||||
.append(uuid.toString()).executeQuery();
|
||||
|
||||
try {
|
||||
result.accept(set != null && set.next() && set.getString("uuid") != null);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
result.accept(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAlertsState(UUID uuid, boolean enabled) {
|
||||
if(MySQL.isClosed()) return;
|
||||
|
||||
if(enabled) {
|
||||
//We want to make sure there isn't already a uuid inserted to prevent double insertions
|
||||
alertsState(uuid, alreadyEnabled -> { //No need to make another thread execute, already async
|
||||
if(!alreadyEnabled) {
|
||||
Query.prepare("insert into `alerts` (`uuid`) values (?)").append(uuid.toString())
|
||||
.execute();
|
||||
} //No need to insert again of already enabled
|
||||
});
|
||||
//Removing any uuid from the alerts table will disable alerts globally.
|
||||
} else VPNExecutor.threadExecutor.execute(() ->
|
||||
Query.prepare("delete from `alerts` where `uuid` = ?")
|
||||
.append(uuid.toString())
|
||||
.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().getVpnConfig().isDatabaseEnabled())
|
||||
return;
|
||||
AntiVPN.getInstance().getExecutor().log("Initializing H2...");
|
||||
MySQL.initH2();
|
||||
|
||||
AntiVPN.getInstance().getExecutor().log("Creating tables...");
|
||||
|
||||
//Running check for old table types to update
|
||||
|
||||
Query.prepare("create table if not exists `whitelisted` (`uuid` varchar(36) not null)").execute();
|
||||
Query.prepare("create table if not exists `whitelisted-ips` (`ip` varchar(45) not null)").execute();
|
||||
Query.prepare("create table if not exists `responses` (`ip` varchar(45) not null, `asn` varchar(12),"
|
||||
+ "`countryName` text, `countryCode` varchar(10), `city` text, `timeZone` varchar(64), "
|
||||
+ "`method` varchar(32), `isp` text, `proxy` boolean, `cached` boolean, `inserted` timestamp,"
|
||||
+ "`latitude` double, `longitude` double)").execute();
|
||||
Query.prepare("create table if not exists `alerts` (`uuid` varchar(36) not null)").execute();
|
||||
|
||||
AntiVPN.getInstance().getExecutor().log("Creating indexes...");
|
||||
try {
|
||||
Query.prepare("create index if not exists `uuid_1` on `whitelisted` (`uuid`)").execute();
|
||||
Query.prepare("create index if not exists `ip_1` on `responses` (`ip`)").execute();
|
||||
Query.prepare("create index if not exists `proxy_1` on `responses` (`proxy`)").execute();
|
||||
Query.prepare("create index if not exists `inserted_1` on `responses` (`inserted`)").execute();
|
||||
Query.prepare("create index if not exists `ip_1` on `whitelisted-ips` (`ip`)").execute();
|
||||
} catch (Exception e) {
|
||||
System.err.println("MySQL Excepton created" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled())
|
||||
return;
|
||||
MySQL.shutdown();
|
||||
}
|
||||
}
|
||||
@@ -7,26 +7,50 @@ import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
import com.mongodb.client.model.Filters;
|
||||
import com.mongodb.client.model.Indexes;
|
||||
import com.mongodb.client.model.UpdateOptions;
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.api.VPNExecutor;
|
||||
import dev.brighten.antivpn.database.VPNDatabase;
|
||||
import dev.brighten.antivpn.utils.VPNResponse;
|
||||
import dev.brighten.antivpn.web.objects.VPNResponse;
|
||||
import org.bson.Document;
|
||||
import org.bson.conversions.Bson;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class MongoVPN implements VPNDatabase {
|
||||
|
||||
private MongoCollection<Document> settingsDocument, cacheDocument;
|
||||
private MongoClient client;
|
||||
private MongoDatabase antivpnDatabase;
|
||||
|
||||
public MongoVPN() {
|
||||
VPNExecutor.threadExecutor.scheduleAtFixedRate(() -> {
|
||||
if(!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()) return;
|
||||
|
||||
//Refreshing whitelisted players
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted().clear();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted()
|
||||
.addAll(AntiVPN.getInstance().getDatabase().getAllWhitelisted());
|
||||
|
||||
//Refreshing whitlisted IPs
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps().clear();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps()
|
||||
.addAll(AntiVPN.getInstance().getDatabase().getAllWhitelistedIps());
|
||||
}, 2, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
@Override
|
||||
public Optional<VPNResponse> getStoredResponse(String ip) {
|
||||
Document rdoc = cacheDocument.find(Filters.eq("ip", ip)).first();
|
||||
|
||||
if(rdoc != null) {
|
||||
long lastUpdate = rdoc.get("lastAccess", 0L);
|
||||
|
||||
if(System.currentTimeMillis() - lastUpdate > TimeUnit.HOURS.toMillis(1)) {
|
||||
VPNExecutor.threadExecutor.execute(() -> deleteResponse(ip));
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(VPNResponse.builder().asn(rdoc.getString("asn")).ip(ip)
|
||||
.countryName(rdoc.getString("countryName"))
|
||||
.countryCode(rdoc.getString("countryCode"))
|
||||
@@ -39,6 +63,7 @@ public class MongoVPN implements VPNDatabase {
|
||||
.success(true)
|
||||
.latitude(rdoc.getDouble("latitude"))
|
||||
.longitude(rdoc.getDouble("longitude"))
|
||||
.lastAccess(rdoc.get("lastAccess", 0L))
|
||||
.build());
|
||||
}
|
||||
return Optional.empty();
|
||||
@@ -60,13 +85,20 @@ public class MongoVPN implements VPNDatabase {
|
||||
rdoc.put("success", toCache.isSuccess());
|
||||
rdoc.put("latitude", toCache.getLatitude());
|
||||
rdoc.put("longitude", toCache.getLongitude());
|
||||
rdoc.put("lastAccess", System.currentTimeMillis());
|
||||
|
||||
VPNExecutor.threadExecutor.execute(() -> {
|
||||
cacheDocument.deleteMany(Filters.eq("ip", toCache.getIp()));
|
||||
cacheDocument.insertOne(rdoc);
|
||||
Bson update = new Document("$set", rdoc);
|
||||
cacheDocument.updateOne(Filters.eq("ip", toCache.getIp()), update,
|
||||
new UpdateOptions().upsert(true));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteResponse(String ip) {
|
||||
cacheDocument.deleteMany(Filters.eq("ip", ip));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWhitelisted(UUID uuid) {
|
||||
return settingsDocument
|
||||
@@ -86,8 +118,10 @@ public class MongoVPN implements VPNDatabase {
|
||||
if(whitelisted) {
|
||||
Document wdoc = new Document("setting", "whitelist");
|
||||
wdoc.put("uuid", uuid.toString());
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted().add(uuid);
|
||||
VPNExecutor.threadExecutor.execute(() -> settingsDocument.insertOne(wdoc));
|
||||
} else {
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted().remove(uuid);
|
||||
VPNExecutor.threadExecutor.execute(() -> settingsDocument.deleteMany(Filters
|
||||
.and(
|
||||
Filters.eq("setting", "whitelist"),
|
||||
@@ -98,10 +132,12 @@ public class MongoVPN implements VPNDatabase {
|
||||
@Override
|
||||
public void setWhitelisted(String ip, boolean whitelisted) {
|
||||
if(whitelisted) {
|
||||
Document wdoc = new Document("setting", "whitelist");
|
||||
wdoc.put("ip", ip);
|
||||
Document wdoc = new Document("setting", "whitelist").append("ip", ip);
|
||||
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps().add(ip);
|
||||
VPNExecutor.threadExecutor.execute(() -> settingsDocument.insertOne(wdoc));
|
||||
} else {
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps().remove(ip);
|
||||
VPNExecutor.threadExecutor.execute(() -> settingsDocument.deleteMany(Filters
|
||||
.and(
|
||||
Filters.eq("setting", "whitelist"),
|
||||
@@ -170,18 +206,20 @@ public class MongoVPN implements VPNDatabase {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
if(AntiVPN.getInstance().getVpnConfig().mongoDatabaseURL().length() > 0) { //URL
|
||||
if(!AntiVPN.getInstance().getVpnConfig().mongoDatabaseURL().isEmpty()) { //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())));
|
||||
});
|
||||
.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
|
||||
settingsBld.credential(MongoCredential
|
||||
.createCredential(AntiVPN.getInstance().getVpnConfig().getUsername(),
|
||||
AntiVPN.getInstance().getVpnConfig().getDatabaseName(),
|
||||
AntiVPN.getInstance().getVpnConfig().getPassword().toCharArray()));
|
||||
@@ -189,7 +227,7 @@ public class MongoVPN implements VPNDatabase {
|
||||
|
||||
client = MongoClients.create(settingsBld.build());
|
||||
}
|
||||
antivpnDatabase = client.getDatabase(AntiVPN.getInstance().getVpnConfig().getDatabaseName());
|
||||
MongoDatabase antivpnDatabase = client.getDatabase(AntiVPN.getInstance().getVpnConfig().getDatabaseName());
|
||||
|
||||
settingsDocument = antivpnDatabase.getCollection("settings");
|
||||
if(settingsDocument.listIndexes().first() == null) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import dev.brighten.antivpn.api.VPNExecutor;
|
||||
import dev.brighten.antivpn.database.VPNDatabase;
|
||||
import dev.brighten.antivpn.database.sql.utils.MySQL;
|
||||
import dev.brighten.antivpn.database.sql.utils.Query;
|
||||
import dev.brighten.antivpn.utils.VPNResponse;
|
||||
import dev.brighten.antivpn.web.objects.VPNResponse;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
@@ -20,39 +20,25 @@ import java.util.function.Consumer;
|
||||
|
||||
public class MySqlVPN implements VPNDatabase {
|
||||
|
||||
private Thread whitelistedThread;
|
||||
|
||||
public MySqlVPN() {
|
||||
whitelistedThread = new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(TimeUnit.SECONDS.toMillis(2));
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
while (true) {
|
||||
// Updating from database
|
||||
if (AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()) {
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted().clear();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted()
|
||||
.addAll(AntiVPN.getInstance().getDatabase().getAllWhitelisted());
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps().clear();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps()
|
||||
.addAll(AntiVPN.getInstance().getDatabase().getAllWhitelistedIps());
|
||||
}
|
||||
try {
|
||||
Thread.sleep(TimeUnit.SECONDS.toMillis(4));
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
VPNExecutor.threadExecutor.scheduleAtFixedRate(() -> {
|
||||
if(!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed()) return;
|
||||
|
||||
whitelistedThread.start();
|
||||
//Refreshing whitelisted players
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted().clear();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted()
|
||||
.addAll(AntiVPN.getInstance().getDatabase().getAllWhitelisted());
|
||||
|
||||
//Refreshing whitlisted IPs
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps().clear();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps()
|
||||
.addAll(AntiVPN.getInstance().getDatabase().getAllWhitelistedIps());
|
||||
}, 2, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VPNResponse> getStoredResponse(String ip) {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()|| MySQL.isClosed())
|
||||
if (isDisabled())
|
||||
return Optional.empty();
|
||||
|
||||
ResultSet rs = Query.prepare("select * from `responses` where `ip` = ? limit 1").append(ip).executeQuery();
|
||||
@@ -65,7 +51,13 @@ public class MySqlVPN implements VPNDatabase {
|
||||
rs.getString("method"), rs.getString("isp"), "N/A",
|
||||
rs.getBoolean("proxy"), rs.getBoolean("cached"), true,
|
||||
rs.getDouble("latitude"), rs.getDouble("longitude"),
|
||||
System.currentTimeMillis(), -1);
|
||||
rs.getTimestamp("inserted").getTime(), -1);
|
||||
|
||||
if(System.currentTimeMillis() - response.getLastAccess() > TimeUnit.HOURS.toMillis(1)) {
|
||||
VPNExecutor.threadExecutor.execute(() -> deleteResponse(ip));
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(response);
|
||||
}
|
||||
} catch (SQLException throwables) {
|
||||
@@ -86,7 +78,7 @@ public class MySqlVPN implements VPNDatabase {
|
||||
*/
|
||||
@Override
|
||||
public void cacheResponse(VPNResponse toCache) {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
|
||||
if (isDisabled())
|
||||
return;
|
||||
|
||||
Query.prepare("insert into `responses` (`ip`,`asn`,`countryName`,`countryCode`,`city`,`timeZone`,"
|
||||
@@ -98,10 +90,18 @@ public class MySqlVPN implements VPNDatabase {
|
||||
.append(toCache.getLatitude()).append(toCache.getLongitude()).execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteResponse(String ip) {
|
||||
if(!isDisabled())
|
||||
return;
|
||||
|
||||
Query.prepare("delete from `responses` where `ip` = ?").append(ip).execute();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean isWhitelisted(UUID uuid) {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
|
||||
if (isDisabled())
|
||||
return false;
|
||||
ResultSet set = Query.prepare("select uuid from `whitelisted` where `uuid` = ? limit 1")
|
||||
.append(uuid.toString()).executeQuery();
|
||||
@@ -112,7 +112,7 @@ public class MySqlVPN implements VPNDatabase {
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean isWhitelisted(String ip) {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
|
||||
if (isDisabled())
|
||||
return false;
|
||||
ResultSet set = Query.prepare("select `ip` from `whitelisted-ips` where `ip` = ? limit 1")
|
||||
.append(ip).executeQuery();
|
||||
@@ -123,7 +123,7 @@ public class MySqlVPN implements VPNDatabase {
|
||||
|
||||
@Override
|
||||
public void setWhitelisted(UUID uuid, boolean whitelisted) {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
|
||||
if (isDisabled())
|
||||
return;
|
||||
|
||||
if (whitelisted) {
|
||||
@@ -139,7 +139,7 @@ public class MySqlVPN implements VPNDatabase {
|
||||
|
||||
@Override
|
||||
public void setWhitelisted(String ip, boolean whitelisted) {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed())
|
||||
if (isDisabled())
|
||||
return;
|
||||
|
||||
if(whitelisted) {
|
||||
@@ -242,9 +242,7 @@ public class MySqlVPN implements VPNDatabase {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled())
|
||||
return;
|
||||
AntiVPN.getInstance().getExecutor().log("Initializing MySQL...");
|
||||
if(AntiVPN.getInstance().getVpnConfig().getDatabaseType().contains("sql")) {
|
||||
MySQL.init();
|
||||
} else MySQL.initH2();
|
||||
MySQL.init();
|
||||
|
||||
AntiVPN.getInstance().getExecutor().log("Creating tables...");
|
||||
|
||||
@@ -335,6 +333,10 @@ public class MySqlVPN implements VPNDatabase {
|
||||
System.err.println("MySQL Excepton created" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDisabled() {
|
||||
return !AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()|| MySQL.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package dev.brighten.antivpn.database.sql.utils;
|
||||
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import org.h2.jdbc.JdbcSQLNonTransientConnectionException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Files;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MySQL {
|
||||
private static Connection conn;
|
||||
@@ -36,22 +42,66 @@ public class MySQL {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean attemptedTwice = false;
|
||||
public static void initH2() {
|
||||
File dataFolder = new File(AntiVPN.getInstance().getPluginFolder(), "databases" + File.separator + "database");
|
||||
File dataFolder = new File(AntiVPN.getInstance().getPluginFolder(), "databases");
|
||||
File databaseFile = new File(dataFolder, "database");
|
||||
try {
|
||||
Class.forName("org.h2.Driver");
|
||||
conn = new NonClosableConnection(DriverManager.getConnection ("jdbc:h2:file:" +
|
||||
dataFolder.getAbsolutePath(),
|
||||
AntiVPN.getInstance().getVpnConfig().getUsername(),AntiVPN.getInstance().getVpnConfig().getPassword()));
|
||||
Constructor jdbcConnection = Class.forName("org.h2.jdbc.JdbcConnection")
|
||||
.getConstructor(String.class, Properties.class, String.class, Object.class, boolean.class);
|
||||
conn = new NonClosableConnection((Connection)jdbcConnection.newInstance("jdbc:h2:file:" +
|
||||
databaseFile.getAbsolutePath(),
|
||||
new Properties(), AntiVPN.getInstance().getVpnConfig().getUsername(),
|
||||
AntiVPN.getInstance().getVpnConfig().getPassword(), false));
|
||||
conn.setAutoCommit(true);
|
||||
Query.use(conn);
|
||||
AntiVPN.getInstance().getExecutor().log("Connection to SQlLite has been established.");
|
||||
AntiVPN.getInstance().getExecutor().log("Connection to H2 has been established.");
|
||||
} catch (SQLException ex) {
|
||||
AntiVPN.getInstance().getExecutor().log("SQLite exception on initialize");
|
||||
AntiVPN.getInstance().getExecutor().log("H2 exception on initialize");
|
||||
ex.printStackTrace();
|
||||
} catch (ClassNotFoundException ex) {
|
||||
AntiVPN.getInstance().getExecutor().log("No H2 library found!");
|
||||
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException e) {
|
||||
AntiVPN.getInstance().getExecutor().log("Java exception on initialize");
|
||||
e.printStackTrace();
|
||||
} catch(InvocationTargetException e) {
|
||||
if(attemptedTwice) return;
|
||||
if(e.getCause() instanceof JdbcSQLNonTransientConnectionException) {
|
||||
File[] files = dataFolder.listFiles();
|
||||
|
||||
if(files == null) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
File oldDbs = new File(dataFolder, "old");
|
||||
|
||||
boolean made = false;
|
||||
if(!oldDbs.isDirectory()) {
|
||||
made = oldDbs.mkdir();
|
||||
} else made = true;
|
||||
|
||||
if(!made) {
|
||||
throw new RuntimeException(String.format("Unable to upgrade H2 files since this application " +
|
||||
"was unable to create a new directory %s (insufficient permissions?)!", oldDbs.getPath()));
|
||||
}
|
||||
AntiVPN.getInstance().getExecutor().log("Upgrading h2 files...");
|
||||
for (File file : files) {
|
||||
if(file.getName().endsWith(".db")) {
|
||||
try {
|
||||
Files.copy(file.toPath(), new File(oldDbs, file.getName()).toPath());
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
if(file.delete()) {
|
||||
AntiVPN.getInstance().getExecutor().log("Successfully deleted old " + file.getName());
|
||||
} else throw new RuntimeException("Unable to delete old database file " + file.getName());
|
||||
}
|
||||
}
|
||||
initH2();
|
||||
} else e.printStackTrace();
|
||||
}
|
||||
attemptedTwice = true;
|
||||
}
|
||||
|
||||
public static void use() {
|
||||
@@ -70,6 +120,7 @@ public class MySQL {
|
||||
} else conn.close();
|
||||
conn = null;
|
||||
}
|
||||
attemptedTwice = false;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* This file is part of helper, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.depends;
|
||||
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.utils.NonnullByDefault;
|
||||
import dev.brighten.antivpn.utils.Supplier;
|
||||
import dev.brighten.antivpn.utils.Suppliers;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Resolves {@link MavenLibrary} annotations for a class, and loads the dependency
|
||||
* into the classloader.
|
||||
*/
|
||||
@NonnullByDefault
|
||||
public final class LibraryLoader {
|
||||
|
||||
@SuppressWarnings("Guava")
|
||||
private static final Supplier<URLClassLoaderAccess> URL_INJECTOR = Suppliers.memoize(() -> URLClassLoaderAccess.create((URLClassLoader) AntiVPN.getInstance().getClass().getClassLoader()));
|
||||
|
||||
/**
|
||||
* Resolves all {@link MavenLibrary} annotations on the given object.
|
||||
*
|
||||
* @param object the object to load libraries for.
|
||||
*/
|
||||
public static void loadAll(Object object) {
|
||||
loadAll(object.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves all {@link MavenLibrary} annotations on the given class.
|
||||
*
|
||||
* @param clazz the class to load libraries for.
|
||||
*/
|
||||
public static void loadAll(Class<?> clazz) {
|
||||
MavenLibrary[] libs = clazz.getDeclaredAnnotationsByType(MavenLibrary.class);
|
||||
if (libs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (MavenLibrary lib : libs) {
|
||||
load(lib.groupId(), lib.artifactId(), lib.version(), lib.repo().url());
|
||||
}
|
||||
}
|
||||
|
||||
public static void load(String groupId, String artifactId, String version) {
|
||||
load(groupId, artifactId, version, "https://repo1.maven.org/maven2");
|
||||
}
|
||||
|
||||
public static void load(String groupId, String artifactId, String version, String repoUrl) {
|
||||
load(new Dependency(groupId, artifactId, version, repoUrl));
|
||||
}
|
||||
|
||||
public static void load(Dependency d) {
|
||||
AntiVPN.getInstance().getExecutor().log(String.format("Loading dependency %s:%s:%s from %s", d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getRepoUrl()));
|
||||
String name = d.getArtifactId() + "-" + d.getVersion();
|
||||
|
||||
File saveLocation = new File(getLibFolder(), name + ".jar");
|
||||
if (!saveLocation.exists()) {
|
||||
|
||||
try {
|
||||
AntiVPN.getInstance().getExecutor().log("Dependency '" + name + "' is not already in the libraries folder. Attempting to download...");
|
||||
URL url = d.getUrl();
|
||||
|
||||
try (InputStream is = url.openStream()) {
|
||||
Files.copy(is, saveLocation.toPath());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
AntiVPN.getInstance().getExecutor().log("Dependency '" + name + "' successfully downloaded.");
|
||||
}
|
||||
|
||||
if (!saveLocation.exists()) {
|
||||
throw new RuntimeException("Unable to download dependency: " + d.toString());
|
||||
}
|
||||
|
||||
try {
|
||||
URL_INJECTOR.get().addURL(saveLocation.toURI().toURL());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to load dependency: " + saveLocation.toString(), e);
|
||||
}
|
||||
|
||||
AntiVPN.getInstance().getExecutor().log("Loaded dependency '" + name + "' successfully.");
|
||||
}
|
||||
|
||||
private static File getLibFolder() {
|
||||
File pluginDataFolder = AntiVPN.getInstance().getPluginFolder();
|
||||
File libs = new File(pluginDataFolder, "libraries");
|
||||
libs.mkdirs();
|
||||
return libs;
|
||||
}
|
||||
|
||||
@NonnullByDefault
|
||||
public static final class Dependency {
|
||||
private final String groupId;
|
||||
private final String artifactId;
|
||||
private final String version;
|
||||
private final String repoUrl;
|
||||
|
||||
public Dependency(String groupId, String artifactId, String version, String repoUrl) {
|
||||
this.groupId = Objects.requireNonNull(groupId, "groupId");
|
||||
this.artifactId = Objects.requireNonNull(artifactId, "artifactId");
|
||||
this.version = Objects.requireNonNull(version, "version");
|
||||
this.repoUrl = Objects.requireNonNull(repoUrl, "repoUrl");
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
return this.groupId;
|
||||
}
|
||||
|
||||
public String getArtifactId() {
|
||||
return this.artifactId;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public String getRepoUrl() {
|
||||
return this.repoUrl;
|
||||
}
|
||||
|
||||
public URL getUrl() throws MalformedURLException {
|
||||
String repo = this.repoUrl;
|
||||
if (!repo.endsWith("/")) {
|
||||
repo += "/";
|
||||
}
|
||||
repo += "%s/%s/%s/%s-%s.jar";
|
||||
|
||||
String url = String.format(repo, this.groupId.replace(".", "/"), this.artifactId, this.version, this.artifactId, this.version);
|
||||
return new URL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof Dependency)) return false;
|
||||
final Dependency other = (Dependency) o;
|
||||
return this.getGroupId().equals(other.getGroupId()) &&
|
||||
this.getArtifactId().equals(other.getArtifactId()) &&
|
||||
this.getVersion().equals(other.getVersion()) &&
|
||||
this.getRepoUrl().equals(other.getRepoUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
result = result * PRIME + this.getGroupId().hashCode();
|
||||
result = result * PRIME + this.getArtifactId().hashCode();
|
||||
result = result * PRIME + this.getVersion().hashCode();
|
||||
result = result * PRIME + this.getRepoUrl().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LibraryLoader.Dependency(" +
|
||||
"groupId=" + this.getGroupId() + ", " +
|
||||
"artifactId=" + this.getArtifactId() + ", " +
|
||||
"version=" + this.getVersion() + ", " +
|
||||
"repoUrl=" + this.getRepoUrl() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of helper, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.depends;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Annotation to indicate the required libraries for a class.
|
||||
*/
|
||||
@Documented
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MavenLibraries {
|
||||
|
||||
MavenLibrary[] value() default {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of helper, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.depends;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Annotation to indicate a required library for a class.
|
||||
*/
|
||||
@Documented
|
||||
@Repeatable(MavenLibraries.class)
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MavenLibrary {
|
||||
|
||||
/**
|
||||
* The group id of the library
|
||||
*
|
||||
* @return the group id of the library
|
||||
*/
|
||||
String groupId();
|
||||
|
||||
/**
|
||||
* The artifact id of the library
|
||||
*
|
||||
* @return the artifact id of the library
|
||||
*/
|
||||
String artifactId();
|
||||
|
||||
/**
|
||||
* The version of the library
|
||||
*
|
||||
* @return the version of the library
|
||||
*/
|
||||
String version();
|
||||
|
||||
/**
|
||||
* The repo where the library can be obtained from
|
||||
*
|
||||
* @return the repo where the library can be obtained from
|
||||
*/
|
||||
Repository repo() default @Repository(url = "https://repo1.maven.org/maven2");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of helper, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.depends;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Represents a maven repository.
|
||||
*/
|
||||
@Documented
|
||||
@Target(ElementType.LOCAL_VARIABLE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Repository {
|
||||
|
||||
/**
|
||||
* Gets the base url of the repository.
|
||||
*
|
||||
* @return the base url of the repository
|
||||
*/
|
||||
String url();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* This file is part of helper, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.depends;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Provides access to {@link URLClassLoader}#addURL.
|
||||
*/
|
||||
public abstract class URLClassLoaderAccess {
|
||||
|
||||
/**
|
||||
* Creates a {@link URLClassLoaderAccess} for the given class loader.
|
||||
*
|
||||
* @param classLoader the class loader
|
||||
* @return the access object
|
||||
*/
|
||||
static URLClassLoaderAccess create(URLClassLoader classLoader) {
|
||||
if (Reflection.isSupported()) {
|
||||
return new Reflection(classLoader);
|
||||
} else if (Unsafe.isSupported()) {
|
||||
return new Unsafe(classLoader);
|
||||
} else {
|
||||
return Noop.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
private final URLClassLoader classLoader;
|
||||
|
||||
protected URLClassLoaderAccess(URLClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the given URL to the class loader.
|
||||
*
|
||||
* @param url the URL to add
|
||||
*/
|
||||
public abstract void addURL(URL url);
|
||||
|
||||
/**
|
||||
* Accesses using reflection, not supported on Java 9+.
|
||||
*/
|
||||
private static class Reflection extends URLClassLoaderAccess {
|
||||
private static final Method ADD_URL_METHOD;
|
||||
|
||||
static {
|
||||
Method addUrlMethod;
|
||||
try {
|
||||
addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
addUrlMethod.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
addUrlMethod = null;
|
||||
}
|
||||
ADD_URL_METHOD = addUrlMethod;
|
||||
}
|
||||
|
||||
private static boolean isSupported() {
|
||||
return ADD_URL_METHOD != null;
|
||||
}
|
||||
|
||||
Reflection(URLClassLoader classLoader) {
|
||||
super(classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(URL url) {
|
||||
try {
|
||||
ADD_URL_METHOD.invoke(super.classLoader, url);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses using sun.misc.Unsafe, supported on Java 9+.
|
||||
*
|
||||
* @author Vaishnav Anil (<a href="https://github.com/slimjar/slimjar">...</a>)
|
||||
*/
|
||||
private static class Unsafe extends URLClassLoaderAccess {
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
|
||||
static {
|
||||
sun.misc.Unsafe unsafe;
|
||||
try {
|
||||
Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
unsafe = (sun.misc.Unsafe) unsafeField.get(null);
|
||||
} catch (Throwable t) {
|
||||
unsafe = null;
|
||||
}
|
||||
UNSAFE = unsafe;
|
||||
}
|
||||
|
||||
private static boolean isSupported() {
|
||||
return UNSAFE != null;
|
||||
}
|
||||
|
||||
private final Collection<URL> unopenedURLs;
|
||||
private final Collection<URL> pathURLs;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Unsafe(URLClassLoader classLoader) {
|
||||
super(classLoader);
|
||||
|
||||
Collection<URL> unopenedURLs;
|
||||
Collection<URL> pathURLs;
|
||||
try {
|
||||
Object ucp = fetchField(URLClassLoader.class, classLoader, "ucp");
|
||||
unopenedURLs = (Collection<URL>) fetchField(ucp.getClass(), ucp, "unopenedUrls");
|
||||
pathURLs = (Collection<URL>) fetchField(ucp.getClass(), ucp, "path");
|
||||
} catch (Throwable e) {
|
||||
unopenedURLs = null;
|
||||
pathURLs = null;
|
||||
}
|
||||
this.unopenedURLs = unopenedURLs;
|
||||
this.pathURLs = pathURLs;
|
||||
}
|
||||
|
||||
private static Object fetchField(final Class<?> clazz, final Object object, final String name) throws NoSuchFieldException {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
long offset = UNSAFE.objectFieldOffset(field);
|
||||
return UNSAFE.getObject(object, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(URL url) {
|
||||
this.unopenedURLs.add(url);
|
||||
this.pathURLs.add(url);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Noop extends URLClassLoaderAccess {
|
||||
private static final Noop INSTANCE = new Noop();
|
||||
|
||||
private Noop() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(URL url) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package dev.brighten.antivpn.message;
|
||||
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
@@ -27,6 +29,8 @@ public class MessageHandler {
|
||||
|
||||
public void addString(VpnString string, Function<VpnString, String> getter) {
|
||||
string.setConfigStringGetter(getter);
|
||||
getter.apply(string);
|
||||
AntiVPN.getInstance().getExecutor().log("Added string " + string.getKey());
|
||||
messages.put(string.getKey(), string);
|
||||
}
|
||||
|
||||
@@ -35,5 +39,8 @@ public class MessageHandler {
|
||||
"&cYou must be a player to execute this command!"), getter);
|
||||
addString(new VpnString("command-alerts-toggled",
|
||||
"&7Your player proxy notifications have been set to: &e%state%"), getter);
|
||||
addString(new VpnString("command-reload-complete",
|
||||
"&aSuccessfully reloaded KauriVPN plugin!"), getter);
|
||||
addString(new VpnString("no-permission", "&cNo permission."), getter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ public class VpnString {
|
||||
public VpnString(String key, String defaultMessage) {
|
||||
this.key = key;
|
||||
this.defaultMessage = defaultMessage;
|
||||
this.message = defaultMessage;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@@ -30,7 +29,7 @@ public class VpnString {
|
||||
}
|
||||
|
||||
public String getFormattedMessage(Var<String, Object>... replacements) {
|
||||
String formatted = message;
|
||||
String formatted = configStringGetter.apply(this);
|
||||
|
||||
for (Var<String, Object> replacement : replacements) {
|
||||
formatted = formatted
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.utils;
|
||||
|
||||
/**
|
||||
* Holder for extra methods of {@code Objects} only in web. Intended to be empty for regular
|
||||
* version.
|
||||
*/
|
||||
abstract class ExtraObjectsMethodsForWeb {}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of helper, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.utils;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NonnullByDefault {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.utils;
|
||||
|
||||
/** A utility method to perform unchecked casts to suppress errors produced by nullness analyses. */
|
||||
final class NullnessCasts {
|
||||
/**
|
||||
* Accepts a {@code @Nullable T} and returns a plain {@code T}, without performing any check that
|
||||
* that conversion is safe.
|
||||
*
|
||||
* <p>This method is intended to help with usages of type parameters that have {
|
||||
* ParametricNullness parametric nullness}. If a type parameter instead ranges over only non-null
|
||||
* types (or if the type is a non-variable type, like {@code String}), then code should almost
|
||||
* never use this method, preferring instead to call {@code requireNonNull} so as to benefit from
|
||||
* its runtime check.
|
||||
*
|
||||
* <p>An example use case for this method is in implementing an {@code Iterator<T>} whose {@code
|
||||
* next} field is lazily initialized. The type of that field would be {@code @Nullable T}, and the
|
||||
* code would be responsible for populating a "real" {@code T} (which might still be the value
|
||||
* {@code null}!) before returning it to callers. Depending on how the code is structured, a
|
||||
* nullness analysis might not understand that the field has been populated. To avoid that problem
|
||||
* without having to add {@code @SuppressWarnings}, the code can call this method.
|
||||
*
|
||||
* <p>Why <i>not</i> just add {@code SuppressWarnings}? The problem is that this method is
|
||||
* typically useful for {@code return} statements. That leaves the code with two options: Either
|
||||
* add the suppression to the whole method (which turns off checking for a large section of code),
|
||||
* or extract a variable, and put the suppression on that. However, a local variable typically
|
||||
* doesn't work: Because nullness analyses typically infer the nullness of local variables,
|
||||
* there's no way to assign a {@code @Nullable T} to a field {@code T foo;} and instruct the
|
||||
* analysis that that means "plain {@code T}" rather than the inferred type {@code @Nullable T}.
|
||||
* (Even if supported added {@code @NonNull}, that would not help, since the problem case
|
||||
* addressed by this method is the case in which {@code T} has parametric nullness -- and thus its
|
||||
* value may be legitimately {@code null}.)
|
||||
*/
|
||||
@SuppressWarnings("nullness")
|
||||
static <T extends Object> T uncheckedCastNullableTToT(T t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
private NullnessCasts() {}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.utils;
|
||||
|
||||
import com.mongodb.lang.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Helper functions that can operate on any {@code Object}.
|
||||
*
|
||||
* <p>See the Guava User Guide on <a
|
||||
* href="https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained">writing {@code Object}
|
||||
* methods with {@code Objects}</a>.
|
||||
*
|
||||
* @author Laurence Gonsalves
|
||||
* @since 2.0
|
||||
*/
|
||||
public final class Objects extends ExtraObjectsMethodsForWeb {
|
||||
private Objects() {}
|
||||
|
||||
/**
|
||||
* Determines whether two possibly-null objects are equal. Returns:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@code true} if {@code a} and {@code b} are both null.
|
||||
* <li>{@code true} if {@code a} and {@code b} are both non-null and they are equal according to
|
||||
* {@link Object#equals(Object)}.
|
||||
* <li>{@code false} in all other situations.
|
||||
* </ul>
|
||||
*
|
||||
* <p>This assumes that any non-null objects passed to this function conform to the {@code
|
||||
* equals()} contract.
|
||||
*
|
||||
* <p><b>Note for Java 7 and later:</b> This method should be treated as deprecated; use {@link
|
||||
* java.util.Objects#equals} instead.
|
||||
*/
|
||||
public static boolean equal(Object a, Object b) {
|
||||
return a == b || (a != null && a.equals(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a hash code for multiple values. The hash code is generated by calling {@link
|
||||
* Arrays#hashCode(Object[])}. Note that array arguments to this method, with the exception of a
|
||||
* single Object array, do not get any special handling; their hash codes are based on identity
|
||||
* and not contents.
|
||||
*
|
||||
* <p>This is useful for implementing {@link Object#hashCode()}. For example, in an object that
|
||||
* has three properties, {@code x}, {@code y}, and {@code z}, one could write:
|
||||
*
|
||||
* <pre>{@code
|
||||
* public int hashCode() {
|
||||
* return Objects.hashCode(getX(), getY(), getZ());
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p><b>Warning:</b> When a single object is supplied, the returned hash code does not equal the
|
||||
* hash code of that object.
|
||||
*
|
||||
* <p><b>Note for Java 7 and later:</b> This method should be treated as deprecated; use {@link
|
||||
* java.util.Objects#hash} instead.
|
||||
*/
|
||||
public static int hashCode(@Nullable Object... objects) {
|
||||
return Arrays.hashCode(objects);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,602 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package dev.brighten.antivpn.utils;
|
||||
|
||||
public final class Preconditions {
|
||||
private Preconditions() {
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean expression) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean expression, Object errorMessage) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException(String.valueOf(errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, char p1) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, int p1) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, long p1) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, Object p1) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, char p1, char p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, char p1, int p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, char p1, long p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, char p1, Object p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, int p1, char p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, int p1, int p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, int p1, long p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, int p1, Object p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, long p1, char p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, long p1, int p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, long p1, long p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, long p1, Object p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, Object p1, char p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, Object p1, int p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, Object p1, long p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, Object p1, Object p2) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, Object p1, Object p2, Object p3) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2, p3));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean b, String errorMessageTemplate, Object p1, Object p2, Object p3, Object p4) {
|
||||
if (!b) {
|
||||
throw new IllegalArgumentException(format(errorMessageTemplate, p1, p2, p3, p4));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean expression) {
|
||||
if (!expression) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean expression, Object errorMessage) {
|
||||
if (!expression) {
|
||||
throw new IllegalStateException(String.valueOf(errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
if (!expression) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, errorMessageArgs));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, char p1) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, int p1) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, long p1) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, Object p1) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, char p1, char p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, char p1, int p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, char p1, long p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, char p1, Object p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, int p1, char p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, int p1, int p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, int p1, long p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, int p1, Object p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, long p1, char p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, long p1, int p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, long p1, long p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, long p1, Object p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, Object p1, char p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, Object p1, int p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, Object p1, long p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, Object p1, Object p2) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, Object p1, Object p2, Object p3) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2, p3));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean b, String errorMessageTemplate, Object p1, Object p2, Object p3, Object p4) {
|
||||
if (!b) {
|
||||
throw new IllegalStateException(format(errorMessageTemplate, p1, p2, p3, p4));
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T reference) {
|
||||
if (reference == null) {
|
||||
throw new NullPointerException();
|
||||
} else {
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T reference, Object errorMessage) {
|
||||
if (reference == null) {
|
||||
throw new NullPointerException(String.valueOf(errorMessage));
|
||||
} else {
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T reference, String errorMessageTemplate, Object... errorMessageArgs) {
|
||||
if (reference == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, errorMessageArgs));
|
||||
} else {
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, char p1) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, int p1) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, long p1) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, Object p1) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, char p1, char p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, char p1, int p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, char p1, long p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, char p1, Object p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, int p1, char p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, int p1, int p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, int p1, long p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, int p1, Object p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, long p1, char p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, long p1, int p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, long p1, long p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, long p1, Object p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, Object p1, char p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, Object p1, int p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, Object p1, long p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, Object p1, Object p2) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, Object p1, Object p2, Object p3) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2, p3));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T checkNotNull(T obj, String errorMessageTemplate, Object p1, Object p2, Object p3, Object p4) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException(format(errorMessageTemplate, p1, p2, p3, p4));
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static int checkElementIndex(int index, int size) {
|
||||
return checkElementIndex(index, size, "index");
|
||||
}
|
||||
|
||||
public static int checkElementIndex(int index, int size, String desc) {
|
||||
if (index >= 0 && index < size) {
|
||||
return index;
|
||||
} else {
|
||||
throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
|
||||
}
|
||||
}
|
||||
|
||||
private static String badElementIndex(int index, int size, String desc) {
|
||||
if (index < 0) {
|
||||
return format("%s (%s) must not be negative", desc, index);
|
||||
} else if (size < 0) {
|
||||
throw new IllegalArgumentException("negative size: " + size);
|
||||
} else {
|
||||
return format("%s (%s) must be less than size (%s)", desc, index, size);
|
||||
}
|
||||
}
|
||||
|
||||
public static int checkPositionIndex(int index, int size) {
|
||||
return checkPositionIndex(index, size, "index");
|
||||
}
|
||||
|
||||
public static int checkPositionIndex(int index, int size, String desc) {
|
||||
if (index >= 0 && index <= size) {
|
||||
return index;
|
||||
} else {
|
||||
throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc));
|
||||
}
|
||||
}
|
||||
|
||||
private static String badPositionIndex(int index, int size, String desc) {
|
||||
if (index < 0) {
|
||||
return format("%s (%s) must not be negative", desc, index);
|
||||
} else if (size < 0) {
|
||||
throw new IllegalArgumentException("negative size: " + size);
|
||||
} else {
|
||||
return format("%s (%s) must not be greater than size (%s)", desc, index, size);
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkPositionIndexes(int start, int end, int size) {
|
||||
if (start < 0 || end < start || end > size) {
|
||||
throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
|
||||
}
|
||||
}
|
||||
|
||||
private static String badPositionIndexes(int start, int end, int size) {
|
||||
if (start >= 0 && start <= size) {
|
||||
return end >= 0 && end <= size ? format("end index (%s) must not be less than start index (%s)", end, start) : badPositionIndex(end, size, "end index");
|
||||
} else {
|
||||
return badPositionIndex(start, size, "start index");
|
||||
}
|
||||
}
|
||||
|
||||
static String format(String template, Object... args) {
|
||||
template = String.valueOf(template);
|
||||
StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
|
||||
int templateStart = 0;
|
||||
|
||||
int i;
|
||||
int placeholderStart;
|
||||
for(i = 0; i < args.length; templateStart = placeholderStart + 2) {
|
||||
placeholderStart = template.indexOf("%s", templateStart);
|
||||
if (placeholderStart == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
builder.append(template, templateStart, placeholderStart);
|
||||
builder.append(args[i++]);
|
||||
}
|
||||
|
||||
builder.append(template, templateStart, template.length());
|
||||
if (i < args.length) {
|
||||
builder.append(" [");
|
||||
builder.append(args[i++]);
|
||||
|
||||
while(i < args.length) {
|
||||
builder.append(", ");
|
||||
builder.append(args[i++]);
|
||||
}
|
||||
|
||||
builder.append(']');
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package dev.brighten.antivpn.utils;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Supplier<T> extends java.util.function.Supplier<T> {
|
||||
T get();
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.utils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static dev.brighten.antivpn.utils.NullnessCasts.uncheckedCastNullableTToT;
|
||||
import static dev.brighten.antivpn.utils.Preconditions.checkArgument;
|
||||
import static dev.brighten.antivpn.utils.Preconditions.checkNotNull;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* Useful suppliers.
|
||||
*
|
||||
* <p>All methods return serializable suppliers as long as they're given serializable parameters.
|
||||
*
|
||||
* @author Laurence Gonsalves
|
||||
* @author Harry Heymann
|
||||
* @since 2.0
|
||||
*/
|
||||
public final class Suppliers {
|
||||
private Suppliers() {}
|
||||
|
||||
/**
|
||||
* Returns a new supplier which is the composition of the provided function and supplier. In other
|
||||
* words, the new supplier's value will be computed by retrieving the value from {@code supplier},
|
||||
* and then applying {@code function} to that value. Note that the resulting supplier will not
|
||||
* call {@code supplier} or invoke {@code function} until it is called.
|
||||
*/
|
||||
public static <F extends Object, T extends Object> Supplier<T> compose(
|
||||
Function<? super F, T> function, Supplier<F> supplier) {
|
||||
return new SupplierComposition<>(function, supplier);
|
||||
}
|
||||
|
||||
private static class SupplierComposition<F extends Object, T extends Object>
|
||||
implements Supplier<T>, Serializable {
|
||||
final Function<? super F, T> function;
|
||||
final Supplier<F> supplier;
|
||||
|
||||
SupplierComposition(Function<? super F, T> function, Supplier<F> supplier) {
|
||||
this.function = checkNotNull(function);
|
||||
this.supplier = checkNotNull(supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return function.apply(supplier.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof SupplierComposition) {
|
||||
SupplierComposition<?, ?> that = (SupplierComposition<?, ?>) obj;
|
||||
return function.equals(that.function) && supplier.equals(that.supplier);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(function, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Suppliers.compose(" + function + ", " + supplier + ")";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a supplier which caches the instance retrieved during the first call to {@code get()}
|
||||
* and returns that value on subsequent calls to {@code get()}. See: <a
|
||||
* href="http://en.wikipedia.org/wiki/Memoization">memoization</a>
|
||||
*
|
||||
* <p>The returned supplier is thread-safe. The delegate's {@code get()} method will be invoked at
|
||||
* most once unless the underlying {@code get()} throws an exception. The supplier's serialized
|
||||
* form does not contain the cached value, which will be recalculated when {@code get()} is called
|
||||
* on the reserialized instance.
|
||||
*
|
||||
* <p>When the underlying delegate throws an exception then this memoizing supplier will keep
|
||||
* delegating calls until it returns valid data.
|
||||
*
|
||||
* <p>If {@code delegate} is an instance created by an earlier call to {@code memoize}, it is
|
||||
* returned directly.
|
||||
*/
|
||||
public static <T extends Object> Supplier<T> memoize(Supplier<T> delegate) {
|
||||
if (delegate instanceof NonSerializableMemoizingSupplier
|
||||
|| delegate instanceof MemoizingSupplier) {
|
||||
return delegate;
|
||||
}
|
||||
return delegate instanceof Serializable
|
||||
? new MemoizingSupplier<T>(delegate)
|
||||
: new NonSerializableMemoizingSupplier<T>(delegate);
|
||||
}
|
||||
|
||||
static class MemoizingSupplier<T extends Object> implements Supplier<T>, Serializable {
|
||||
final Supplier<T> delegate;
|
||||
transient volatile boolean initialized;
|
||||
// "value" does not need to be volatile; visibility piggy-backs
|
||||
// on volatile read of "initialized".
|
||||
transient T value;
|
||||
|
||||
MemoizingSupplier(Supplier<T> delegate) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
// A 2-field variant of Double Checked Locking.
|
||||
if (!initialized) {
|
||||
synchronized (this) {
|
||||
if (!initialized) {
|
||||
T t = delegate.get();
|
||||
value = t;
|
||||
initialized = true;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
// This is safe because we checked `initialized.`
|
||||
return uncheckedCastNullableTToT(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Suppliers.memoize("
|
||||
+ (initialized ? "<supplier that returned " + value + ">" : delegate)
|
||||
+ ")";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
static class NonSerializableMemoizingSupplier<T extends Object> implements Supplier<T> {
|
||||
volatile Supplier<T> delegate;
|
||||
volatile boolean initialized;
|
||||
// "value" does not need to be volatile; visibility piggy-backs
|
||||
// on volatile read of "initialized".
|
||||
T value;
|
||||
|
||||
NonSerializableMemoizingSupplier(Supplier<T> delegate) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
// A 2-field variant of Double Checked Locking.
|
||||
if (!initialized) {
|
||||
synchronized (this) {
|
||||
if (!initialized) {
|
||||
/*
|
||||
* requireNonNull is safe because we read and write `delegate` under synchronization.
|
||||
*
|
||||
* TODO(cpovirk): To avoid having to check for null, replace `delegate` with a singleton
|
||||
* `Supplier` that always throws an exception.
|
||||
*/
|
||||
T t = requireNonNull(delegate).get();
|
||||
value = t;
|
||||
initialized = true;
|
||||
// Release the delegate to GC.
|
||||
delegate = null;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
// This is safe because we checked `initialized.`
|
||||
return uncheckedCastNullableTToT(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
Supplier<T> delegate = this.delegate;
|
||||
return "Suppliers.memoize("
|
||||
+ (delegate == null ? "<supplier that returned " + value + ">" : delegate)
|
||||
+ ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a supplier that caches the instance supplied by the delegate and removes the cached
|
||||
* value after the specified time has passed. Subsequent calls to {@code get()} return the cached
|
||||
* value if the expiration time has not passed. After the expiration time, a new value is
|
||||
* retrieved, cached, and returned. See: <a
|
||||
* href="http://en.wikipedia.org/wiki/Memoization">memoization</a>
|
||||
*
|
||||
* <p>The returned supplier is thread-safe. The supplier's serialized form does not contain the
|
||||
* cached value, which will be recalculated when {@code get()} is called on the reserialized
|
||||
* instance. The actual memoization does not happen when the underlying delegate throws an
|
||||
* exception.
|
||||
*
|
||||
* <p>When the underlying delegate throws an exception then this memoizing supplier will keep
|
||||
* delegating calls until it returns valid data.
|
||||
*
|
||||
* @param duration the length of time after a value is created that it should stop being returned
|
||||
* by subsequent {@code get()} calls
|
||||
* @param unit the unit that {@code duration} is expressed in
|
||||
* @throws IllegalArgumentException if {@code duration} is not positive
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("GoodTime") // should accept a java.time.Duration
|
||||
public static <T extends Object> Supplier<T> memoizeWithExpiration(
|
||||
Supplier<T> delegate, long duration, TimeUnit unit) {
|
||||
return new ExpiringMemoizingSupplier<>(delegate, duration, unit);
|
||||
}
|
||||
|
||||
@SuppressWarnings("GoodTime") // lots of violations
|
||||
static class ExpiringMemoizingSupplier<T extends Object>
|
||||
implements Supplier<T>, Serializable {
|
||||
final Supplier<T> delegate;
|
||||
final long durationNanos;
|
||||
transient volatile T value;
|
||||
// The special value 0 means "not yet initialized".
|
||||
transient volatile long expirationNanos;
|
||||
|
||||
ExpiringMemoizingSupplier(Supplier<T> delegate, long duration, TimeUnit unit) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
this.durationNanos = unit.toNanos(duration);
|
||||
checkArgument(duration > 0, "duration (%s %s) must be > 0", duration, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
// Another variant of Double Checked Locking.
|
||||
//
|
||||
// We use two volatile reads. We could reduce this to one by
|
||||
// putting our fields into a holder class, but (at least on x86)
|
||||
// the extra memory consumption and indirection are more
|
||||
// expensive than the extra volatile reads.
|
||||
long nanos = expirationNanos;
|
||||
long now = System.nanoTime();
|
||||
if (nanos == 0 || now - nanos >= 0) {
|
||||
synchronized (this) {
|
||||
if (nanos == expirationNanos) { // recheck for lost race
|
||||
T t = delegate.get();
|
||||
value = t;
|
||||
nanos = now + durationNanos;
|
||||
// In the very unlikely event that nanos is 0, set it to 1;
|
||||
// no one will notice 1 ns of tardiness.
|
||||
expirationNanos = (nanos == 0) ? 1 : nanos;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
// This is safe because we checked `expirationNanos.`
|
||||
return uncheckedCastNullableTToT(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// This is a little strange if the unit the user provided was not NANOS,
|
||||
// but we don't want to store the unit just for toString
|
||||
return "Suppliers.memoizeWithExpiration(" + delegate + ", " + durationNanos + ", NANOS)";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/** Returns a supplier that always supplies {@code instance}. */
|
||||
public static <T extends Object> Supplier<T> ofInstance(
|
||||
T instance) {
|
||||
return new SupplierOfInstance<>(instance);
|
||||
}
|
||||
|
||||
private static class SupplierOfInstance<T extends Object>
|
||||
implements Supplier<T>, Serializable {
|
||||
final T instance;
|
||||
|
||||
SupplierOfInstance(T instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof SupplierOfInstance) {
|
||||
SupplierOfInstance<?> that = (SupplierOfInstance<?>) obj;
|
||||
return Objects.equal(instance, that.instance);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Suppliers.ofInstance(" + instance + ")";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a supplier whose {@code get()} method synchronizes on {@code delegate} before calling
|
||||
* it, making it thread-safe.
|
||||
*/
|
||||
public static <T extends Object> Supplier<T> synchronizedSupplier(
|
||||
Supplier<T> delegate) {
|
||||
return new ThreadSafeSupplier<>(delegate);
|
||||
}
|
||||
|
||||
private static class ThreadSafeSupplier<T extends Object>
|
||||
implements Supplier<T>, Serializable {
|
||||
final Supplier<T> delegate;
|
||||
|
||||
ThreadSafeSupplier(Supplier<T> delegate) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
synchronized (delegate) {
|
||||
return delegate.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Suppliers.synchronizedSupplier(" + delegate + ")";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function that accepts a supplier and returns the result of invoking {@link
|
||||
* Supplier#get} on that supplier.
|
||||
*
|
||||
* <p><b>Java 8 users:</b> use the method reference {@code Supplier::get} instead.
|
||||
*
|
||||
* @since 8.0
|
||||
*/
|
||||
public static <T extends Object> Function<Supplier<T>, T> supplierFunction() {
|
||||
@SuppressWarnings("unchecked") // implementation is "fully variant"
|
||||
SupplierFunction<T> sf = (SupplierFunction<T>) SupplierFunctionImpl.INSTANCE;
|
||||
return sf;
|
||||
}
|
||||
|
||||
private interface SupplierFunction<T extends Object> extends Function<Supplier<T>, T> {}
|
||||
|
||||
private enum SupplierFunctionImpl implements SupplierFunction<Object> {
|
||||
INSTANCE;
|
||||
|
||||
// Note: This makes T a "pass-through type"
|
||||
@Override
|
||||
public Object apply(Supplier<Object> input) {
|
||||
return input.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Suppliers.supplierFunction()";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,17 +23,17 @@ public class YamlConfiguration extends ConfigurationProvider
|
||||
@Override
|
||||
protected Yaml initialValue()
|
||||
{
|
||||
Representer representer = new Representer()
|
||||
DumperOptions options = new DumperOptions();
|
||||
options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK );
|
||||
Representer representer = new Representer(options)
|
||||
{
|
||||
{
|
||||
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 );
|
||||
return new Yaml( new Constructor(new LoaderOptions()), representer, options );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package dev.brighten.antivpn.web;
|
||||
|
||||
import dev.brighten.antivpn.utils.json.JSONException;
|
||||
import dev.brighten.antivpn.utils.json.JSONObject;
|
||||
import dev.brighten.antivpn.utils.json.JsonReader;
|
||||
import dev.brighten.antivpn.web.objects.QueryResponse;
|
||||
import dev.brighten.antivpn.web.objects.VPNResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class FunkemunkyAPI {
|
||||
|
||||
/**
|
||||
*
|
||||
* Queries https://funkemunky.cc/vpn API and returns information on the IP
|
||||
*
|
||||
* @param ip String
|
||||
* @param license String
|
||||
* @param cachedResults boolean
|
||||
* @return VPNResponse
|
||||
* @throws JSONException Throws when JSON response is not formatted properly.
|
||||
* @throws IOException Throws when there is an error connecting to and processing information from API.
|
||||
*/
|
||||
public static VPNResponse getVPNResponse(String ip, String license, boolean cachedResults /* faster if set to true*/)
|
||||
throws JSONException, IOException {
|
||||
JSONObject result = JsonReader.readJsonFromUrl(String
|
||||
.format("https://funkemunky.cc/vpn?ip=%s&license=%s&cache=%s",
|
||||
ip, license.length() == 0 ? "none" : license, cachedResults));
|
||||
|
||||
return VPNResponse.fromJson(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Feeds into {@link FunkemunkyAPI#getQueryResponse(String)} using "none" as argument
|
||||
* to grab query information based on the connecting IP address.
|
||||
*
|
||||
* @return QueryResponse
|
||||
* @throws JSONException Throws when JSON response is not formatted properly.
|
||||
* @throws IOException Throws when there is an error connecting to and processing information from API.
|
||||
*/
|
||||
public static QueryResponse getQueryResponse() throws JSONException, IOException {
|
||||
return getQueryResponse("none");
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries https://funkemunky.cc/vpn/queryCheck and returns information based on the
|
||||
* provided licence input.
|
||||
*
|
||||
* @param license String
|
||||
* @return QueryResponse
|
||||
* @throws JSONException Throws when JSON response is not formatted properly.
|
||||
* @throws IOException Throws when there is an error connecting to and processing information from API.
|
||||
*/
|
||||
public static QueryResponse getQueryResponse(String license) throws JSONException, IOException {
|
||||
JSONObject result = JsonReader.readJsonFromUrl("https://funkemunky.cc/vpn/queryCheck?license=" + license);
|
||||
|
||||
return QueryResponse.fromJson(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package dev.brighten.antivpn.web.objects;
|
||||
|
||||
import dev.brighten.antivpn.utils.json.JSONException;
|
||||
import dev.brighten.antivpn.utils.json.JSONObject;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* Used to format the JSON response from https://funkemunky.cc/vpn/queryCheck into an object for project use.
|
||||
*/
|
||||
@Data
|
||||
@Builder(toBuilder = true)
|
||||
public class QueryResponse {
|
||||
|
||||
private boolean validPlan;
|
||||
private String planType;
|
||||
private long queries;
|
||||
private long queriesMax;
|
||||
|
||||
/**
|
||||
* Takes a JSON String and feeds it into {@link QueryResponse#fromJson(JSONObject)}
|
||||
*
|
||||
* @param jsonString String (formatted in JSON)
|
||||
* @return QueryResponse
|
||||
* @throws JSONException Throws when JSON is not formatted properly.
|
||||
*/
|
||||
public static QueryResponse fromJson(String jsonString) throws JSONException {
|
||||
return fromJson(new JSONObject(jsonString));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats response from https://funkemunky.cc/vpn/queryCheck into {@link QueryResponse} for project use.
|
||||
*
|
||||
* @param object JSONObject
|
||||
* @return QueryResponse
|
||||
* @throws JSONException Throws when JSON is not formatted properly.
|
||||
*/
|
||||
public static QueryResponse fromJson(JSONObject object) throws JSONException {
|
||||
boolean validPlan = object.getBoolean("validPlan");
|
||||
|
||||
if(!validPlan) { // Nothing else will be returned from API if validPlan is false.
|
||||
return QueryResponse.builder().validPlan(false).build();
|
||||
}
|
||||
|
||||
return QueryResponse.builder().validPlan(object.getBoolean("validPlan"))
|
||||
.planType(object.getString("planType"))
|
||||
.queries(object.getLong("queries"))
|
||||
.queriesMax(object.getLong("queryLimit")).build();
|
||||
}
|
||||
}
|
||||
+27
-29
@@ -1,13 +1,13 @@
|
||||
package dev.brighten.antivpn.utils;
|
||||
package dev.brighten.antivpn.web.objects;
|
||||
|
||||
import dev.brighten.antivpn.utils.json.JSONException;
|
||||
import dev.brighten.antivpn.utils.json.JSONObject;
|
||||
import lombok.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
@Builder
|
||||
public class VPNResponse {
|
||||
private String asn, ip, countryName, countryCode, city, timeZone, method, isp, failureReason = "N/A";
|
||||
@@ -29,34 +29,35 @@ public class VPNResponse {
|
||||
json.put("proxy", proxy);
|
||||
json.put("success", success);
|
||||
json.put("timeZone", timeZone);
|
||||
json.put("success", true);
|
||||
json.put("queriesLeft", queriesLeft);
|
||||
json.put("cached", cached);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Feeds into {@link VPNResponse#fromJson(JSONObject)} formatting the JSON {@link String} into
|
||||
* a {@link JSONObject}
|
||||
*
|
||||
* @param json String
|
||||
* @return VPNResponse
|
||||
*/
|
||||
public static VPNResponse fromJson(String json) throws JSONException {
|
||||
JSONObject jsonObject = new JSONObject(json);
|
||||
|
||||
if(jsonObject.getBoolean("success")) {
|
||||
return new VPNResponse(jsonObject.getString("asn"), jsonObject.getString("ip"),
|
||||
jsonObject.getString("countryName"), jsonObject.getString("countryCode"),
|
||||
jsonObject.getString("city"), jsonObject.getString("timeZone"),
|
||||
jsonObject.has("method") ? jsonObject.getString("method") : "N/A",
|
||||
jsonObject.getString("isp"), "N/A", jsonObject.getBoolean("proxy"),
|
||||
jsonObject.getBoolean("cached"), jsonObject.getBoolean("success"),
|
||||
jsonObject.getDouble("latitude"), jsonObject.getDouble("longitude"),
|
||||
jsonObject.getLong("lastAccess"), jsonObject.getInt("queriesLeft"));
|
||||
} else {
|
||||
VPNResponse response = new VPNResponse(false);
|
||||
|
||||
response.failureReason = jsonObject.getString("failureReason");
|
||||
|
||||
return response;
|
||||
}
|
||||
return fromJson(new JSONObject(json));
|
||||
}
|
||||
|
||||
public static final VPNResponse FAILED_RESPONSE = VPNResponse.builder()
|
||||
.success(false)
|
||||
.failureReason("Internal plugin API error.")
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Formats response from <a href="https://funkemunky.cc/vpn">...</a> into {@link VPNResponse} for project use.
|
||||
*
|
||||
* @param jsonObject JSONObject
|
||||
* @return VPNResponse
|
||||
* @throws JSONException Throws when JSON is not formatted properly.
|
||||
*/
|
||||
public static VPNResponse fromJson(JSONObject jsonObject) throws JSONException {
|
||||
if(jsonObject.getBoolean("success")) {
|
||||
return new VPNResponse(jsonObject.getString("asn"), jsonObject.getString("ip"),
|
||||
@@ -68,11 +69,8 @@ public class VPNResponse {
|
||||
jsonObject.getDouble("latitude"), jsonObject.getDouble("longitude"),
|
||||
jsonObject.getLong("lastAccess"), jsonObject.getInt("queriesLeft"));
|
||||
} else {
|
||||
VPNResponse response = new VPNResponse(false);
|
||||
|
||||
response.failureReason = jsonObject.getString("failureReason");
|
||||
|
||||
return response;
|
||||
return VPNResponse.builder().success(false)
|
||||
.failureReason(jsonObject.getString("failureReason")).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@ prefixWhitelists: []
|
||||
# Configure your database here.
|
||||
database:
|
||||
# Enable to cache queries and save alerts state beyond restarts
|
||||
enabled: false
|
||||
useCredentials: true
|
||||
enabled: true
|
||||
useCredentials: false
|
||||
#Options Mongo, MySQL, or H2
|
||||
type: H2
|
||||
# The database name you would like to use
|
||||
@@ -61,8 +61,16 @@ countries:
|
||||
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%"
|
||||
vanillaKickReason: |-
|
||||
&cSorry, but our server does not allow connections from
|
||||
&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
|
||||
# Here you can configure messages for KauriVPN.
|
||||
messages:
|
||||
command-misc-playerRequired: '&cYou must be a player to execute this command!'
|
||||
command-alerts-toggled: '&7Your player proxy notifications have been set to: &e%state%'
|
||||
command-reload-complete: '&aSuccessfully reloaded KauriVPN plugin!'
|
||||
no-permission: '&cNo permission.'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
[](https://sourcespy.com/github/funkemunkyantivpn/)
|
||||
|
||||
# AntiVPN
|
||||
An antivpn plugin utilizing the KauriVPN API
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.9.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>Sponge</artifactId>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sponge</id>
|
||||
<url>https://repo.spongepowered.org/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>spongeapi</artifactId>
|
||||
<version>8.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>Common</artifactId>
|
||||
<version>1.9.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,31 @@
|
||||
package dev.brighten.antivpn.sponge;
|
||||
|
||||
import dev.brighten.antivpn.api.APIPlayer;
|
||||
import dev.brighten.antivpn.sponge.util.StringUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
|
||||
|
||||
public class SpongePlayer extends APIPlayer {
|
||||
|
||||
private final ServerPlayer player;
|
||||
|
||||
public SpongePlayer(ServerPlayer player) {
|
||||
super(player.uniqueId(), player.name(), player.connection().address().getAddress());
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
//player.sendMessage(StringUtil.translateColorCodes('&', message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kickPlayer(String reason) {
|
||||
player.kick(Component.text(StringUtil.translateColorCodes('&', reason)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
return player.hasPermission(permission);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package dev.brighten.antivpn.sponge;
|
||||
|
||||
import dev.brighten.antivpn.api.APIPlayer;
|
||||
import dev.brighten.antivpn.api.PlayerExecutor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SpongePlayerExecutor implements PlayerExecutor {
|
||||
@Override
|
||||
public Optional<APIPlayer> getPlayer(String name) {
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<APIPlayer> getPlayer(UUID uuid) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadPlayer(UUID uuid) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<APIPlayer> getOnlinePlayers() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package dev.brighten.antivpn.sponge;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.spongepowered.api.Server;
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.lifecycle.StartedEngineEvent;
|
||||
import org.spongepowered.plugin.builtin.jvm.Plugin;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Plugin("kaurivpn")
|
||||
public class SpongePlugin {
|
||||
|
||||
public static SpongePlugin INSTANCE;
|
||||
//Plugin init
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Listener
|
||||
public void onServerStart(final StartedEngineEvent<Server> event) {
|
||||
INSTANCE = this;
|
||||
|
||||
logger.info("Starting AntiVPN services...");
|
||||
//Start AntiVPN
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package dev.brighten.antivpn.sponge.util;
|
||||
|
||||
public class StringUtil {
|
||||
|
||||
public static String translateColorCodes(char altColorChar, String textToTranslate) {
|
||||
char[] b = textToTranslate.toCharArray();
|
||||
|
||||
for(int i = 0; i < b.length - 1; ++i) {
|
||||
if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i + 1]) > -1) {
|
||||
b[i] = 167;
|
||||
b[i + 1] = Character.toLowerCase(b[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
return new String(b);
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.7.1</version>
|
||||
<version>1.9.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<dependency>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>Common</artifactId>
|
||||
<version>1.7.1</version>
|
||||
<version>1.9.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -67,6 +67,10 @@
|
||||
<!-- Replace this with your package! -->
|
||||
<shadedPattern>dev.brighten.antivpn.velocity.org.bstats</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.yaml.snakeyaml</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.shaded.org.yaml.snakeyaml</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<executions>
|
||||
|
||||
@@ -1,137 +1,160 @@
|
||||
package dev.brighten.antivpn.velocity;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.velocitypowered.api.event.ResultedEvent;
|
||||
import com.velocitypowered.api.event.connection.DisconnectEvent;
|
||||
import com.velocitypowered.api.event.connection.LoginEvent;
|
||||
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.api.APIPlayer;
|
||||
import dev.brighten.antivpn.api.VPNExecutor;
|
||||
import dev.brighten.antivpn.velocity.util.StringUtils;
|
||||
import dev.brighten.antivpn.web.objects.VPNResponse;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class VelocityListener extends VPNExecutor {
|
||||
|
||||
private ScheduledTask cacheResetTask;
|
||||
private final Cache<UUID, VPNResponse> responseCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.maximumSize(2000)
|
||||
.build();
|
||||
|
||||
|
||||
@Override
|
||||
public void registerListeners() {
|
||||
VelocityPlugin.INSTANCE.getServer().getEventManager()
|
||||
.register(VelocityPlugin.INSTANCE, this);
|
||||
|
||||
VelocityPlugin.INSTANCE.getServer().getEventManager().register(VelocityPlugin.INSTANCE, DisconnectEvent.class,
|
||||
event -> AntiVPN.getInstance().getPlayerExecutor().unloadPlayer(event.getPlayer().getUniqueId()));
|
||||
|
||||
VelocityPlugin.INSTANCE.getServer().getEventManager().register(VelocityPlugin.INSTANCE, LoginEvent.class,
|
||||
event -> {
|
||||
if(event.getResult().isAllowed()) {
|
||||
if(event.getPlayer().hasPermission("antivpn.bypass") //Has bypass permission
|
||||
//Is exempt
|
||||
|| AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId())
|
||||
//Or has a name that starts with a certain prefix. This is for Bedrock exempting.
|
||||
|| AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getRemoteAddress()
|
||||
.getAddress().getHostAddress())
|
||||
|| AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream()
|
||||
.anyMatch(prefix -> event.getPlayer().getUsername().startsWith(prefix))) return;
|
||||
if (event.getResult().isAllowed()) {
|
||||
if (event.getPlayer().hasPermission("antivpn.bypass") //Has bypass permission
|
||||
//Is exempt
|
||||
|| AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId())
|
||||
//Or has a name that starts with a certain prefix. This is for Bedrock exempting.
|
||||
|| AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getRemoteAddress()
|
||||
.getAddress().getHostAddress())
|
||||
|| AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream()
|
||||
.anyMatch(prefix -> event.getPlayer().getUsername().startsWith(prefix))) return;
|
||||
|
||||
checkIp(event.getPlayer().getRemoteAddress().getAddress().getHostAddress(),
|
||||
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())));
|
||||
if(responseCache.asMap().containsKey(event.getPlayer().getUniqueId())) {
|
||||
VPNResponse cached = responseCache.getIfPresent(event.getPlayer().getUniqueId());
|
||||
|
||||
//In case the user wants to run their own commands instead of using the
|
||||
// built in kicking
|
||||
if(AntiVPN.getInstance().getVpnConfig().runCommands()) {
|
||||
for (String command : AntiVPN.getInstance().getVpnConfig().commands()) {
|
||||
VelocityPlugin.INSTANCE.getServer().getCommandManager()
|
||||
.executeAsync(VelocityPlugin.INSTANCE.getServer()
|
||||
.getConsoleCommandSource(),
|
||||
StringUtils.translateAlternateColorCodes('&',
|
||||
command.replace("%player%",
|
||||
event.getPlayer().getUsername())));
|
||||
}
|
||||
}
|
||||
AntiVPN.getInstance().detections++;
|
||||
}
|
||||
} else {
|
||||
VelocityPlugin.INSTANCE.getLogger()
|
||||
.log(Level.WARNING,
|
||||
"The API query was not a success! " +
|
||||
"You may need to upgrade your license on " +
|
||||
"https://funkemunky.cc/shop");
|
||||
if (cached != null && cached.isProxy()) {
|
||||
event.setResult(ResultedEvent.ComponentResult.denied(LegacyComponentSerializer.builder()
|
||||
.character('&')
|
||||
.build().deserialize(AntiVPN.getInstance().getVpnConfig()
|
||||
.getKickString())));
|
||||
return;
|
||||
}
|
||||
AntiVPN.getInstance().checked++;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runCacheReset() {
|
||||
cacheResetTask = VelocityPlugin.INSTANCE.getServer().getScheduler()
|
||||
.buildTask(VelocityPlugin.INSTANCE, this::resetCache)
|
||||
.repeat(20, TimeUnit.MINUTES)
|
||||
.schedule();
|
||||
checkIp(event.getPlayer().getRemoteAddress().getAddress().getHostAddress(),
|
||||
AntiVPN.getInstance().getVpnConfig().cachedResults(), result -> {
|
||||
if (result.isSuccess()) {
|
||||
// If the countryList() size is zero, no need to check.
|
||||
// Running country check first
|
||||
if (!AntiVPN.getInstance().getVpnConfig().countryList().isEmpty()
|
||||
&& !(AntiVPN.getInstance().getExecutor()
|
||||
.isWhitelisted(event.getPlayer().getUniqueId()) //Is exempt
|
||||
//Or has a name that starts with a certain prefix. This is for Bedrock exempting.
|
||||
|| AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer()
|
||||
.getRemoteAddress().getAddress().getHostAddress()))
|
||||
// This bit of code will decide whether or not to kick the player
|
||||
// If it contains the code and it is set to whitelist, it will not kick
|
||||
// as they are equal and vise versa. However, if the contains does not match
|
||||
// the state, it will kick.
|
||||
&& AntiVPN.getInstance().getVpnConfig().countryList()
|
||||
.contains(result.getCountryCode())
|
||||
!= AntiVPN.getInstance().getVpnConfig().whitelistCountries()) {
|
||||
//Using our built in kicking system if no commands are configured
|
||||
if (AntiVPN.getInstance().getVpnConfig().countryKickCommands().isEmpty()) {
|
||||
final String kickReason = AntiVPN.getInstance().getVpnConfig()
|
||||
.countryVanillaKickReason();
|
||||
// Kicking our player
|
||||
event.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++;
|
||||
}
|
||||
} else {
|
||||
VelocityPlugin.INSTANCE.getLogger()
|
||||
.log(Level.WARNING,
|
||||
"The API query was not a success! " +
|
||||
"You may need to upgrade your license on " +
|
||||
"https://funkemunky.cc/shop");
|
||||
}
|
||||
AntiVPN.getInstance().checked++;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if(cacheResetTask != null) {
|
||||
if (cacheResetTask != null) {
|
||||
cacheResetTask.cancel();
|
||||
cacheResetTask = null;
|
||||
}
|
||||
@@ -139,8 +162,13 @@ public class VelocityListener extends VPNExecutor {
|
||||
VelocityPlugin.INSTANCE.getServer().getEventManager().unregisterListener(VelocityPlugin.INSTANCE, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, String log, Object... objects) {
|
||||
VelocityPlugin.INSTANCE.getLogger().log(level, String.format(log, objects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String log, Object... objects) {
|
||||
VelocityPlugin.INSTANCE.getLogger().log(Level.INFO, String.format(log, objects));
|
||||
log(Level.INFO, String.format(log, objects));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,14 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class VelocityPlayerExecutor implements PlayerExecutor {
|
||||
|
||||
private final Map<Player, VelocityPlayer> cachedPlayers = new WeakHashMap<>();
|
||||
private final Map<UUID, VelocityPlayer> cachedPlayers = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Optional<APIPlayer> getPlayer(String name) {
|
||||
Optional<Player> player = VelocityPlugin.INSTANCE.getServer().getPlayer(name);
|
||||
|
||||
return player.map(value -> cachedPlayers.computeIfAbsent(value, VelocityPlayer::new));
|
||||
return player.map(value -> cachedPlayers.computeIfAbsent(value.getUniqueId(),
|
||||
key -> new VelocityPlayer(value)));
|
||||
|
||||
}
|
||||
|
||||
@@ -23,13 +24,19 @@ public class VelocityPlayerExecutor implements PlayerExecutor {
|
||||
public Optional<APIPlayer> getPlayer(UUID uuid) {
|
||||
Optional<Player> player = VelocityPlugin.INSTANCE.getServer().getPlayer(uuid);
|
||||
|
||||
return player.map(value -> cachedPlayers.computeIfAbsent(value, VelocityPlayer::new));
|
||||
return player.map(value -> cachedPlayers.computeIfAbsent(value.getUniqueId(),
|
||||
key -> new VelocityPlayer(value)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadPlayer(UUID uuid) {
|
||||
cachedPlayers.remove(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<APIPlayer> getOnlinePlayers() {
|
||||
return VelocityPlugin.INSTANCE.getServer().getAllPlayers().stream()
|
||||
.map(pl -> cachedPlayers.computeIfAbsent(pl, VelocityPlayer::new))
|
||||
.map(pl -> cachedPlayers.computeIfAbsent(pl.getUniqueId(), key -> new VelocityPlayer(pl)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package dev.brighten.antivpn.velocity.command;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.command.SimpleCommand;
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.command.Command;
|
||||
import lombok.val;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@@ -11,6 +12,7 @@ import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class VelocityCommand implements SimpleCommand {
|
||||
@@ -26,8 +28,9 @@ public class VelocityCommand implements SimpleCommand {
|
||||
CommandSource sender = invocation.source();
|
||||
if(!invocation.source().hasPermission("antivpn.command.*")
|
||||
&& !invocation.source().hasPermission(command.permission())) {
|
||||
invocation.source().sendMessage(Component.text("No permission").toBuilder()
|
||||
.color(TextColor.color(255,0,0)).build());
|
||||
invocation.source().sendMessage(LegacyComponentSerializer.builder().character('&')
|
||||
.build().deserialize(AntiVPN.getInstance().getMessageHandler()
|
||||
.getString("no-permission").getMessage()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -40,6 +43,9 @@ public class VelocityCommand implements SimpleCommand {
|
||||
.anyMatch(alias -> alias.equalsIgnoreCase(args[0]))) {
|
||||
if(!sender.hasPermission("antivpn.command.*")
|
||||
&& !sender.hasPermission(child.permission())) {
|
||||
invocation.source().sendMessage(LegacyComponentSerializer.builder().character('&')
|
||||
.build().deserialize(AntiVPN.getInstance().getMessageHandler()
|
||||
.getString("no-permission").getMessage()));
|
||||
invocation.source().sendMessage(Component.text("No permission")
|
||||
.toBuilder().color(TextColor.color(255,0,0)).build());
|
||||
return;
|
||||
@@ -73,7 +79,10 @@ public class VelocityCommand implements SimpleCommand {
|
||||
.mapToObj(i -> args[i + 1]).toArray(String[]::new));
|
||||
}
|
||||
}
|
||||
}else if (children.length > 0){ // && args.length == 0 is always true here
|
||||
return Arrays.stream(children).map(Command::name).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return command.tabComplete(new VelocityCommandExecutor(sender), "alias", args);
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -16,8 +16,9 @@ public class VelocityCommandExecutor implements CommandExecutor {
|
||||
private final CommandSource sender;
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
sender.sendMessage(LegacyComponentSerializer.builder().character('&').build().deserialize(message));
|
||||
public void sendMessage(String message, Object... objects) {
|
||||
sender.sendMessage(LegacyComponentSerializer.builder().character('&').build()
|
||||
.deserialize(String.format(message, objects)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.7.1</version>
|
||||
<version>1.9.2</version>
|
||||
|
||||
<modules>
|
||||
<module>Common</module>
|
||||
@@ -15,6 +15,7 @@
|
||||
<module>Bukkit</module>
|
||||
<module>Assembly</module>
|
||||
<module>Velocity</module>
|
||||
<module>Sponge</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
||||
Reference in New Issue
Block a user