Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1582,15 +1582,15 @@ protected void handleLoginMessage(JsonEnvelope message) {
boolean accepted = false;
String deliveryServer = server;
if (legacy) {
// Preserve the original login contract for cached rewards. In
// PLUGINMESSAGING mode the player-facing proxy is authoritative for online
// state and backend presence messages are disabled entirely.
accepted = true;
if (method == BungeeMethod.PLUGINMESSAGING) {
String proxyServer = getCurrentPlayerServer(player);
if (proxyServer != null && !proxyServer.isBlank()) {
accepted = isLegacyLoginDestinationAuthoritative(player, uuid, proxyServer);
if (accepted) {
deliveryServer = proxyServer;
}
} else if (method != null && method.supportsBackendPresence()
&& isPresenceServerValid(server, VotingPluginWire.SUB_LOGIN)) {
accepted = isLegacyLoginDestinationAuthoritative(player, uuid, server);
}
} else if (method != null && method.supportsBackendPresence() && event.connectionId != null
&& isPresenceServerValid(server, VotingPluginWire.SUB_LOGIN)
Expand Down Expand Up @@ -1618,6 +1618,52 @@ && isPresenceGenerationValid(event.backendIncarnationId, event.backendStartedAt,
}
}

/**
* Validates a legacy login against an authority independent of the envelope.
* Player-facing proxies use their native live route and UUID. A dedicated
* voting proxy has no native player session, so it requires an exact modern
* presence match for the claimed destination.
*/
private boolean isLegacyLoginDestinationAuthoritative(String player, String uuid, String server) {
if (server == null || server.isBlank()) {
return false;
}

UUID claimedUuid;
try {
claimedUuid = UUID.fromString(uuid.trim());
} catch (RuntimeException e) {
return false;
}

if (isDedicatedVotingProxyEnabled()) {
PlayerPresence presence = backendPlayerPresenceTracker.getPlayer(player).orElse(null);
return presence != null && presence.getServer().equalsIgnoreCase(server)
&& (!getConfig().getOnlineMode() || presence.getUuid().equals(claimedUuid));
}

if (!isPlayerOnline(player)) {
return false;
}
String proxyServer = getCurrentPlayerServer(player);
if (proxyServer == null || !proxyServer.equalsIgnoreCase(server)) {
return false;
}
if (!getConfig().getOnlineMode()) {
return true;
}

String authoritativeUuid = getUUID(player);
if (authoritativeUuid == null || authoritativeUuid.isBlank()) {
return false;
}
try {
return claimedUuid.equals(UUID.fromString(authoritativeUuid.trim()));
} catch (IllegalArgumentException e) {
return false;
}
}

private VoteLogMysqlTable voteLogMysqlTable;

@Getter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,12 @@ void immediatePluginMessageReportsActualDeliveryResult() {
}

@Test
void pluginMessagingLegacyLoginUsesTheProxyCurrentServer() {
void pluginMessagingLegacyLoginUsesTheProxyCurrentServerAndUuid() {
String uuid = java.util.UUID.randomUUID().toString();
Mockito.when(votingPluginProxy.getConfig().getOnlineMode()).thenReturn(true);
votingPluginProxy.setMethod(BungeeMethod.PLUGINMESSAGING);
VotingPluginProxyTestImpl spyProxy = Mockito.spy(votingPluginProxy);
Mockito.doReturn(uuid).when(spyProxy).getUUID("Player");
doNothing().when(spyProxy).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());

spyProxy.handleLoginMessageForTest(VotingPluginWire.login("Player", uuid, "claimed-backend"));
Expand All @@ -137,15 +139,136 @@ void pluginMessagingLegacyLoginUsesTheProxyCurrentServer() {
}

@Test
void standaloneTransportLegacyLoginKeepsOriginalCompatibilityPath() {
void pluginMessagingLegacyLoginRejectsMismatchedUuid() {
String authoritativeUuid = java.util.UUID.randomUUID().toString();
String claimedUuid = java.util.UUID.randomUUID().toString();
Mockito.when(votingPluginProxy.getConfig().getOnlineMode()).thenReturn(true);
votingPluginProxy.setMethod(BungeeMethod.PLUGINMESSAGING);
VotingPluginProxyTestImpl spyProxy = Mockito.spy(votingPluginProxy);
Mockito.doReturn(authoritativeUuid).when(spyProxy).getUUID("Player");
doNothing().when(spyProxy).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());

spyProxy.handleLoginMessageForTest(VotingPluginWire.login("Player", claimedUuid, "Server1"));

verify(spyProxy, never()).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());
}

@Test
void standaloneTransportLegacyLoginUsesProxyAuthoritativeRoute() {
String uuid = java.util.UUID.randomUUID().toString();
Mockito.when(votingPluginProxy.getConfig().getOnlineMode()).thenReturn(true);
votingPluginProxy.setMethod(BungeeMethod.MQTT);
VotingPluginProxyTestImpl spyProxy = Mockito.spy(votingPluginProxy);
Mockito.doReturn(uuid).when(spyProxy).getUUID("Player");
doNothing().when(spyProxy).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());

spyProxy.handleLoginMessageForTest(VotingPluginWire.login("Player", uuid, "Server1"));

verify(spyProxy).login("Player", uuid, "Server1");
}

@Test
void standaloneTransportLegacyLoginRejectsUnknownServer() {
String uuid = java.util.UUID.randomUUID().toString();
votingPluginProxy.setMethod(BungeeMethod.MQTT);
VotingPluginProxyTestImpl spyProxy = Mockito.spy(votingPluginProxy);
Mockito.doReturn(false).when(spyProxy).isServerValid("unknown-server");
doNothing().when(spyProxy).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());

spyProxy.handleLoginMessageForTest(VotingPluginWire.login("Player", uuid, "survival"));
spyProxy.handleLoginMessageForTest(VotingPluginWire.login("Player", uuid, "unknown-server"));

verify(spyProxy).login("Player", uuid, "survival");
verify(spyProxy, never()).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());
}

@Test
void standaloneTransportLegacyLoginAcceptsModernToLegacyHandoffUsingProxyRoute() {
java.util.UUID playerUuid = java.util.UUID.randomUUID();
java.util.UUID incarnation = java.util.UUID.randomUUID();
long now = System.currentTimeMillis();
Mockito.when(votingPluginProxy.getConfig().getOnlineMode()).thenReturn(true);
votingPluginProxy.setMethod(BungeeMethod.MQTT);
assertTrue(votingPluginProxy.getBackendPlayerPresenceTracker().backendStarted("Server1", incarnation,
1000L, 1000L, now));
assertTrue(votingPluginProxy.getBackendPlayerPresenceTracker().playerOnline("Player",
playerUuid.toString(), "Server1", java.util.UUID.randomUUID(), incarnation, 1000L, 1100L,
now));
VotingPluginProxyTestImpl spyProxy = Mockito.spy(votingPluginProxy);
Mockito.doReturn("Server2").when(spyProxy).getCurrentPlayerServer("Player");
Mockito.doReturn(playerUuid.toString()).when(spyProxy).getUUID("Player");
doNothing().when(spyProxy).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());

spyProxy.handleLoginMessageForTest(
VotingPluginWire.login("Player", playerUuid.toString(), "Server2"));

verify(spyProxy).login("Player", playerUuid.toString(), "Server2");
}

@Test
void standaloneTransportLegacyLoginRejectsClaimNotMatchingProxyRoute() {
String uuid = java.util.UUID.randomUUID().toString();
Mockito.when(votingPluginProxy.getConfig().getOnlineMode()).thenReturn(true);
votingPluginProxy.setMethod(BungeeMethod.MQTT);
VotingPluginProxyTestImpl spyProxy = Mockito.spy(votingPluginProxy);
Mockito.doReturn(uuid).when(spyProxy).getUUID("Player");
doNothing().when(spyProxy).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());

spyProxy.handleLoginMessageForTest(VotingPluginWire.login("Player", uuid, "Server2"));

verify(spyProxy, never()).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());
}

@Test
void standaloneTransportLegacyLoginRejectsNameUuidMismatch() {
String aliceUuid = java.util.UUID.randomUUID().toString();
String bobUuid = java.util.UUID.randomUUID().toString();
Mockito.when(votingPluginProxy.getConfig().getOnlineMode()).thenReturn(true);
votingPluginProxy.setMethod(BungeeMethod.MQTT);
VotingPluginProxyTestImpl spyProxy = Mockito.spy(votingPluginProxy);
Mockito.doReturn(aliceUuid).when(spyProxy).getUUID("Alice");
doNothing().when(spyProxy).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());

spyProxy.handleLoginMessageForTest(VotingPluginWire.login("Alice", bobUuid, "Server1"));

verify(spyProxy, never()).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());
}

@Test
void dedicatedProxyLegacyLoginRequiresConfirmedDestinationPresence() {
java.util.UUID playerUuid = java.util.UUID.randomUUID();
java.util.UUID incarnation = java.util.UUID.randomUUID();
long now = System.currentTimeMillis();
Mockito.when(votingPluginProxy.getConfig().getOnlineMode()).thenReturn(true);
Mockito.when(votingPluginProxy.getConfig().getDedicatedVotingProxy()).thenReturn(true);
votingPluginProxy.setMethod(BungeeMethod.MQTT);
assertTrue(votingPluginProxy.getBackendPlayerPresenceTracker().backendStarted("Server1", incarnation,
1000L, 1000L, now));
assertTrue(votingPluginProxy.getBackendPlayerPresenceTracker().playerOnline("Player",
playerUuid.toString(), "Server1", java.util.UUID.randomUUID(), incarnation, 1000L, 1100L,
now));
VotingPluginProxyTestImpl spyProxy = Mockito.spy(votingPluginProxy);
doNothing().when(spyProxy).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());

spyProxy.handleLoginMessageForTest(
VotingPluginWire.login("Player", playerUuid.toString(), "Server2"));
verify(spyProxy, never()).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());

spyProxy.handleLoginMessageForTest(
VotingPluginWire.login("Player", playerUuid.toString(), "Server1"));
verify(spyProxy).login("Player", playerUuid.toString(), "Server1");
}

@Test
void dedicatedProxyLegacyLoginRejectsUnknownIdentity() {
String uuid = java.util.UUID.randomUUID().toString();
Mockito.when(votingPluginProxy.getConfig().getOnlineMode()).thenReturn(true);
Mockito.when(votingPluginProxy.getConfig().getDedicatedVotingProxy()).thenReturn(true);
votingPluginProxy.setMethod(BungeeMethod.MQTT);
VotingPluginProxyTestImpl spyProxy = Mockito.spy(votingPluginProxy);
doNothing().when(spyProxy).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());

spyProxy.handleLoginMessageForTest(VotingPluginWire.login("Player", uuid, "Server1"));

verify(spyProxy, never()).login(Mockito.anyString(), Mockito.anyString(), Mockito.anyString());
}

@Test
Expand Down
Loading