Skip to content

Commit 5912e2e

Browse files
authored
Improved user text input sanitisation and extended supported chars in DB (#122)
2 parents c540a90 + 308dfcc commit 5912e2e

File tree

7 files changed

+65
-11
lines changed

7 files changed

+65
-11
lines changed

src/main/java/pro/cloudnode/smp/bankaccounts/BankConfig.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
import java.util.List;
2525
import java.util.Objects;
2626
import java.util.Optional;
27+
import java.util.Set;
2728
import java.util.TimeZone;
29+
import java.util.regex.Pattern;
2830

2931
public final class BankConfig {
3032
public @NotNull FileConfiguration config;
@@ -421,6 +423,11 @@ public int invoicePerPage() {
421423
return config.getInt("invoice.per-page");
422424
}
423425

426+
// disallowed-regex
427+
public @NotNull Pattern disallowedRegex() {
428+
return Pattern.compile(Objects.requireNonNull(config.getString("disallowed-regex")));
429+
}
430+
424431
// messages.command-usage
425432
public @NotNull Component messagesCommandUsage(final @NotNull String command, final @NotNull String arguments) {
426433
return MiniMessage.miniMessage().deserialize(
@@ -624,10 +631,10 @@ public int invoicePerPage() {
624631
}
625632

626633
// messages.errors.disallowed-characters
627-
public @NotNull Component messagesErrorsDisallowedCharacters(final @NotNull String characters) {
634+
public @NotNull Component messagesErrorsDisallowedCharacters(final @NotNull Set<@NotNull String> characters) {
628635
return MiniMessage.miniMessage().deserialize(
629636
Objects.requireNonNull(config.getString("messages.errors.disallowed-characters")),
630-
Placeholder.unparsed("characters", characters)
637+
Placeholder.unparsed("characters", String.join("", characters))
631638
);
632639
}
633640

src/main/java/pro/cloudnode/smp/bankaccounts/Command.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212

1313
import java.util.List;
1414
import java.util.Optional;
15+
import java.util.Set;
16+
import java.util.regex.Matcher;
17+
import java.util.regex.Pattern;
18+
import java.util.stream.Collectors;
1519

1620
public abstract class Command implements CommandExecutor, TabCompleter {
1721
/**
@@ -81,4 +85,18 @@ public final boolean onCommand(final @NotNull CommandSender sender, final @NotNu
8185
final @Nullable List<@NotNull String> suggestions = tab(sender, args);
8286
return Optional.ofNullable(suggestions).map(s -> s.stream().filter(suggestion -> suggestion.toLowerCase().startsWith(args[args.length - 1].toLowerCase())).toList()).orElse(null);
8387
}
88+
89+
protected static @NotNull Set<@NotNull String> getDisallowedCharacters(final @Nullable String input) {
90+
if (input == null) return Set.of();
91+
final @NotNull Set<@NotNull String> chars = input
92+
.codePoints()
93+
.filter(codePoint -> codePoint > 0xFFFF)
94+
.mapToObj(codePoint -> new String(Character.toChars(codePoint)))
95+
.collect(Collectors.toSet());
96+
final @NotNull Matcher matcher = BankAccounts.getInstance().config().disallowedRegex().matcher(input);
97+
while (matcher.find()) chars.add(matcher.group());
98+
if (input.contains("<")) chars.add("<");
99+
if (input.contains(">")) chars.add(">");
100+
return chars;
101+
}
84102
}

src/main/java/pro/cloudnode/smp/bankaccounts/commands/BankCommand.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Arrays;
2121
import java.util.Objects;
2222
import java.util.Optional;
23+
import java.util.Set;
2324
import java.util.stream.Collectors;
2425
import java.util.stream.Stream;
2526

@@ -382,8 +383,9 @@ public static boolean setName(final @NotNull CommandSender sender, final @NotNul
382383
name = name.length() > 32 ? name.substring(0, 32) : name;
383384
name = name.isEmpty() ? null : name;
384385

385-
if (name != null && (name.contains("<") || name.contains(">")))
386-
return sendMessage(sender, BankAccounts.getInstance().config().messagesErrorsDisallowedCharacters("<>"));
386+
final @NotNull Set<@NotNull String> disallowedChars = getDisallowedCharacters(name);
387+
if (!disallowedChars.isEmpty())
388+
return sendMessage(sender, BankAccounts.getInstance().config().messagesErrorsDisallowedCharacters(disallowedChars));
387389

388390
account.get().name = name;
389391
account.get().update();
@@ -499,10 +501,11 @@ public static boolean transfer(final @NotNull CommandSender sender, final @NotNu
499501

500502
@Nullable String description = args.length > 3 ? String
501503
.join(" ", Arrays.copyOfRange(argsCopy, 3, argsCopy.length)).trim() : null;
502-
if (description != null && description.length() > 64) description = description.substring(0, 64);
504+
if (description != null && description.length() > 64) description = description.substring(0, 63) + "…";
503505

504-
if (description != null && (description.contains("<") || description.contains(">")))
505-
return sendMessage(sender, BankAccounts.getInstance().config().messagesErrorsDisallowedCharacters("<>"));
506+
final @NotNull Set<@NotNull String> disallowedChars = getDisallowedCharacters(description);
507+
if (!disallowedChars.isEmpty())
508+
return sendMessage(sender, BankAccounts.getInstance().config().messagesErrorsDisallowedCharacters(disallowedChars));
506509

507510
if (!confirm && BankAccounts.getInstance().config().transferConfirmationEnabled()) {
508511
final @NotNull BigDecimal minAmount = BankAccounts.getInstance().config().transferConfirmationMinAmount();

src/main/java/pro/cloudnode/smp/bankaccounts/commands/InvoiceCommand.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.util.Arrays;
1818
import java.util.List;
1919
import java.util.Optional;
20+
import java.util.Set;
2021
import java.util.stream.Stream;
2122

2223
public final class InvoiceCommand extends Command {
@@ -176,7 +177,12 @@ public static boolean create(final @NotNull CommandSender sender, @NotNull Strin
176177
if (account.get().frozen)
177178
return sendMessage(sender, BankAccounts.getInstance().config().messagesErrorsFrozen(account.get()));
178179

179-
final @Nullable String description = argsCopy.length < 3 ? null : String.join(" ", Arrays.copyOfRange(argsCopy, 2, argsCopy.length));
180+
@Nullable String description = argsCopy.length < 3 ? null : String.join(" ", Arrays.copyOfRange(argsCopy, 2, argsCopy.length));
181+
if (description != null && description.length() > 64) description = description.substring(0, 63) + "…";
182+
183+
final @NotNull Set<@NotNull String> disallowedChars = getDisallowedCharacters(description);
184+
if (!disallowedChars.isEmpty())
185+
return sendMessage(sender, BankAccounts.getInstance().config().messagesErrorsDisallowedCharacters(disallowedChars));
180186

181187
final @NotNull Invoice invoice = new Invoice(account.get(), amount, description, target);
182188
invoice.insert();

src/main/java/pro/cloudnode/smp/bankaccounts/commands/POSCommand.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Arrays;
2121
import java.util.Date;
2222
import java.util.Optional;
23+
import java.util.Set;
2324

2425
/**
2526
* Create a POS at the location the player is looking at.
@@ -76,10 +77,11 @@ public boolean execute(final @NotNull CommandSender sender, final @NotNull Strin
7677
if (POS.get(chest).isPresent()) return sendMessage(sender, BankAccounts.getInstance().config().messagesErrorsPosAlreadyExists());
7778

7879
@Nullable String description = args.length > 2 ? String.join(" ", Arrays.copyOfRange(args, 2, args.length)) : null;
79-
if (description != null && description.length() > 64) description = description.substring(0, 64);
80+
if (description != null && description.length() > 64) description = description.substring(0, 63) + "…";
8081

81-
if (description != null && (description.contains("<") || description.contains(">")))
82-
return sendMessage(sender, BankAccounts.getInstance().config().messagesErrorsDisallowedCharacters("<>"));
82+
final @NotNull Set<@NotNull String> disallowedChars = getDisallowedCharacters(description);
83+
if (!disallowedChars.isEmpty())
84+
return sendMessage(sender, BankAccounts.getInstance().config().messagesErrorsDisallowedCharacters(disallowedChars));
8385

8486
final @NotNull POS pos = new POS(target.getLocation(), price, description, account.get(), new Date());
8587
pos.save();

src/main/resources/config.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,12 @@ invoice:
257257
# Number of invoices to return per page
258258
per-page: 10
259259

260+
# Advanced: do not edit unless you have good understanding of RegEx
261+
# Regular expression for disallowed characters user-provided text inputs
262+
# e.g. account name, transaction description, POS description, invoice description
263+
# Note: additionally <> and characters with code point above 0xFFFF are always disallowed.
264+
disallowed-regex: [\x00-\x08\x0B-\x1F\x7F-\x9F\u2400-\u2421\u200B-\u200D\uFEFF\uD800-\uDB7F\uDFFF]
265+
260266
# Messages
261267
messages:
262268
# Command usage message

src/main/resources/db-init/mysql.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,15 @@ WHERE `world` NOT LIKE '%-%-%-%-%';
5454

5555
ALTER TABLE `pos`
5656
CHANGE COLUMN `world` `world` CHAR(36) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL;
57+
58+
ALTER TABLE `bank_accounts`
59+
CHANGE COLUMN `name` `name` VARCHAR(24) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL;
60+
61+
ALTER TABLE `bank_transactions`
62+
CHANGE COLUMN `description` `description` VARCHAR(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL;
63+
64+
ALTER TABLE `pos`
65+
CHANGE COLUMN `description` `description` VARCHAR(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL;
66+
67+
ALTER TABLE `bank_invoices`
68+
CHANGE COLUMN `description` `description` VARCHAR(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL;

0 commit comments

Comments
 (0)