Skip to content

Commit

Permalink
Write some docs
Browse files Browse the repository at this point in the history
  • Loading branch information
acrylic-style committed May 27, 2022
1 parent 3656418 commit f696c31
Show file tree
Hide file tree
Showing 17 changed files with 201 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface Player {
UUID getUniqueId();

/**
* Sends a message to the player. This method might do nothing depending on the implementation.
* Sends a message to the player.
* @param message the message
*/
void sendMessage(@NotNull String message);
Expand All @@ -35,5 +35,11 @@ default String getUsernameOrUniqueId() {
return getUsername() != null ? getUsername() : getUniqueId().toString();
}

/**
* Checks if the player has the challenge equals to the provided challenge. Challenge token is used for securing
* initial encryption packet.
* @param challenge the challenge token to check
* @return true if the player has the challenge equals to the provided challenge
*/
boolean isChallengeEquals(@NotNull String challenge);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
import java.util.UUID;

/**
* Simple instance of {@link Player}.
* Simple instance of {@link Player}. It lacks most of the features, and for example, you can't send messages to this
* instance.
*/
public final class SimplePlayer implements Player {
private final UUID uuid;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package net.azisaba.azipluginmessaging.api.protocol;

public enum PacketFlow {
/**
* Server (Backend) -> Proxy
*/
TO_PROXY,
/**
* Proxy -> Server (Backend)
*/
TO_SERVER,
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,22 @@
import org.jetbrains.annotations.NotNull;

public abstract class PacketQueue {
/**
* Empty packet queue that does nothing.
*/
public static final PacketQueue EMPTY = new Empty();

/**
* Adds the message to the queue.
* @param protocol The protocol.
* @param message The message.
*/
public abstract void add(@NotNull Protocol<?, ?> protocol, @NotNull Message message);

/**
* Removes the message from the queue and sends all messages to provided sender.
* @param sender the sender
*/
public abstract void flush(@NotNull PacketSender sender);

private static class Empty extends PacketQueue {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,15 @@
public final class Protocol<T extends MessageHandler<M>, M extends Message> {
private static final Map<Byte, Protocol<?, ?>> TO_PROXY_BY_ID = new ConcurrentHashMap<>();
private static final Map<Byte, Protocol<?, ?>> TO_SERVER_BY_ID = new ConcurrentHashMap<>();

/**
* Legacy plugin channel id
*/
public static final String LEGACY_CHANNEL_ID = "AziPluginMessaging";

/**
* Modern plugin channel id
*/
public static final String CHANNEL_ID = "azipm:main";

public static final Protocol<ProxyboundEncryptionPacket, EncryptionMessage> P_ENCRYPTION = new Protocol<>(PacketFlow.TO_PROXY, 0x00, new ProxyboundEncryptionPacket());
Expand All @@ -65,6 +73,16 @@ public final class Protocol<T extends MessageHandler<M>, M extends Message> {
private final byte id;
private final T handler;

/**
* Creates a new packet. Handler should be a subclass of {@link ProxyMessageHandler} if packet flow is
* {@link PacketFlow#TO_PROXY}, and a subclass of {@link ServerMessageHandler} if packet flow is
* {@link PacketFlow#TO_SERVER}.
* @param packetFlow The packet flow
* @param id The packet id, must be unique in the packet flow
* @param handler The handler
* @throws IllegalArgumentException if the id is already registered
* @throws IllegalArgumentException if the handler is implementing wrong type for the packet flow
*/
private Protocol(@NotNull PacketFlow packetFlow, int id, @NotNull T handler) {
this.packetFlow = packetFlow;
this.id = (byte) (id & 0xFF);
Expand All @@ -74,15 +92,15 @@ private Protocol(@NotNull PacketFlow packetFlow, int id, @NotNull T handler) {
throw new IllegalArgumentException("Handler must be instance of ProxyMessageHandler");
}
if (TO_PROXY_BY_ID.containsKey(this.id)) {
throw new AssertionError("Duplicate protocol id: " + this.id);
throw new IllegalArgumentException("Duplicate protocol id: " + this.id);
}
TO_PROXY_BY_ID.put(this.id, this);
} else {
if (!(handler instanceof ServerMessageHandler)) {
throw new IllegalArgumentException("Handler must be instance of ServerMessageHandler");
}
if (TO_SERVER_BY_ID.containsKey(this.id)) {
throw new AssertionError("Duplicate protocol id: " + this.id);
throw new IllegalArgumentException("Duplicate protocol id: " + this.id);
}
TO_SERVER_BY_ID.put(this.id, this);
}
Expand Down Expand Up @@ -149,9 +167,11 @@ public boolean sendPacket(@Nullable PacketSender sender, @NotNull M msg) {
}

/**
* This method is called when a packet is received (proxy-side).
* This method is called when a raw packet is received (proxy-side).
* @param server the server connection
* @param rawData the data of the packet
* @throws RuntimeException if the connection is encrypted but cannot decrypt the packet
* @throws RuntimeException if the packet must be received encrypted but the connection is not encrypted
*/
public static void handleProxySide(ServerConnection server, byte[] rawData) {
byte[] data;
Expand All @@ -168,7 +188,7 @@ public static void handleProxySide(ServerConnection server, byte[] rawData) {
DataInputStream in = new DataInputStream(bin)) {
byte id = (byte) (in.readByte() & 0xFF);
if (id != 0 && !server.isEncrypted()) {
throw new RuntimeException("Packet " + id + " must be sent encrypted (server: " + server + ")");
throw new RuntimeException("Packet " + id + " must be received encrypted (server: " + server + ")");
}
Protocol<?, ?> protocol = Protocol.getById(PacketFlow.TO_PROXY, id);
if (protocol == null) {
Expand All @@ -183,7 +203,7 @@ public static void handleProxySide(ServerConnection server, byte[] rawData) {
Logger.getCurrentLogger().info("Received packet {} (0x{}) from server connection {} (encrypted: {})", id, hex, server, server.isEncrypted());
}
if (protocol.packetFlow != PacketFlow.TO_PROXY) {
throw new IllegalArgumentException("Packet " + protocol + " is not proxybound");
throw new AssertionError("Packet " + protocol + " is not proxybound");
}
@SuppressWarnings("unchecked")
ProxyMessageHandler<Message> handler = (ProxyMessageHandler<Message>) protocol.getHandler();
Expand All @@ -195,8 +215,10 @@ public static void handleProxySide(ServerConnection server, byte[] rawData) {
}

/**
* This method is called when a packet is received (server-side).
* This method is called when a raw packet is received (server-side).
* @param rawData the data of the packet
* @throws RuntimeException if the connection is encrypted but cannot decrypt the packet
* @throws RuntimeException if the packet must be received encrypted but the connection is not encrypted
*/
public static void handleServerSide(@NotNull PacketSender sender, byte[] rawData) {
byte[] data;
Expand All @@ -213,7 +235,7 @@ public static void handleServerSide(@NotNull PacketSender sender, byte[] rawData
DataInputStream in = new DataInputStream(bin)) {
byte id = (byte) (in.readByte() & 0xFF);
if (id != 0 && !sender.isEncrypted()) {
throw new RuntimeException("Packet " + id + " must be sent encrypted (sender: " + sender + ")");
throw new RuntimeException("Packet " + id + " must be received encrypted (sender: " + sender + ")");
}
Protocol<?, ?> protocol = Protocol.getById(PacketFlow.TO_SERVER, id);
if (protocol == null) {
Expand All @@ -226,7 +248,7 @@ public static void handleServerSide(@NotNull PacketSender sender, byte[] rawData
Logger.getCurrentLogger().info("Received packet {} (0x{}) from {}", id, hex, sender);
}
if (protocol.packetFlow != PacketFlow.TO_SERVER) {
throw new IllegalArgumentException("Packet " + protocol + " is not serverbound");
throw new AssertionError("Packet " + protocol + " is not serverbound");
}
@SuppressWarnings("unchecked")
ServerMessageHandler<Message> handler = (ServerMessageHandler<Message>) protocol.getHandler();
Expand All @@ -237,6 +259,10 @@ public static void handleServerSide(@NotNull PacketSender sender, byte[] rawData
}
}

/**
* Returns the packet flow of this packet.
* @return the packet flow
*/
@NotNull
@Contract(pure = true)
public PacketFlow getPacketFlow() {
Expand Down Expand Up @@ -271,10 +297,15 @@ public PacketFlow getPacketFlow() {
}
}

/**
* Returns the protocol data in string form.
* @return the protocol data
*/
@Override
public String toString() {
return "Protocol{" +
"id=" + id +
", packetFlow=" + packetFlow +
", handler=" + handler +
'}';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import java.io.IOException;
import java.util.UUID;

/**
* Sends the arbitrary message to a player.
*/
public class ServerboundActionResponsePacket implements ServerMessageHandler<ServerboundActionResponseMessage> {
@NotNull
@Override
Expand All @@ -20,6 +23,8 @@ public ServerboundActionResponseMessage read(@NotNull DataInputStream in) throws

@Override
public void handle(@NotNull PacketSender sender, @NotNull ServerboundActionResponseMessage msg) throws Exception {
AziPluginMessagingProvider.get().getPlayer(msg.getUniqueId()).ifPresent(player -> player.sendMessage(msg.getMessage()));
AziPluginMessagingProvider.get()
.getPlayer(msg.getUniqueId())
.ifPresent(player -> player.sendMessage(msg.getMessage()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,29 @@ public class ServerboundActionResponseMessage implements Message {
private final UUID uuid;
private final String message;

/**
* Creates a new instance.
* @param uuid The UUID of the player.
* @param message The message (may contain \u00a7).
*/
public ServerboundActionResponseMessage(@NotNull UUID uuid, @NotNull String message) {
this.uuid = uuid;
this.message = message;
}

/**
* Gets the UUID of the player.
* @return the uuid
*/
@NotNull
public UUID getUniqueId() {
return uuid;
}

/**
* Gets the message.
* @return the message
*/
@NotNull
public String getMessage() {
return message;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package net.azisaba.azipluginmessaging.api.server;

import org.jetbrains.annotations.NotNull;

import java.security.KeyPair;
import java.security.PublicKey;

/**
* Represents something that can have a connection.
*/
public interface Connection {
/**
* Marks the connection as encrypted.
* @param encrypted true if the connection is encrypted; false otherwise
*/
void setEncrypted(boolean encrypted);

/**
* Checks if the connection is encrypted.
* @return true if the connection is encrypted; false otherwise
*/
boolean isEncrypted();

/**
* Gets the local key pair for encrypting packets.
* @return the local key pair
*/
@NotNull
KeyPair getKeyPair();

/**
* Gets the remote public key for decrypting packets.
* @return the remote public key
*/
@NotNull
PublicKey getRemotePublicKey();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,13 @@
/**
* Represents an object that can send packet to target.
*/
public interface PacketSender {
public interface PacketSender extends Connection {
/**
* Attempt to send a packet to the target.
* @param data the data
* @return true if the packet was sent successfully; false otherwise
*/
boolean sendPacket(byte @NotNull [] data);

void setEncrypted(boolean encrypted);

boolean isEncrypted();

@NotNull
KeyPair getKeyPair();

@NotNull
PublicKey getRemotePublicKey();

void setRemotePublicKey(@NotNull PublicKey publicKey);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,22 @@
import java.util.Base64;

public class Base64Util {
/**
* Encodes the given byte array to a base64 string.
* @param bytes the byte array
* @return the base64 string
*/
@Contract("_ -> new")
public static @NotNull String encode(byte[] bytes) {
public static @NotNull String encode(byte @NotNull [] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}

public static byte[] decode(@NotNull String string) {
/**
* Decodes the given base64 string to a byte array.
* @param string the base64 string
* @return the byte array
*/
public static byte @NotNull [] decode(@NotNull String string) {
return Base64.getDecoder().decode(string);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
import java.util.Arrays;
import java.util.List;

/**
* @deprecated Deprecated because {@link #SARA_GROUPS} is deprecated.
*/
@Deprecated
public class Constants {
/**
* @deprecated <code>sara</code> track in LuckPerms should be used instead
*/
@Deprecated
public static final List<Integer> SARA_GROUPS = Arrays.asList(50000, 20000, 10000, 5000, 2000, 1000, 500, 100);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@
import java.security.PublicKey;
import java.security.spec.RSAKeyGenParameterSpec;

/**
* Represents a utility class for encryption.
*/
public class EncryptionUtil {
/**
* Algorithm to use for encrypting and decrypting packets.
*/
public static final String ALGORITHM = "RSA";

/**
Expand Down Expand Up @@ -56,11 +62,22 @@ public static byte[] decrypt(byte[] data, @NotNull PrivateKey key) throws Except
return cipher.doFinal(data);
}

/**
* Encodes the public key as base64 string.
* @param key The key to encode
* @return The base64 string
*/
@Contract("_ -> new")
public static @NotNull String encodePublicKey(@NotNull PublicKey key) {
return Base64Util.encode(key.getEncoded());
}

/**
* Decodes the base64 string to a public key.
* @param key The base64 string
* @return The public key
* @throws Exception If a public key could not be decoded for any reason
*/
@Contract("_ -> new")
public static @NotNull PublicKey decodePublicKey(@NotNull String key) throws Exception {
return KeyFactoryUtil.getPublicKey(Base64Util.decode(key));
Expand Down
Loading

0 comments on commit f696c31

Please sign in to comment.