added connection key and recorded event to LoginLog

This commit is contained in:
MineTec committed 2026-10-14 17:00:11 +02:00
1 parent 095db7e796
commit 86ae261c60
4 files changed
+148 -6

No files matched your search

@@ -0,0 +1,49 @@
package eu.mhsl.craftattack.spawn.core.event;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.time.Instant;
import java.util.UUID;
/**
* Fired after a login attempt was stored in login_attempts. Called on the database thread:
* handlers must return quickly and must never wait for results of the shared Database.
*/
public class LoginAttemptRecordedEvent extends Event {
private static final HandlerList HANDLERS = new HandlerList();
@Override
public @NotNull HandlerList getHandlers() {
return HANDLERS;
}
public static HandlerList getHandlerList() {
return HANDLERS;
}
public record RecordedAttempt(
long id,
Instant at,
UUID uuid,
String name,
String ip,
@Nullable String network,
String stage,
String result
) {
}
private final RecordedAttempt attempt;
public LoginAttemptRecordedEvent(RecordedAttempt attempt) {
super(true);
this.attempt = attempt;
}
public RecordedAttempt getAttempt() {
return this.attempt;
}
}
@@ -0,0 +1,72 @@
package eu.mhsl.craftattack.spawn.core.util.network;
import org.jetbrains.annotations.Nullable;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Groups IP addresses by internet connection: an IPv4 address stands for itself,
* an IPv6 address for its /64 prefix (one prefix per household line).
*/
public final class Networks {
private static final Pattern IPV4 = Pattern.compile("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$");
private static final Pattern IPV6 = Pattern.compile("^[0-9a-fA-F:.]*:[0-9a-fA-F:.]*$");
private static final String IPV6_SUFFIX = "::/64";
private Networks() {
}
/**
* @return the connection key ("93.204.10.20" or "2003:e1:1f00:ab00::/64"), or null if the text is no IP address
*/
public static @Nullable String networkOf(@Nullable String ip) {
if(ip == null) return null;
String text = ip.trim();
Matcher ipv4 = IPV4.matcher(text);
if(ipv4.matches()) return ipv4Of(ipv4);
if(!IPV6.matcher(text).matches()) return null;
InetAddress address;
try {
// the text contains a colon, so it is parsed as IPv6 literal and never resolved via DNS
address = InetAddress.getByName(text);
} catch(UnknownHostException e) {
return null;
}
if(address instanceof Inet4Address) return address.getHostAddress();
byte[] bytes = address.getAddress();
return String.format("%x:%x:%x:%x%s", group(bytes, 0), group(bytes, 2), group(bytes, 4), group(bytes, 6), IPV6_SUFFIX);
}
/**
* Shortened form for display: "93.204.x.x" or "2003:e1:x:x::/64".
*/
public static String mask(String network) {
if(network.endsWith(IPV6_SUFFIX)) {
String[] groups = network.substring(0, network.length() - IPV6_SUFFIX.length()).split(":");
return groups[0] + ":" + groups[1] + ":x:x" + IPV6_SUFFIX;
}
String[] octets = network.split("\\.");
return octets.length == 4 ? octets[0] + "." + octets[1] + ".x.x" : network;
}
private static @Nullable String ipv4Of(Matcher matcher) {
StringJoiner joiner = new StringJoiner(".");
for(int i = 1; i <= 4; i++) {
int octet = Integer.parseInt(matcher.group(i));
if(octet > 255) return null;
joiner.add(Integer.toString(octet));
}
return joiner.toString();
}
private static int group(byte[] bytes, int offset) {
return ((bytes[offset] & 0xff) << 8) | (bytes[offset + 1] & 0xff);
}
}