9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-27 02:49:15 +00:00

feat(network): 添加严格校验用户申请资源包使用的UUID

This commit is contained in:
jhqwqmc
2025-09-14 00:48:22 +08:00
parent d0a91744ae
commit 08200e5f75
7 changed files with 72 additions and 14 deletions

View File

@@ -60,6 +60,7 @@ import net.momirealms.craftengine.core.plugin.context.NetworkTextReplaceContext;
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
import net.momirealms.craftengine.core.plugin.logger.Debugger;
import net.momirealms.craftengine.core.plugin.network.*;
import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider;
@@ -1239,17 +1240,17 @@ public class PacketConsumers {
try {
BukkitServerPlayer player = (BukkitServerPlayer) user;
String name = (String) NetworkReflections.methodHandle$ServerboundHelloPacket$nameGetter.invokeExact(packet);
player.setName(name);
player.setUnverifiedName(name);
if (VersionHelper.isOrAbove1_20_2()) {
UUID uuid = (UUID) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet);
player.setUUID(uuid);
player.setUnverifiedUUID(uuid);
} else {
@SuppressWarnings("unchecked")
Optional<UUID> uuid = (Optional<UUID>) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet);
if (uuid.isPresent()) {
player.setUUID(uuid.get());
player.setUnverifiedUUID(uuid.get());
} else {
player.setUUID(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)));
player.setUnverifiedUUID(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)));
}
}
} catch (Throwable e) {
@@ -2499,6 +2500,18 @@ public class PacketConsumers {
// 防止后续加入的JoinWorldTask再次处理
user.setShouldProcessFinishConfiguration(false);
// 检查用户UUID是否已经校验
if (!user.isVerifiedUUID()) {
if (Config.strictPlayerUuidValidation()) {
TranslationManager.instance().log("warning.network.resource_pack.unverified_uuid", user.name(), user.uuid().toString());
user.kick(Component.translatable("disconnect.loginFailed"));
return;
}
if (Config.debugResourcePack()) {
TranslationManager.instance().log("warning.network.resource_pack.unverified_uuid", user.name(), user.uuid().toString());
}
}
// 取消 ClientboundFinishConfigurationPacket让客户端发呆并结束掉当前的进入世界任务
event.setCancelled(true);
try {
@@ -2548,8 +2561,8 @@ public class PacketConsumers {
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> LOGIN_FINISHED = (user, event, packet) -> {
try {
GameProfile gameProfile = FastNMS.INSTANCE.field$ClientboundLoginFinishedPacket$gameProfile(packet);
user.setName(gameProfile.getName());
user.setUUID(gameProfile.getId());
user.setVerifiedName(gameProfile.getName());
user.setVerifiedUUID(gameProfile.getId());
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginFinishedPacket", e);
}

View File

@@ -72,6 +72,8 @@ public class BukkitServerPlayer extends Player {
private ChannelHandler connection;
private String name;
private UUID uuid;
private boolean isVerifiedName;
private boolean isVerifiedUUID;
private ConnectionState decoderState;
private ConnectionState encoderState;
private boolean shouldProcessFinishConfiguration = true;
@@ -140,7 +142,9 @@ public class BukkitServerPlayer extends Player {
this.playerRef = new WeakReference<>(player);
this.serverPlayerRef = new WeakReference<>(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player));
this.uuid = player.getUniqueId();
this.isVerifiedUUID = true;
this.name = player.getName();
this.isVerifiedName = true;
byte[] bytes = player.getPersistentDataContainer().get(KeyUtils.toNamespacedKey(CooldownData.COOLDOWN_KEY), PersistentDataType.BYTE_ARRAY);
this.trackedChunks = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(768, 0.5f);
this.entityTypeView = new ConcurrentHashMap<>(256);
@@ -321,22 +325,46 @@ public class BukkitServerPlayer extends Player {
}
@Override
public void setName(String name) {
if (this.name != null) return;
public boolean isVerifiedName() {
return this.isVerifiedName;
}
@Override
public void setUnverifiedName(String name) {
if (this.isVerifiedName) return;
this.name = name;
}
@Override
public void setVerifiedName(String name) {
if (this.isVerifiedName) return;
this.name = name;
this.isVerifiedName = true;
}
@Override
public UUID uuid() {
return this.uuid;
}
@Override
public void setUUID(UUID uuid) {
if (this.uuid != null) return;
public boolean isVerifiedUUID() {
return this.isVerifiedUUID;
}
@Override
public void setUnverifiedUUID(UUID uuid) {
if (this.isVerifiedUUID) return;
this.uuid = uuid;
}
@Override
public void setVerifiedUUID(UUID uuid) {
if (this.isVerifiedUUID) return;
this.uuid = uuid;
this.isVerifiedUUID = true;
}
@Override
public void playSound(Key sound, SoundSource source, float volume, float pitch) {
platformPlayer().playSound(platformPlayer(), sound.toString(), SoundUtils.toBukkit(source), volume, pitch);

View File

@@ -98,6 +98,8 @@ resource-pack:
file-to-upload: "./generated/resource_pack.zip"
# Resend the resource pack to players upon successful upload
resend-on-upload: true
# Whether a verified player UUID is required to get the resource pack
strict-player-uuid-validation: true
duplicated-files-handler:
- term:
type: any_of

View File

@@ -63,7 +63,8 @@ command.upload.failure.not_supported: "<red>Current hosting method '<arg:0>' doe
command.upload.on_progress: "<white>Started uploading progress. Check the console for more information.</white>"
command.send_resource_pack.success.single: "<white>Sent resource pack to <arg:0>.</white>"
command.send_resource_pack.success.multiple: "<white>Send resource packs to <arg:0> players.</white>"
warning.config.pack.duplicated_files: "</red>Duplicated files Found. Please resolve them through config.yml 'resource-pack.duplicated-files-handler' section.</red>"
warning.network.resource_pack.unverified_uuid: "<yellow>Player <arg:0> attempts to request a resource package using a UUID (<arg:1>) that is not authenticated by the server.</yellow>"
warning.config.pack.duplicated_files: "<red>Duplicated files Found. Please resolve them through config.yml 'resource-pack.duplicated-files-handler' section.</red>"
warning.config.yaml.duplicated_key: "<red>Issue found in file <arg:0> - Found duplicated key '<arg:1>' at line <arg:2>, this might cause unexpected results.</red>"
warning.config.yaml.inconsistent_value_type: "<red>Issue found in file <arg:0> - Found duplicated key '<arg:1>' at line <arg:2> with different value types, this might cause unexpected results.</red>"
warning.config.type.int: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to integer type for option '<arg:3>'.</yellow>"

View File

@@ -63,7 +63,8 @@ command.upload.failure.not_supported: "<red>当前托管模式 '<arg:0>' 不支
command.upload.on_progress: "<white>已开始上传进程. 检查控制台以获取详细信息</white>"
command.send_resource_pack.success.single: "<white>发送资源包给 <arg:0></white>"
command.send_resource_pack.success.multiple: "<white>发送资源包给 <arg:0> 个玩家</white>"
warning.config.pack.duplicated_files: "</red>发现重复文件 请通过 config.yml 的 'resource-pack.duplicated-files-handler' 部分解决</red>"
warning.network.resource_pack.unverified_uuid: "<yellow>玩家 <arg:0> 使用未经服务器验证的 UUID (<arg:1>) 尝试请求获取资源包</yellow>"
warning.config.pack.duplicated_files: "<red>发现重复文件 请通过 config.yml 的 'resource-pack.duplicated-files-handler' 部分解决</red>"
warning.config.yaml.duplicated_key: "<red>在文件 <arg:0> 发现问题 - 在第<arg:2>行发现重复的键 '<arg:1>', 这可能会导致一些意料之外的问题</red>"
warning.config.yaml.inconsistent_value_type: "<red>在文件 <arg:0> 发现问题 - 在第<arg:2>行发现重复且值类型不同的键 '<arg:1>', 这可能会导致一些意料之外的问题</red>"
warning.config.type.int: "<yellow>在文件 <arg:0> 发现问题 - 无法加载 '<arg:1>': 无法将 '<arg:2>' 转换为整数类型 (选项 '<arg:3>')</yellow>"

View File

@@ -93,6 +93,7 @@ public class Config {
protected boolean resource_pack$delivery$send_on_join;
protected boolean resource_pack$delivery$resend_on_upload;
protected boolean resource_pack$delivery$auto_upload;
protected boolean resource_pack$delivery$strict_player_uuid_validation;
protected Path resource_pack$delivery$file_to_upload;
protected Component resource_pack$send$prompt;
@@ -271,6 +272,7 @@ public class Config {
resource_pack$delivery$kick_if_declined = config.getBoolean("resource-pack.delivery.kick-if-declined", true);
resource_pack$delivery$kick_if_failed_to_apply = config.getBoolean("resource-pack.delivery.kick-if-failed-to-apply", true);
resource_pack$delivery$auto_upload = config.getBoolean("resource-pack.delivery.auto-upload", true);
resource_pack$delivery$strict_player_uuid_validation = config.getBoolean("resource-pack.delivery.strict-player-uuid-validation", true);
resource_pack$delivery$file_to_upload = resolvePath(config.getString("resource-pack.delivery.file-to-upload", "./generated/resource_pack.zip"));
resource_pack$send$prompt = AdventureHelper.miniMessage().deserialize(config.getString("resource-pack.delivery.prompt", "<yellow>To fully experience our server, please accept our custom resource pack.</yellow>"));
resource_pack$protection$crash_tools$method_1 = config.getBoolean("resource-pack.protection.crash-tools.method-1", false);
@@ -590,6 +592,9 @@ public class Config {
public static boolean autoUpload() {
return instance.resource_pack$delivery$auto_upload;
}
public static boolean strictPlayerUuidValidation() {
return instance.resource_pack$delivery$strict_player_uuid_validation;
}
public static Path fileToUpload() {
return instance.resource_pack$delivery$file_to_upload;

View File

@@ -31,11 +31,19 @@ public interface NetWorkUser {
String name();
void setName(String name);
boolean isVerifiedName();
void setUnverifiedName(String name);
void setVerifiedName(String name);
UUID uuid();
void setUUID(UUID uuid);
boolean isVerifiedUUID();
void setUnverifiedUUID(UUID uuid);
void setVerifiedUUID(UUID uuid);
void sendPacket(Object packet, boolean immediately);