99 lines
4.1 KiB
Java
99 lines
4.1 KiB
Java
/*
|
|
* 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<ProfilePublicKey> 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<Data> 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);
|
|
}
|
|
}
|
|
}
|
|
|