Skip to content

Commit

Permalink
Add challenge token field
Browse files Browse the repository at this point in the history
  • Loading branch information
acrylic-style committed Apr 14, 2022
1 parent 90d6bf7 commit 83e0c1e
Show file tree
Hide file tree
Showing 16 changed files with 88 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.DataOutputStream;
import java.io.IOException;
import java.util.UUID;

public interface Player {
Expand Down Expand Up @@ -36,4 +34,6 @@ public interface Player {
default String getUsernameOrUniqueId() {
return getUsername() != null ? getUsername() : getUniqueId().toString();
}

boolean isChallengeEquals(@NotNull String challenge);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public void sendMessage(@NotNull String message) {
// no-op
}

@Override
public boolean isChallengeEquals(@NotNull String challenge) {
return false;
}

@Contract("_ -> new")
@NotNull
public static SimplePlayer read(@NotNull DataInputStream in) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
import net.azisaba.azipluginmessaging.api.protocol.handler.ServerMessageHandler;
import net.azisaba.azipluginmessaging.api.protocol.handler.ServerboundActionResponsePacket;
import net.azisaba.azipluginmessaging.api.protocol.handler.ServerboundEncryptionPacket;
import net.azisaba.azipluginmessaging.api.protocol.message.EncryptionMessage;
import net.azisaba.azipluginmessaging.api.protocol.message.Message;
import net.azisaba.azipluginmessaging.api.protocol.message.PlayerMessage;
import net.azisaba.azipluginmessaging.api.protocol.message.PlayerWithServerMessage;
import net.azisaba.azipluginmessaging.api.protocol.message.ProxyboundGiveSaraMessage;
import net.azisaba.azipluginmessaging.api.protocol.message.ProxyboundSetRankMessage;
import net.azisaba.azipluginmessaging.api.protocol.message.PublicKeyMessage;
import net.azisaba.azipluginmessaging.api.protocol.message.ServerboundActionResponseMessage;
import net.azisaba.azipluginmessaging.api.server.PacketSender;
import net.azisaba.azipluginmessaging.api.server.ServerConnection;
Expand All @@ -43,15 +43,15 @@ public final class Protocol<T extends MessageHandler<M>, M extends Message> {
public static final String LEGACY_CHANNEL_ID = "AziPluginMessaging";
public static final String CHANNEL_ID = "azipm:main";

public static final Protocol<ProxyboundEncryptionPacket, PublicKeyMessage> P_ENCRYPTION = new Protocol<>(PacketFlow.TO_PROXY, 0x00, new ProxyboundEncryptionPacket());
public static final Protocol<ProxyboundEncryptionPacket, EncryptionMessage> P_ENCRYPTION = new Protocol<>(PacketFlow.TO_PROXY, 0x00, new ProxyboundEncryptionPacket());
public static final Protocol<ProxyboundSetRankPacket, ProxyboundSetRankMessage> P_SET_RANK = new Protocol<>(PacketFlow.TO_PROXY, 0x01, new ProxyboundSetRankPacket());
public static final Protocol<ProxyboundGiveGamingSaraPacket, PlayerMessage> P_GIVE_GAMING_SARA = new Protocol<>(PacketFlow.TO_PROXY, 0x02, new ProxyboundGiveGamingSaraPacket());
public static final Protocol<ProxyboundGiveSaraPacket, ProxyboundGiveSaraMessage> P_GIVE_SARA = new Protocol<>(PacketFlow.TO_PROXY, 0x03, new ProxyboundGiveSaraPacket());
public static final Protocol<ProxyboundToggleGamingSaraPacket, PlayerMessage> P_TOGGLE_GAMING_SARA = new Protocol<>(PacketFlow.TO_PROXY, 0x04, new ProxyboundToggleGamingSaraPacket());
public static final Protocol<ProxyboundToggleSaraHidePacket, PlayerMessage> P_TOGGLE_SARA_HIDE = new Protocol<>(PacketFlow.TO_PROXY, 0x05, new ProxyboundToggleSaraHidePacket()); // Note that this is non-contextual
public static final Protocol<ProxyboundToggleSaraShowPacket, PlayerWithServerMessage> P_TOGGLE_SARA_SHOW = new Protocol<>(PacketFlow.TO_PROXY, 0x06, new ProxyboundToggleSaraShowPacket()); // Note that this is contextual

public static final Protocol<ServerboundEncryptionPacket, PublicKeyMessage> S_ENCRYPTION = new Protocol<>(PacketFlow.TO_SERVER, 0x00, new ServerboundEncryptionPacket());
public static final Protocol<ServerboundEncryptionPacket, EncryptionMessage> S_ENCRYPTION = new Protocol<>(PacketFlow.TO_SERVER, 0x00, new ServerboundEncryptionPacket());
public static final Protocol<ServerboundActionResponsePacket, ServerboundActionResponseMessage> S_ACTION_RESPONSE = new Protocol<>(PacketFlow.TO_SERVER, 0x01, new ServerboundActionResponsePacket());

private final PacketFlow packetFlow;
Expand Down Expand Up @@ -168,9 +168,7 @@ public static void handleProxySide(ServerConnection server, byte[] rawData) {
Message message = handler.read(server, in);
handler.handle(server, message);
} catch (Exception | AssertionError e) {
Logger.getCurrentLogger().warn(
"Failed to handle plugin message from server connection {} (player: {})",
server.getServerInfo().getName(), server.getPlayer().getUniqueId(), e);
Logger.getCurrentLogger().warn("Failed to handle plugin message from " + server, e);
}
}

Expand Down Expand Up @@ -210,7 +208,7 @@ public static void handleServerSide(@NotNull PacketSender sender, byte[] rawData
Message message = handler.read(in);
handler.handle(sender, message);
} catch (Exception | AssertionError e) {
Logger.getCurrentLogger().warn("Failed to handle plugin message from proxy", e);
Logger.getCurrentLogger().warn("Failed to handle plugin message from " + sender, e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import net.azisaba.azipluginmessaging.api.Logger;
import net.azisaba.azipluginmessaging.api.protocol.Protocol;
import net.azisaba.azipluginmessaging.api.protocol.message.PublicKeyMessage;
import net.azisaba.azipluginmessaging.api.protocol.message.EncryptionMessage;
import net.azisaba.azipluginmessaging.api.server.PacketSender;
import net.azisaba.azipluginmessaging.api.server.ServerConnection;
import net.azisaba.azipluginmessaging.api.util.Constants;
Expand All @@ -11,18 +11,18 @@

import java.io.DataInputStream;

public class ProxyboundEncryptionPacket implements ProxyMessageHandler<PublicKeyMessage> {
public class ProxyboundEncryptionPacket implements ProxyMessageHandler<EncryptionMessage> {
@Override
public @NotNull PublicKeyMessage read(@NotNull ServerConnection server, @NotNull DataInputStream in) {
public @NotNull EncryptionMessage read(@NotNull ServerConnection server, @NotNull DataInputStream in) {
try {
return PublicKeyMessage.read(in);
return EncryptionMessage.read(in);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

@Override
public void handle(@NotNull PacketSender sender, @NotNull PublicKeyMessage msg) throws Exception {
public void handle(@NotNull PacketSender sender, @NotNull EncryptionMessage msg) throws Exception {
// Set public key of the server for encryption (note that this does not set the encrypted flag)
sender.setRemotePublicKey(msg.getPublicKey());

Expand All @@ -32,7 +32,7 @@ public void handle(@NotNull PacketSender sender, @NotNull PublicKeyMessage msg)
}

// Send our public key to the server
if (!Protocol.S_ENCRYPTION.sendPacket(sender, new PublicKeyMessage(sender.getKeyPair().getPublic()))) {
if (!Protocol.S_ENCRYPTION.sendPacket(sender, new EncryptionMessage(msg.getChallenge(), sender.getKeyPair().getPublic()))) {
Logger.getCurrentLogger().warn("Failed to send public key to the server " + sender);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
package net.azisaba.azipluginmessaging.api.protocol.handler;

import net.azisaba.azipluginmessaging.api.Logger;
import net.azisaba.azipluginmessaging.api.protocol.message.PublicKeyMessage;
import net.azisaba.azipluginmessaging.api.entity.Player;
import net.azisaba.azipluginmessaging.api.protocol.message.EncryptionMessage;
import net.azisaba.azipluginmessaging.api.server.PacketSender;
import net.azisaba.azipluginmessaging.api.util.Constants;
import org.jetbrains.annotations.NotNull;

import java.io.DataInputStream;

public class ServerboundEncryptionPacket implements ServerMessageHandler<PublicKeyMessage> {
public class ServerboundEncryptionPacket implements ServerMessageHandler<EncryptionMessage> {
@Override
public @NotNull PublicKeyMessage read(@NotNull DataInputStream in) {
public @NotNull EncryptionMessage read(@NotNull DataInputStream in) {
try {
return PublicKeyMessage.read(in);
return EncryptionMessage.read(in);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

@Override
public void handle(@NotNull PacketSender sender, @NotNull PublicKeyMessage msg) throws Exception {
public void handle(@NotNull PacketSender sender, @NotNull EncryptionMessage msg) throws Exception {
if (sender instanceof Player && !((Player) sender).isChallengeEquals(msg.getChallenge())) {
throw new RuntimeException("Challenge token does not match.");
}

// Set the public key from the proxy
sender.setRemotePublicKey(msg.getPublicKey());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,33 @@
import java.io.IOException;
import java.security.PublicKey;

public class PublicKeyMessage implements Message {
public class EncryptionMessage implements Message {
private final String challenge;
private final PublicKey publicKey;

public PublicKeyMessage(@NotNull PublicKey publicKey) {
public EncryptionMessage(@NotNull String challenge, @NotNull PublicKey publicKey) {
this.challenge = challenge;
this.publicKey = publicKey;
}

@NotNull
public String getChallenge() {
return challenge;
}

@NotNull
public PublicKey getPublicKey() {
return publicKey;
}

@Override
public void write(@NotNull DataOutputStream out) throws IOException {
out.writeUTF(challenge);
out.writeUTF(EncryptionUtil.encodePublicKey(publicKey));
}

@Contract("_ -> new")
public static @NotNull PublicKeyMessage read(@NotNull DataInputStream in) throws Exception {
return new PublicKeyMessage(EncryptionUtil.decodePublicKey(in.readUTF()));
public static @NotNull EncryptionMessage read(@NotNull DataInputStream in) throws Exception {
return new EncryptionMessage(in.readUTF(), EncryptionUtil.decodePublicKey(in.readUTF()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.azisaba.azipluginmessaging.api.util;

import org.jetbrains.annotations.NotNull;

import java.math.BigInteger;
import java.security.SecureRandom;

public class TokenUtil {
private static final SecureRandom RANDOM = new SecureRandom();

public static @NotNull String generateNewToken() {
return new BigInteger(130, RANDOM).toString(32);
}
}
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {
}

group = "net.azisaba.azipluginmessaging"
version = "2.0.0"
version = "2.0.1"

repositories {
mavenCentral()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ public AziPluginMessagingSpigot(@NotNull SpigotPlugin plugin) {
public @NotNull Optional<net.azisaba.azipluginmessaging.api.entity.Player> getPlayer(@NotNull UUID uuid) {
Player player = Bukkit.getPlayer(uuid);
if (player == null) return Optional.empty();
return Optional.of(new PlayerImpl(player));
return Optional.of(PlayerImpl.of(player));
}

@SuppressWarnings("unchecked")
@Override
public <T> PlayerAdapter<T> getPlayerAdapter(@NotNull Class<T> clazz) {
if (!Player.class.equals(clazz)) throw new IllegalArgumentException("This environment does not support " + clazz.getTypeName());
return (PlayerAdapter<T>) (PlayerAdapter<Player>) PlayerImpl::new;
return (PlayerAdapter<T>) (PlayerAdapter<Player>) PlayerImpl::of;
}

public static class ServerImpl implements Server {
Expand All @@ -58,7 +58,7 @@ public static class ServerImpl implements Server {
// prefer encrypted players (that is, player who is connected to the proxy where AziPluginMessaging is installed)
List<PlayerImpl> players = Bukkit.getOnlinePlayers()
.stream()
.map(PlayerImpl::new)
.map(PlayerImpl::of)
.collect(Collectors.toList());
if (players.size() == 0) throw new IllegalArgumentException("No player is online.");
Optional<PlayerImpl> encryptedPlayer = players.stream().filter(PlayerImpl::isEncrypted).findAny();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
public class PluginMessageReceiver implements PluginMessageListener {
@Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
Protocol.handleServerSide(new PlayerImpl(player), message);
Protocol.handleServerSide(PlayerImpl.of(player), message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import net.azisaba.azipluginmessaging.api.AziPluginMessagingProvider;
import net.azisaba.azipluginmessaging.api.AziPluginMessagingProviderProvider;
import net.azisaba.azipluginmessaging.api.protocol.Protocol;
import net.azisaba.azipluginmessaging.api.protocol.message.PublicKeyMessage;
import net.azisaba.azipluginmessaging.api.protocol.message.EncryptionMessage;
import net.azisaba.azipluginmessaging.api.server.PacketSender;
import net.azisaba.azipluginmessaging.api.util.EncryptionUtil;
import net.azisaba.azipluginmessaging.api.util.TokenUtil;
import net.azisaba.azipluginmessaging.spigot.command.AziPluginMessagingCommand;
import net.azisaba.azipluginmessaging.spigot.entity.PlayerImpl;
import org.bukkit.Bukkit;
Expand Down Expand Up @@ -36,8 +37,7 @@ public void onEnable() {
Bukkit.getMessenger().registerOutgoingPluginChannel(this, Protocol.LEGACY_CHANNEL_ID);
Bukkit.getMessenger().registerIncomingPluginChannel(this, Protocol.LEGACY_CHANNEL_ID, new PluginMessageReceiver());
} catch (IllegalArgumentException e) {
getLogger().info("Could not register legacy channel");
e.printStackTrace();
getLogger().info("Could not register legacy channel, you can ignore this message if you're running on 1.13+");
}
Bukkit.getMessenger().registerOutgoingPluginChannel(this, Protocol.CHANNEL_ID);
Bukkit.getMessenger().registerIncomingPluginChannel(this, Protocol.CHANNEL_ID, new PluginMessageReceiver());
Expand All @@ -61,7 +61,7 @@ public void onPlayerJoin(PlayerJoinEvent e) {
} catch (Exception ex) {
throw new RuntimeException(ex);
}
PlayerImpl player = new PlayerImpl(e.getPlayer());
PlayerImpl player = PlayerImpl.of(e.getPlayer());

// set keypair
player.setKeyPair(keyPair);
Expand All @@ -72,8 +72,10 @@ public void onPlayerJoin(PlayerJoinEvent e) {
// set public key to null too
player.setRemotePublicKeyInternal(null);

player.challenge = TokenUtil.generateNewToken();

// send our public key
Protocol.P_ENCRYPTION.sendPacket(player, new PublicKeyMessage(keyPair.getPublic()));
Protocol.P_ENCRYPTION.sendPacket(player, new EncryptionMessage(player.challenge, keyPair.getPublic()));
}, "AziPluginMessaging-" + e.getPlayer().getName()).start();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void execute(@NotNull CommandSender sender, @NotNull String[] args) {
sender.sendMessage(ChatColor.RED + "You are not a player");
return;
} else {
target = new PlayerImpl((org.bukkit.entity.Player) sender);
target = PlayerImpl.of((org.bukkit.entity.Player) sender);
}
}
boolean res = Protocol.P_SET_RANK.sendPacket(SpigotPlugin.getAnyPacketSender(), new ProxyboundSetRankMessage(rank, target));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public void execute(@NotNull CommandSender sender, @NotNull String[] args) {
sender.sendMessage(ChatColor.RED + "Usage: " + getFullUsage());
return;
} else {
target = new PlayerImpl((org.bukkit.entity.Player) sender);
target = PlayerImpl.of((org.bukkit.entity.Player) sender);
}
}
boolean res = Protocol.P_TOGGLE_GAMING_SARA.sendPacket(SpigotPlugin.getAnyPacketSender(), new PlayerMessage(target));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,30 @@

import java.security.KeyPair;
import java.security.PublicKey;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public class PlayerImpl implements Player, PacketSender {
private static final Map<UUID, Map.Entry<KeyPair, PublicKey>> KEY_MAP = new ConcurrentHashMap<>();
private static final Map<UUID, PlayerImpl> MAP = new ConcurrentHashMap<>();
private final org.bukkit.entity.Player handle;
private KeyPair keyPair;
private PublicKey remotePublicKey;
private boolean encrypted = false;
public String challenge = null;

@Contract(value = "null -> fail", pure = true)
public PlayerImpl(@Nullable org.bukkit.entity.Player handle) {
private PlayerImpl(@Nullable org.bukkit.entity.Player handle) {
if (handle == null) {
throw new IllegalArgumentException("player is null");
}
this.handle = Objects.requireNonNull(handle);
Map.Entry<KeyPair, PublicKey> key = KEY_MAP.get(handle.getUniqueId());
if (key != null) {
this.keyPair = key.getKey();
if (key.getValue() != null) {
this.remotePublicKey = key.getValue();
this.encrypted = true;
}
}
}

@NotNull
public static PlayerImpl of(@NotNull org.bukkit.entity.Player player) {
return MAP.computeIfAbsent(player.getUniqueId(), u -> new PlayerImpl(player));
}

@NotNull
Expand Down Expand Up @@ -72,7 +69,6 @@ public KeyPair getKeyPair() {
}

public void setKeyPair(@NotNull KeyPair keyPair) {
KEY_MAP.put(getUniqueId(), new AbstractMap.SimpleImmutableEntry<>(keyPair, remotePublicKey));
this.keyPair = keyPair;
}

Expand All @@ -95,15 +91,19 @@ public PublicKey getRemotePublicKey() {
@Override
public void setRemotePublicKey(@NotNull PublicKey remotePublicKey) {
Objects.requireNonNull(remotePublicKey, "remotePublicKey is null");
KEY_MAP.put(getUniqueId(), new AbstractMap.SimpleImmutableEntry<>(keyPair, remotePublicKey));
this.remotePublicKey = remotePublicKey;
}

public void setRemotePublicKeyInternal(@Nullable PublicKey remotePublicKey) {
KEY_MAP.put(getUniqueId(), new AbstractMap.SimpleImmutableEntry<>(keyPair, remotePublicKey));
this.remotePublicKey = remotePublicKey;
}

@Override
public boolean isChallengeEquals(@NotNull String challenge) {
if (this.challenge == null) return false;
return this.challenge.equals(challenge);
}

@Override
public String toString() {
return "PlayerImpl{" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class PlayerUtil {
UUID uuid = UUID.fromString(nameOrUUID);
return new SimplePlayer(uuid, null);
} catch (IllegalArgumentException ignored) {}
return new PlayerImpl(Objects.requireNonNull(Bukkit.getPlayerExact(nameOrUUID), "player " + nameOrUUID + " does not exist"));
return PlayerImpl.of(Objects.requireNonNull(Bukkit.getPlayerExact(nameOrUUID), "player " + nameOrUUID + " does not exist"));
}

public static @NotNull Player getOfflinePlayer(@NotNull String nameOrUUID) {
Expand Down
Loading

0 comments on commit 83e0c1e

Please sign in to comment.