Compare commits

...

41 Commits

Author SHA1 Message Date
Dawson Hessler 96e48594d8 Fixing velocity loading issues 2023-07-12 08:45:39 -04:00
Dawson Hessler c1ab71c7ed Merge branch 'master' of https://github.com/funkemunky/AntiVPN 2023-07-06 20:26:07 -04:00
Dawson Hessler 4bda24f10c Bump to 1.9.0 2023-07-06 20:26:02 -04:00
Dawson 259cff4402 Merge pull request #32 from AlexProgrammerDE/patch-1
Remove unused import
2023-07-06 20:15:51 -04:00
Dawson Hessler c54e90dca1 Removing usages of System.out.print 2023-07-06 20:13:47 -04:00
Alex 4f1e3848de Remove unused import 2023-07-04 17:30:39 +02:00
Dawson 1606ad192e Working on spongepowered version of plugin 2023-05-25 10:24:42 -04:00
Dawson Hessler 40308869c0 1.8.4 Added cache for logins for faster response 2023-05-23 08:09:41 -04:00
Dawson Hessler 6959f35d0c Fixing whitelist issues in bukkit and bungee 2023-04-18 06:45:28 -04:00
Dawson Hessler 21b6924cce Fixing error with inserted type mismatch in H2 and MySQL 2023-04-18 06:42:07 -04:00
Dawson Hessler 9c843cd061 Updating to 1.8.3.1
Turns out we accidentally already used the 1.8.3 version
2023-03-13 15:08:04 -04:00
Dawson Hessler 91a09f6940 Updating version to 1.8.3 2023-03-13 15:04:14 -04:00
Dawson Hessler 36b44200c4 Adding response expiry since I just realized it never expires 2023-03-13 15:00:39 -04:00
Dawson e6bc601372 Fixing compile bug 2023-02-28 14:31:40 -05:00
Dawson 9dbf0e8635 Merge branch 'master' of https://github.com/funkemunky/AntiVPN 2022-11-02 10:39:50 -04:00
Dawson dd1b6afbb7 Working on adding sponge support 2022-11-02 10:39:48 -04:00
Dawson Hessler 14e266b978 Fixing load issue with snakeyaml on 1.12+ servers 2022-09-02 09:34:47 -04:00
Dawson Hessler cc289f41ff Instead of deleting old files, make new one 2022-08-29 07:34:53 -04:00
Dawson Hessler bf5b81b750 1.8.2.1, fixed H2 and removed debug 2022-08-29 07:19:42 -04:00
Dawson a480f13302 Merge pull request #26 from funkemunky/reload-commmand
Shrunk jar file size, fixed errors, added database reload
2022-08-28 13:18:09 -04:00
Dawson Hessler 4a95b51350 Replaced incorrect SQLLite messaging with H2 2022-08-28 13:17:30 -04:00
Dawson Hessler 9dc312186b Shrunk jar file size, fixed errors, added database reload
- Fixed H2 database error on index creation when loading plugin by using dynamic library downloader/loader from Lucko's Helper.
- Shrunk jar file size extensively so it can be uploaded to Spigot directly.
- Updated h2database driver to 2.1.214 to patch vulnerability
- Updated mysql database driver to 8.0.30 to patch vulnerability
- Updated MongoDB java driver to 3.12.11.
2022-08-28 13:14:13 -04:00
Dawson 3f9a2100a9 Merge pull request #25 from funkemunky/reload-commmand
New /antivpn reload and Message Configuration
2022-08-28 12:14:35 -04:00
Dawson Hessler 4c82755935 Adding comment and added some default messages to help formatting on generation 2022-08-28 12:13:57 -04:00
Dawson Hessler 0048cf6b8c 1.8.2 2022-08-28 12:12:24 -04:00
Dawson Hessler 795c869fc0 Fixed reloading and adding of messages into config 2022-08-28 12:11:41 -04:00
Dawson Hessler 95a00a4d0a Adding ability to configure "no permission" message 2022-08-28 11:53:46 -04:00
Dawson Hessler a6f26d4ba7 Merge branch 'master' into reload-commmand 2022-08-28 11:42:58 -04:00
Dawson 7a0786e29f Shit 2022-08-24 11:43:29 -04:00
Dawson df4a14086b Updating workflow
- Now uploading alpha jars on workflow.
- Caching depends to make it run faster
2022-08-19 11:12:34 -04:00
Dawson f55fa88c2b Merge pull request #24 from funkemunky/dependabot/maven/Common/mysql-mysql-connector-java-8.0.28
Bump mysql-connector-java from 8.0.27 to 8.0.28 in /Common
2022-08-19 11:10:29 -04:00
Dawson 4f79522010 Fixing memory leak 2022-08-19 11:09:52 -04:00
Dawson Hessler 7654cca651 Adding reload command 2022-08-05 14:14:42 -04:00
Dawson Hessler e01cbf95f2 Fixing whitelist ip and uuid checking 2022-07-10 12:59:45 -04:00
Dawson Hessler db49d400a0 Fixing whitelist checking for users 2022-07-10 12:57:05 -04:00
dependabot[bot] b39cc3e19c Bump mysql-connector-java from 8.0.27 to 8.0.28 in /Common
Bumps [mysql-connector-java](https://github.com/mysql/mysql-connector-j) from 8.0.27 to 8.0.28.
- [Release notes](https://github.com/mysql/mysql-connector-j/releases)
- [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES)
- [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.27...8.0.28)

---
updated-dependencies:
- dependency-name: mysql:mysql-connector-java
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-21 04:21:04 +00:00
Dawson ff25c75055 Update .gitignore 2022-06-17 13:05:52 -04:00
Dawson 733e797a17 Implemented /kaurivpn plan 2022-06-06 10:15:40 -04:00
Dawson 0c903794e5 Cleaning up, adding QueryResponse
- Putting API classes under its own package.
- Moved API calls from AntiVPN into new FunkemunkyAPI class.
- Added QueryResponse object and FunkemunkyAPI#getQueryResponse get grab plan information.
2022-06-06 09:32:48 -04:00
Dawson bddf26359d 1.7.1.1 2022-06-05 08:45:52 -04:00
funkemunky 4424b2b9a5 Fixing multiple bugs
- Fixes /antivpn alerts error caused by VpnStrings not being initialized. All of that initialized is now done globally inside AntiVPN class instead of individually per platform.
- Fixed bug where MySQL will only load H2.
- H2 is now a separate object and will not create an sql error on startup from the index creation process.
2022-04-11 12:58:43 -04:00
61 changed files with 3094 additions and 343 deletions
+10 -1
View File
@@ -13,8 +13,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
+3
View File
@@ -13,6 +13,9 @@ local.properties
.settings/
.loadpath
.recommenders
*.iml
.idea/
# External tool builders
.externalToolBuilders/
+4 -17
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.7.1</version>
<version>1.9.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Assembly</artifactId>
@@ -19,27 +19,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>
+4 -17
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.7.1</version>
<version>1.9.1</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>
+20 -34
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.7.1</version>
<version>1.9.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Bukkit</artifactId>
@@ -26,23 +26,32 @@
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<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>
<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>
<configuration>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>dev.brighten.antivpn.bukkit.org.bstats</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
</plugins>
</build>
@@ -56,30 +65,8 @@
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Common</artifactId>
<version>1.7.1</version>
<version>1.9.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>
@@ -93,4 +80,3 @@
<maven.compiler.source>8</maven.compiler.source>
</properties>
</project>
+21 -12
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.7.1</version>
<version>1.9.1</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.1</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,9 +1,12 @@
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;
@@ -12,14 +15,22 @@ 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.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
public class BukkitListener extends VPNExecutor implements Listener {
private BukkitTask cacheResetTask;
private final Cache<UUID, VPNResponse> responseCache = CacheBuilder.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.maximumSize(10000)
.build();
@Override
public void registerListeners() {
BukkitPlugin.pluginInstance.getServer().getPluginManager()
@@ -28,11 +39,12 @@ public class BukkitListener extends VPNExecutor implements Listener {
@Override
public void runCacheReset() {
// Reset cache every 20 minutes
cacheResetTask = new BukkitRunnable() {
public void run() {
resetCache();
}
}.runTaskTimerAsynchronously(BukkitPlugin.pluginInstance, 24000, 24000); //Reset cache every 20 minutes
}.runTaskTimerAsynchronously(BukkitPlugin.pluginInstance, 24000, 24000);
HandlerList.unregisterAll(this);
threadExecutor.shutdown();
@@ -43,9 +55,14 @@ public class BukkitListener extends VPNExecutor implements Listener {
if(cacheResetTask != null && !cacheResetTask.isCancelled()) cacheResetTask.cancel();
}
@Override
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 +91,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,6 +110,21 @@ 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
if(AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getAddress().getAddress()
.getHostAddress())) {
log("IP is whitelisted: %s",
event.getPlayer().getAddress().getAddress().getHostAddress());
return;
}
// If the countryList() size is zero, no need to check.
// Running country check first
if(AntiVPN.getInstance().getVpnConfig().countryList().size() > 0
@@ -116,7 +160,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 +187,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;
}
+12 -16
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.7.1</version>
<version>1.9.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Bungee</artifactId>
@@ -41,6 +41,14 @@
<pattern>org.bstats</pattern>
<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>
</plugin>
@@ -50,28 +58,16 @@
<dependency>
<groupId>dev.brighten.antivpn</groupId>
<artifactId>Common</artifactId>
<version>1.7.1</version>
<version>1.9.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>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
</dependency>
+10 -2
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.7.1</version>
<version>1.9.1</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.1</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,6 +24,11 @@ public class BungeeListener extends VPNExecutor implements Listener {
private ScheduledTask cacheResetTask;
private final Cache<UUID, VPNResponse> responseCache = CacheBuilder.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.maximumSize(10000)
.build();
@Override
public void registerListeners() {
BungeePlugin.pluginInstance.getProxy().getPluginManager()
@@ -41,25 +52,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 +171,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,5 +1,6 @@
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;
@@ -14,9 +15,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 +26,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 +39,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
+38 -13
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.7.1</version>
<version>1.9.1</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>
@@ -45,24 +71,18 @@
</repositories>
<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>
<version>8.0.30</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.1.214</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
@@ -70,11 +90,16 @@
<version>1.30</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.10</version>
<scope>compile</scope>
<version>3.12.11</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.1.214")
@MavenLibrary(groupId = "org.mongodb", artifactId = "mongo-java-driver", version = "3.12.11")
@MavenLibrary(groupId = "mysql", artifactId = "mysql-connector-java", version = "8.0.30")
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();
}
@@ -2,8 +2,9 @@ package dev.brighten.antivpn.api;
import dev.brighten.antivpn.AntiVPN;
import dev.brighten.antivpn.utils.EvictingMap;
import dev.brighten.antivpn.utils.VPNResponse;
import dev.brighten.antivpn.web.objects.VPNResponse;
import dev.brighten.antivpn.utils.json.JSONException;
import dev.brighten.antivpn.web.FunkemunkyAPI;
import lombok.Getter;
import java.io.IOException;
@@ -11,6 +12,7 @@ import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
import java.util.logging.Level;
public abstract class VPNExecutor {
public static ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
@@ -31,13 +33,21 @@ public abstract class VPNExecutor {
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);
}
@@ -49,7 +59,7 @@ public abstract class VPNExecutor {
if(cachedRes.isPresent()) return cachedRes.get();
else {
try {
VPNResponse response = AntiVPN
VPNResponse response = FunkemunkyAPI
.getVPNResponse(ip, AntiVPN.getInstance().getVpnConfig().getLicense(), cachedResults);
if(response.isSuccess()) {
@@ -78,7 +88,7 @@ public abstract class VPNExecutor {
if(cachedRes.isPresent()) return cachedRes.get();
else {
try {
VPNResponse response = AntiVPN
VPNResponse response = FunkemunkyAPI
.getVPNResponse(ip, AntiVPN.getInstance().getVpnConfig().getLicense(), cachedResults);
if(response.isSuccess()) {
@@ -2,11 +2,12 @@ package dev.brighten.antivpn.command;
import dev.brighten.antivpn.api.APIPlayer;
import java.util.Objects;
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
@@ -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,73 @@
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.database.local.H2VPN;
import dev.brighten.antivpn.database.mongo.MongoVPN;
import dev.brighten.antivpn.database.sql.MySqlVPN;
import dev.brighten.antivpn.message.VpnString;
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();
// Clearing the local response cache
VPNExecutor.responseCache.clear();
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,290 @@
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 {
private Thread whitelistedThread;
public H2VPN() {
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();
}
}
});
whitelistedThread.start();
}
@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,13 +7,16 @@ 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 {
@@ -27,6 +30,13 @@ public class MongoVPN implements VPNDatabase {
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 +49,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 +71,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 +104,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 +118,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"),
@@ -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;
@@ -52,7 +52,7 @@ public class MySqlVPN implements VPNDatabase {
@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 +65,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 +92,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 +104,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 +126,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 +137,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 +153,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 +256,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 +347,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 (https://github.com/slimjar/slimjar)
*/
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,378 @@
/*
* 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 static java.util.Objects.requireNonNull;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import static dev.brighten.antivpn.utils.Preconditions.checkArgument;
import static dev.brighten.antivpn.utils.Preconditions.checkNotNull;
import static dev.brighten.antivpn.utils.NullnessCasts.uncheckedCastNullableTToT;
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()";
}
}
}
@@ -0,0 +1,59 @@
package dev.brighten.antivpn.web;
import dev.brighten.antivpn.web.objects.QueryResponse;
import dev.brighten.antivpn.web.objects.VPNResponse;
import dev.brighten.antivpn.utils.json.JSONException;
import dev.brighten.antivpn.utils.json.JSONObject;
import dev.brighten.antivpn.utils.json.JsonReader;
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();
}
}
@@ -1,13 +1,11 @@
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.*;
@Getter
@Setter
@Data
@AllArgsConstructor
@RequiredArgsConstructor
@Builder
public class VPNResponse {
private String asn, ip, countryName, countryCode, city, timeZone, method, isp, failureReason = "N/A";
@@ -29,34 +27,31 @@ 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
* @throws JSONException
*/
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));
}
/**
* Formats response from https://funkemunky.cc/vpn 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 +63,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();
}
}
}
+11 -3
View File
@@ -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.'
+41
View File
@@ -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.1</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.1</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
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>AntiVPN</artifactId>
<groupId>dev.brighten.antivpn</groupId>
<version>1.7.1</version>
<version>1.9.1</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.1</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,124 +1,155 @@
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(10000)
.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++;
});
}
});
}
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
&& !(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().size() == 0) {
final String kickReason = AntiVPN.getInstance().getVpnConfig()
.countryVanillaKickReason();
// Kicking our player
event.getPlayer().disconnect(LegacyComponentSerializer.builder().character('&')
.build().deserialize(kickReason
.replace("%player%", event.getPlayer().getUsername())
.replace("%country%", result.getCountryName())
.replace("%code%", result.getCountryCode())));
} else {
for (String cmd : AntiVPN.getInstance().getVpnConfig().countryKickCommands()) {
final String formattedCommand = StringUtils
.translateAlternateColorCodes('&',
cmd.replace("%player%",
event.getPlayer().getUsername())
.replace("%country%", result.getCountryName())
.replace("%code%", result.getCountryCode()));
// Running the command from console
VelocityPlugin.INSTANCE.getServer().getCommandManager()
.executeAsync(VelocityPlugin.INSTANCE.getServer()
.getConsoleCommandSource(),
StringUtils.translateAlternateColorCodes('&',
formattedCommand));
}
}
} else if (result.isProxy()) {
if (AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect())
event.getPlayer().disconnect(LegacyComponentSerializer.builder().character('&')
.build().deserialize(AntiVPN.getInstance().getVpnConfig()
.getKickString()));
VelocityPlugin.INSTANCE.getLogger().info(event.getPlayer().getUsername()
+ " joined on a VPN/Proxy (" + result.getMethod() + ")");
//Ensuring the user wishes to alert to staff
if (AntiVPN.getInstance().getVpnConfig().alertToStaff())
AntiVPN.getInstance().getPlayerExecutor().getOnlinePlayers().stream()
.filter(APIPlayer::isAlertsEnabled)
.forEach(pl ->
pl.sendMessage(AntiVPN.getInstance().getVpnConfig()
.alertMessage()
.replace("%player%",
event.getPlayer().getUsername())
.replace("%reason%",
result.getMethod())
.replace("%country%",
result.getCountryName())
.replace("%city%",
result.getCity())));
//In case the user wants to run their own commands instead of using the
// built in kicking
if (AntiVPN.getInstance().getVpnConfig().runCommands()) {
for (String command : AntiVPN.getInstance().getVpnConfig().commands()) {
VelocityPlugin.INSTANCE.getServer().getCommandManager()
.executeAsync(VelocityPlugin.INSTANCE.getServer()
.getConsoleCommandSource(),
StringUtils.translateAlternateColorCodes('&',
command.replace("%player%",
event.getPlayer().getUsername())));
}
}
AntiVPN.getInstance().detections++;
}
} 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
@@ -131,7 +162,7 @@ public class VelocityListener extends VPNExecutor {
@Override
public void shutdown() {
if(cacheResetTask != null) {
if (cacheResetTask != null) {
cacheResetTask.cancel();
cacheResetTask = null;
}
@@ -139,8 +170,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;
@@ -26,8 +27,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 +42,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;
@@ -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
+2 -1
View File
@@ -7,7 +7,7 @@
<groupId>dev.brighten.antivpn</groupId>
<artifactId>AntiVPN</artifactId>
<packaging>pom</packaging>
<version>1.7.1</version>
<version>1.9.1</version>
<modules>
<module>Common</module>
@@ -15,6 +15,7 @@
<module>Bukkit</module>
<module>Assembly</module>
<module>Velocity</module>
<module>Sponge</module>
</modules>
<properties>