126 lines
5.1 KiB
Java
126 lines
5.1 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* com.mojang.logging.LogUtils
|
|
* org.jspecify.annotations.Nullable
|
|
* org.slf4j.Logger
|
|
*/
|
|
package net.minecraft.network.chat;
|
|
|
|
import com.mojang.logging.LogUtils;
|
|
import java.time.Instant;
|
|
import java.util.UUID;
|
|
import java.util.function.BooleanSupplier;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.network.chat.FilterMask;
|
|
import net.minecraft.network.chat.MessageSignature;
|
|
import net.minecraft.network.chat.PlayerChatMessage;
|
|
import net.minecraft.network.chat.SignedMessageBody;
|
|
import net.minecraft.network.chat.SignedMessageLink;
|
|
import net.minecraft.network.chat.ThrowingComponent;
|
|
import net.minecraft.util.SignatureValidator;
|
|
import net.minecraft.util.Signer;
|
|
import net.minecraft.world.entity.player.ProfilePublicKey;
|
|
import org.jspecify.annotations.Nullable;
|
|
import org.slf4j.Logger;
|
|
|
|
public class SignedMessageChain {
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
private @Nullable SignedMessageLink nextLink;
|
|
private Instant lastTimeStamp = Instant.EPOCH;
|
|
|
|
public SignedMessageChain(UUID profileId, UUID sessionId) {
|
|
this.nextLink = SignedMessageLink.root(profileId, sessionId);
|
|
}
|
|
|
|
public Encoder encoder(Signer signer) {
|
|
return body -> {
|
|
SignedMessageLink link = this.nextLink;
|
|
if (link == null) {
|
|
return null;
|
|
}
|
|
this.nextLink = link.advance();
|
|
return new MessageSignature(signer.sign(output -> PlayerChatMessage.updateSignature(output, link, body)));
|
|
};
|
|
}
|
|
|
|
public Decoder decoder(final ProfilePublicKey profilePublicKey) {
|
|
final SignatureValidator signatureValidator = profilePublicKey.createSignatureValidator();
|
|
return new Decoder(){
|
|
|
|
@Override
|
|
public PlayerChatMessage unpack(@Nullable MessageSignature signature, SignedMessageBody body) throws DecodeException {
|
|
if (signature == null) {
|
|
throw new DecodeException(DecodeException.MISSING_PROFILE_KEY);
|
|
}
|
|
if (profilePublicKey.data().hasExpired()) {
|
|
throw new DecodeException(DecodeException.EXPIRED_PROFILE_KEY);
|
|
}
|
|
SignedMessageLink link = SignedMessageChain.this.nextLink;
|
|
if (link == null) {
|
|
throw new DecodeException(DecodeException.CHAIN_BROKEN);
|
|
}
|
|
if (body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) {
|
|
this.setChainBroken();
|
|
throw new DecodeException(DecodeException.OUT_OF_ORDER_CHAT);
|
|
}
|
|
SignedMessageChain.this.lastTimeStamp = body.timeStamp();
|
|
PlayerChatMessage unpacked = new PlayerChatMessage(link, signature, body, null, FilterMask.PASS_THROUGH);
|
|
if (!unpacked.verify(signatureValidator)) {
|
|
this.setChainBroken();
|
|
throw new DecodeException(DecodeException.INVALID_SIGNATURE);
|
|
}
|
|
if (unpacked.hasExpiredServer(Instant.now())) {
|
|
LOGGER.warn("Received expired chat: '{}'. Is the client/server system time unsynchronized?", (Object)body.content());
|
|
}
|
|
SignedMessageChain.this.nextLink = link.advance();
|
|
return unpacked;
|
|
}
|
|
|
|
@Override
|
|
public void setChainBroken() {
|
|
SignedMessageChain.this.nextLink = null;
|
|
}
|
|
};
|
|
}
|
|
|
|
@FunctionalInterface
|
|
public static interface Encoder {
|
|
public static final Encoder UNSIGNED = body -> null;
|
|
|
|
public @Nullable MessageSignature pack(SignedMessageBody var1);
|
|
}
|
|
|
|
public static class DecodeException
|
|
extends ThrowingComponent {
|
|
private static final Component MISSING_PROFILE_KEY = Component.translatable("chat.disabled.missingProfileKey");
|
|
private static final Component CHAIN_BROKEN = Component.translatable("chat.disabled.chain_broken");
|
|
private static final Component EXPIRED_PROFILE_KEY = Component.translatable("chat.disabled.expiredProfileKey");
|
|
private static final Component INVALID_SIGNATURE = Component.translatable("chat.disabled.invalid_signature");
|
|
private static final Component OUT_OF_ORDER_CHAT = Component.translatable("chat.disabled.out_of_order_chat");
|
|
|
|
public DecodeException(Component component) {
|
|
super(component);
|
|
}
|
|
}
|
|
|
|
@FunctionalInterface
|
|
public static interface Decoder {
|
|
public static Decoder unsigned(UUID profileId, BooleanSupplier enforcesSecureChat) {
|
|
return (signature, body) -> {
|
|
if (enforcesSecureChat.getAsBoolean()) {
|
|
throw new DecodeException(DecodeException.MISSING_PROFILE_KEY);
|
|
}
|
|
return PlayerChatMessage.unsigned(profileId, body.content());
|
|
};
|
|
}
|
|
|
|
public PlayerChatMessage unpack(@Nullable MessageSignature var1, SignedMessageBody var2) throws DecodeException;
|
|
|
|
default public void setChainBroken() {
|
|
}
|
|
}
|
|
}
|
|
|