/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.datafixers.kinds.App * com.mojang.datafixers.kinds.Applicative * com.mojang.serialization.Codec * com.mojang.serialization.codecs.RecordCodecBuilder */ package net.minecraft.world.entity.player; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.Applicative; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.PublicKey; import java.time.Duration; import java.time.Instant; import java.util.Arrays; import java.util.UUID; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ThrowingComponent; import net.minecraft.util.Crypt; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.SignatureValidator; public record ProfilePublicKey(Data data) { public static final Component EXPIRED_PROFILE_PUBLIC_KEY = Component.translatable("multiplayer.disconnect.expired_public_key"); private static final Component INVALID_SIGNATURE = Component.translatable("multiplayer.disconnect.invalid_public_key_signature"); public static final Duration EXPIRY_GRACE_PERIOD = Duration.ofHours(8L); public static final Codec TRUSTED_CODEC = Data.CODEC.xmap(ProfilePublicKey::new, ProfilePublicKey::data); public static ProfilePublicKey createValidated(SignatureValidator validator, UUID profileId, Data data) throws ValidationException { if (!data.validateSignature(validator, profileId)) { throw new ValidationException(INVALID_SIGNATURE); } return new ProfilePublicKey(data); } public SignatureValidator createSignatureValidator() { return SignatureValidator.from(this.data.key, "SHA256withRSA"); } public record Data(Instant expiresAt, PublicKey key, byte[] keySignature) { private static final int MAX_KEY_SIGNATURE_SIZE = 4096; public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group((App)ExtraCodecs.INSTANT_ISO8601.fieldOf("expires_at").forGetter(Data::expiresAt), (App)Crypt.PUBLIC_KEY_CODEC.fieldOf("key").forGetter(Data::key), (App)ExtraCodecs.BASE64_STRING.fieldOf("signature_v2").forGetter(Data::keySignature)).apply((Applicative)i, Data::new)); public Data(FriendlyByteBuf input) { this(input.readInstant(), input.readPublicKey(), input.readByteArray(4096)); } public void write(FriendlyByteBuf output) { output.writeInstant(this.expiresAt); output.writePublicKey(this.key); output.writeByteArray(this.keySignature); } private boolean validateSignature(SignatureValidator validator, UUID profileId) { return validator.validate(this.signedPayload(profileId), this.keySignature); } private byte[] signedPayload(UUID profileId) { byte[] keyBytes = this.key.getEncoded(); byte[] signedPayload = new byte[24 + keyBytes.length]; ByteBuffer buffer = ByteBuffer.wrap(signedPayload).order(ByteOrder.BIG_ENDIAN); buffer.putLong(profileId.getMostSignificantBits()).putLong(profileId.getLeastSignificantBits()).putLong(this.expiresAt.toEpochMilli()).put(keyBytes); return signedPayload; } public boolean hasExpired() { return this.expiresAt.isBefore(Instant.now()); } public boolean hasExpired(Duration gracePeriod) { return this.expiresAt.plus(gracePeriod).isBefore(Instant.now()); } @Override public boolean equals(Object o) { if (o instanceof Data) { Data data = (Data)o; return this.expiresAt.equals(data.expiresAt) && this.key.equals(data.key) && Arrays.equals(this.keySignature, data.keySignature); } return false; } } public static class ValidationException extends ThrowingComponent { public ValidationException(Component component) { super(component); } } }