mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2025-01-09 18:07:36 +01:00
expand and document WrappedProfilePublicKey (#1618)
This commit is contained in:
parent
868b357527
commit
d7bf43001f
@ -1,13 +1,23 @@
|
|||||||
package com.comphenix.protocol.wrappers;
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Base64.Encoder;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around the profile public key.
|
||||||
|
*
|
||||||
|
* @since 1.19
|
||||||
|
*/
|
||||||
public class WrappedProfilePublicKey extends AbstractWrapper {
|
public class WrappedProfilePublicKey extends AbstractWrapper {
|
||||||
|
|
||||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getProfilePublicKeyClass();
|
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getProfilePublicKeyClass();
|
||||||
@ -16,65 +26,177 @@ public class WrappedProfilePublicKey extends AbstractWrapper {
|
|||||||
private static final ConstructorAccessor CONSTRUCTOR = Accessors.getConstructorAccessor(HANDLE_TYPE, KEY_DATA_TYPE);
|
private static final ConstructorAccessor CONSTRUCTOR = Accessors.getConstructorAccessor(HANDLE_TYPE, KEY_DATA_TYPE);
|
||||||
private static final FieldAccessor DATA_ACCESSOR = Accessors.getFieldAccessor(HANDLE_TYPE, KEY_DATA_TYPE, true);
|
private static final FieldAccessor DATA_ACCESSOR = Accessors.getFieldAccessor(HANDLE_TYPE, KEY_DATA_TYPE, true);
|
||||||
|
|
||||||
|
// lazy initialized when needed
|
||||||
|
private static FieldAccessor PROFILE_KEY_ACCESSOR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new profile public key wrapper directly from a nms ProfilePublicKey object.
|
||||||
|
*
|
||||||
|
* @param handle the handle to create the wrapper from.
|
||||||
|
*/
|
||||||
public WrappedProfilePublicKey(Object handle) {
|
public WrappedProfilePublicKey(Object handle) {
|
||||||
super(HANDLE_TYPE);
|
super(HANDLE_TYPE);
|
||||||
this.setHandle(handle);
|
this.setHandle(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new profile public key wrapper holding the given key data.
|
||||||
|
*
|
||||||
|
* @param keyData the data of the key.
|
||||||
|
*/
|
||||||
public WrappedProfilePublicKey(WrappedProfileKeyData keyData) {
|
public WrappedProfilePublicKey(WrappedProfileKeyData keyData) {
|
||||||
this(CONSTRUCTOR.invoke(keyData.getHandle()));
|
this(CONSTRUCTOR.invoke(keyData.getHandle()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the profile public key from the given player instance.
|
||||||
|
*
|
||||||
|
* @param player the player to get the key of.
|
||||||
|
* @return a wrapper around the public key of the given player.
|
||||||
|
*/
|
||||||
|
public static WrappedProfilePublicKey ofPlayer(Player player) {
|
||||||
|
FieldAccessor accessor = PROFILE_KEY_ACCESSOR;
|
||||||
|
if (accessor == null) {
|
||||||
|
accessor = Accessors.getFieldAccessor(MinecraftReflection.getEntityHumanClass(), HANDLE_TYPE, true);
|
||||||
|
PROFILE_KEY_ACCESSOR = accessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object nmsPlayer = BukkitUnwrapper.getInstance().unwrapItem(player);
|
||||||
|
return new WrappedProfilePublicKey(accessor.get(nmsPlayer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a wrapper around the key data stored in this public key.
|
||||||
|
*
|
||||||
|
* @return the data of this key.
|
||||||
|
*/
|
||||||
public WrappedProfileKeyData getKeyData() {
|
public WrappedProfileKeyData getKeyData() {
|
||||||
return new WrappedProfileKeyData(DATA_ACCESSOR.get(this.getHandle()));
|
return new WrappedProfileKeyData(DATA_ACCESSOR.get(this.getHandle()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the data of this key. Note that changing the key data might lead to unexpected issues with the server, for
|
||||||
|
* example chat message validation to fail.
|
||||||
|
*
|
||||||
|
* @param keyData the new data of this key.
|
||||||
|
*/
|
||||||
public void setKeyData(WrappedProfileKeyData keyData) {
|
public void setKeyData(WrappedProfileKeyData keyData) {
|
||||||
DATA_ACCESSOR.set(this.getHandle(), keyData.getHandle());
|
DATA_ACCESSOR.set(this.getHandle(), keyData.getHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around the data stored in a profile key.
|
||||||
|
*
|
||||||
|
* @since 1.19
|
||||||
|
*/
|
||||||
public static class WrappedProfileKeyData extends AbstractWrapper {
|
public static class WrappedProfileKeyData extends AbstractWrapper {
|
||||||
|
|
||||||
private static final ConstructorAccessor CONSTRUCTOR = Accessors.getConstructorAccessor(
|
private static final ConstructorAccessor CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||||
KEY_DATA_TYPE,
|
KEY_DATA_TYPE,
|
||||||
Instant.class, PublicKey.class, byte[].class);
|
Instant.class, PublicKey.class, byte[].class);
|
||||||
|
private static final Encoder MIME_ENCODER = Base64.getMimeEncoder(76, "\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
private final StructureModifier<Object> modifier;
|
private final StructureModifier<Object> modifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new key data instance directly from the given nms KeyData object.
|
||||||
|
*
|
||||||
|
* @param handle the handle to create the wrapper from.
|
||||||
|
*/
|
||||||
public WrappedProfileKeyData(Object handle) {
|
public WrappedProfileKeyData(Object handle) {
|
||||||
super(KEY_DATA_TYPE);
|
super(KEY_DATA_TYPE);
|
||||||
this.setHandle(handle);
|
this.setHandle(handle);
|
||||||
this.modifier = new StructureModifier<>(KEY_DATA_TYPE).withTarget(handle);
|
this.modifier = new StructureModifier<>(KEY_DATA_TYPE).withTarget(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new data wrapper instance using the given parameters.
|
||||||
|
*
|
||||||
|
* @param expireTime the instant when the key data expires.
|
||||||
|
* @param key the public key used to verify incoming data.
|
||||||
|
* @param signature the signature of the public key.
|
||||||
|
*/
|
||||||
public WrappedProfileKeyData(Instant expireTime, PublicKey key, byte[] signature) {
|
public WrappedProfileKeyData(Instant expireTime, PublicKey key, byte[] signature) {
|
||||||
this(CONSTRUCTOR.invoke(expireTime, key, signature));
|
this(CONSTRUCTOR.invoke(expireTime, key, signature));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the time instant when this key data expires.
|
||||||
|
*
|
||||||
|
* @return the time instant when this key data expires.
|
||||||
|
*/
|
||||||
public Instant getExpireTime() {
|
public Instant getExpireTime() {
|
||||||
return this.modifier.<Instant>withType(Instant.class).read(0);
|
return this.modifier.<Instant>withType(Instant.class).read(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the time when this key data expires.
|
||||||
|
*
|
||||||
|
* @param expireTime the new time when this key data expires.
|
||||||
|
*/
|
||||||
public void setExpireTime(Instant expireTime) {
|
public void setExpireTime(Instant expireTime) {
|
||||||
this.modifier.<Instant>withType(Instant.class).write(0, expireTime);
|
this.modifier.<Instant>withType(Instant.class).write(0, expireTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this key data is expired.
|
||||||
|
*
|
||||||
|
* @return true if this key data is expired, false otherwise.
|
||||||
|
*/
|
||||||
public boolean isExpired() {
|
public boolean isExpired() {
|
||||||
return this.getExpireTime().isBefore(Instant.now());
|
return this.getExpireTime().isBefore(Instant.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the signed payload of this key data. The signature of this data must verify against the payload data of
|
||||||
|
* the key. If it does not, the key data is considered unsigned.
|
||||||
|
* <p>
|
||||||
|
* Note that this method takes the expiry time of the key into accountability, if this key is expired it will no
|
||||||
|
* longer match the key data signature.
|
||||||
|
*
|
||||||
|
* @return the signed payload version of this profile key data.
|
||||||
|
*/
|
||||||
|
public String getSignedPayload() {
|
||||||
|
String rsaString = "-----BEGIN RSA PUBLIC KEY-----\n"
|
||||||
|
+ MIME_ENCODER.encodeToString(this.getKey().getEncoded())
|
||||||
|
+ "\n-----END RSA PUBLIC KEY-----\n";
|
||||||
|
return this.getExpireTime().toEpochMilli() + rsaString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the public key of this key data.
|
||||||
|
*
|
||||||
|
* @return the public key of this key data.
|
||||||
|
*/
|
||||||
public PublicKey getKey() {
|
public PublicKey getKey() {
|
||||||
return this.modifier.<PublicKey>withType(PublicKey.class).read(0);
|
return this.modifier.<PublicKey>withType(PublicKey.class).read(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the public key of this key data.
|
||||||
|
*
|
||||||
|
* @param key the new public key of this key data.
|
||||||
|
*/
|
||||||
public void setKey(PublicKey key) {
|
public void setKey(PublicKey key) {
|
||||||
this.modifier.<PublicKey>withType(PublicKey.class).write(0, key);
|
this.modifier.<PublicKey>withType(PublicKey.class).write(0, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the signature of this key data.
|
||||||
|
*
|
||||||
|
* @return the key data of this signature.
|
||||||
|
* @see #getSignedPayload()
|
||||||
|
*/
|
||||||
public byte[] getSignature() {
|
public byte[] getSignature() {
|
||||||
return this.modifier.<byte[]>withType(byte[].class).read(0);
|
return this.modifier.<byte[]>withType(byte[].class).read(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the signature of this key data.
|
||||||
|
*
|
||||||
|
* @param signature the new signature of this key data.
|
||||||
|
* @see #getSignedPayload()
|
||||||
|
*/
|
||||||
public void setSignature(byte[] signature) {
|
public void setSignature(byte[] signature) {
|
||||||
this.modifier.<byte[]>withType(byte[].class).write(0, signature);
|
this.modifier.<byte[]>withType(byte[].class).write(0, signature);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user