Skip to content

Commit be51a0f

Browse files
committed
Confirm before linking by default
1 parent 22e40dc commit be51a0f

6 files changed

Lines changed: 139 additions & 23 deletions

File tree

build.gradle

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ plugins {
99
allprojects {
1010
group = 'com.xinecraft'
1111
description = 'Minetrax'
12-
version = '6.3.0'
12+
version = '7.0.0'
1313

1414
repositories {
1515
mavenLocal()
@@ -21,7 +21,6 @@ allprojects {
2121
maven { url "https://repo.aikar.co/content/groups/aikar/" }
2222
maven { url 'https://papermc.io/repo/repository/maven-public/' }
2323
maven { url 'https://hub.spigotmc.org/nexus/content/groups/public/' }
24-
maven { url "https://maven.matrixstudios.ltd/public" }
2524

2625
maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
2726
maven { url 'https://repo.extendedclip.com/content/repositories/placeholderapi/' }

bukkit/src/main/java/com/xinecraft/minetrax/bukkit/MinetraxBukkit.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ public final class MinetraxBukkit extends JavaPlugin implements Listener, Minetr
9393
private List<String> playerLinkInitAlreadyLinkedMessage;
9494
private List<String> playerLinkErrorMessage;
9595
private List<String> playerLinkSuccessMessage;
96+
private List<String> playerLinkConfirmationMessage;
97+
private String playerLinkConfirmationTitle;
98+
private String playerLinkConfirmationSubtitle;
99+
private ConcurrentHashMap<String, String> playerLinkPendingVerificationMap = new ConcurrentHashMap<>();
100+
private Boolean isPlayerLinkConfirmationEnabled;
96101
private long afkThresholdInMs;
97102
public ConcurrentHashMap<String, PlayerData> playersDataMap;
98103
public ConcurrentHashMap<String, PlayerSessionIntelData> playerSessionIntelDataMap;
@@ -110,6 +115,8 @@ public final class MinetraxBukkit extends JavaPlugin implements Listener, Minetr
110115
public Boolean isBanWardenEnabled = false;
111116
public Gson gson = null;
112117
private MinetraxCommon common;
118+
private String processingMessage;
119+
private String cancelledMessage;
113120

114121
private static Permission perms = null;
115122
private static Economy economy = null;
@@ -243,7 +250,7 @@ public void onEnable() {
243250

244251
// Setup Schedulers
245252
if (isRemindPlayerToLinkEnabled) {
246-
getServer().getScheduler().scheduleSyncRepeatingTask(this, new AccountLinkReminderTask(), remindPlayerToLinkInterval * 20L, remindPlayerToLinkInterval * 20L);
253+
getServer().getScheduler().runTaskTimerAsynchronously(this, new AccountLinkReminderTask(), remindPlayerToLinkInterval * 20L, remindPlayerToLinkInterval * 20L);
247254
}
248255
if (isServerIntelEnabled) {
249256
getServer().getScheduler().runTaskTimerAsynchronously(this, new ServerIntelReportTask(), 60 * 20L, 60 * 20L); // every minute
@@ -341,6 +348,10 @@ private void initVariables() {
341348
playerLinkInitAlreadyLinkedMessage = this.getConfig().getStringList("player-link-init-already-linked-message");
342349
playerLinkErrorMessage = this.getConfig().getStringList("player-link-error-message");
343350
playerLinkSuccessMessage = this.getConfig().getStringList("player-link-success-message");
351+
isPlayerLinkConfirmationEnabled = this.getConfig().getBoolean("enable-player-link-confirmation", true);
352+
playerLinkConfirmationMessage = this.getConfig().getStringList("player-link-confirmation-message");
353+
playerLinkConfirmationTitle = this.getConfig().getString("player-link-confirmation-title");
354+
playerLinkConfirmationSubtitle = this.getConfig().getString("player-link-confirmation-subtitle");
344355
afkThresholdInMs = this.getConfig().getLong("afk-threshold-in-seconds", 300) * 1000;
345356
isAllowOnlyWhitelistedCommandsFromWeb = this.getConfig().getBoolean("allow-only-whitelisted-commands-from-web");
346357
whitelistedCommandsFromWeb = this.getConfig().getStringList("whitelisted-commands-from-web");
@@ -349,6 +360,8 @@ private void initVariables() {
349360
isSkinsRestorerHookEnabled = this.getConfig().getBoolean("enable-skinsrestorer-hook", true);
350361
isBanWardenEnabled = this.getConfig().getBoolean("enable-banwarden", true);
351362
serverSessionId = UUID.randomUUID().toString();
363+
processingMessage = this.getConfig().getString("processing-message", "&6Processing...");
364+
cancelledMessage = this.getConfig().getString("cancelled-message", "&cCancelled!");
352365
}
353366

354367
private void startWebQueryServer() {

bukkit/src/main/java/com/xinecraft/minetrax/bukkit/commands/AccountLinkCommand.java

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,21 @@
66
import com.xinecraft.minetrax.common.responses.GenericApiResponse;
77
import com.xinecraft.minetrax.common.utils.MinetraxHttpUtil;
88
import de.themoep.minedown.adventure.MineDown;
9+
import net.kyori.adventure.title.Title;
910
import org.bukkit.Bukkit;
1011
import org.bukkit.command.Command;
1112
import org.bukkit.command.CommandExecutor;
1213
import org.bukkit.command.CommandSender;
1314
import org.bukkit.entity.Player;
1415
import org.jetbrains.annotations.NotNull;
1516

17+
import java.time.Duration;
1618
import java.util.List;
19+
import java.util.concurrent.ConcurrentHashMap;
1720

1821
public class AccountLinkCommand implements CommandExecutor {
22+
private final boolean isConfirmationEnabled = MinetraxBukkit.getPlugin().getIsPlayerLinkConfirmationEnabled();
23+
1924
@Override
2025
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, String[] strings) {
2126
if (!(commandSender instanceof Player player)) {
@@ -25,9 +30,19 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command
2530

2631
PlayerData playerData = MinetraxBukkit.getPlugin().playersDataMap.get(player.getUniqueId().toString());
2732

28-
List<String> withoutParamsMessage = playerData != null && playerData.is_verified ? MinetraxBukkit.getPlugin().getPlayerLinkInitAlreadyLinkedMessage() : MinetraxBukkit.getPlugin().getPlayerLinkInitMessage();
33+
// Already linked
34+
if (playerData != null && playerData.is_verified) {
35+
for (String line : MinetraxBukkit.getPlugin().getPlayerLinkInitAlreadyLinkedMessage()) {
36+
line = line.replace("{WEB_URL}", MinetraxBukkit.getPlugin().getApiHost());
37+
line = line.replace("{LINK_URL}", MinetraxHttpUtil.getUrl(MinetraxHttpUtil.ACCOUNT_LINK_ROUTE));
38+
MinetraxBukkit.getPlugin().adventure().player(player).sendMessage(MineDown.parse(line));
39+
}
40+
return true;
41+
}
42+
2943
// Send Init message if only /link
3044
if (strings.length == 0) {
45+
List<String> withoutParamsMessage = MinetraxBukkit.getPlugin().getPlayerLinkInitMessage();
3146
for (String line : withoutParamsMessage) {
3247
line = line.replace("{LINK_URL}", MinetraxHttpUtil.getUrl(MinetraxHttpUtil.ACCOUNT_LINK_ROUTE));
3348
line = line.replace("{WEB_URL}", MinetraxBukkit.getPlugin().getApiHost());
@@ -38,6 +53,49 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command
3853

3954
// Send Linking message if /link <otp>
4055
String otpCode = strings[0];
56+
if (isConfirmationEnabled) {
57+
ConcurrentHashMap<String, String> pendingVerifications = MinetraxBukkit.getPlugin().getPlayerLinkPendingVerificationMap();
58+
if (otpCode.equalsIgnoreCase("confirm")) {
59+
String pendingOtp = pendingVerifications.get(player.getUniqueId().toString());
60+
if (pendingOtp == null) {
61+
MinetraxBukkit.getPlugin().adventure().player(player).sendMessage(
62+
MineDown.parse("&cNo OTP pending confirmation. Please enter your OTP first.")
63+
);
64+
return true;
65+
}
66+
String processingMessage = MinetraxBukkit.getPlugin().getProcessingMessage();
67+
MinetraxBukkit.getPlugin().adventure().player(player).sendMessage(MineDown.parse(processingMessage));
68+
linkAccount(player, pendingOtp);
69+
pendingVerifications.remove(player.getUniqueId().toString());
70+
} else if (otpCode.equalsIgnoreCase("deny") || otpCode.equalsIgnoreCase("cancel")) {
71+
pendingVerifications.remove(player.getUniqueId().toString());
72+
String cancelledMessage = MinetraxBukkit.getPlugin().getCancelledMessage();
73+
MinetraxBukkit.getPlugin().adventure().player(player).sendMessage(MineDown.parse(cancelledMessage));
74+
} else {
75+
pendingVerifications.put(player.getUniqueId().toString(), otpCode);
76+
77+
String playerLinkConfirmationTitle = MinetraxBukkit.getPlugin().getPlayerLinkConfirmationTitle();
78+
String playerLinkConfirmationSubtitle = MinetraxBukkit.getPlugin().getPlayerLinkConfirmationSubtitle();
79+
if (!playerLinkConfirmationSubtitle.isBlank() || !playerLinkConfirmationTitle.isBlank()) {
80+
final Title.Times times = Title.Times.times(Duration.ofMillis(500), Duration.ofMillis(6000), Duration.ofMillis(1000));
81+
final Title title = Title.title(MineDown.parse(playerLinkConfirmationTitle), MineDown.parse(playerLinkConfirmationSubtitle), times);
82+
MinetraxBukkit.getPlugin().adventure().player(player).showTitle(title);
83+
}
84+
85+
for (String line : MinetraxBukkit.getPlugin().getPlayerLinkConfirmationMessage()) {
86+
line = line.replace("{LINK_URL}", MinetraxHttpUtil.getUrl(MinetraxHttpUtil.ACCOUNT_LINK_ROUTE));
87+
line = line.replace("{WEB_URL}", MinetraxBukkit.getPlugin().getApiHost());
88+
MinetraxBukkit.getPlugin().adventure().player(player).sendMessage(MineDown.parse(line));
89+
}
90+
}
91+
} else {
92+
linkAccount(player, otpCode);
93+
}
94+
95+
return true;
96+
}
97+
98+
private void linkAccount(Player player, String otpCode) {
4199
Bukkit.getScheduler().runTaskAsynchronously(MinetraxBukkit.getPlugin(), () -> {
42100
try {
43101
GenericApiResponse response = LinkAccount.link(
@@ -51,7 +109,6 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command
51109
line = line.replace("{ERROR_MESSAGE}", response.getMessage());
52110
MinetraxBukkit.getPlugin().adventure().player(player).sendMessage(MineDown.parse(line));
53111
}
54-
return;
55112
} else {
56113
for (String line : MinetraxBukkit.getPlugin().getPlayerLinkSuccessMessage()) {
57114
line = line.replace("{LINK_URL}", MinetraxHttpUtil.getUrl(MinetraxHttpUtil.ACCOUNT_LINK_ROUTE));
@@ -67,7 +124,5 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command
67124
}
68125
}
69126
});
70-
71-
return true;
72127
}
73128
}

bukkit/src/main/java/com/xinecraft/minetrax/bukkit/listeners/PlayerJoinLeaveListener.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,20 @@
55
import com.xinecraft.minetrax.bukkit.MinetraxBukkit;
66
import com.xinecraft.minetrax.bukkit.utils.PlayerUtil;
77
import com.xinecraft.minetrax.bukkit.utils.SkinUtil;
8-
import com.xinecraft.minetrax.common.utils.LoggingUtil;
9-
import com.xinecraft.minetrax.common.utils.VersionUtil;
108
import com.xinecraft.minetrax.common.actions.FetchPlayerData;
119
import com.xinecraft.minetrax.common.actions.ReportPlayerIntel;
1210
import com.xinecraft.minetrax.common.actions.ReportServerChat;
1311
import com.xinecraft.minetrax.common.data.PlayerData;
1412
import com.xinecraft.minetrax.common.data.PlayerSessionIntelData;
1513
import com.xinecraft.minetrax.common.data.PlayerWorldStatsIntelData;
1614
import com.xinecraft.minetrax.common.responses.GenericApiResponse;
15+
import com.xinecraft.minetrax.common.utils.LoggingUtil;
16+
import com.xinecraft.minetrax.common.utils.MinetraxHttpUtil;
17+
import com.xinecraft.minetrax.common.utils.VersionUtil;
1718
import com.xinecraft.minetrax.common.utils.WhoisUtil;
1819
import de.themoep.minedown.adventure.MineDown;
1920
import net.skinsrestorer.api.PropertyUtils;
20-
import net.skinsrestorer.api.SkinsRestorer;
21-
import net.skinsrestorer.api.SkinsRestorerProvider;
2221
import net.skinsrestorer.api.property.SkinProperty;
23-
import net.skinsrestorer.api.storage.PlayerStorage;
2422
import org.bukkit.Bukkit;
2523
import org.bukkit.ChatColor;
2624
import org.bukkit.World;
@@ -51,6 +49,13 @@ public void onPlayerJoin(PlayerJoinEvent event) {
5149
// perform whois & add player to list of linkedPlayers hashmap
5250
this.broadcastWhoisForPlayer(event.getPlayer());
5351
}
52+
53+
// Schedule AccountLinkReminder
54+
if (MinetraxBukkit.getPlugin().getIsRemindPlayerToLinkEnabled()) {
55+
Bukkit.getScheduler().runTaskLater(MinetraxBukkit.getPlugin(), () -> {
56+
runAccountLinkReminder(event.getPlayer());
57+
}, 20L * 30L);
58+
}
5459
}
5560

5661
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@@ -238,4 +243,29 @@ public void run() {
238243
// Remove player data map.
239244
MinetraxBukkit.getPlugin().playersDataMap.remove(key);
240245
}
246+
247+
private void runAccountLinkReminder(Player player) {
248+
// If player is not online, return.
249+
if (!player.isOnline()) {
250+
return;
251+
}
252+
253+
Boolean isAlreadyLinkedReminderEnabled = MinetraxBukkit.getPlugin().getIsRemindPlayerWhenAlreadyLinkedEnabled();
254+
PlayerData playerData = MinetraxBukkit.getPlugin().playersDataMap.get(player.getUniqueId().toString());
255+
256+
if (playerData == null) {
257+
return;
258+
}
259+
if (playerData.is_verified && !isAlreadyLinkedReminderEnabled) {
260+
return;
261+
}
262+
263+
List<String> messageList = playerData.is_verified ? MinetraxBukkit.getPlugin().getRemindPlayerWhenAlreadyLinkedMessage() : MinetraxBukkit.getPlugin().getRemindPlayerToLinkMessage();
264+
for (String line : messageList) {
265+
line = line.replace("{LINK_URL}", MinetraxHttpUtil.getUrl(MinetraxHttpUtil.ACCOUNT_LINK_ROUTE));
266+
line = line.replace("{WEB_URL}", MinetraxBukkit.getPlugin().getApiHost());
267+
line = line.replace("{PROFILE_URL}", playerData.profile_link);
268+
MinetraxBukkit.getPlugin().adventure().player(player).sendMessage(MineDown.parse(line));
269+
}
270+
}
241271
}

bukkit/src/main/resources/config.yml

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,30 +47,42 @@ remind-player-link-message:
4747
- "&cPlease follow these steps to link:"
4848
- "&61. &fVisit &b[{WEB_URL}]({WEB_URL} Click to visit)&f and log in or register."
4949
- "&62. &fNavigate to &eProfile > Linked Players&f, or directly visit &b[{LINK_URL}]({LINK_URL} Click to visit)&f."
50-
- "&63. &fCopy the generated code and enter it in the chat, eg: &e/link 123456"
50+
- "&63. &fCopy the generated code, enter it in the chat and confirm, eg: &e/link 123456"
5151
# Keep sending reminder to player even if they are already linked.
5252
remind-player-when-already-linked: false
5353
# The message send to player to remind them that their account is already linked
5454
remind-player-already-linked-message:
55-
- "&aYay! Your player is already linked."
56-
- "&aVisit [{WEB_URL}]({WEB_URL} Click to visit) to view your stats and more."
55+
- "&a&lYour player is already linked."
56+
- "&aVisit [{LINK_URL}]({LINK_URL} Click to visit) to manage."
5757
# Message when player send /account-link without otp parameter
5858
player-link-init-message:
5959
- "&6&lPlease follow these steps to link:"
6060
- "&61. &fVisit &b[{WEB_URL}]({WEB_URL} Click to visit)&f and log in or register."
6161
- "&62. &fNavigate to &eProfile > Linked Players&f, or directly visit &b[{LINK_URL}]({LINK_URL} Click to visit)&f."
62-
- "&63. &fCopy the generated code and enter it in the chat, eg: &e/link 123456"
62+
- "&63. &fCopy the generated code, enter it in the chat and confirm, eg: &e/link 123456"
6363
# Message when player send /account-link while player is already linked
6464
player-link-init-already-linked-message:
65-
- "&aYay! Your player is already linked."
66-
- "&aVisit [{WEB_URL}]({WEB_URL} Click to visit) to view your stats and more."
65+
- "&a&lYour player is already linked."
66+
- "&aVisit [{LINK_URL}]({LINK_URL} Click to visit) to manage."
6767
# If get error message response from server
6868
player-link-error-message:
69-
- "&c&lOops! Some error occurred while linking your account:"
70-
- "&c{ERROR_MESSAGE}"
69+
- "&cOops! Some error occurred while linking:"
70+
- "&c&l{ERROR_MESSAGE}"
7171
# Message when player linking is successful
7272
player-link-success-message:
7373
- "&a&lCongratulations! Your account has been successfully linked."
74+
# Enable player link confirmation to prevent accidental linking
75+
enable-player-link-confirmation: true
76+
# Message when player linking need confirmation
77+
player-link-confirmation-message:
78+
- "&6&lAre you sure you want to link your account?"
79+
- "&lClick -> [&a&lConfirm](run_command=/link confirm) [&c&lDeny](run_command=/link deny)"
80+
- ""
81+
- "&6or manually type &a/link confirm&r &6or &c/link deny&r"
82+
# Title to show when player linking need confirmation
83+
player-link-confirmation-title: "&6Confirmation Required"
84+
# Subtitle to show when player linking need confirmation
85+
player-link-confirmation-subtitle: "Please check chat to &aconfirm&f or &cdeny&f linking."
7486
# If this is enabled it will send whois information about players when they join the server
7587
enable-whois-on-player-join: true
7688
# If this is enabled players with permission can run the /webwhois or /ww command
@@ -87,21 +99,21 @@ whois-player-on-join-message:
8799
- "&6Position&r: &b&l#{POSITION}&r - &6Rank&r: &b&l{RANK}&r"
88100
- "&6Rating&r: &b&l{RATING}&r - &6Score&r: &b&l{SCORE}&r"
89101
- "&6Linked with&r: &b&l{USER}&r - &6Last Seen&r: &b&l{LAST_SEEN}&r"
90-
- "&e&o[{URL}]({URL})&r"
102+
- "&e&o[{URL}]({URL})"
91103
# This is the format of message that is sent when player runs /ww command
92104
whois-player-on-command-message:
93105
- "&a&l{USERNAME}&r is from &a&l{COUNTRY}&r"
94106
- "&6Position&r: &b&l#{POSITION}&r - &6Rank&r: &b&l{RANK}&r"
95107
- "&6Rating&r: &b&l{RATING}&r - &6Score&r: &b&l{SCORE}&r"
96108
- "&6Linked with&r: &b&l{USER}&r - &6Last Seen&r: &b&l{LAST_SEEN}&r"
97-
- "&e&o[{URL}]({URL})&r"
109+
- "&e&o[{URL}]({URL})"
98110
# This is the format of message that is sent when admin runs /ww command
99111
whois-player-on-admin-command-message:
100112
- "&a&l{USERNAME}&r is from &a&l{GEO}&r"
101113
- "&6Position&r: &b&l#{POSITION}&r - &6Rank&r: &b&l{RANK}&r"
102114
- "&6Rating&r: &b&l{RATING}&r - &6Score&r: &b&l{SCORE}&r"
103115
- "&6Linked with&r: &b&l{USER}&r - &6Last Seen&r: &b&l{LAST_SEEN}&r"
104-
- "&e&o[{URL}]({URL})&r"
116+
- "&e&o[{URL}]({URL})"
105117
# This is the message sent when there are more than 1 player found
106118
whois-multiple-players-title-message: '&a&lThere is total &e&l{COUNT}&r &a&lplayers found.'
107119
# This is the message sent to show list of players found
@@ -124,3 +136,7 @@ whitelisted-commands-from-web:
124136
enable-skinsrestorer-hook: true
125137
# If enabled this will let minetrax hook into your ban plugin and sync bans to website.
126138
enable-banwarden: true
139+
# Processing text
140+
processing-message: '&7Processing...'
141+
# Cancelled text
142+
cancelled-message: '&7Cancelled!'

common/src/main/java/com/xinecraft/minetrax/common/utils/VersionUtil.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
public class VersionUtil {
1111
private static final Map<Integer, String> protocolToVersion = new HashMap<>();
1212
static {
13+
protocolToVersion.put(769, "1.21");
14+
protocolToVersion.put(768, "1.21");
15+
protocolToVersion.put(767, "1.21");
1316
protocolToVersion.put(766, "1.20");
1417
protocolToVersion.put(765, "1.20");
1518
protocolToVersion.put(764, "1.20");

0 commit comments

Comments
 (0)