mirror of
https://github.com/funkemunky/AntiVPN.git
synced 2026-05-31 17:31:55 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 353b7dad78 | |||
| 0291aca052 | |||
| ae5893be89 | |||
| f9ed53bfec | |||
| cb32dfc370 | |||
| 4c7ff3d061 | |||
| aec0bb2738 | |||
| 3f5ab39877 | |||
| f2e59c0075 | |||
| a01b595953 | |||
| b2fcc4ff26 | |||
| 5363b7c469 | |||
| df48e3dfd4 | |||
| 0686c5fd3e | |||
| 5b6d214e6f |
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report that will allow us to fix any unexpected behavior
|
||||
title: "[BUG]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**What instance are you running KauriVPN on?**
|
||||
*Put an 'x' in the brackets to check it*
|
||||
- [ ] Velocity
|
||||
- [ ] Bukkit/Spigot
|
||||
- [ ] Bungeecord
|
||||
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea you would like added
|
||||
title: "[FEATURE] "
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -3,29 +3,26 @@ on:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 17.0.2
|
||||
uses: actions/setup-java@v1
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17.0
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
distribution: 'zulu'
|
||||
cache: 'maven'
|
||||
- name: Compile
|
||||
run: mvn -B -Pclean install
|
||||
run: mvn -B package --file pom.xml
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload AntiVPN
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AntiVPN
|
||||
path: Assembly/target/Assembly-*.jar
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.9.2</version>
|
||||
<version>1.9.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
+5
-5
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.9.2</version>
|
||||
<version>1.9.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -70,15 +70,15 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.github.spigot</groupId>
|
||||
<artifactId>1.13.2</artifactId>
|
||||
<version>1.13.2</version>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.20.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>Common</artifactId>
|
||||
<version>1.9.2</version>
|
||||
<version>1.9.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class BukkitListener extends VPNExecutor implements Listener {
|
||||
private final Cache<UUID, VPNResponse> responseCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
@@ -50,20 +51,22 @@ public class BukkitListener extends VPNExecutor implements Listener {
|
||||
log(Level.INFO, String.format(log, objects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logException(String message, Exception ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, message, ex);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(final PlayerJoinEvent event) {
|
||||
AntiVPN.getInstance().getPlayerExecutor().getPlayer(event.getPlayer().getUniqueId())
|
||||
.ifPresent(player -> {
|
||||
AntiVPN.getInstance().getDatabase().alertsState(player.getUuid(), enabled -> {
|
||||
if(enabled) {
|
||||
AntiVPN.getInstance().getExecutor().log("Enabled");
|
||||
player.setAlertsEnabled(true);
|
||||
player.sendMessage(AntiVPN.getInstance().getMessageHandler()
|
||||
.getString("command-alerts-toggled")
|
||||
.getFormattedMessage(new VpnString.Var<>("state", true)));
|
||||
} else AntiVPN.getInstance().getExecutor().log("Not enabled");
|
||||
});
|
||||
});
|
||||
.ifPresent(player -> AntiVPN.getInstance().getDatabase().alertsState(player.getUuid(), enabled -> {
|
||||
if(enabled) {
|
||||
player.setAlertsEnabled(true);
|
||||
player.sendMessage(AntiVPN.getInstance().getMessageHandler()
|
||||
.getString("command-alerts-toggled")
|
||||
.getFormattedMessage(new VpnString.Var<>("state", true)));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -76,7 +79,6 @@ 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());
|
||||
|
||||
@@ -93,88 +95,126 @@ public class BukkitListener extends VPNExecutor implements Listener {
|
||||
AntiVPN.getInstance().getVpnConfig().cachedResults(), result -> {
|
||||
if(result.isSuccess()) {
|
||||
//We need to run on main thread or kicking and running commands will cause errors
|
||||
new BukkitRunnable() {
|
||||
public void run() {
|
||||
//If the player is whitelisted, we don't want to kick them
|
||||
if(AntiVPN.getInstance().getExecutor().isWhitelisted(event.getPlayer().getUniqueId())) {
|
||||
log("UUID is whitelisted: %s",
|
||||
event.getPlayer().getUniqueId().toString());
|
||||
return;
|
||||
}
|
||||
{
|
||||
//If the IP is whitelisted, we don't want to kick them
|
||||
InetSocketAddress address = event.getPlayer().getAddress();
|
||||
if (address != null){
|
||||
InetAddress address1 = address.getAddress();
|
||||
if (address1 != null && AntiVPN.getInstance().getExecutor().isWhitelisted(address1.getHostAddress())) {
|
||||
log("IP is whitelisted: %s",
|
||||
address1.getHostAddress());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
//If the 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 countryList() size is zero, no need to check.
|
||||
// Running country check first
|
||||
if(!AntiVPN.getInstance().getVpnConfig().countryList().isEmpty()
|
||||
// This bit of code will decide whether or not to kick the player
|
||||
// If it contains the code and it is set to whitelist, it will not kick as they are equal
|
||||
// and vise versa. However, if the contains does not match the state, it will kick.
|
||||
&& AntiVPN.getInstance().getVpnConfig().countryList()
|
||||
.contains(result.getCountryCode())
|
||||
!= AntiVPN.getInstance().getVpnConfig().whitelistCountries()) {
|
||||
//Using our built in kicking system if no commands are configured
|
||||
if(AntiVPN.getInstance().getVpnConfig().countryKickCommands().isEmpty()) {
|
||||
final String kickReason = AntiVPN.getInstance().getVpnConfig()
|
||||
.countryVanillaKickReason();
|
||||
// Kicking our player
|
||||
//If the IP is whitelisted, we don't want to kick them
|
||||
InetSocketAddress address = event.getPlayer().getAddress();
|
||||
if (address != null){
|
||||
InetAddress address1 = address.getAddress();
|
||||
if (address1 != null && AntiVPN.getInstance().getExecutor()
|
||||
.isWhitelisted(address1.getHostAddress())) {
|
||||
log("IP is whitelisted: %s",
|
||||
address1.getHostAddress());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the countryList() size is zero, no need to check.
|
||||
// Running country check first
|
||||
if(!AntiVPN.getInstance().getVpnConfig().countryList().isEmpty()
|
||||
// This bit of code will decide whether or not to kick the player
|
||||
// If it contains the code and it is set to whitelist, it will not kick as they are equal
|
||||
// and vise versa. However, if the contains does not match the state, it will kick.
|
||||
&& AntiVPN.getInstance().getVpnConfig().countryList()
|
||||
.contains(result.getCountryCode())
|
||||
!= AntiVPN.getInstance().getVpnConfig().whitelistCountries()) {
|
||||
final String kickReason = AntiVPN.getInstance().getVpnConfig()
|
||||
.countryVanillaKickReason();
|
||||
|
||||
// Start "online" fix
|
||||
// In case the response was so fast from API the player wouldn't be "online".
|
||||
event.setResult(PlayerLoginEvent.Result.KICK_BANNED);
|
||||
event.setKickMessage(ChatColor
|
||||
.translateAlternateColorCodes('&',
|
||||
kickReason
|
||||
.replace("%player%", event.getPlayer().getName())
|
||||
.replace("%country%", result.getCountryName())
|
||||
.replace("%code%", result.getCountryCode())));
|
||||
// End "online" fix
|
||||
|
||||
//Using our built in kicking system if no commands are configured
|
||||
if(AntiVPN.getInstance().getVpnConfig().countryKickCommands().isEmpty()) {
|
||||
// Kicking our player
|
||||
new BukkitRunnable() {
|
||||
public void run() {
|
||||
event.getPlayer().kickPlayer(ChatColor
|
||||
.translateAlternateColorCodes('&',
|
||||
kickReason
|
||||
.replace("%player%", event.getPlayer().getName())
|
||||
.replace("%country%", result.getCountryName())
|
||||
.replace("%code%", result.getCountryCode())));
|
||||
} else {
|
||||
for (String cmd : AntiVPN.getInstance().getVpnConfig().countryKickCommands()) {
|
||||
final String formattedCommand = ChatColor.translateAlternateColorCodes('&',
|
||||
cmd.replace("%player%", event.getPlayer().getName())
|
||||
.replace("%country%", result.getCountryName())
|
||||
.replace("%code%", result.getCountryCode()));
|
||||
|
||||
// Runs our command from console
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), formattedCommand);
|
||||
}
|
||||
}
|
||||
} else if(result.isProxy()) {
|
||||
if(AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect())
|
||||
}.runTask(BukkitPlugin.pluginInstance);
|
||||
} else {
|
||||
final String playerName = event.getPlayer().getName();
|
||||
|
||||
BukkitPlugin.pluginInstance.getPlayerCommandRunner()
|
||||
.addAction(event.getPlayer().getUniqueId(), () -> {
|
||||
for (String cmd : AntiVPN.getInstance().getVpnConfig().countryKickCommands()) {
|
||||
final String formattedCommand = ChatColor.translateAlternateColorCodes('&',
|
||||
cmd.replace("%player%", playerName)
|
||||
.replace("%country%", result.getCountryName())
|
||||
.replace("%code%", result.getCountryCode()));
|
||||
|
||||
// Runs our command from console
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), formattedCommand);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if(result.isProxy()) {
|
||||
|
||||
// Start "online" fix
|
||||
// In case the response was so fast from API the player wouldn't be "online".
|
||||
event.setResult(PlayerLoginEvent.Result.KICK_BANNED);
|
||||
event.setKickMessage(ChatColor
|
||||
.translateAlternateColorCodes('&',
|
||||
AntiVPN.getInstance().getVpnConfig().getKickString()
|
||||
.replace("%player%", event.getPlayer().getName())
|
||||
.replace("%country%", result.getCountryName())
|
||||
.replace("%code%", result.getCountryCode())));
|
||||
// End "online" fix
|
||||
|
||||
if(AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) {
|
||||
new BukkitRunnable() {
|
||||
public void run() {
|
||||
player.kickPlayer(org.bukkit.ChatColor.translateAlternateColorCodes('&',
|
||||
AntiVPN.getInstance().getVpnConfig().getKickString()));
|
||||
log(Level.INFO, event.getPlayer().getName()
|
||||
+ " 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().getName())
|
||||
.replace("%reason%", result.getMethod())
|
||||
.replace("%country%", result.getCountryName())
|
||||
.replace("%city%", result.getCity())));
|
||||
|
||||
//In case the user wants to run their own commands instead of using the built in kicking
|
||||
if(AntiVPN.getInstance().getVpnConfig().runCommands()) {
|
||||
for (String command : AntiVPN.getInstance().getVpnConfig().commands()) {
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
|
||||
ChatColor.translateAlternateColorCodes('&',
|
||||
command.replace("%player%",
|
||||
event.getPlayer().getName())));
|
||||
}
|
||||
}
|
||||
AntiVPN.getInstance().detections++;
|
||||
}
|
||||
}.runTask(BukkitPlugin.pluginInstance);
|
||||
}
|
||||
}.runTask(BukkitPlugin.pluginInstance);
|
||||
log(Level.INFO, event.getPlayer().getName()
|
||||
+ " 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().getName())
|
||||
.replace("%reason%", result.getMethod())
|
||||
.replace("%country%", result.getCountryName())
|
||||
.replace("%city%", result.getCity())));
|
||||
|
||||
//In case the user wants to run their own commands instead of using the built in kicking
|
||||
if(AntiVPN.getInstance().getVpnConfig().runCommands()) {
|
||||
String playerName = event.getPlayer().getName();
|
||||
BukkitPlugin.pluginInstance.getPlayerCommandRunner()
|
||||
.addAction(event.getPlayer().getUniqueId(), () -> {
|
||||
for (String command : AntiVPN.getInstance().getVpnConfig().commands()) {
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
|
||||
ChatColor.translateAlternateColorCodes('&',
|
||||
command.replace("%player%",
|
||||
playerName)));
|
||||
}
|
||||
});
|
||||
}
|
||||
AntiVPN.getInstance().detections++;
|
||||
}
|
||||
} else {
|
||||
log(Level.WARNING,
|
||||
"The API query was not a success! " +
|
||||
|
||||
@@ -3,6 +3,7 @@ package dev.brighten.antivpn.bukkit;
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.bukkit.command.BukkitCommand;
|
||||
import dev.brighten.antivpn.command.Command;
|
||||
import lombok.Getter;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -21,8 +22,12 @@ public class BukkitPlugin extends JavaPlugin {
|
||||
|
||||
public static BukkitPlugin pluginInstance;
|
||||
private SimpleCommandMap commandMap;
|
||||
private List<org.bukkit.command.Command> registeredCommands = new ArrayList<>();
|
||||
private final List<org.bukkit.command.Command> registeredCommands = new ArrayList<>();
|
||||
|
||||
@Getter
|
||||
private SingleLineChart vpnDetections, ipsChecked;
|
||||
@Getter
|
||||
private PlayerCommandRunner playerCommandRunner;
|
||||
|
||||
public void onEnable() {
|
||||
pluginInstance = this;
|
||||
@@ -30,6 +35,9 @@ public class BukkitPlugin extends JavaPlugin {
|
||||
Bukkit.getLogger().info("Starting AntiVPN services...");
|
||||
AntiVPN.start(new BukkitListener(), new BukkitPlayerExecutor(), getDataFolder());
|
||||
|
||||
playerCommandRunner = new PlayerCommandRunner();
|
||||
playerCommandRunner.start();
|
||||
|
||||
// Loading our bStats metrics to be pushed to https://bstats.org
|
||||
if(AntiVPN.getInstance().getVpnConfig().metrics()) {
|
||||
Bukkit.getLogger().info("Starting bStats metrics...");
|
||||
@@ -84,6 +92,7 @@ public class BukkitPlugin extends JavaPlugin {
|
||||
public void onDisable() {
|
||||
Bukkit.getLogger().info("Stopping plugin services...");
|
||||
AntiVPN.getInstance().stop();
|
||||
playerCommandRunner.stop();
|
||||
|
||||
Bukkit.getLogger().info("Unregistering commands...");
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package dev.brighten.antivpn.bukkit;
|
||||
|
||||
import dev.brighten.antivpn.utils.MiscUtils;
|
||||
import lombok.Data;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class PlayerCommandRunner {
|
||||
private final ScheduledExecutorService executorService;
|
||||
private final Queue<PlayerAction> playerActions = new ArrayBlockingQueue<>(10000);
|
||||
|
||||
public PlayerCommandRunner() {
|
||||
executorService = Executors.newSingleThreadScheduledExecutor(
|
||||
MiscUtils.createThreadFactory("AntiVPN:PlayerCommandRunner")
|
||||
);
|
||||
}
|
||||
|
||||
void start() {
|
||||
executorService.scheduleAtFixedRate(() -> {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
while(!playerActions.isEmpty()) {
|
||||
PlayerAction action = playerActions.peek();
|
||||
|
||||
if(action == null) continue;
|
||||
|
||||
if(currentTime - action.start > 2000L || Bukkit.getPlayer(action.getUuid()) != null) {
|
||||
new BukkitRunnable() {
|
||||
public void run() {
|
||||
action.getAction().run();
|
||||
}
|
||||
}.runTask(BukkitPlugin.pluginInstance);
|
||||
|
||||
playerActions.poll();
|
||||
}
|
||||
}
|
||||
}, 1000, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
void stop() {
|
||||
executorService.shutdown();
|
||||
playerActions.clear();
|
||||
}
|
||||
|
||||
void addAction(UUID uuid, Runnable action) {
|
||||
playerActions.add(new PlayerAction(uuid, System.currentTimeMillis(), action));
|
||||
}
|
||||
|
||||
@Data
|
||||
static class PlayerAction {
|
||||
private final UUID uuid;
|
||||
private final long start;
|
||||
private final Runnable action;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.9.2</version>
|
||||
<version>1.9.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<dependency>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>Common</artifactId>
|
||||
<version>1.9.2</version>
|
||||
<version>1.9.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -15,6 +15,7 @@ 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 net.md_5.bungee.event.EventPriority;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -55,7 +56,12 @@ public class BungeeListener extends VPNExecutor implements Listener {
|
||||
log(Level.INFO, String.format(log, objects));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@Override
|
||||
public void logException(String message, Exception ex) {
|
||||
BungeeCord.getInstance().getLogger().log(Level.SEVERE, message, ex);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onListener(final PreLoginEvent event) {
|
||||
if(!responseCache.asMap().containsKey(event.getConnection().getUniqueId())) return;
|
||||
|
||||
@@ -72,7 +78,7 @@ public class BungeeListener extends VPNExecutor implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onListener(final PostLoginEvent event) {
|
||||
if(event.getPlayer().hasPermission("antivpn.bypass") //Has bypass permission
|
||||
|| AntiVPN.getInstance().getVpnConfig().getPrefixWhitelists().stream()
|
||||
@@ -98,14 +104,14 @@ public class BungeeListener extends VPNExecutor implements Listener {
|
||||
|
||||
responseCache.put(event.getPlayer().getUniqueId(), result);
|
||||
|
||||
if(AntiVPN.getInstance().getVpnConfig().countryList().size() > 0
|
||||
if(!AntiVPN.getInstance().getVpnConfig().countryList().isEmpty()
|
||||
// This bit of code will decide whether or not to kick the player
|
||||
// If it contains the code and it is set to whitelist, it will not kick as they are equal
|
||||
// and vise versa. However, if the contains does not match the state, it will kick.
|
||||
&& 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) {
|
||||
if(AntiVPN.getInstance().getVpnConfig().countryKickCommands().isEmpty()) {
|
||||
final String kickReason = AntiVPN.getInstance().getVpnConfig()
|
||||
.countryVanillaKickReason();
|
||||
// Kicking our player
|
||||
|
||||
+18
-9
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.9.2</version>
|
||||
<version>1.9.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,17 +21,24 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<version>3.10.1</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
<compilerArgument>-XDignore.symbol.file</compilerArgument>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.30</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
<version>3.4.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
@@ -49,6 +56,10 @@
|
||||
<pattern>com.google.common</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.shaded.com.google.common</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.h2</pattern>
|
||||
<shadedPattern>dev.brighten.antivpn.shaded.org.h2</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
@@ -74,15 +85,13 @@
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>8.2.0</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
<version>9.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>2.2.224</version>
|
||||
<scope>provided</scope>
|
||||
<version>2.2.220</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
@@ -99,7 +108,7 @@
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<version>3.12.14</version>
|
||||
<scope>provided</scope>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@ 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;
|
||||
@@ -31,9 +29,6 @@ import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter(AccessLevel.PRIVATE)
|
||||
@MavenLibrary(groupId = "com.h2database", artifactId ="h2", version = "2.2.224")
|
||||
@MavenLibrary(groupId = "org.mongodb", artifactId = "mongo-java-driver", version = "3.12.14")
|
||||
@MavenLibrary(groupId = "com.mysql", artifactId = "mysql-connector-j", version = "8.2.0")
|
||||
public class AntiVPN {
|
||||
|
||||
private static AntiVPN INSTANCE;
|
||||
@@ -56,8 +51,6 @@ public class AntiVPN {
|
||||
INSTANCE.executor = executor;
|
||||
INSTANCE.playerExecutor = playerExecutor;
|
||||
|
||||
LibraryLoader.loadAll(INSTANCE);
|
||||
|
||||
try {
|
||||
File configFile = new File(pluginFolder, "config.yml");
|
||||
if(!configFile.exists()){
|
||||
|
||||
@@ -38,6 +38,12 @@ public abstract class VPNExecutor {
|
||||
|
||||
public abstract void log(String log, Object... objects);
|
||||
|
||||
public abstract void logException(String message, Exception ex);
|
||||
|
||||
public void logException(Exception ex) {
|
||||
logException("An exception occurred: " + ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
public boolean isWhitelisted(UUID uuid) {
|
||||
if(AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()) {
|
||||
return AntiVPN.getInstance().getDatabase().isWhitelisted(uuid);
|
||||
|
||||
@@ -10,6 +10,7 @@ import dev.brighten.antivpn.web.FunkemunkyAPI;
|
||||
import dev.brighten.antivpn.web.objects.QueryResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class PlanCommand extends Command {
|
||||
@@ -53,7 +54,7 @@ public class PlanCommand extends Command {
|
||||
VPNExecutor.threadExecutor.execute(() -> {
|
||||
QueryResponse result;
|
||||
try {
|
||||
if(AntiVPN.getInstance().getVpnConfig().getLicense().equals("")) {
|
||||
if(AntiVPN.getInstance().getVpnConfig().getLicense().isEmpty()) {
|
||||
result = FunkemunkyAPI.getQueryResponse();
|
||||
} else {
|
||||
result = FunkemunkyAPI.getQueryResponse(AntiVPN.getInstance().getVpnConfig().getLicense());
|
||||
@@ -81,11 +82,11 @@ public class PlanCommand extends Command {
|
||||
result.getQueries(), queryMax);
|
||||
executor.sendMessage(StringUtil.line("&8"));
|
||||
} catch(JSONException e) {
|
||||
e.printStackTrace();
|
||||
AntiVPN.getInstance().getExecutor().logException(e);
|
||||
executor.sendMessage("&cThere was a JSONException thrown while looking up your query " +
|
||||
"information. Check console for more details.");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
AntiVPN.getInstance().getExecutor().logException(e);
|
||||
executor.sendMessage("&cThere was a IOException thrown while looking up your query " +
|
||||
"information. Check console for more details.");
|
||||
}
|
||||
@@ -95,6 +96,6 @@ public class PlanCommand extends Command {
|
||||
|
||||
@Override
|
||||
public List<String> tabComplete(CommandExecutor executor, String alias, String[] args) {
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package dev.brighten.antivpn.database.sql.utils;
|
||||
|
||||
import com.mysql.cj.jdbc.Driver;
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import org.h2.jdbc.JdbcSQLNonTransientConnectionException;
|
||||
import org.h2.jdbc.JdbcConnection;
|
||||
|
||||
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;
|
||||
@@ -19,11 +16,7 @@ public class MySQL {
|
||||
public static void init() {
|
||||
try {
|
||||
if (conn == null || conn.isClosed()) {
|
||||
try {
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
} catch (ClassNotFoundException e) {
|
||||
Class.forName("com.mysql.jdbc.Driver");
|
||||
}
|
||||
DriverManager.registerDriver(new Driver());
|
||||
conn = DriverManager.getConnection("jdbc:mysql://" + AntiVPN.getInstance().getVpnConfig().getIp()
|
||||
+ ":" + AntiVPN.getInstance().getVpnConfig().getPort()
|
||||
+ "/?useSSL=true&autoReconnect=true",
|
||||
@@ -37,78 +30,31 @@ public class MySQL {
|
||||
AntiVPN.getInstance().getExecutor().log("Connection to MySQL has been established.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
AntiVPN.getInstance().getExecutor().log("Failed to load mysql: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
AntiVPN.getInstance().getExecutor().logException("Failed to load mysql: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean attemptedTwice = false;
|
||||
public static void initH2() {
|
||||
File dataFolder = new File(AntiVPN.getInstance().getPluginFolder(), "databases");
|
||||
File databaseFile = new File(dataFolder, "database");
|
||||
try {
|
||||
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(),
|
||||
conn = new NonClosableConnection(new JdbcConnection("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 H2 has been established.");
|
||||
} catch (SQLException ex) {
|
||||
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();
|
||||
AntiVPN.getInstance().getExecutor().logException("H2 exception on initialize: " + ex.getMessage(), ex);
|
||||
}
|
||||
attemptedTwice = true;
|
||||
}
|
||||
|
||||
public static void use() {
|
||||
try {
|
||||
init();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
AntiVPN.getInstance().getExecutor().logException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,9 +66,8 @@ public class MySQL {
|
||||
} else conn.close();
|
||||
conn = null;
|
||||
}
|
||||
attemptedTwice = false;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
AntiVPN.getInstance().getExecutor().logException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +78,7 @@ public class MySQL {
|
||||
try {
|
||||
return conn.isClosed();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
AntiVPN.getInstance().getExecutor().logException(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* 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() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* 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 {};
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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");
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* This file is part of helper, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.depends;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Provides access to {@link URLClassLoader}#addURL.
|
||||
*/
|
||||
public abstract class URLClassLoaderAccess {
|
||||
|
||||
/**
|
||||
* Creates a {@link URLClassLoaderAccess} for the given class loader.
|
||||
*
|
||||
* @param classLoader the class loader
|
||||
* @return the access object
|
||||
*/
|
||||
static URLClassLoaderAccess create(URLClassLoader classLoader) {
|
||||
if (Reflection.isSupported()) {
|
||||
return new Reflection(classLoader);
|
||||
} else if (Unsafe.isSupported()) {
|
||||
return new Unsafe(classLoader);
|
||||
} else {
|
||||
return Noop.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
private final URLClassLoader classLoader;
|
||||
|
||||
protected URLClassLoaderAccess(URLClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the given URL to the class loader.
|
||||
*
|
||||
* @param url the URL to add
|
||||
*/
|
||||
public abstract void addURL(URL url);
|
||||
|
||||
/**
|
||||
* Accesses using reflection, not supported on Java 9+.
|
||||
*/
|
||||
private static class Reflection extends URLClassLoaderAccess {
|
||||
private static final Method ADD_URL_METHOD;
|
||||
|
||||
static {
|
||||
Method addUrlMethod;
|
||||
try {
|
||||
addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
addUrlMethod.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
addUrlMethod = null;
|
||||
}
|
||||
ADD_URL_METHOD = addUrlMethod;
|
||||
}
|
||||
|
||||
private static boolean isSupported() {
|
||||
return ADD_URL_METHOD != null;
|
||||
}
|
||||
|
||||
Reflection(URLClassLoader classLoader) {
|
||||
super(classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(URL url) {
|
||||
try {
|
||||
ADD_URL_METHOD.invoke(super.classLoader, url);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses using sun.misc.Unsafe, supported on Java 9+.
|
||||
*
|
||||
* @author Vaishnav Anil (<a href="https://github.com/slimjar/slimjar">...</a>)
|
||||
*/
|
||||
private static class Unsafe extends URLClassLoaderAccess {
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
|
||||
static {
|
||||
sun.misc.Unsafe unsafe;
|
||||
try {
|
||||
Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
unsafe = (sun.misc.Unsafe) unsafeField.get(null);
|
||||
} catch (Throwable t) {
|
||||
unsafe = null;
|
||||
}
|
||||
UNSAFE = unsafe;
|
||||
}
|
||||
|
||||
private static boolean isSupported() {
|
||||
return UNSAFE != null;
|
||||
}
|
||||
|
||||
private final Collection<URL> unopenedURLs;
|
||||
private final Collection<URL> pathURLs;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Unsafe(URLClassLoader classLoader) {
|
||||
super(classLoader);
|
||||
|
||||
Collection<URL> unopenedURLs;
|
||||
Collection<URL> pathURLs;
|
||||
try {
|
||||
Object ucp = fetchField(URLClassLoader.class, classLoader, "ucp");
|
||||
unopenedURLs = (Collection<URL>) fetchField(ucp.getClass(), ucp, "unopenedUrls");
|
||||
pathURLs = (Collection<URL>) fetchField(ucp.getClass(), ucp, "path");
|
||||
} catch (Throwable e) {
|
||||
unopenedURLs = null;
|
||||
pathURLs = null;
|
||||
}
|
||||
this.unopenedURLs = unopenedURLs;
|
||||
this.pathURLs = pathURLs;
|
||||
}
|
||||
|
||||
private static Object fetchField(final Class<?> clazz, final Object object, final String name) throws NoSuchFieldException {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
long offset = UNSAFE.objectFieldOffset(field);
|
||||
return UNSAFE.getObject(object, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(URL url) {
|
||||
this.unopenedURLs.add(url);
|
||||
this.pathURLs.add(url);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Noop extends URLClassLoaderAccess {
|
||||
private static final Noop INSTANCE = new Noop();
|
||||
|
||||
private Noop() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(URL url) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* 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 {}
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.brighten.antivpn.utils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class MiscUtils {
|
||||
@@ -41,6 +42,14 @@ public class MiscUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static ThreadFactory createThreadFactory(String threadName) {
|
||||
return r -> {
|
||||
Thread thread = new Thread(r);
|
||||
thread.setName(threadName);
|
||||
return thread;
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean isIpv4(String ip)
|
||||
{
|
||||
return ipv4.matcher(ip).matches();
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 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() {}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -1,602 +0,0 @@
|
||||
//
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
//
|
||||
// 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();
|
||||
}
|
||||
@@ -1,377 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.utils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static dev.brighten.antivpn.utils.NullnessCasts.uncheckedCastNullableTToT;
|
||||
import static dev.brighten.antivpn.utils.Preconditions.checkArgument;
|
||||
import static dev.brighten.antivpn.utils.Preconditions.checkNotNull;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* Useful suppliers.
|
||||
*
|
||||
* <p>All methods return serializable suppliers as long as they're given serializable parameters.
|
||||
*
|
||||
* @author Laurence Gonsalves
|
||||
* @author Harry Heymann
|
||||
* @since 2.0
|
||||
*/
|
||||
public final class Suppliers {
|
||||
private Suppliers() {}
|
||||
|
||||
/**
|
||||
* Returns a new supplier which is the composition of the provided function and supplier. In other
|
||||
* words, the new supplier's value will be computed by retrieving the value from {@code supplier},
|
||||
* and then applying {@code function} to that value. Note that the resulting supplier will not
|
||||
* call {@code supplier} or invoke {@code function} until it is called.
|
||||
*/
|
||||
public static <F extends Object, T extends Object> Supplier<T> compose(
|
||||
Function<? super F, T> function, Supplier<F> supplier) {
|
||||
return new SupplierComposition<>(function, supplier);
|
||||
}
|
||||
|
||||
private static class SupplierComposition<F extends Object, T extends Object>
|
||||
implements Supplier<T>, Serializable {
|
||||
final Function<? super F, T> function;
|
||||
final Supplier<F> supplier;
|
||||
|
||||
SupplierComposition(Function<? super F, T> function, Supplier<F> supplier) {
|
||||
this.function = checkNotNull(function);
|
||||
this.supplier = checkNotNull(supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return function.apply(supplier.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof SupplierComposition) {
|
||||
SupplierComposition<?, ?> that = (SupplierComposition<?, ?>) obj;
|
||||
return function.equals(that.function) && supplier.equals(that.supplier);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(function, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Suppliers.compose(" + function + ", " + supplier + ")";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a supplier which caches the instance retrieved during the first call to {@code get()}
|
||||
* and returns that value on subsequent calls to {@code get()}. See: <a
|
||||
* href="http://en.wikipedia.org/wiki/Memoization">memoization</a>
|
||||
*
|
||||
* <p>The returned supplier is thread-safe. The delegate's {@code get()} method will be invoked at
|
||||
* most once unless the underlying {@code get()} throws an exception. The supplier's serialized
|
||||
* form does not contain the cached value, which will be recalculated when {@code get()} is called
|
||||
* on the reserialized instance.
|
||||
*
|
||||
* <p>When the underlying delegate throws an exception then this memoizing supplier will keep
|
||||
* delegating calls until it returns valid data.
|
||||
*
|
||||
* <p>If {@code delegate} is an instance created by an earlier call to {@code memoize}, it is
|
||||
* returned directly.
|
||||
*/
|
||||
public static <T extends Object> Supplier<T> memoize(Supplier<T> delegate) {
|
||||
if (delegate instanceof NonSerializableMemoizingSupplier
|
||||
|| delegate instanceof MemoizingSupplier) {
|
||||
return delegate;
|
||||
}
|
||||
return delegate instanceof Serializable
|
||||
? new MemoizingSupplier<T>(delegate)
|
||||
: new NonSerializableMemoizingSupplier<T>(delegate);
|
||||
}
|
||||
|
||||
static class MemoizingSupplier<T extends Object> implements Supplier<T>, Serializable {
|
||||
final Supplier<T> delegate;
|
||||
transient volatile boolean initialized;
|
||||
// "value" does not need to be volatile; visibility piggy-backs
|
||||
// on volatile read of "initialized".
|
||||
transient T value;
|
||||
|
||||
MemoizingSupplier(Supplier<T> delegate) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
// A 2-field variant of Double Checked Locking.
|
||||
if (!initialized) {
|
||||
synchronized (this) {
|
||||
if (!initialized) {
|
||||
T t = delegate.get();
|
||||
value = t;
|
||||
initialized = true;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
// This is safe because we checked `initialized.`
|
||||
return uncheckedCastNullableTToT(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Suppliers.memoize("
|
||||
+ (initialized ? "<supplier that returned " + value + ">" : delegate)
|
||||
+ ")";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
static class NonSerializableMemoizingSupplier<T extends Object> implements Supplier<T> {
|
||||
volatile Supplier<T> delegate;
|
||||
volatile boolean initialized;
|
||||
// "value" does not need to be volatile; visibility piggy-backs
|
||||
// on volatile read of "initialized".
|
||||
T value;
|
||||
|
||||
NonSerializableMemoizingSupplier(Supplier<T> delegate) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
// A 2-field variant of Double Checked Locking.
|
||||
if (!initialized) {
|
||||
synchronized (this) {
|
||||
if (!initialized) {
|
||||
/*
|
||||
* requireNonNull is safe because we read and write `delegate` under synchronization.
|
||||
*
|
||||
* TODO(cpovirk): To avoid having to check for null, replace `delegate` with a singleton
|
||||
* `Supplier` that always throws an exception.
|
||||
*/
|
||||
T t = requireNonNull(delegate).get();
|
||||
value = t;
|
||||
initialized = true;
|
||||
// Release the delegate to GC.
|
||||
delegate = null;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
// This is safe because we checked `initialized.`
|
||||
return uncheckedCastNullableTToT(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
Supplier<T> delegate = this.delegate;
|
||||
return "Suppliers.memoize("
|
||||
+ (delegate == null ? "<supplier that returned " + value + ">" : delegate)
|
||||
+ ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a supplier that caches the instance supplied by the delegate and removes the cached
|
||||
* value after the specified time has passed. Subsequent calls to {@code get()} return the cached
|
||||
* value if the expiration time has not passed. After the expiration time, a new value is
|
||||
* retrieved, cached, and returned. See: <a
|
||||
* href="http://en.wikipedia.org/wiki/Memoization">memoization</a>
|
||||
*
|
||||
* <p>The returned supplier is thread-safe. The supplier's serialized form does not contain the
|
||||
* cached value, which will be recalculated when {@code get()} is called on the reserialized
|
||||
* instance. The actual memoization does not happen when the underlying delegate throws an
|
||||
* exception.
|
||||
*
|
||||
* <p>When the underlying delegate throws an exception then this memoizing supplier will keep
|
||||
* delegating calls until it returns valid data.
|
||||
*
|
||||
* @param duration the length of time after a value is created that it should stop being returned
|
||||
* by subsequent {@code get()} calls
|
||||
* @param unit the unit that {@code duration} is expressed in
|
||||
* @throws IllegalArgumentException if {@code duration} is not positive
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("GoodTime") // should accept a java.time.Duration
|
||||
public static <T extends Object> Supplier<T> memoizeWithExpiration(
|
||||
Supplier<T> delegate, long duration, TimeUnit unit) {
|
||||
return new ExpiringMemoizingSupplier<>(delegate, duration, unit);
|
||||
}
|
||||
|
||||
@SuppressWarnings("GoodTime") // lots of violations
|
||||
static class ExpiringMemoizingSupplier<T extends Object>
|
||||
implements Supplier<T>, Serializable {
|
||||
final Supplier<T> delegate;
|
||||
final long durationNanos;
|
||||
transient volatile T value;
|
||||
// The special value 0 means "not yet initialized".
|
||||
transient volatile long expirationNanos;
|
||||
|
||||
ExpiringMemoizingSupplier(Supplier<T> delegate, long duration, TimeUnit unit) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
this.durationNanos = unit.toNanos(duration);
|
||||
checkArgument(duration > 0, "duration (%s %s) must be > 0", duration, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
// Another variant of Double Checked Locking.
|
||||
//
|
||||
// We use two volatile reads. We could reduce this to one by
|
||||
// putting our fields into a holder class, but (at least on x86)
|
||||
// the extra memory consumption and indirection are more
|
||||
// expensive than the extra volatile reads.
|
||||
long nanos = expirationNanos;
|
||||
long now = System.nanoTime();
|
||||
if (nanos == 0 || now - nanos >= 0) {
|
||||
synchronized (this) {
|
||||
if (nanos == expirationNanos) { // recheck for lost race
|
||||
T t = delegate.get();
|
||||
value = t;
|
||||
nanos = now + durationNanos;
|
||||
// In the very unlikely event that nanos is 0, set it to 1;
|
||||
// no one will notice 1 ns of tardiness.
|
||||
expirationNanos = (nanos == 0) ? 1 : nanos;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
// This is safe because we checked `expirationNanos.`
|
||||
return uncheckedCastNullableTToT(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// This is a little strange if the unit the user provided was not NANOS,
|
||||
// but we don't want to store the unit just for toString
|
||||
return "Suppliers.memoizeWithExpiration(" + delegate + ", " + durationNanos + ", NANOS)";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/** Returns a supplier that always supplies {@code instance}. */
|
||||
public static <T extends Object> Supplier<T> ofInstance(
|
||||
T instance) {
|
||||
return new SupplierOfInstance<>(instance);
|
||||
}
|
||||
|
||||
private static class SupplierOfInstance<T extends Object>
|
||||
implements Supplier<T>, Serializable {
|
||||
final T instance;
|
||||
|
||||
SupplierOfInstance(T instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof SupplierOfInstance) {
|
||||
SupplierOfInstance<?> that = (SupplierOfInstance<?>) obj;
|
||||
return Objects.equal(instance, that.instance);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Suppliers.ofInstance(" + instance + ")";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a supplier whose {@code get()} method synchronizes on {@code delegate} before calling
|
||||
* it, making it thread-safe.
|
||||
*/
|
||||
public static <T extends Object> Supplier<T> synchronizedSupplier(
|
||||
Supplier<T> delegate) {
|
||||
return new ThreadSafeSupplier<>(delegate);
|
||||
}
|
||||
|
||||
private static class ThreadSafeSupplier<T extends Object>
|
||||
implements Supplier<T>, Serializable {
|
||||
final Supplier<T> delegate;
|
||||
|
||||
ThreadSafeSupplier(Supplier<T> delegate) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
synchronized (delegate) {
|
||||
return delegate.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Suppliers.synchronizedSupplier(" + delegate + ")";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function that accepts a supplier and returns the result of invoking {@link
|
||||
* Supplier#get} on that supplier.
|
||||
*
|
||||
* <p><b>Java 8 users:</b> use the method reference {@code Supplier::get} instead.
|
||||
*
|
||||
* @since 8.0
|
||||
*/
|
||||
public static <T extends Object> Function<Supplier<T>, T> supplierFunction() {
|
||||
@SuppressWarnings("unchecked") // implementation is "fully variant"
|
||||
SupplierFunction<T> sf = (SupplierFunction<T>) SupplierFunctionImpl.INSTANCE;
|
||||
return sf;
|
||||
}
|
||||
|
||||
private interface SupplierFunction<T extends Object> extends Function<Supplier<T>, T> {}
|
||||
|
||||
private enum SupplierFunctionImpl implements SupplierFunction<Object> {
|
||||
INSTANCE;
|
||||
|
||||
// Note: This makes T a "pass-through type"
|
||||
@Override
|
||||
public Object apply(Supplier<Object> input) {
|
||||
return input.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Suppliers.supplierFunction()";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ alerts:
|
||||
&7in location &8(&f%city%&7, &f%country%&8)'
|
||||
# Configuration for country gatekeepings
|
||||
countries:
|
||||
# You must use ISO codes for country configuration: https://www.iban.com/country-code
|
||||
# You must use ISO codes for country configuration: https://www.iban.com/country-codes
|
||||
# Leave empty to disable this configuration
|
||||
list: []
|
||||
# Set whitelist to true to only allow listed country codes, and false to deny listed country codes.
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.9.2</version>
|
||||
<version>1.9.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<dependency>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>Common</artifactId>
|
||||
<version>1.9.2</version>
|
||||
<version>1.9.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<version>1.9.2</version>
|
||||
<version>1.9.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -27,13 +27,13 @@
|
||||
<dependency>
|
||||
<groupId>com.velocitypowered</groupId>
|
||||
<artifactId>velocity-api</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<version>3.1.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>Common</artifactId>
|
||||
<version>1.9.2</version>
|
||||
<version>1.9.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -11,6 +11,7 @@ import dev.brighten.antivpn.api.APIPlayer;
|
||||
import dev.brighten.antivpn.api.VPNExecutor;
|
||||
import dev.brighten.antivpn.velocity.util.StringUtils;
|
||||
import dev.brighten.antivpn.web.objects.VPNResponse;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
import java.util.UUID;
|
||||
@@ -50,10 +51,7 @@ public class VelocityListener extends VPNExecutor {
|
||||
VPNResponse cached = responseCache.getIfPresent(event.getPlayer().getUniqueId());
|
||||
|
||||
if (cached != null && cached.isProxy()) {
|
||||
event.setResult(ResultedEvent.ComponentResult.denied(LegacyComponentSerializer.builder()
|
||||
.character('&')
|
||||
.build().deserialize(AntiVPN.getInstance().getVpnConfig()
|
||||
.getKickString())));
|
||||
event.setResult(ResultedEvent.ComponentResult.denied(Component.text("No")));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -81,11 +79,20 @@ public class VelocityListener extends VPNExecutor {
|
||||
final String kickReason = AntiVPN.getInstance().getVpnConfig()
|
||||
.countryVanillaKickReason();
|
||||
// Kicking our player
|
||||
event.getPlayer().disconnect(LegacyComponentSerializer.builder().character('&')
|
||||
event.setResult(ResultedEvent.ComponentResult.denied(LegacyComponentSerializer.builder()
|
||||
.character('&')
|
||||
.build().deserialize(kickReason
|
||||
.replace("%player%", event.getPlayer().getUsername())
|
||||
.replace("%country%", result.getCountryName())
|
||||
.replace("%code%", result.getCountryCode())));
|
||||
.replace("%code%", result.getCountryCode()))));
|
||||
VelocityPlugin.INSTANCE.getServer().getScheduler()
|
||||
.buildTask(VelocityPlugin.INSTANCE, () ->
|
||||
event.getPlayer().disconnect(LegacyComponentSerializer.builder()
|
||||
.character('&')
|
||||
.build().deserialize(kickReason
|
||||
.replace("%player%", event.getPlayer().getUsername())
|
||||
.replace("%country%", result.getCountryName())
|
||||
.replace("%code%", result.getCountryCode()))));
|
||||
} else {
|
||||
for (String cmd : AntiVPN.getInstance().getVpnConfig().countryKickCommands()) {
|
||||
final String formattedCommand = StringUtils
|
||||
@@ -103,10 +110,27 @@ public class VelocityListener extends VPNExecutor {
|
||||
}
|
||||
}
|
||||
} else if (result.isProxy()) {
|
||||
if (AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect())
|
||||
event.getPlayer().disconnect(LegacyComponentSerializer.builder().character('&')
|
||||
if (AntiVPN.getInstance().getVpnConfig().kickPlayersOnDetect()) {
|
||||
// Delay code execution
|
||||
event.setResult(ResultedEvent.ComponentResult.denied(LegacyComponentSerializer.builder()
|
||||
.character('&')
|
||||
.build().deserialize(AntiVPN.getInstance().getVpnConfig()
|
||||
.getKickString()));
|
||||
.getKickString()
|
||||
.replace("%player%", event.getPlayer().getUsername())
|
||||
.replace("%country%", result.getCountryName())
|
||||
.replace("%code%", result.getCountryCode()))));
|
||||
|
||||
VelocityPlugin.INSTANCE.getServer().getScheduler()
|
||||
.buildTask(VelocityPlugin.INSTANCE, () ->
|
||||
event.getPlayer().disconnect(LegacyComponentSerializer.builder()
|
||||
.character('&')
|
||||
.build().deserialize(AntiVPN.getInstance().getVpnConfig()
|
||||
.getKickString()
|
||||
.replace("%player%", event.getPlayer().getUsername())
|
||||
.replace("%country%", result.getCountryName())
|
||||
.replace("%code%", result.getCountryCode()))))
|
||||
.delay(1, TimeUnit.SECONDS).schedule();
|
||||
}
|
||||
VelocityPlugin.INSTANCE.getLogger().info(event.getPlayer().getUsername()
|
||||
+ " joined on a VPN/Proxy (" + result.getMethod() + ")");
|
||||
//Ensuring the user wishes to alert to staff
|
||||
@@ -171,4 +195,9 @@ public class VelocityListener extends VPNExecutor {
|
||||
public void log(String log, Object... objects) {
|
||||
log(Level.INFO, String.format(log, objects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logException(String message, Exception ex) {
|
||||
VelocityPlugin.INSTANCE.getLogger().log(Level.SEVERE, message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<groupId>dev.brighten.antivpn</groupId>
|
||||
<artifactId>AntiVPN</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.9.2</version>
|
||||
<version>1.9.3</version>
|
||||
|
||||
<modules>
|
||||
<module>Common</module>
|
||||
@@ -38,7 +38,7 @@
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.20</version>
|
||||
<version>1.18.30</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
@@ -53,6 +53,10 @@
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>funkemunky-releases</id>
|
||||
<url>https://nexus.funkemunky.cc/content/repositories/releases/</url>
|
||||
@@ -61,9 +65,9 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cc.funkemunky.utils</groupId>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.0</version>
|
||||
<version>1.18.30</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
Reference in New Issue
Block a user