Complete private authentication, server integrations and activity reporting
Add Fabric/Forge version builds and Paper integration, preserve permanent player identities across renames, harden session authorization, and surface privacy-conscious launcher/server activity in the panel.
This commit is contained in:
commit
a1f19e86c6
74 files changed
+2108
-95
No files matched your search
@@ -0,0 +1,130 @@
|
||||
package net.scopenet.paper;
|
||||
|
||||
import net.scopenet.integration.*;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.event.block.*;
|
||||
import org.bukkit.event.entity.*;
|
||||
import org.bukkit.event.player.*;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class ScopenetPlugin extends JavaPlugin implements Listener {
|
||||
private Integration integration;
|
||||
|
||||
@Override public void onEnable() {
|
||||
// Install the deny-by-default listener even if configuration is invalid.
|
||||
getServer().getPluginManager().registerEvents(this, this);
|
||||
saveDefaultConfig();
|
||||
try {
|
||||
integration = new Integration(
|
||||
Settings.of(getConfig().getString("panel-url", ""), getConfig().getString("token", "")),
|
||||
getServer().getName(), Bukkit.getBukkitVersion().split("-")[0], getDescription().getVersion(),
|
||||
Bukkit.getOnlineMode(), Bukkit.getMaxPlayers(), getLogger()::warning,
|
||||
(id, message) -> {
|
||||
if (!isEnabled()) return;
|
||||
Bukkit.getScheduler().runTask(this, () -> {
|
||||
Player player = Bukkit.getPlayer(id);
|
||||
if (player != null) player.kickPlayer(message);
|
||||
});
|
||||
});
|
||||
Bukkit.getScheduler().runTaskTimer(this, integration::tick, 1, 1);
|
||||
// Reloading an auth plugin cannot silently admit existing sessions.
|
||||
for (Player player : Bukkit.getOnlinePlayers()) player.kickPlayer("SCOPENET restarted. Please reconnect.");
|
||||
} catch (Exception e) {
|
||||
getLogger().severe("SCOPENET is blocking joins: " + e.getMessage());
|
||||
for (Player player : Bukkit.getOnlinePlayers()) player.kickPlayer(Integration.UNAVAILABLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onDisable() {
|
||||
if (integration != null) integration.close();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void login(AsyncPlayerPreLoginEvent event) {
|
||||
if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) return;
|
||||
String denial = Integration.UNAVAILABLE;
|
||||
if (integration != null) {
|
||||
try {
|
||||
denial = integration.login(event.getUniqueId(), event.getName(), event.getAddress().getHostAddress())
|
||||
.get(7, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) { Thread.currentThread().interrupt(); }
|
||||
catch (Exception ignored) { /* fail closed */ }
|
||||
}
|
||||
if (denial != null) event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, denial);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void join(PlayerJoinEvent event) {
|
||||
if (integration != null) integration.activity.join(event.getPlayer().getUniqueId(), event.getPlayer().getName());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void leave(PlayerQuitEvent event) {
|
||||
if (integration != null) integration.activity.leave(event.getPlayer().getUniqueId(), event.getPlayer().getName());
|
||||
}
|
||||
|
||||
private void add(Player player, String stat) {
|
||||
if (integration != null) integration.activity.add(player.getUniqueId(), player.getName(), stat, 1);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void broken(BlockBreakEvent event) { add(event.getPlayer(), "blocks_broken"); }
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void placed(BlockPlaceEvent event) { add(event.getPlayer(), "blocks_placed"); }
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void chat(AsyncPlayerChatEvent event) { add(event.getPlayer(), "messages"); }
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void command(PlayerCommandPreprocessEvent event) {
|
||||
audit(event.getPlayer(), "command", event.getMessage().strip().split("\\s+", 2)[0]);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void statistic(PlayerStatisticIncrementEvent event) {
|
||||
if (integration == null) return;
|
||||
String item = event.getMaterial() != null ? ":" + event.getMaterial().name()
|
||||
: event.getEntityType() != null ? ":" + event.getEntityType().name() : "";
|
||||
integration.activity.action(event.getPlayer().getUniqueId(), event.getPlayer().getName(),
|
||||
event.getStatistic().name() + item, event.getNewValue() - event.getPreviousValue());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void inventory(InventoryClickEvent event) {
|
||||
if (event.getWhoClicked() instanceof Player player)
|
||||
audit(player, "inventory", event.getAction().name() + " slot=" + event.getRawSlot()
|
||||
+ (event.getCurrentItem() == null ? "" : " item=" + event.getCurrentItem().getType().name()));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void advancement(PlayerAdvancementDoneEvent event) {
|
||||
audit(event.getPlayer(), "advancement", event.getAdvancement().getKey().toString());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void teleport(PlayerTeleportEvent event) {
|
||||
if (event.getTo() != null) audit(event.getPlayer(), "teleport", event.getCause().name() + " → "
|
||||
+ event.getTo().getWorld().getName() + " " + event.getTo().getBlockX() + ","
|
||||
+ event.getTo().getBlockY() + "," + event.getTo().getBlockZ());
|
||||
}
|
||||
|
||||
private void audit(Player player, String kind, String detail) {
|
||||
if (integration != null) integration.activity.event(player.getUniqueId(), player.getName(), kind, detail);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void death(EntityDeathEvent event) {
|
||||
if (event.getEntity() instanceof Player player) {
|
||||
add(player, "deaths");
|
||||
if (integration != null) integration.activity.event(player.getUniqueId(), player.getName(), "death",
|
||||
event instanceof PlayerDeathEvent death ? death.getDeathMessage() : null);
|
||||
}
|
||||
Player killer = event.getEntity().getKiller();
|
||||
if (killer != null) add(killer, event.getEntity() instanceof Player ? "player_kills" : "mob_kills");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Create a server under Servers in the panel, then paste its token here.
|
||||
panel-url: "https://panel.example.com"
|
||||
token: ""
|
||||
@@ -0,0 +1,6 @@
|
||||
name: SCOPENET
|
||||
version: '${version}'
|
||||
main: net.scopenet.paper.ScopenetPlugin
|
||||
api-version: '1.20'
|
||||
description: SCOPENET private authentication, access control and activity reporting.
|
||||
load: STARTUP
|
||||
Reference in new issue
Block a user