Skip to content
Closed
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
1,345 changes: 683 additions & 662 deletions VotingPlugin/pom.xml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,10 @@ private void handleWireVote(JsonEnvelope msg) {

boolean setTotalsOnBackend = !v.manageTotals;

user.bungeeVotePluginMessaging(service, v.time, text, setTotalsOnBackend, v.wasOnline, v.broadcast, v.num);
boolean identifiedQueuedDelivery = VotingPluginWire.SUB_VOTE_ONLINE.equals(msg.getSubChannel())
&& v.voteId != null;
Comment on lines +654 to +655

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Verify queue provenance before bypassing the delay

A VoteOnline subchannel plus any non-null wire-supplied UUID does not prove that this message is the current delivery of an OnlineCache entry. After processedWireVotes expires the UUID in 30 minutes (or after a backend restart), replaying a previously accepted VoteOnline reserves the ID again; its timestamp still equals LastVotes, so this classification causes the listener to skip WaitUntilVoteDelay and process duplicate rewards/totals. A forged VoteOnline with a fresh UUID and the stored timestamp has the same result. Bind the exception to actual queue-delivery provenance rather than these forgeable fields.

Useful? React with 👍 / 👎.

user.bungeeVotePluginMessaging(service, v.time, text, setTotalsOnBackend, v.wasOnline, v.broadcast, v.num,
identifiedQueuedDelivery);
Comment on lines +656 to +657

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Suppress per-server points when the delay rejects the vote

When PerServerPoints is enabled and an ordinary, stale, or unidentified proxy vote fails WaitUntilVoteDelay, bungeeVotePluginMessaging only fires the event and returns normally after PlayerVoteListener exits early. The handler then unconditionally executes the user.addPoints(...) block immediately below, so a delay-rejected message still awards points; forged messages with fresh vote IDs can repeat this even though their normal rewards and totals are blocked. Propagate whether the event was accepted and grant per-server points only after successful processing.

Useful? React with 👍 / 👎.


if (plugin.getBungeeSettings().isPerServerPoints()) {
user.addPoints(plugin.getConfigFile().getPointsOnVote());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ public static HandlerList getHandlerList() {
@Getter
@Setter
private boolean wasOnline;

/** Whether this event is the identified delivery of a queued proxy vote. */
@Getter
@Setter
private boolean queuedProxyVote;

@Getter
@Setter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ public void onplayerVote(PlayerVoteEvent event) {
}
}

boolean queuedProxyVoteAlreadyRecorded = ProxyVoteDelayCheck.isQueuedVoteAlreadyRecorded(event.isBungee(),
event.getTime(), user.getTime(voteSite));
boolean queuedProxyVoteAlreadyRecorded = event.isBungee() && event.isQueuedProxyVote()
&& event.getTime() > 0L && event.getTime() == user.getTime(voteSite);
if (voteSite.isWaitUntilVoteDelay() && !queuedProxyVoteAlreadyRecorded && !user.canVoteSite(voteSite)) {
if (!event.isRealVote()) {
plugin.getLogger().info(user.getPlayerName() + " did a not real vote, bypassing WaitUntilVoteDelay");
Expand All @@ -183,11 +183,6 @@ public void onplayerVote(PlayerVoteEvent event) {
.info(user.getPlayerName() + " has bypass permission for WaitUntilVoteDelay, bypassing");
}
}
if (queuedProxyVoteAlreadyRecorded) {
plugin.debug("Allowing queued proxy vote for " + user.getPlayerName() + " on " + voteSite.getKey()
+ "; proxy vote time already matches LastVotes: " + event.getTime());
}

UUID voteUUID = UUID.randomUUID();
if (event.isBungee() && event.getBungeeTextTotals() != null) {
voteUUID = event.getBungeeTextTotals().getVoteUUID();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,8 @@ public void addWeekVoteStreak() {
* @param broadcast whether to broadcast the vote
* @param num the vote number
*/
public void bungeeVotePluginMessaging(String service, long time, VoteTotalsSnapshot text, boolean setTotals,
boolean wasOnline, boolean broadcast, int num) {
public void bungeeVotePluginMessaging(String service, long time, VoteTotalsSnapshot text, boolean setTotals,
boolean wasOnline, boolean broadcast, int num, boolean queuedProxyVote) {
Comment on lines +262 to +263

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the existing public vote-messaging overload

Changing this public method's descriptor from seven parameters to eight removes the method that already-compiled integrations link against. The project publishes the plugin as a Maven dependency and generates API documentation, so any downstream plugin calling the former bungeeVotePluginMessaging(..., int) overload will fail with NoSuchMethodError after upgrading even though its source remains valid against the prior release. Keep the old overload and delegate it to the new method with queuedProxyVote set to false.

Useful? React with 👍 / 👎.

if (plugin.getBungeeSettings().isUseBungeecoord()) {
plugin.debug("Pluginmessaging vote for " + getPlayerName() + " on " + service);

Expand All @@ -275,6 +275,7 @@ public void bungeeVotePluginMessaging(String service, long time, VoteTotalsSnaps
voteEvent.setWasOnline(wasOnline);
voteEvent.setBroadcast(broadcast);
voteEvent.setVoteNumber(num);
voteEvent.setQueuedProxyVote(queuedProxyVote);
plugin.getServer().getPluginManager().callEvent(voteEvent);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.bencodez.votingplugin.tests;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;

import com.bencodez.votingplugin.events.PlayerVoteEvent;

/**
* Tests queue-delivery metadata carried by proxy vote events.
*/
public class PlayerVoteEventTest {

@Test
public void eventIsNotQueuedByDefault() {
PlayerVoteEvent event = new PlayerVoteEvent(null, "Player", "Service", true);

assertFalse(event.isQueuedProxyVote());
}

@Test
public void eventCanMarkAnIdentifiedQueuedProxyDelivery() {
PlayerVoteEvent event = new PlayerVoteEvent(null, "Player", "Service", true);

event.setQueuedProxyVote(true);

assertTrue(event.isQueuedProxyVote());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public void voteRoundTripPreservesVoteId() {
Vote vote = VotingPluginWire.readVote(envelope);

assertEquals(voteId, vote.voteId);
assertEquals(VotingPluginWire.SUB_VOTE, envelope.getSubChannel());
assertEquals("Player", vote.player);
assertEquals("Service", vote.service);
}
Expand All @@ -39,6 +40,20 @@ public void voteOnlineRoundTripAllowsMissingVoteId() {
Vote vote = VotingPluginWire.readVote(envelope);

assertNull(vote.voteId);
assertEquals(VotingPluginWire.SUB_VOTE_ONLINE, envelope.getSubChannel());
}

@Test
public void voteOnlineRoundTripPreservesIdentifiedQueuedVote() {
UUID voteId = UUID.randomUUID();

JsonEnvelope envelope = VotingPluginWire.voteOnline("Player", UUID.randomUUID().toString(), "Service",
100L, true, true, "totals", voteId, true, false, 1, 1);

Vote vote = VotingPluginWire.readVote(envelope);

assertEquals(VotingPluginWire.SUB_VOTE_ONLINE, envelope.getSubChannel());
assertEquals(voteId, vote.voteId);
}

@Test
Expand Down
Loading