From 38785a9505543e0396e2aa6dd524b2ca9f7a4a7b Mon Sep 17 00:00:00 2001 From: Aurora Lahtela <24460436+AuroraLS3@users.noreply.github.com> Date: Sat, 14 Jan 2023 22:17:50 +0200 Subject: [PATCH] Added Untrusted-annotation to be more careful around user given data - Fixed SQL-injection vulnerability in an endpoint - Fixed XSS on Whitelist deny 403 page - Fixed XSS on Internal Error 500 page if untrusted data ends up in exception message --- .../PlanPlaceholderExtension.java | 17 ++-- .../djrapitops/plan/commands/PlanCommand.java | 21 ++-- .../plan/commands/TabCompleteCache.java | 11 ++- .../subcommands/DataUtilityCommands.java | 21 ++-- .../subcommands/DatabaseCommands.java | 31 +++--- .../commands/subcommands/LinkCommands.java | 21 ++-- .../subcommands/PluginStatusCommands.java | 8 +- .../subcommands/RegistrationCommands.java | 25 ++--- .../plan/commands/use/Arguments.java | 2 + .../commands/use/CommandWithSubcommands.java | 17 ++-- .../plan/delivery/domain/Nickname.java | 3 + .../plan/delivery/domain/auth/User.java | 7 +- .../domain/datatransfer/InputFilterDto.java | 4 +- .../domain/datatransfer/InputQueryDto.java | 4 + .../delivery/domain/datatransfer/ViewDto.java | 2 + .../delivery/rendering/json/JSONFactory.java | 3 +- .../rendering/pages/InternalErrorPage.java | 12 ++- .../plan/delivery/web/ResolverSvc.java | 3 +- .../webserver/PassBruteForceGuard.java | 7 +- .../webserver/RequestBodyConverter.java | 3 +- .../delivery/webserver/ResponseFactory.java | 6 +- .../delivery/webserver/ResponseResolver.java | 5 +- .../webserver/auth/ActiveCookieStore.java | 9 +- .../webserver/auth/AllowedIpList.java | 3 +- .../auth/AuthenticationExtractor.java | 5 +- .../plan/delivery/webserver/auth/Cookie.java | 2 + .../webserver/auth/CookieAuthentication.java | 4 +- .../webserver/auth/RegistrationBin.java | 10 +- .../configuration/WebserverLogMessages.java | 3 +- .../delivery/webserver/http/AccessLogger.java | 6 +- .../webserver/http/InternalRequest.java | 4 +- .../webserver/http/JettyInternalRequest.java | 11 ++- .../webserver/http/RequestHandler.java | 21 ++-- .../resolver/PlayerPageResolver.java | 15 ++- .../webserver/resolver/RootPageResolver.java | 3 +- .../resolver/ServerPageResolver.java | 5 +- .../resolver/StaticResourceResolver.java | 5 +- .../resolver/auth/LoginPageResolver.java | 5 +- .../resolver/auth/LoginResolver.java | 15 +-- .../resolver/auth/LogoutResolver.java | 13 +-- .../resolver/auth/RegisterPageResolver.java | 3 +- .../resolver/auth/RegisterResolver.java | 15 +-- .../resolver/json/ExtensionJSONResolver.java | 7 +- .../resolver/json/GraphsJSONResolver.java | 24 ++--- .../resolver/json/LocaleJSONResolver.java | 7 +- .../json/NetworkPerformanceJSONResolver.java | 3 +- .../json/PlayersTableJSONResolver.java | 3 +- .../resolver/json/QueryJSONResolver.java | 26 ++--- .../json/ServerIdentityJSONResolver.java | 3 +- .../resolver/json/ServerTabJSONResolver.java | 3 +- .../resolver/json/SessionsJSONResolver.java | 3 +- .../queries/ExtensionUserIdsInGroupQuery.java | 13 ++- .../gathering/domain/FinishedSession.java | 1 + .../gathering/domain/event/JoinAddress.java | 3 + .../gathering/importing/ImportSystem.java | 3 +- .../plan/identification/Identifiers.java | 99 ++++++++++--------- .../plan/identification/UUIDUtility.java | 21 ++-- .../placeholder/OperatorPlaceholders.java | 5 +- .../plan/placeholder/PlanPlaceholders.java | 9 +- .../plan/placeholder/ServerPlaceHolders.java | 9 +- .../plan/placeholder/SessionPlaceHolders.java | 5 +- .../plan/storage/database/DBType.java | 3 +- .../analysis/ActivityIndexQueries.java | 2 +- .../database/queries/filter/Filter.java | 5 +- .../database/queries/filter/QueryFilters.java | 13 +-- .../filter/filters/ActivityIndexFilter.java | 5 +- .../filter/filters/AllPlayersFilter.java | 3 +- .../queries/filter/filters/BannedFilter.java | 5 +- .../filter/filters/DateRangeFilter.java | 11 ++- .../filter/filters/GeolocationsFilter.java | 3 +- .../filter/filters/JoinAddressFilter.java | 3 +- .../filter/filters/MultiOptionFilter.java | 7 +- .../filter/filters/OperatorsFilter.java | 5 +- .../filters/PlayedBetweenDateRangeFilter.java | 5 +- .../filter/filters/PlayedOnServerFilter.java | 5 +- .../filters/PluginBooleanGroupFilter.java | 38 ++++--- .../filter/filters/PluginGroupsFilter.java | 3 +- .../RegisteredBetweenDateRangeFilter.java | 7 +- .../queries/objects/GeoInfoQueries.java | 10 +- .../queries/objects/JoinAddressQueries.java | 6 +- .../queries/objects/ServerQueries.java | 5 +- .../database/queries/objects/TPSQueries.java | 2 +- .../objects/UserIdentifierQueries.java | 5 +- .../queries/objects/WebUserQueries.java | 3 +- .../events/CookieChangeTransaction.java | 6 +- .../events/StoreJoinAddressTransaction.java | 7 +- .../plan/storage/file/PlanFiles.java | 3 +- .../plan/utilities/PassEncryptUtil.java | 5 +- .../plan/utilities/{ => dev}/Benchmark.java | 2 +- .../plan/utilities/dev/Untrusted.java | 31 ++++++ 90 files changed, 498 insertions(+), 347 deletions(-) rename Plan/common/src/main/java/com/djrapitops/plan/utilities/{ => dev}/Benchmark.java (98%) create mode 100644 Plan/common/src/main/java/com/djrapitops/plan/utilities/dev/Untrusted.java diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/PlanPlaceholderExtension.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/PlanPlaceholderExtension.java index 5a8c4da63..29564d807 100644 --- a/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/PlanPlaceholderExtension.java +++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/addons/placeholderapi/PlanPlaceholderExtension.java @@ -19,6 +19,7 @@ package com.djrapitops.plan.addons.placeholderapi; import com.djrapitops.plan.PlanSystem; import com.djrapitops.plan.placeholder.PlanPlaceholders; import com.djrapitops.plan.processing.Processing; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.logging.ErrorContext; import com.djrapitops.plan.utilities.logging.ErrorLogger; import com.djrapitops.plan.version.VersionChecker; @@ -89,7 +90,7 @@ public class PlanPlaceholderExtension extends PlaceholderExpansion { } @Override - public String onRequest(OfflinePlayer player, String params) { + public String onRequest(OfflinePlayer player, @Untrusted String params) { UUID uuid = player != null ? player.getUniqueId() : null; if ("Server thread".equalsIgnoreCase(Thread.currentThread().getName())) { return getCached(params, uuid); @@ -97,7 +98,7 @@ public class PlanPlaceholderExtension extends PlaceholderExpansion { return getPlaceholderValue(params, uuid); } - private String getPlaceholderValue(String params, UUID uuid) { + private String getPlaceholderValue(@Untrusted String params, UUID uuid) { try { String value = placeholders.onPlaceholderRequest(uuid, parseRequest(params), parseParameters(params)); @@ -114,14 +115,16 @@ public class PlanPlaceholderExtension extends PlaceholderExpansion { } } - private String parseRequest(String params) { + @Untrusted + private String parseRequest(@Untrusted String params) { return params.split(":")[0]; } - private List parseParameters(String params) { + @Untrusted + private List parseParameters(@Untrusted String params) { List parameters = new ArrayList<>(); boolean first = true; - for (String parameter : params.split(":")) { + for (@Untrusted String parameter : params.split(":")) { if (first) { first = false; } else { @@ -131,8 +134,8 @@ public class PlanPlaceholderExtension extends PlaceholderExpansion { return parameters; } - private String getCached(String params, UUID uuid) { - String key = params + "-" + uuid; + private String getCached(@Untrusted String params, UUID uuid) { + @Untrusted String key = params + "-" + uuid; if (!currentlyProcessing.contains(key)) { currentlyProcessing.add(key); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/commands/PlanCommand.java b/Plan/common/src/main/java/com/djrapitops/plan/commands/PlanCommand.java index fa0ecc5d8..269c185ae 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/commands/PlanCommand.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/commands/PlanCommand.java @@ -24,6 +24,7 @@ import com.djrapitops.plan.settings.locale.Locale; import com.djrapitops.plan.settings.locale.lang.DeepHelpLang; import com.djrapitops.plan.settings.locale.lang.HelpLang; import com.djrapitops.plan.storage.database.DBType; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.logging.ErrorContext; import com.djrapitops.plan.utilities.logging.ErrorLogger; @@ -84,7 +85,7 @@ public class PlanCommand { this.errorLogger = errorLogger; } - private void handleException(RuntimeException error, CMDSender sender, Arguments arguments) { + private void handleException(RuntimeException error, CMDSender sender, @Untrusted Arguments arguments) { if (error instanceof IllegalArgumentException) { sender.send("§c" + error.getMessage()); } else { @@ -131,13 +132,13 @@ public class PlanCommand { return command; } - public List serverNames(CMDSender sender, Arguments arguments) { - String asString = arguments.concatenate(" "); + public List serverNames(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String asString = arguments.concatenate(" "); return tabCompleteCache.getMatchingServerIdentifiers(asString); } - private List playerNames(CMDSender sender, Arguments arguments) { - String asString = arguments.concatenate(" "); + private List playerNames(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String asString = arguments.concatenate(" "); return tabCompleteCache.getMatchingPlayerIdentifiers(asString); } @@ -254,12 +255,12 @@ public class PlanCommand { .build(); } - private List webUserNames(CMDSender sender, Arguments arguments) { + private List webUserNames(CMDSender sender, @Untrusted Arguments arguments) { if (!sender.hasPermission(Permissions.UNREGISTER_OTHER)) { return Collections.emptyList(); } - String username = arguments.concatenate(" "); + @Untrusted String username = arguments.concatenate(" "); return tabCompleteCache.getMatchingUserIdentifiers(username); } @@ -388,15 +389,15 @@ public class PlanCommand { .build(); } - private List getBackupFilenames(CMDSender sender, Arguments arguments) { + private List getBackupFilenames(CMDSender sender, @Untrusted Arguments arguments) { if (arguments.get(1).isPresent()) { return DBType.names(); } - Optional firstArgument = arguments.get(0); + @Untrusted Optional firstArgument = arguments.get(0); if (firstArgument.isEmpty()) { return tabCompleteCache.getMatchingBackupFilenames(null); } - String part = firstArgument.get(); + @Untrusted String part = firstArgument.get(); return tabCompleteCache.getMatchingBackupFilenames(part); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/commands/TabCompleteCache.java b/Plan/common/src/main/java/com/djrapitops/plan/commands/TabCompleteCache.java index b2e49236e..2572b77e4 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/commands/TabCompleteCache.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/commands/TabCompleteCache.java @@ -27,6 +27,7 @@ import com.djrapitops.plan.storage.database.queries.objects.ServerQueries; import com.djrapitops.plan.storage.database.queries.objects.UserIdentifierQueries; import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries; import com.djrapitops.plan.storage.file.PlanFiles; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.jetbrains.annotations.NotNull; import javax.inject.Inject; @@ -115,25 +116,25 @@ public class TabCompleteCache implements SubSystem { backupFileNames.clear(); } - public List getMatchingServerIdentifiers(String searchFor) { + public List getMatchingServerIdentifiers(@Untrusted String searchFor) { return findMatches(serverIdentifiers, searchFor); } - public List getMatchingPlayerIdentifiers(String searchFor) { + public List getMatchingPlayerIdentifiers(@Untrusted String searchFor) { playerIdentifiers.addAll(serverSensor.getOnlinePlayerNames()); return findMatches(playerIdentifiers, searchFor); } - public List getMatchingUserIdentifiers(String searchFor) { + public List getMatchingUserIdentifiers(@Untrusted String searchFor) { return findMatches(userIdentifiers, searchFor); } - public List getMatchingBackupFilenames(String searchFor) { + public List getMatchingBackupFilenames(@Untrusted String searchFor) { return findMatches(backupFileNames, searchFor); } @NotNull - List findMatches(Collection searchList, String searchFor) { + List findMatches(Collection searchList, @Untrusted String searchFor) { List filtered = searchList.stream() .filter(identifier -> searchFor == null || searchFor.isEmpty() || identifier.startsWith(searchFor)) .sorted(String.CASE_INSENSITIVE_ORDER) diff --git a/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/DataUtilityCommands.java b/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/DataUtilityCommands.java index 0a8319df2..0f272cba0 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/DataUtilityCommands.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/DataUtilityCommands.java @@ -46,6 +46,7 @@ import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.Database; import com.djrapitops.plan.storage.database.queries.containers.ContainerFetchQueries; import com.djrapitops.plan.storage.database.queries.objects.UserIdentifierQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -95,8 +96,8 @@ public class DataUtilityCommands { } } - public void onExport(CMDSender sender, Arguments arguments) { - String exportKind = arguments.get(0) + public void onExport(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String exportKind = arguments.get(0) .orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_ACCEPTS_ARGUMENTS, locale.getString(HelpLang.ARG_EXPORT_KIND), "players, server_json"))); ensureDatabaseIsOpen(); @@ -104,7 +105,7 @@ public class DataUtilityCommands { getExportFunction(exportKind).accept(sender); } - private Consumer getExportFunction(String exportArg) { + private Consumer getExportFunction(@Untrusted String exportArg) { if ("players".equals(exportArg)) { return this::exportPlayers; } else if ("server_json".endsWith(exportArg)) { @@ -176,8 +177,8 @@ public class DataUtilityCommands { } } - public void onImport(CMDSender sender, Arguments arguments) { - String importKind = arguments.get(0) + public void onImport(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String importKind = arguments.get(0) .orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_ACCEPTS_ARGUMENTS, locale.getString(HelpLang.ARG_IMPORT_KIND), importSystem.getImporterNames().toString()))); ensureDatabaseIsOpen(); @@ -185,7 +186,7 @@ public class DataUtilityCommands { findAndProcessImporter(sender, importKind); } - private void findAndProcessImporter(CMDSender sender, String importKind) { + private void findAndProcessImporter(CMDSender sender, @Untrusted String importKind) { Optional foundImporter = importSystem.getImporter(importKind); if (foundImporter.isPresent()) { Importer importer = foundImporter.get(); @@ -199,8 +200,8 @@ public class DataUtilityCommands { } } - public void onSearch(CMDSender sender, Arguments arguments) { - String searchingFor = arguments.concatenate(" "); + public void onSearch(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String searchingFor = arguments.concatenate(" "); if (searchingFor.trim().isEmpty()) { throw new IllegalArgumentException(locale.getString(CommandLang.FAIL_EMPTY_SEARCH_STRING)); } @@ -221,8 +222,8 @@ public class DataUtilityCommands { sender.send(sender.getFormatter().table(asTableString.toString(), "::")); } - public void onInGame(CMDSender sender, Arguments arguments) { - String identifier = arguments.concatenate(" "); + public void onInGame(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String identifier = arguments.concatenate(" "); UUID playerUUID = identifiers.getPlayerUUID(identifier); UUID senderUUID = sender.getUUID().orElse(null); if (playerUUID == null) playerUUID = senderUUID; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/DatabaseCommands.java b/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/DatabaseCommands.java index 8624da57a..dd812d5bd 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/DatabaseCommands.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/DatabaseCommands.java @@ -46,6 +46,7 @@ import com.djrapitops.plan.storage.database.transactions.Transaction; import com.djrapitops.plan.storage.database.transactions.commands.*; import com.djrapitops.plan.storage.database.transactions.patches.BadFabricJoinAddressValuePatch; import com.djrapitops.plan.storage.file.PlanFiles; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.logging.ErrorContext; import com.djrapitops.plan.utilities.logging.ErrorLogger; import net.playeranalytics.plugin.player.UUIDFetcher; @@ -113,7 +114,7 @@ public class DatabaseCommands { this.processing = processing; } - public void onBackup(CMDSender sender, Arguments arguments) { + public void onBackup(CMDSender sender, @Untrusted Arguments arguments) { String dbName = arguments.get(0) .orElse(dbSystem.getDatabase().getType().getName()) .toLowerCase(); @@ -129,7 +130,7 @@ public class DatabaseCommands { sender.send(locale.getString(CommandLang.PROGRESS_SUCCESS)); } - public void performBackup(CMDSender sender, Arguments arguments, String dbName, Database fromDB) { + public void performBackup(CMDSender sender, @Untrusted Arguments arguments, String dbName, Database fromDB) { Database toDB = null; try { String timeStamp = timestamp.apply(System.currentTimeMillis()); @@ -150,8 +151,8 @@ public class DatabaseCommands { } } - public void onRestore(String mainCommand, CMDSender sender, Arguments arguments) { - String backupDbName = arguments.get(0) + public void onRestore(String mainCommand, CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String backupDbName = arguments.get(0) .orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_REQ_ARGS, 1, "<" + locale.getString(HelpLang.ARG_BACKUP_FILE) + ">"))); boolean containsDBFileExtension = backupDbName.endsWith(".db"); @@ -219,7 +220,7 @@ public class DatabaseCommands { } } - public void onMove(String mainCommand, CMDSender sender, Arguments arguments) { + public void onMove(String mainCommand, CMDSender sender, @Untrusted Arguments arguments) { DBType fromDB = arguments.get(0).flatMap(DBType::getForName) .orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_INCORRECT_DB, arguments.get(0).orElse("")))); @@ -282,7 +283,7 @@ public class DatabaseCommands { } - public void onClear(String mainCommand, CMDSender sender, Arguments arguments) { + public void onClear(String mainCommand, CMDSender sender, @Untrusted Arguments arguments) { DBType fromDB = arguments.get(0).flatMap(DBType::getForName) .orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_INCORRECT_DB, arguments.get(0).orElse("")))); @@ -335,8 +336,8 @@ public class DatabaseCommands { } } - public void onFixFabricJoinAddresses(String mainCommand, CMDSender sender, Arguments arguments) { - String identifier = arguments.concatenate(" "); + public void onFixFabricJoinAddresses(String mainCommand, CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String identifier = arguments.concatenate(" "); Optional serverUUID = identifiers.getServerUUID(identifier); if (serverUUID.isEmpty()) { throw new IllegalArgumentException(locale.getString(CommandLang.FAIL_SERVER_NOT_FOUND, identifier)); @@ -385,8 +386,8 @@ public class DatabaseCommands { } } - public void onRemove(String mainCommand, CMDSender sender, Arguments arguments) { - String identifier = arguments.concatenate(" "); + public void onRemove(String mainCommand, CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String identifier = arguments.concatenate(" "); UUID playerUUID = identifiers.getPlayerUUID(identifier); if (playerUUID == null) { throw new IllegalArgumentException(locale.getString(CommandLang.FAIL_PLAYER_NOT_FOUND, identifier)); @@ -444,9 +445,9 @@ public class DatabaseCommands { } } - public void onUninstalled(CMDSender sender, Arguments arguments) { + public void onUninstalled(CMDSender sender, @Untrusted Arguments arguments) { ensureDatabaseIsOpen(); - String identifier = arguments.concatenate(" "); + @Untrusted String identifier = arguments.concatenate(" "); Server server = dbSystem.getDatabase() .query(ServerQueries.fetchServerMatchingIdentifier(identifier)) .orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_SERVER_NOT_FOUND, identifier))); @@ -460,7 +461,7 @@ public class DatabaseCommands { sender.send(locale.getString(CommandLang.DB_UNINSTALLED)); } - public void onHotswap(CMDSender sender, Arguments arguments) { + public void onHotswap(CMDSender sender, @Untrusted Arguments arguments) { DBType toDB = arguments.get(0).flatMap(DBType::getForName) .orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_INCORRECT_DB, arguments.get(0).orElse("")))); @@ -482,7 +483,7 @@ public class DatabaseCommands { statusCommands.onReload(sender); } - public void onOnlineConversion(String mainCommand, CMDSender sender, Arguments arguments) { + public void onOnlineConversion(String mainCommand, CMDSender sender, @Untrusted Arguments arguments) { boolean removeOfflinePlayers = arguments.get(0) .map("--remove_offline"::equals) .orElse(false); @@ -491,7 +492,7 @@ public class DatabaseCommands { Map baseUsersByUUID = dbSystem.getDatabase().query(BaseUserQueries.fetchAllBaseUsersByUUID()); List playerNames = baseUsersByUUID.values().stream().map(BaseUser::getName).collect(Collectors.toList()); sender.send("Performing lookup for " + playerNames.size() + " uuids from Mojang.."); - sender.send("Preparation estimated complete at: " + clock.apply(System.currentTimeMillis() + playerNames.size() * 100) + " (due to request rate limiting)"); + sender.send("Preparation estimated complete at: " + clock.apply(System.currentTimeMillis() + playerNames.size() * 100L) + " (due to request rate limiting)"); Map onlineUUIDsOfPlayers = getUUIDViaUUIDFetcher(playerNames); if (onlineUUIDsOfPlayers.isEmpty()) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/LinkCommands.java b/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/LinkCommands.java index 7088684f3..97c9a306a 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/LinkCommands.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/LinkCommands.java @@ -33,6 +33,7 @@ import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.Database; import com.djrapitops.plan.storage.database.queries.objects.ServerQueries; import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -92,9 +93,9 @@ public class LinkCommands { * @param sender Sender of command. * @param arguments Given arguments. */ - public void onServerCommand(CMDSender sender, Arguments arguments) { + public void onServerCommand(CMDSender sender, @Untrusted Arguments arguments) { Server server; - String identifier = arguments.concatenate(" "); + @Untrusted String identifier = arguments.concatenate(" "); if (arguments.isEmpty()) { server = serverInfo.getServer(); } else { @@ -117,7 +118,7 @@ public class LinkCommands { * @param sender Sender of command. * @param arguments Given arguments. */ - public void onServersCommand(CMDSender sender, Arguments arguments) { + public void onServersCommand(CMDSender sender, @Untrusted Arguments arguments) { ensureDatabaseIsOpen(); String m = colors.getMainColor(); String s = colors.getSecondaryColor(); @@ -148,8 +149,8 @@ public class LinkCommands { * @param sender Sender of command. * @param arguments Given arguments. */ - public void onPlayerCommand(CMDSender sender, Arguments arguments) { - String identifier = arguments.concatenate(" "); + public void onPlayerCommand(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String identifier = arguments.concatenate(" "); UUID playerUUID = identifiers.getPlayerUUID(identifier); UUID senderUUID = sender.getUUID().orElse(null); if (playerUUID == null) playerUUID = senderUUID; @@ -174,7 +175,7 @@ public class LinkCommands { * @param sender Sender of command * @param arguments Only present to fulfill Subcommand#onCommand requirements. */ - public void onPlayersCommand(CMDSender sender, Arguments arguments) { + public void onPlayersCommand(CMDSender sender, @Untrusted Arguments arguments) { String address = getAddress(sender) + "/players"; sender.buildMessage() .addPart(colors.getMainColor() + locale.getString(CommandLang.LINK_PLAYERS)) @@ -188,7 +189,7 @@ public class LinkCommands { * @param sender Sender of command * @param arguments Only present to fulfill Subcommand#onCommand requirements. */ - public void onNetworkCommand(CMDSender sender, Arguments arguments) { + public void onNetworkCommand(CMDSender sender, @Untrusted Arguments arguments) { String address = getAddress(sender) + "/network"; sender.buildMessage() .addPart(colors.getMainColor() + locale.getString(CommandLang.LINK_NETWORK)) @@ -205,7 +206,7 @@ public class LinkCommands { * @param sender Sender of command. * @param arguments Given arguments. */ - public void onWebUsersCommand(CMDSender sender, Arguments arguments) { + public void onWebUsersCommand(CMDSender sender, @Untrusted Arguments arguments) { ensureDatabaseIsOpen(); String m = colors.getMainColor(); String s = colors.getSecondaryColor(); @@ -227,8 +228,8 @@ public class LinkCommands { } } - public void onJson(CMDSender sender, Arguments arguments) { - String identifier = arguments.concatenate(" "); + public void onJson(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String identifier = arguments.concatenate(" "); UUID playerUUID = identifiers.getPlayerUUID(identifier); UUID senderUUID = sender.getUUID().orElse(null); if (playerUUID == null) playerUUID = senderUUID; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/PluginStatusCommands.java b/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/PluginStatusCommands.java index 7b68251d7..137e80a8d 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/PluginStatusCommands.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/PluginStatusCommands.java @@ -26,6 +26,7 @@ import com.djrapitops.plan.settings.locale.lang.GenericLang; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.Database; import com.djrapitops.plan.storage.database.queries.objects.ServerQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.logging.ErrorContext; import com.djrapitops.plan.utilities.logging.ErrorLogger; import com.djrapitops.plan.version.VersionChecker; @@ -33,7 +34,6 @@ import net.playeranalytics.plugin.PluginInformation; import javax.inject.Inject; import javax.inject.Singleton; -import java.util.Optional; @Singleton public class PluginStatusCommands { @@ -80,15 +80,15 @@ public class PluginStatusCommands { }, "Plan Reload Thread").start(); } - public void onDisable(CMDSender sender, Arguments arguments) { + public void onDisable(CMDSender sender, @Untrusted Arguments arguments) { if (arguments.isEmpty()) { plugin.onDisable(); sender.send(locale.getString(CommandLang.DISABLE_DISABLED)); return; } - Optional kickCountDisable = arguments.get(0).filter("kickcount"::equalsIgnoreCase); - if (kickCountDisable.isPresent()) { + boolean kickCountDisable = arguments.get(0).map("kickcount"::equalsIgnoreCase).orElse(false); + if (kickCountDisable) { status.setCountKicks(false); sender.send(locale.getString(CommandLang.FEATURE_DISABLED, "Kick Counting")); } else { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/RegistrationCommands.java b/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/RegistrationCommands.java index 3609284ef..e1c92dd11 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/RegistrationCommands.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/commands/subcommands/RegistrationCommands.java @@ -34,6 +34,7 @@ import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries; import com.djrapitops.plan.storage.database.transactions.commands.RemoveWebUserTransaction; import com.djrapitops.plan.storage.database.transactions.commands.StoreWebUserTransaction; import com.djrapitops.plan.utilities.PassEncryptUtil; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.logging.ErrorContext; import com.djrapitops.plan.utilities.logging.ErrorLogger; import net.playeranalytics.plugin.server.PluginLogger; @@ -87,7 +88,7 @@ public class RegistrationCommands { } } - public void onRegister(CMDSender sender, Arguments arguments) { + public void onRegister(CMDSender sender, @Untrusted Arguments arguments) { ensureDatabaseIsOpen(); if (arguments.isEmpty()) { String address = linkCommands.getAddress(sender) + "/register"; @@ -96,7 +97,7 @@ public class RegistrationCommands { .apply(builder -> linkCommands.linkTo(builder, sender, address)) .send(); } else { - Optional code = arguments.getAfter("--code"); + @Untrusted Optional code = arguments.getAfter("--code"); if (code.isPresent()) { registerUsingCode(sender, code.get()); } else { @@ -105,7 +106,7 @@ public class RegistrationCommands { } } - public void registerUsingCode(CMDSender sender, String code) { + public void registerUsingCode(CMDSender sender, @Untrusted String code) { UUID linkedToUUID = sender.getUUID().orElse(null); Optional user = RegistrationBin.register(code, linkedToUUID); if (user.isPresent()) { @@ -115,8 +116,8 @@ public class RegistrationCommands { } } - public void registerUsingLegacy(CMDSender sender, Arguments arguments) { - String password = arguments.get(0) + public void registerUsingLegacy(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String password = arguments.get(0) .orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_REQ_ARGS, 1, ""))); String passwordHash = PassEncryptUtil.createHash(password); int permissionLevel = arguments.getInteger(2) @@ -128,10 +129,10 @@ public class RegistrationCommands { if (senderUUID.isPresent() && senderName.isPresent()) { String playerName = senderName.get(); UUID linkedToUUID = senderUUID.get(); - String username = arguments.get(1).orElse(playerName); + @Untrusted String username = arguments.get(1).orElse(playerName); registerUser(new User(username, playerName, linkedToUUID, passwordHash, permissionLevel, Collections.emptyList()), sender, permissionLevel); } else { - String username = arguments.get(1) + @Untrusted String username = arguments.get(1) .orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_REQ_ARGS, 3, " "))); registerUser(new User(username, "console", null, passwordHash, permissionLevel, Collections.emptyList()), sender, permissionLevel); } @@ -170,13 +171,13 @@ public class RegistrationCommands { } } - public void onUnregister(String mainCommand, CMDSender sender, Arguments arguments) { - Optional givenUsername = arguments.get(0).filter(arg -> sender.hasPermission(Permissions.UNREGISTER_OTHER)); + public void onUnregister(String mainCommand, CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted Optional givenUsername = arguments.get(0).filter(arg -> sender.hasPermission(Permissions.UNREGISTER_OTHER)); Database database = dbSystem.getDatabase(); UUID playerUUID = sender.getUUID().orElse(null); - String username; + @Untrusted String username; if (givenUsername.isEmpty() && playerUUID != null) { username = database.query(WebUserQueries.fetchUser(playerUUID)) .map(User::getUsername) @@ -231,8 +232,8 @@ public class RegistrationCommands { } - public void onLogoutCommand(CMDSender sender, Arguments arguments) { - String loggingOut = arguments.get(0) + public void onLogoutCommand(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted String loggingOut = arguments.get(0) .orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_REQ_ONE_ARG, locale.getString(HelpLang.ARG_USERNAME) + "/*"))); if ("*".equals(loggingOut)) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/commands/use/Arguments.java b/Plan/common/src/main/java/com/djrapitops/plan/commands/use/Arguments.java index 36e0f4ade..3743d590d 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/commands/use/Arguments.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/commands/use/Arguments.java @@ -16,6 +16,7 @@ */ package com.djrapitops.plan.commands.use; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.TextStringBuilder; @@ -29,6 +30,7 @@ import java.util.Optional; * * @author AuroraLS3 */ +@Untrusted public class Arguments { private final List args; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/commands/use/CommandWithSubcommands.java b/Plan/common/src/main/java/com/djrapitops/plan/commands/use/CommandWithSubcommands.java index 1b4a893f4..8c4097d69 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/commands/use/CommandWithSubcommands.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/commands/use/CommandWithSubcommands.java @@ -18,6 +18,7 @@ package com.djrapitops.plan.commands.use; import com.djrapitops.plan.settings.locale.Locale; import com.djrapitops.plan.settings.locale.lang.CommandLang; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.java.TriConsumer; import java.util.ArrayList; @@ -54,7 +55,7 @@ public class CommandWithSubcommands extends Subcommand { return subcommands; } - public Optional findSubCommand(Arguments arguments) { + public Optional findSubCommand(@Untrusted Arguments arguments) { return arguments.get(0).flatMap(alias -> { for (Subcommand subcommand : subcommands) { if (subcommand.getAliases().contains(alias)) { @@ -65,7 +66,7 @@ public class CommandWithSubcommands extends Subcommand { }); } - public void onHelp(CMDSender sender, Arguments arguments) { + public void onHelp(CMDSender sender, @Untrusted Arguments arguments) { List hasPermissionFor = getPermittedSubcommands(sender); sender.buildMessage() .addPart(locale.getString(CommandLang.HEADER_HELP, getPrimaryAlias())) @@ -89,7 +90,7 @@ public class CommandWithSubcommands extends Subcommand { .send(); } - public void onCommand(CMDSender sender, Arguments arguments) { + public void onCommand(CMDSender sender, @Untrusted Arguments arguments) { if (sender.isMissingPermissionsFor(this)) { sender.send(locale.getString(CommandLang.FAIL_NO_PERMISSION) + " " + getRequiredPermissions()); return; @@ -101,10 +102,10 @@ public class CommandWithSubcommands extends Subcommand { } } - public void executeCommand(CMDSender sender, Arguments arguments) { - Optional gotAlias = arguments.get(0); + public void executeCommand(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted Optional gotAlias = arguments.get(0); if (gotAlias.isPresent()) { - String alias = gotAlias.get(); + @Untrusted String alias = gotAlias.get(); if ("help".equals(alias)) { onHelp(sender, arguments); return; @@ -128,8 +129,8 @@ public class CommandWithSubcommands extends Subcommand { fallback.accept(sender, arguments); } - public List onTabComplete(CMDSender sender, Arguments arguments) { - Optional gotAlias = arguments.get(0); + public List onTabComplete(CMDSender sender, @Untrusted Arguments arguments) { + @Untrusted Optional gotAlias = arguments.get(0); List options = new ArrayList<>(); if (gotAlias.isPresent()) { subcommandsLoop: diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/Nickname.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/Nickname.java index 617ccf731..bb156991a 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/Nickname.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/Nickname.java @@ -17,6 +17,7 @@ package com.djrapitops.plan.delivery.domain; import com.djrapitops.plan.identification.ServerUUID; +import com.djrapitops.plan.utilities.dev.Untrusted; import java.util.Objects; @@ -27,6 +28,7 @@ import java.util.Objects; */ public class Nickname implements DateHolder { + @Untrusted private final String name; private final long date; private final ServerUUID serverUUID; @@ -37,6 +39,7 @@ public class Nickname implements DateHolder { this.serverUUID = serverUUID; } + @Untrusted public String getName() { return name.length() <= 75 ? name : name.substring(0, 74); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/auth/User.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/auth/User.java index e89dff5dc..0a99f1d27 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/auth/User.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/auth/User.java @@ -18,6 +18,7 @@ package com.djrapitops.plan.delivery.domain.auth; import com.djrapitops.plan.delivery.web.resolver.request.WebUser; import com.djrapitops.plan.utilities.PassEncryptUtil; +import com.djrapitops.plan.utilities.dev.Untrusted; import java.util.Collection; import java.util.Objects; @@ -30,6 +31,7 @@ import java.util.UUID; */ public class User implements Comparable { + @Untrusted private final String username; private final String linkedTo; private final UUID linkedToUUID; // null for 'console' @@ -37,7 +39,7 @@ public class User implements Comparable { private int permissionLevel; private final Collection permissions; - public User(String username, String linkedTo, UUID linkedToUUID, String passwordHash, int permissionLevel, Collection permissions) { + public User(@Untrusted String username, String linkedTo, UUID linkedToUUID, String passwordHash, int permissionLevel, Collection permissions) { this.username = username; this.linkedTo = linkedTo; this.linkedToUUID = linkedToUUID; @@ -46,7 +48,7 @@ public class User implements Comparable { this.permissions = permissions; } - public boolean doesPasswordMatch(String password) { + public boolean doesPasswordMatch(@Untrusted String password) { return PassEncryptUtil.verifyPassword(password, passwordHash); } @@ -54,6 +56,7 @@ public class User implements Comparable { return new WebUser(linkedTo, linkedToUUID, username, permissions); } + @Untrusted public String getUsername() { return username; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/InputFilterDto.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/InputFilterDto.java index 013b5ec62..149297739 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/InputFilterDto.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/InputFilterDto.java @@ -17,6 +17,7 @@ package com.djrapitops.plan.delivery.domain.datatransfer; import com.djrapitops.plan.storage.database.queries.filter.Filter; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -28,6 +29,7 @@ import java.util.*; * * @author AuroraLS3 */ +@Untrusted public class InputFilterDto { private final String kind; @@ -38,7 +40,7 @@ public class InputFilterDto { this.parameters = parameters; } - public static List parse(String json, Gson gson) throws IOException { + public static List parse(@Untrusted String json, Gson gson) throws IOException { return gson.getAdapter(new TypeToken>() {}).fromJson(json); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/InputQueryDto.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/InputQueryDto.java index 243a32101..bcfbf4c44 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/InputQueryDto.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/InputQueryDto.java @@ -16,11 +16,14 @@ */ package com.djrapitops.plan.delivery.domain.datatransfer; +import com.djrapitops.plan.utilities.dev.Untrusted; + import java.util.List; import java.util.Objects; public class InputQueryDto { + @Untrusted public final List filters; private final ViewDto view; @@ -33,6 +36,7 @@ public class InputQueryDto { return view; } + @Untrusted public List getFilters() { return filters; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/ViewDto.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/ViewDto.java index 12d899923..67b85bdeb 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/ViewDto.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/domain/datatransfer/ViewDto.java @@ -19,6 +19,7 @@ package com.djrapitops.plan.delivery.domain.datatransfer; import com.djrapitops.plan.delivery.formatting.Formatter; import com.djrapitops.plan.delivery.formatting.Formatters; import com.djrapitops.plan.identification.ServerUUID; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.apache.commons.lang3.StringUtils; import java.text.ParseException; @@ -31,6 +32,7 @@ import java.util.stream.Collectors; /** * Represents query page view that the user wants to see data for. */ +@Untrusted public class ViewDto { private static final String DATE_PATTERN = "dd/MM/yyyy kk:mm"; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java index 5f32811f4..7d2faa273 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/json/JSONFactory.java @@ -45,6 +45,7 @@ import com.djrapitops.plan.storage.database.queries.objects.*; import com.djrapitops.plan.storage.database.queries.objects.playertable.NetworkTablePlayersQuery; import com.djrapitops.plan.storage.database.queries.objects.playertable.ServerTablePlayersQuery; import com.djrapitops.plan.utilities.comparators.SessionStartComparator; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.java.Maps; import javax.inject.Inject; @@ -175,7 +176,7 @@ public class JSONFactory { return new PlayerKillMutator(kills).toJSONAsMap(formatters); } - public Optional serverForIdentifier(String identifier) { + public Optional serverForIdentifier(@Untrusted String identifier) { return dbSystem.getDatabase() .query(ServerQueries.fetchServerMatchingIdentifier(identifier)) .map(ServerDto::fromServer); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/pages/InternalErrorPage.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/pages/InternalErrorPage.java index cb63709ff..99e12e7f1 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/pages/InternalErrorPage.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/rendering/pages/InternalErrorPage.java @@ -21,7 +21,9 @@ import com.djrapitops.plan.delivery.rendering.html.Contributors; import com.djrapitops.plan.delivery.rendering.html.Html; import com.djrapitops.plan.delivery.rendering.html.icon.Icon; import com.djrapitops.plan.exceptions.ExceptionWithContext; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.version.VersionChecker; +import org.apache.commons.text.StringEscapeUtils; import org.apache.commons.text.TextStringBuilder; /** @@ -32,7 +34,9 @@ import org.apache.commons.text.TextStringBuilder; public class InternalErrorPage implements Page { private final String template; + @Untrusted private final String errorMsg; + @Untrusted private final Throwable error; private final VersionChecker versionChecker; @@ -66,13 +70,13 @@ public class InternalErrorPage implements Page { paragraph.append("Please report this issue here: "); paragraph.append(Html.LINK.create("https://github.com/plan-player-analytics/Plan/issues", "Issues")); paragraph.append("

");
-        paragraph.append(error).append(" | ").append(errorMsg);
+        paragraph.append(StringEscapeUtils.escapeHtml4(error.toString())).append(" | ").append(StringEscapeUtils.escapeHtml4(errorMsg));
 
         if (error instanceof ExceptionWithContext) {
             ((ExceptionWithContext) error).getContext()
                     .ifPresent(context -> paragraph.append(context.getWhatToDo()
                                     .map(whatToDo -> "
What to do about it: " + whatToDo) - .orElse("
Error message: " + error.getMessage())) + .orElse("
Error message: " + StringEscapeUtils.escapeHtml4(error.getMessage()))) .append("

Related things:
") .appendWithSeparators(context.toLines(), "
") .append("
")); @@ -91,8 +95,8 @@ public class InternalErrorPage implements Page { return paragraph.toString(); } - private void appendCause(Throwable cause, TextStringBuilder paragraph) { - paragraph.append("
Caused by: ").append(cause); + private void appendCause(@Untrusted Throwable cause, TextStringBuilder paragraph) { + paragraph.append("
Caused by: ").append(StringEscapeUtils.escapeHtml4(cause.toString())); for (StackTraceElement element : cause.getStackTrace()) { paragraph.append("
"); paragraph.append(" ").append(element); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/web/ResolverSvc.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/web/ResolverSvc.java index 1253a118b..7b56d95d6 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/web/ResolverSvc.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/web/ResolverSvc.java @@ -17,6 +17,7 @@ package com.djrapitops.plan.delivery.web; import com.djrapitops.plan.delivery.web.resolver.Resolver; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -69,7 +70,7 @@ public class ResolverSvc implements ResolverService { } @Override - public List getResolvers(String target) { + public List getResolvers(@Untrusted String target) { List resolvers = new ArrayList<>(); for (Container container : basicResolvers) { if (container.matcher.test(target)) resolvers.add(container.resolver); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/PassBruteForceGuard.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/PassBruteForceGuard.java index 3b4fa1a61..19eac6a04 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/PassBruteForceGuard.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/PassBruteForceGuard.java @@ -16,6 +16,7 @@ */ package com.djrapitops.plan.delivery.webserver; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; @@ -33,7 +34,7 @@ public class PassBruteForceGuard { .expireAfterWrite(90, TimeUnit.SECONDS) .build(); - public boolean shouldPreventRequest(String accessor) { + public boolean shouldPreventRequest(@Untrusted String accessor) { Integer attempts = failedLoginAttempts.getIfPresent(accessor); if (attempts == null) return false; // Too many attempts, forbid further attempts. @@ -41,7 +42,7 @@ public class PassBruteForceGuard { } // Don't call on first connection. - public void increaseAttemptCountOnFailedLogin(String accessor) { + public void increaseAttemptCountOnFailedLogin(@Untrusted String accessor) { // Authentication was attempted, but failed so new attempt is going to be given if not forbidden failedLoginAttempts.cleanUp(); @@ -59,7 +60,7 @@ public class PassBruteForceGuard { failedLoginAttempts.put(accessor, attempts + 1); } - public void resetAttemptCount(String accessor) { + public void resetAttemptCount(@Untrusted String accessor) { // Successful login failedLoginAttempts.cleanUp(); failedLoginAttempts.invalidate(accessor); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/RequestBodyConverter.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/RequestBodyConverter.java index 12d8638cb..6e14165b9 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/RequestBodyConverter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/RequestBodyConverter.java @@ -18,6 +18,7 @@ package com.djrapitops.plan.delivery.webserver; import com.djrapitops.plan.delivery.web.resolver.request.Request; import com.djrapitops.plan.delivery.web.resolver.request.URIQuery; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -38,7 +39,7 @@ public class RequestBodyConverter { return new URIQuery(new String(request.getRequestBody(), StandardCharsets.UTF_8)); } - public static T bodyJson(Request request, Gson gson, Class ofType) { + public static T bodyJson(@Untrusted Request request, Gson gson, Class ofType) { return gson.fromJson(new String(request.getRequestBody(), StandardCharsets.UTF_8), ofType); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseFactory.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseFactory.java index 0ac817028..a1ea83b93 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseFactory.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseFactory.java @@ -36,10 +36,12 @@ import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.Database; import com.djrapitops.plan.storage.database.queries.containers.ContainerFetchQueries; import com.djrapitops.plan.storage.file.PlanFiles; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.java.Maps; import com.djrapitops.plan.utilities.java.UnaryChain; import dagger.Lazy; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; import javax.inject.Inject; import javax.inject.Singleton; @@ -375,11 +377,11 @@ public class ResponseFactory { .build(); } - public Response ipWhitelist403(String accessor) { + public Response ipWhitelist403(@Untrusted String accessor) { return Response.builder() .setMimeType(MimeType.HTML) .setContent("

403 Forbidden

" + - "

IP-whitelist enabled, \"" + accessor + "\" is not on the list!

") + "

IP-whitelist enabled, \"" + StringEscapeUtils.escapeHtml4(accessor) + "\" is not on the list!

") .setStatus(403) .build(); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseResolver.java index 81e18b438..40d099f27 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/ResponseResolver.java @@ -34,6 +34,7 @@ import com.djrapitops.plan.delivery.webserver.resolver.swagger.SwaggerJsonResolv import com.djrapitops.plan.delivery.webserver.resolver.swagger.SwaggerPageResolver; import com.djrapitops.plan.exceptions.WebUserAuthException; import com.djrapitops.plan.exceptions.connection.ForbiddenException; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.logging.ErrorContext; import com.djrapitops.plan.utilities.logging.ErrorLogger; import dagger.Lazy; @@ -167,7 +168,7 @@ public class ResponseResolver { return request -> Optional.of(response.get()); } - public Response getResponse(Request request) { + public Response getResponse(@Untrusted Request request) { try { return tryToGetResponse(request); } catch (NotFoundException e) { @@ -189,7 +190,7 @@ public class ResponseResolver { * @throws ForbiddenException If the user is not allowed to see the page * @throws BadRequestException If the request did not have required things. */ - private Response tryToGetResponse(Request request) { + private Response tryToGetResponse(@Untrusted Request request) { if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { // https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS return Response.builder().setStatus(204).build(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/ActiveCookieStore.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/ActiveCookieStore.java index 3110b2aa9..121f4e7a6 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/ActiveCookieStore.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/ActiveCookieStore.java @@ -25,6 +25,7 @@ import com.djrapitops.plan.settings.config.paths.WebserverSettings; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries; import com.djrapitops.plan.storage.database.transactions.events.CookieChangeTransaction; +import com.djrapitops.plan.utilities.dev.Untrusted; import net.playeranalytics.plugin.server.PluginLogger; import org.apache.commons.codec.digest.DigestUtils; @@ -70,7 +71,7 @@ public class ActiveCookieStore implements SubSystem { Holder.getActiveCookieStore().removeCookie(cookie); } - public static void removeUserCookie(String username) { + public static void removeUserCookie(@Untrusted String username) { USERS_BY_COOKIE.entrySet().stream().filter(entry -> entry.getValue().getUsername().equals(username)) .findAny() .map(Map.Entry::getKey) @@ -106,7 +107,7 @@ public class ActiveCookieStore implements SubSystem { USERS_BY_COOKIE.clear(); } - public Optional checkCookie(String cookie) { + public Optional checkCookie(@Untrusted String cookie) { return Optional.ofNullable(USERS_BY_COOKIE.get(cookie)); } @@ -124,14 +125,14 @@ public class ActiveCookieStore implements SubSystem { )); } - public void removeCookie(String cookie) { + public void removeCookie(@Untrusted String cookie) { checkCookie(cookie).map(User::getUsername) .ifPresent(this::deleteCookieByUser); USERS_BY_COOKIE.remove(cookie); deleteCookie(cookie); } - private void deleteCookie(String cookie) { + private void deleteCookie(@Untrusted String cookie) { dbSystem.getDatabase().executeTransaction(CookieChangeTransaction.removeCookie(cookie)); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/AllowedIpList.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/AllowedIpList.java index a711f6b74..95e6b59c6 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/AllowedIpList.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/AllowedIpList.java @@ -18,6 +18,7 @@ package com.djrapitops.plan.delivery.webserver.auth; import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.settings.config.paths.WebserverSettings; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -44,7 +45,7 @@ public class AllowedIpList { } } - public boolean isAllowed(String accessAddress) { + public boolean isAllowed(@Untrusted String accessAddress) { prepare(); List ips = allowList.get(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/AuthenticationExtractor.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/AuthenticationExtractor.java index 68396114a..d650fe075 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/AuthenticationExtractor.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/AuthenticationExtractor.java @@ -17,6 +17,7 @@ package com.djrapitops.plan.delivery.webserver.auth; import com.djrapitops.plan.delivery.webserver.http.InternalRequest; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -37,8 +38,8 @@ public class AuthenticationExtractor { return getCookieAuthentication(internalRequest.getCookies()); } - private Optional getCookieAuthentication(List cookies) { - for (Cookie cookie : cookies) { + private Optional getCookieAuthentication(@Untrusted List cookies) { + for (@Untrusted Cookie cookie : cookies) { if ("auth".equals(cookie.getName())) { return Optional.of(new CookieAuthentication(activeCookieStore, cookie.getValue())); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/Cookie.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/Cookie.java index e723139a7..d59a6c5c1 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/Cookie.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/Cookie.java @@ -16,8 +16,10 @@ */ package com.djrapitops.plan.delivery.webserver.auth; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.apache.commons.lang3.StringUtils; +@Untrusted public class Cookie { private final String name; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/CookieAuthentication.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/CookieAuthentication.java index 23c67c4dc..2da05fc7e 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/CookieAuthentication.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/CookieAuthentication.java @@ -17,13 +17,15 @@ package com.djrapitops.plan.delivery.webserver.auth; import com.djrapitops.plan.delivery.domain.auth.User; +import com.djrapitops.plan.utilities.dev.Untrusted; public class CookieAuthentication implements Authentication { private final ActiveCookieStore activeCookieStore; + @Untrusted private final String cookie; - public CookieAuthentication(ActiveCookieStore activeCookieStore, String cookie) { + public CookieAuthentication(ActiveCookieStore activeCookieStore, @Untrusted String cookie) { this.activeCookieStore = activeCookieStore; this.cookie = cookie; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/RegistrationBin.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/RegistrationBin.java index ca602840f..615f246d4 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/RegistrationBin.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/auth/RegistrationBin.java @@ -18,6 +18,7 @@ package com.djrapitops.plan.delivery.webserver.auth; import com.djrapitops.plan.delivery.domain.auth.User; import com.djrapitops.plan.utilities.PassEncryptUtil; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import org.apache.commons.codec.digest.DigestUtils; @@ -42,29 +43,30 @@ public class RegistrationBin { // Hide static cache constructor } - public static String addInfoForRegistration(String username, String password) { + public static String addInfoForRegistration(@Untrusted String username, @Untrusted String password) { String hash = PassEncryptUtil.createHash(password); String code = DigestUtils.sha256Hex(username + password + System.currentTimeMillis()).substring(0, 12); REGISTRATION_BIN.put(code, new AwaitingForRegistration(username, hash)); return code; } - public static Optional register(String code, UUID linkedToUUID) { + public static Optional register(@Untrusted String code, UUID linkedToUUID) { AwaitingForRegistration found = REGISTRATION_BIN.getIfPresent(code); if (found == null) return Optional.empty(); REGISTRATION_BIN.invalidate(code); return Optional.of(found.toUser(linkedToUUID)); } - public static boolean contains(String code) { + public static boolean contains(@Untrusted String code) { return REGISTRATION_BIN.getIfPresent(code) != null; } private static class AwaitingForRegistration { + @Untrusted private final String username; private final String passwordHash; - public AwaitingForRegistration(String username, String passwordHash) { + public AwaitingForRegistration(@Untrusted String username, String passwordHash) { this.username = username; this.passwordHash = passwordHash; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/configuration/WebserverLogMessages.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/configuration/WebserverLogMessages.java index f4ddec2f6..ae206da75 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/configuration/WebserverLogMessages.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/configuration/WebserverLogMessages.java @@ -21,6 +21,7 @@ import com.djrapitops.plan.delivery.webserver.Addresses; import com.djrapitops.plan.settings.config.paths.WebserverSettings; import com.djrapitops.plan.settings.locale.Locale; import com.djrapitops.plan.settings.locale.lang.PluginLang; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.logging.ErrorContext; import com.djrapitops.plan.utilities.logging.ErrorLogger; import net.playeranalytics.plugin.server.PluginLogger; @@ -61,7 +62,7 @@ public class WebserverLogMessages { } } - public void warnAboutWhitelistBlock(String accessAddress, String requestedURIString) { + public void warnAboutWhitelistBlock(@Untrusted String accessAddress, @Untrusted String requestedURIString) { logger.info(locale.getString(PluginLang.WEB_SERVER_NOTIFY_IP_WHITELIST_BLOCK, accessAddress, requestedURIString)); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/AccessLogger.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/AccessLogger.java index 5d3558b45..3452fdd7f 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/AccessLogger.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/AccessLogger.java @@ -22,6 +22,7 @@ import com.djrapitops.plan.delivery.webserver.configuration.WebserverConfigurati import com.djrapitops.plan.exceptions.database.DBOpException; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.transactions.events.StoreRequestTransaction; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.logging.ErrorContext; import com.djrapitops.plan.utilities.logging.ErrorLogger; import net.playeranalytics.plugin.server.PluginLogger; @@ -46,10 +47,10 @@ public class AccessLogger { this.errorLogger = errorLogger; } - public void log(InternalRequest internalRequest, Request request, Response response) { + public void log(@Untrusted InternalRequest internalRequest, @Untrusted Request request, Response response) { if (webserverConfiguration.logAccessToConsole()) { int code = response.getCode(); - String message = "Access Log: " + internalRequest.getMethod() + " " + + @Untrusted String message = "Access Log: " + internalRequest.getMethod() + " " + getRequestURI(internalRequest, request) + " (from " + internalRequest.getAccessAddress(webserverConfiguration) + ") - " + code; @@ -82,6 +83,7 @@ public class AccessLogger { } } + @Untrusted private String getRequestURI(InternalRequest internalRequest, Request request) { return request != null ? request.getPath().asString() + request.getQuery().asString() : internalRequest.getRequestedURIString(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/InternalRequest.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/InternalRequest.java index 4b96f1719..d2b9cd4a3 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/InternalRequest.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/InternalRequest.java @@ -23,6 +23,7 @@ import com.djrapitops.plan.delivery.webserver.auth.Authentication; import com.djrapitops.plan.delivery.webserver.auth.AuthenticationExtractor; import com.djrapitops.plan.delivery.webserver.auth.Cookie; import com.djrapitops.plan.delivery.webserver.configuration.WebserverConfiguration; +import com.djrapitops.plan.utilities.dev.Untrusted; import java.util.List; import java.util.Optional; @@ -36,10 +37,11 @@ public interface InternalRequest { long getTimestamp(); + @Untrusted default String getAccessAddress(WebserverConfiguration webserverConfiguration) { AccessAddressPolicy accessAddressPolicy = webserverConfiguration.getAccessAddressPolicy(); if (accessAddressPolicy == AccessAddressPolicy.X_FORWARDED_FOR_HEADER) { - String fromHeader = getAccessAddressFromHeader(); + @Untrusted String fromHeader = getAccessAddressFromHeader(); if (fromHeader == null) { webserverConfiguration.getWebserverLogMessages().warnAboutXForwardedForSecurityIssue(); return getAccessAddressFromSocketIp(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/JettyInternalRequest.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/JettyInternalRequest.java index 2cf376876..83eba58af 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/JettyInternalRequest.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/JettyInternalRequest.java @@ -22,6 +22,7 @@ import com.djrapitops.plan.delivery.web.resolver.request.WebUser; import com.djrapitops.plan.delivery.webserver.auth.AuthenticationExtractor; import com.djrapitops.plan.delivery.webserver.auth.Cookie; import com.djrapitops.plan.delivery.webserver.configuration.WebserverConfiguration; +import com.djrapitops.plan.utilities.dev.Untrusted; import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.text.TextStringBuilder; import org.eclipse.jetty.http.HttpHeader; @@ -72,11 +73,11 @@ public class JettyInternalRequest implements InternalRequest { @Override public com.djrapitops.plan.delivery.web.resolver.request.Request toRequest() { String requestMethod = baseRequest.getMethod(); - URIPath path = new URIPath(baseRequest.getHttpURI().getDecodedPath()); - URIQuery query = new URIQuery(baseRequest.getHttpURI().getQuery()); - byte[] requestBody = readRequestBody(); + @Untrusted URIPath path = new URIPath(baseRequest.getHttpURI().getDecodedPath()); + @Untrusted URIQuery query = new URIQuery(baseRequest.getHttpURI().getQuery()); + @Untrusted byte[] requestBody = readRequestBody(); WebUser user = getWebUser(webserverConfiguration, authenticationExtractor); - Map headers = getRequestHeaders(); + @Untrusted Map headers = getRequestHeaders(); return new com.djrapitops.plan.delivery.web.resolver.request.Request(requestMethod, path, query, user, headers, requestBody); } @@ -106,7 +107,7 @@ public class JettyInternalRequest implements InternalRequest { @Override public List getCookies() { - List textCookies = getCookieHeaders(); + @Untrusted List textCookies = getCookieHeaders(); List cookies = new ArrayList<>(); if (!textCookies.isEmpty()) { String[] separated = new TextStringBuilder().appendWithSeparators(textCookies, ";").build().split(";"); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/RequestHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/RequestHandler.java index 253f51390..97ce55c92 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/RequestHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/http/RequestHandler.java @@ -24,6 +24,7 @@ import com.djrapitops.plan.delivery.webserver.ResponseResolver; import com.djrapitops.plan.delivery.webserver.auth.FailReason; import com.djrapitops.plan.delivery.webserver.configuration.WebserverConfiguration; import com.djrapitops.plan.exceptions.WebUserAuthException; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.apache.commons.lang3.StringUtils; import org.eclipse.jetty.http.HttpHeader; @@ -52,10 +53,10 @@ public class RequestHandler { } public Response getResponse(InternalRequest internalRequest) { - String accessAddress = internalRequest.getAccessAddress(webserverConfiguration); + @Untrusted String accessAddress = internalRequest.getAccessAddress(webserverConfiguration); Response response; - Request request = null; + @Untrusted Request request = null; if (bruteForceGuard.shouldPreventRequest(accessAddress)) { response = responseFactory.failedLoginAttempts403(); } else if (!webserverConfiguration.getAllowedIpList().isAllowed(accessAddress)) { @@ -81,17 +82,17 @@ public class RequestHandler { return response; } - private Response attemptToResolve(Request request, String accessAddress) { + private Response attemptToResolve(@Untrusted Request request, @Untrusted String accessAddress) { Response response = protocolUpgradeResponse(request) .orElseGet(() -> responseResolver.getResponse(request)); request.getUser().ifPresent(user -> processSuccessfulLogin(response.getCode(), accessAddress)); return response; } - private Optional protocolUpgradeResponse(Request request) { - Optional upgrade = request.getHeader(HttpHeader.UPGRADE.asString()); + private Optional protocolUpgradeResponse(@Untrusted Request request) { + @Untrusted Optional upgrade = request.getHeader(HttpHeader.UPGRADE.asString()); if (upgrade.isPresent()) { - String value = upgrade.get(); + @Untrusted String value = upgrade.get(); if ("h2c".equals(value) || "h2".equals(value)) { return Optional.of(Response.builder() .setStatus(101) @@ -103,12 +104,12 @@ public class RequestHandler { return Optional.empty(); } - private Response processFailedAuthentication(InternalRequest internalRequest, String accessAddress, WebUserAuthException thrownByAuthentication) { + private Response processFailedAuthentication(InternalRequest internalRequest, @Untrusted String accessAddress, WebUserAuthException thrownByAuthentication) { FailReason failReason = thrownByAuthentication.getFailReason(); if (failReason == FailReason.USER_PASS_MISMATCH) { return processWrongPassword(accessAddress, failReason); } else { - String from = internalRequest.getRequestedURIString(); + @Untrusted String from = internalRequest.getRequestedURIString(); String directTo = StringUtils.startsWithAny(from, "/auth/", "/login") ? "/login" : "/login?from=." + from; return Response.builder() .redirectTo(directTo) @@ -117,7 +118,7 @@ public class RequestHandler { } } - private Response processWrongPassword(String accessAddress, FailReason failReason) { + private Response processWrongPassword(@Untrusted String accessAddress, FailReason failReason) { bruteForceGuard.increaseAttemptCountOnFailedLogin(accessAddress); if (bruteForceGuard.shouldPreventRequest(accessAddress)) { return responseFactory.failedLoginAttempts403(); @@ -126,7 +127,7 @@ public class RequestHandler { } } - private void processSuccessfulLogin(int responseCode, String accessAddress) { + private void processSuccessfulLogin(int responseCode, @Untrusted String accessAddress) { boolean successfulLogin = responseCode != 401; boolean notForbidden = responseCode != 403; if (successfulLogin && notForbidden) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayerPageResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayerPageResolver.java index e4a2c1e13..0d617babb 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayerPageResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/PlayerPageResolver.java @@ -26,7 +26,9 @@ import com.djrapitops.plan.delivery.webserver.ResponseFactory; import com.djrapitops.plan.identification.UUIDUtility; import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.settings.config.paths.PluginSettings; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; import javax.inject.Inject; import javax.inject.Singleton; @@ -60,17 +62,22 @@ public class PlayerPageResolver implements Resolver { public boolean canAccess(Request request) { URIPath path = request.getPath(); WebUser user = request.getUser().orElse(new WebUser("")); - boolean isOwnPage = path.getPart(1).map(nameOrUUID -> { + boolean isOwnPage = isOwnPage(path, user); + return user.hasPermission("page.player.other") || user.hasPermission("page.player.self") && isOwnPage; + } + + @NotNull + private Boolean isOwnPage(@Untrusted URIPath path, WebUser user) { + return path.getPart(1).map(nameOrUUID -> { if (user.getName().equalsIgnoreCase(nameOrUUID)) return true; // name matches user return uuidUtility.getNameOf(nameOrUUID).map(user.getName()::equalsIgnoreCase) // uuid matches user .orElse(false); // uuid or name don't match }).orElse(true); // No name or UUID given - return user.hasPermission("page.player.other") || user.hasPermission("page.player.self") && isOwnPage; } @Override public Optional resolve(Request request) { - URIPath path = request.getPath(); + @Untrusted URIPath path = request.getPath(); if (StringUtils.containsAny(path.asString(), "/vendor/", "/js/", "/css/", "/img/", "/static/")) { return Optional.empty(); } @@ -78,7 +85,7 @@ public class PlayerPageResolver implements Resolver { .map(playerName -> getResponse(request.getPath(), playerName)); } - private Response getResponse(URIPath path, String playerName) { + private Response getResponse(@Untrusted URIPath path, @Untrusted String playerName) { UUID playerUUID = uuidUtility.getUUIDOf(playerName); if (playerUUID == null) return responseFactory.uuidNotFound404(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/RootPageResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/RootPageResolver.java index c47360a3c..16cbcea88 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/RootPageResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/RootPageResolver.java @@ -32,6 +32,7 @@ import dagger.Lazy; import javax.inject.Inject; import javax.inject.Singleton; import java.util.Optional; +import java.util.UUID; /** * Resolves '/' URL (Address Root). @@ -72,7 +73,7 @@ public class RootPageResolver implements NoAuthResolver { } else if (user.hasPermission("page.players")) { return responseFactory.redirectResponse("players"); } else if (user.hasPermission("page.player.self")) { - return responseFactory.redirectResponse("player/" + Html.encodeToURL(user.getName())); + return responseFactory.redirectResponse("player/" + user.getUUID().map(UUID::toString).orElseGet(user::getName)); } else { return responseFactory.forbidden403(user.getName() + " has insufficient permissions to be redirected to any page. Needs one of: 'page.server', 'page.players' or 'page.player.self'"); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/ServerPageResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/ServerPageResolver.java index 7845eaa27..e81fb3921 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/ServerPageResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/ServerPageResolver.java @@ -28,6 +28,7 @@ import com.djrapitops.plan.identification.ServerInfo; import com.djrapitops.plan.identification.ServerUUID; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.objects.ServerQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -58,7 +59,7 @@ public class ServerPageResolver implements Resolver { @Override public boolean canAccess(Request request) { - String firstPart = request.getPath().getPart(0).orElse(""); + @Untrusted String firstPart = request.getPath().getPart(0).orElse(""); WebUser permissions = request.getUser().orElse(new WebUser("")); boolean forServerPage = "server".equalsIgnoreCase(firstPart) && permissions.hasPermission("page.server"); boolean forNetworkPage = "network".equalsIgnoreCase(firstPart) && permissions.hasPermission("page.network"); @@ -92,7 +93,7 @@ public class ServerPageResolver implements Resolver { return Optional.of(responseFactory.serverPageResponse(serverUUID)); } - private Optional getServerUUID(URIPath path) { + private Optional getServerUUID(@Untrusted URIPath path) { if (serverInfo.getServer().isProxy() && path.getPart(0).map("network"::equals).orElse(false) ) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/StaticResourceResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/StaticResourceResolver.java index 6f1f980a0..ec45839d2 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/StaticResourceResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/StaticResourceResolver.java @@ -21,6 +21,7 @@ import com.djrapitops.plan.delivery.web.resolver.Response; import com.djrapitops.plan.delivery.web.resolver.request.Request; import com.djrapitops.plan.delivery.web.resolver.request.URIPath; import com.djrapitops.plan.delivery.webserver.ResponseFactory; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.apache.commons.lang3.StringUtils; import javax.inject.Inject; @@ -51,7 +52,7 @@ public class StaticResourceResolver implements NoAuthResolver { } private Response getResponse(Request request) { - String resource = getPath(request).asString().substring(1); + @Untrusted String resource = getPath(request).asString().substring(1); if (resource.endsWith(".css")) { return responseFactory.cssResponse(resource); } @@ -68,7 +69,7 @@ public class StaticResourceResolver implements NoAuthResolver { } private URIPath getPath(Request request) { - URIPath path = request.getPath(); + @Untrusted URIPath path = request.getPath(); // Remove everything before /vendor /css /js or /img while (!path.getPart(0).map(part -> part.matches(PART_REGEX)).orElse(true)) { path = path.omitFirst(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LoginPageResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LoginPageResolver.java index 56c3c4423..cbb765eee 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LoginPageResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LoginPageResolver.java @@ -22,6 +22,7 @@ import com.djrapitops.plan.delivery.web.resolver.request.Request; import com.djrapitops.plan.delivery.web.resolver.request.WebUser; import com.djrapitops.plan.delivery.webserver.ResponseFactory; import com.djrapitops.plan.delivery.webserver.http.WebServer; +import com.djrapitops.plan.utilities.dev.Untrusted; import dagger.Lazy; import javax.inject.Inject; @@ -44,10 +45,10 @@ public class LoginPageResolver implements NoAuthResolver { } @Override - public Optional resolve(Request request) { + public Optional resolve(@Untrusted Request request) { Optional user = request.getUser(); if (user.isPresent() || !webServer.get().isAuthRequired()) { - Optional from = request.getQuery().get("from") + @Untrusted Optional from = request.getQuery().get("from") .filter(redirectBackTo -> !redirectBackTo.startsWith("http")); return Optional.of(responseFactory.redirectResponse(from.orElse("/"))); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LoginResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LoginResolver.java index 67452a79f..1b57a8f01 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LoginResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LoginResolver.java @@ -30,6 +30,7 @@ import com.djrapitops.plan.exceptions.WebUserAuthException; import com.djrapitops.plan.exceptions.database.DBOpException; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.ExampleObject; @@ -92,11 +93,11 @@ public class LoginResolver implements NoAuthResolver { .build(); } - public User getUser(Request request) { - URIQuery form = RequestBodyConverter.formBody(request); - URIQuery query = request.getQuery(); - String username = getUser(form, query); - String password = getPassword(form, query); + public User getUser(@Untrusted Request request) { + @Untrusted URIQuery form = RequestBodyConverter.formBody(request); + @Untrusted URIQuery query = request.getQuery(); + @Untrusted String username = getUser(form, query); + @Untrusted String password = getPassword(form, query); User user = dbSystem.getDatabase().query(WebUserQueries.fetchUser(username)) .orElseThrow(() -> new WebUserAuthException(FailReason.USER_PASS_MISMATCH)); @@ -107,13 +108,13 @@ public class LoginResolver implements NoAuthResolver { return user; } - private String getPassword(URIQuery form, URIQuery query) { + private String getPassword(@Untrusted URIQuery form, @Untrusted URIQuery query) { return form.get("password") .orElseGet(() -> query.get("password") .orElseThrow(() -> new BadRequestException("'password' parameter not defined"))); } - private String getUser(URIQuery form, URIQuery query) { + private String getUser(@Untrusted URIQuery form, @Untrusted URIQuery query) { return form.get("user") .orElseGet(() -> query.get("user") .orElseThrow(() -> new BadRequestException("'user' parameter not defined"))); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LogoutResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LogoutResolver.java index d064827b0..58c7b9903 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LogoutResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/LogoutResolver.java @@ -22,6 +22,7 @@ import com.djrapitops.plan.delivery.web.resolver.request.Request; import com.djrapitops.plan.delivery.webserver.auth.ActiveCookieStore; import com.djrapitops.plan.delivery.webserver.auth.FailReason; import com.djrapitops.plan.exceptions.WebUserAuthException; +import com.djrapitops.plan.utilities.dev.Untrusted; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.ExampleObject; @@ -57,13 +58,13 @@ public class LogoutResolver implements NoAuthResolver { requestBody = @RequestBody(content = @Content(examples = @ExampleObject())) ) @Override - public Optional resolve(Request request) { - String cookies = request.getHeader("Cookie").orElse(""); - String foundCookie = null; - for (String cookie : cookies.split(";")) { + public Optional resolve(@Untrusted Request request) { + @Untrusted String cookies = request.getHeader("Cookie").orElse(""); + @Untrusted String foundCookie = null; + for (@Untrusted String cookie : cookies.split(";")) { if (cookie.isEmpty()) continue; - String[] split = cookie.split("="); - String name = split[0]; + @Untrusted String[] split = cookie.split("="); + @Untrusted String name = split[0]; if ("auth".equals(name) && split.length > 1) { foundCookie = split[1]; activeCookieStore.removeCookie(foundCookie); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/RegisterPageResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/RegisterPageResolver.java index c346c50bf..df8af9c6d 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/RegisterPageResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/RegisterPageResolver.java @@ -22,6 +22,7 @@ import com.djrapitops.plan.delivery.web.resolver.request.Request; import com.djrapitops.plan.delivery.web.resolver.request.WebUser; import com.djrapitops.plan.delivery.webserver.ResponseFactory; import com.djrapitops.plan.delivery.webserver.http.WebServer; +import com.djrapitops.plan.utilities.dev.Untrusted; import dagger.Lazy; import javax.inject.Inject; @@ -44,7 +45,7 @@ public class RegisterPageResolver implements NoAuthResolver { } @Override - public Optional resolve(Request request) { + public Optional resolve(@Untrusted Request request) { Optional user = request.getUser(); if (user.isPresent() || !webServer.get().isAuthRequired()) { return Optional.of(responseFactory.redirectResponse("/")); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/RegisterResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/RegisterResolver.java index e86910a04..1653e89e1 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/RegisterResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/auth/RegisterResolver.java @@ -27,6 +27,7 @@ import com.djrapitops.plan.delivery.webserver.auth.RegistrationBin; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries; import com.djrapitops.plan.utilities.PassEncryptUtil; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.java.Maps; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -79,8 +80,8 @@ public class RegisterResolver implements NoAuthResolver { } public Response getResponse(Request request) { - URIQuery query = request.getQuery(); - Optional checkCode = query.get("code"); + @Untrusted URIQuery query = request.getQuery(); + @Untrusted Optional checkCode = query.get("code"); if (checkCode.isPresent()) { return Response.builder() .setStatus(200) @@ -88,13 +89,13 @@ public class RegisterResolver implements NoAuthResolver { .build(); } - URIQuery form = RequestBodyConverter.formBody(request); - String username = getUser(form, query); + @Untrusted URIQuery form = RequestBodyConverter.formBody(request); + @Untrusted String username = getUser(form, query); boolean alreadyExists = dbSystem.getDatabase().query(WebUserQueries.fetchUser(username)).isPresent(); if (alreadyExists) throw new BadRequestException("User already exists!"); - String password = getPassword(form, query); + @Untrusted String password = getPassword(form, query); try { String code = RegistrationBin.addInfoForRegistration(username, password); return Response.builder() @@ -109,13 +110,13 @@ public class RegisterResolver implements NoAuthResolver { } } - private String getPassword(URIQuery form, URIQuery query) { + private String getPassword(@Untrusted URIQuery form, @Untrusted URIQuery query) { return form.get("password") .orElseGet(() -> query.get("password") .orElseThrow(() -> new BadRequestException("'password' parameter not defined"))); } - private String getUser(URIQuery form, URIQuery query) { + private String getUser(@Untrusted URIQuery form, @Untrusted URIQuery query) { return form.get("user") .orElseGet(() -> query.get("user") .orElseThrow(() -> new BadRequestException("'user' parameter not defined"))); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ExtensionJSONResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ExtensionJSONResolver.java index 037c4c4f1..a47db1d51 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ExtensionJSONResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ExtensionJSONResolver.java @@ -32,6 +32,7 @@ import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionSer import com.djrapitops.plan.identification.Identifiers; import com.djrapitops.plan.identification.ServerUUID; import com.djrapitops.plan.storage.database.DBSystem; +import com.djrapitops.plan.utilities.dev.Untrusted; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; @@ -88,14 +89,14 @@ public class ExtensionJSONResolver implements Resolver { ) @Override public Optional resolve(Request request) { - String identifier = request.getQuery().get("server") + @Untrusted String identifier = request.getQuery().get("server") .orElseThrow(() -> new BadRequestException("'server' parameter was not given")); ServerUUID serverUUID = identifiers.getServerUUID(identifier) - .orElseThrow(() -> new NotFoundException("Server with identifier '" + identifier + "' was not found in database")); + .orElseThrow(() -> new NotFoundException("Server with given server-parameter was not found in database")); return Optional.of(getResponse(request, serverUUID)); } - private JSONStorage.StoredJSON getJSON(Request request, ServerUUID serverUUID) { + private JSONStorage.StoredJSON getJSON(@Untrusted Request request, ServerUUID serverUUID) { Optional timestamp = Identifiers.getTimestamp(request); return jsonResolverService.resolve( diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/GraphsJSONResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/GraphsJSONResolver.java index 052d5b9e3..1915f136d 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/GraphsJSONResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/GraphsJSONResolver.java @@ -29,6 +29,7 @@ import com.djrapitops.plan.delivery.webserver.cache.DataID; import com.djrapitops.plan.delivery.webserver.cache.JSONStorage; import com.djrapitops.plan.identification.Identifiers; import com.djrapitops.plan.identification.ServerUUID; +import com.djrapitops.plan.utilities.dev.Untrusted; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; @@ -41,7 +42,6 @@ import jakarta.ws.rs.Path; import javax.inject.Inject; import javax.inject.Singleton; -import java.util.Collections; import java.util.Optional; /** @@ -121,7 +121,7 @@ public class GraphsJSONResolver implements Resolver { } private Response getResponse(Request request) { - String type = request.getQuery().get("type") + @Untrusted String type = request.getQuery().get("type") .orElseThrow(() -> new BadRequestException("'type' parameter was not defined.")); DataID dataID = getDataID(type); @@ -132,7 +132,7 @@ public class GraphsJSONResolver implements Resolver { .build(); } - private JSONStorage.StoredJSON getGraphJSON(Request request, DataID dataID) { + private JSONStorage.StoredJSON getGraphJSON(@Untrusted Request request, DataID dataID) { Optional timestamp = Identifiers.getTimestamp(request); JSONStorage.StoredJSON storedJSON; @@ -151,7 +151,7 @@ public class GraphsJSONResolver implements Resolver { return storedJSON; } - private DataID getDataID(String type) { + private DataID getDataID(@Untrusted String type) { switch (type) { case "performance": return DataID.GRAPH_PERFORMANCE; @@ -186,7 +186,7 @@ public class GraphsJSONResolver implements Resolver { } } - private Object generateGraphDataJSONOfType(DataID id, ServerUUID serverUUID, URIQuery query) { + private Object generateGraphDataJSONOfType(DataID id, ServerUUID serverUUID, @Untrusted URIQuery query) { switch (id) { case GRAPH_PERFORMANCE: return graphJSON.performanceGraphJSON(serverUUID); @@ -218,15 +218,15 @@ public class GraphsJSONResolver implements Resolver { query.get("after").map(Long::parseLong).orElse(0L), query.get("before").map(Long::parseLong).orElse(System.currentTimeMillis()) ); - } catch (NumberFormatException e) { - throw new BadRequestException("'after' or 'before' is not a epoch millisecond (number) " + e.getMessage()); + } catch (@Untrusted NumberFormatException e) { + throw new BadRequestException("'after' or 'before' is not a epoch millisecond (number)"); } default: - return Collections.singletonMap("error", "Undefined ID: " + id.name()); + throw new BadRequestException("Graph type not supported with server-parameter (" + id.name() + ")"); } } - private Object generateGraphDataJSONOfType(DataID id, URIQuery query) { + private Object generateGraphDataJSONOfType(DataID id, @Untrusted URIQuery query) { switch (id) { case GRAPH_ACTIVITY: return graphJSON.activityGraphsJSONAsMap(); @@ -246,11 +246,11 @@ public class GraphsJSONResolver implements Resolver { query.get("after").map(Long::parseLong).orElse(0L), query.get("before").map(Long::parseLong).orElse(System.currentTimeMillis()) ); - } catch (NumberFormatException e) { - throw new BadRequestException("'after' or 'before' is not a epoch millisecond (number) " + e.getMessage()); + } catch (@Untrusted NumberFormatException e) { + throw new BadRequestException("'after' or 'before' is not a epoch millisecond (number)"); } default: - return Collections.singletonMap("error", "Undefined ID: " + id.name()); + throw new BadRequestException("Graph type not supported without server-parameter (" + id.name() + ")"); } } } \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/LocaleJSONResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/LocaleJSONResolver.java index 722a1188a..c9d9b4e9b 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/LocaleJSONResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/LocaleJSONResolver.java @@ -31,6 +31,7 @@ import com.djrapitops.plan.settings.locale.LocaleSystem; import com.djrapitops.plan.settings.locale.lang.Lang; import com.djrapitops.plan.storage.file.PlanFiles; import com.djrapitops.plan.storage.file.Resource; +import com.djrapitops.plan.utilities.dev.Untrusted; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; @@ -96,7 +97,7 @@ public class LocaleJSONResolver implements NoAuthResolver { private Response getResponse(Request request) { ResponseBuilder builder = Response.builder(); - Optional langCode = request.getPath().getPart(1); + @Untrusted Optional langCode = request.getPath().getPart(1); Map json = langCode .map(this::getLocaleJSON) .orElseGet(this::getLanguageListJSON); @@ -137,7 +138,7 @@ public class LocaleJSONResolver implements NoAuthResolver { return json; } - private Map getLocaleJSON(String langCode) { + private Map getLocaleJSON(@Untrusted String langCode) { try { LangCode code = LangCode.valueOf(langCode.toUpperCase()); Map json = new TreeMap<>(); @@ -153,7 +154,7 @@ public class LocaleJSONResolver implements NoAuthResolver { } return dfs(loadLocale(file), json); - } catch (IllegalArgumentException noSuchEnum) { + } catch (@Untrusted IllegalArgumentException noSuchEnum) { return Collections.emptyMap(); } catch (IOException dfsFileLookupError) { throw new UncheckedIOException(dfsFileLookupError); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/NetworkPerformanceJSONResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/NetworkPerformanceJSONResolver.java index 2f5034317..52aae6452 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/NetworkPerformanceJSONResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/NetworkPerformanceJSONResolver.java @@ -33,6 +33,7 @@ import com.djrapitops.plan.settings.locale.lang.GenericLang; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.Database; import com.djrapitops.plan.storage.database.queries.objects.TPSQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import io.swagger.v3.oas.annotations.Operation; @@ -119,7 +120,7 @@ public class NetworkPerformanceJSONResolver implements Resolver { .build()); } - private List getUUIDList(String jsonString) { + private List getUUIDList(@Untrusted String jsonString) { return gson.fromJson(jsonString, new TypeToken>() {}.getType()); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/PlayersTableJSONResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/PlayersTableJSONResolver.java index 83267bdff..307b46ca7 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/PlayersTableJSONResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/PlayersTableJSONResolver.java @@ -27,6 +27,7 @@ import com.djrapitops.plan.delivery.webserver.cache.DataID; import com.djrapitops.plan.delivery.webserver.cache.JSONStorage; import com.djrapitops.plan.identification.Identifiers; import com.djrapitops.plan.identification.ServerUUID; +import com.djrapitops.plan.utilities.dev.Untrusted; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; @@ -100,7 +101,7 @@ public class PlayersTableJSONResolver implements Resolver { .build(); } - private JSONStorage.StoredJSON getStoredJSON(Request request) { + private JSONStorage.StoredJSON getStoredJSON(@Untrusted Request request) { Optional timestamp = Identifiers.getTimestamp(request); JSONStorage.StoredJSON storedJSON; if (request.getQuery().get("server").isPresent()) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/QueryJSONResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/QueryJSONResolver.java index bcc557253..160149886 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/QueryJSONResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/QueryJSONResolver.java @@ -47,6 +47,7 @@ import com.djrapitops.plan.storage.database.queries.filter.QueryFilters; import com.djrapitops.plan.storage.database.queries.objects.GeoInfoQueries; import com.djrapitops.plan.storage.database.queries.objects.SessionQueries; import com.djrapitops.plan.storage.database.queries.objects.playertable.QueryTablePlayersQuery; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.java.Maps; import com.google.gson.Gson; import io.swagger.v3.oas.annotations.Operation; @@ -131,12 +132,12 @@ public class QueryJSONResolver implements Resolver { return Optional.of(getResponse(request)); } - private Response getResponse(Request request) { + private Response getResponse(@Untrusted Request request) { Optional cachedResult = checkForCachedResult(request); if (cachedResult.isPresent()) return cachedResult.get(); InputQueryDto inputQuery = parseInputQuery(request); - List queries = inputQuery.getFilters(); + @Untrusted List queries = inputQuery.getFilters(); Filter.Result result = filters.apply(queries); List resultPath = result.getInverseResultPath(); @@ -145,7 +146,7 @@ public class QueryJSONResolver implements Resolver { return buildAndStoreResponse(inputQuery, result, resultPath); } - private InputQueryDto parseInputQuery(Request request) { + private InputQueryDto parseInputQuery(@Untrusted Request request) { if (request.getRequestBody().length == 0) { return parseInputQueryFromQueryParams(request); } else { @@ -153,11 +154,11 @@ public class QueryJSONResolver implements Resolver { } } - private InputQueryDto parseInputQueryFromQueryParams(Request request) { - String q = request.getQuery().get("q").orElseThrow(() -> new BadRequestException("'q' parameter not set (expecting json array)")); + private InputQueryDto parseInputQueryFromQueryParams(@Untrusted Request request) { + @Untrusted String q = request.getQuery().get("q").orElseThrow(() -> new BadRequestException("'q' parameter not set (expecting json array)")); try { - String query = URLDecoder.decode(q, StandardCharsets.UTF_8); - List queryFilters = InputFilterDto.parse(query, gson); + @Untrusted String query = URLDecoder.decode(q, StandardCharsets.UTF_8); + @Untrusted List queryFilters = InputFilterDto.parse(query, gson); ViewDto view = request.getQuery().get("view") .map(viewJson -> gson.fromJson(viewJson, ViewDto.class)) .orElseThrow(() -> new BadRequestException("'view' parameter not set (expecting json object {afterDate, afterTime, beforeDate, beforeTime})")); @@ -167,15 +168,16 @@ public class QueryJSONResolver implements Resolver { } } - private Optional checkForCachedResult(Request request) { + private Optional checkForCachedResult(@Untrusted Request request) { try { return request.getQuery().get("timestamp") - .flatMap(queryTimestamp -> jsonStorage.fetchExactJson("query", Long.parseLong(queryTimestamp))) + .map(Long::parseLong) + .flatMap(queryTimestamp -> jsonStorage.fetchExactJson("query", queryTimestamp)) .map(results -> Response.builder() .setMimeType(MimeType.JSON) .setJSONContent(results.json) .build()); - } catch (NumberFormatException e) { + } catch (@Untrusted NumberFormatException e) { throw new BadRequestException("Could not parse 'timestamp' into a number. Remove parameter or fix it."); } } @@ -183,10 +185,10 @@ public class QueryJSONResolver implements Resolver { private Response buildAndStoreResponse(InputQueryDto input, Filter.Result result, List resultPath) { try { long timestamp = System.currentTimeMillis(); - Map json = Maps.builder(String.class, Object.class) + @Untrusted Map json = Maps.builder(String.class, Object.class) .put("path", resultPath) .put("view", input.getView()) - .put("filters", input.getFilters()) + .put("filters", input.getFilters()) // filters json may contain untrusted data .put("timestamp", timestamp) .build(); if (!result.isEmpty()) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ServerIdentityJSONResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ServerIdentityJSONResolver.java index eff9ae5c1..0f764a3a2 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ServerIdentityJSONResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ServerIdentityJSONResolver.java @@ -24,6 +24,7 @@ import com.djrapitops.plan.delivery.web.resolver.Response; import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException; import com.djrapitops.plan.delivery.web.resolver.exception.NotFoundException; import com.djrapitops.plan.delivery.web.resolver.request.Request; +import com.djrapitops.plan.utilities.dev.Untrusted; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; @@ -75,7 +76,7 @@ public class ServerIdentityJSONResolver implements Resolver { ) @Override public Optional resolve(Request request) { - String serverIdentifier = request.getQuery().get("server") + @Untrusted String serverIdentifier = request.getQuery().get("server") .orElseThrow(() -> new BadRequestException("Missing 'server' query parameter")); ServerDto server = jsonFactory.serverForIdentifier(serverIdentifier) .orElseThrow(() -> new NotFoundException("Server with identifier '" + serverIdentifier + "' was not found in the database")); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ServerTabJSONResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ServerTabJSONResolver.java index 15e53cb3d..88ee29b98 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ServerTabJSONResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/ServerTabJSONResolver.java @@ -26,6 +26,7 @@ import com.djrapitops.plan.delivery.webserver.cache.AsyncJSONResolverService; import com.djrapitops.plan.delivery.webserver.cache.DataID; import com.djrapitops.plan.identification.Identifiers; import com.djrapitops.plan.identification.ServerUUID; +import com.djrapitops.plan.utilities.dev.Untrusted; import java.util.Optional; import java.util.function.Function; @@ -62,7 +63,7 @@ public class ServerTabJSONResolver implements Resolver { return Optional.of(getResponse(request)); } - private Response getResponse(Request request) { + private Response getResponse(@Untrusted Request request) { ServerUUID serverUUID = identifiers.getServerUUID(request); // Can throw BadRequestException return Response.builder() .setMimeType(MimeType.JSON) diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/SessionsJSONResolver.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/SessionsJSONResolver.java index 934cd1275..716ffcba7 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/SessionsJSONResolver.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/SessionsJSONResolver.java @@ -27,6 +27,7 @@ import com.djrapitops.plan.delivery.webserver.cache.DataID; import com.djrapitops.plan.delivery.webserver.cache.JSONStorage; import com.djrapitops.plan.identification.Identifiers; import com.djrapitops.plan.identification.ServerUUID; +import com.djrapitops.plan.utilities.dev.Untrusted; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; @@ -97,7 +98,7 @@ public class SessionsJSONResolver implements Resolver { .build(); } - private JSONStorage.StoredJSON getStoredJSON(Request request) { + private JSONStorage.StoredJSON getStoredJSON(@Untrusted Request request) { Optional timestamp = Identifiers.getTimestamp(request); if (request.getQuery().get("server").isPresent()) { ServerUUID serverUUID = identifiers.getServerUUID(request); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/queries/ExtensionUserIdsInGroupQuery.java b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/queries/ExtensionUserIdsInGroupQuery.java index 7bba8aa41..9cb36223b 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/queries/ExtensionUserIdsInGroupQuery.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/extension/implementation/storage/queries/ExtensionUserIdsInGroupQuery.java @@ -21,7 +21,7 @@ import com.djrapitops.plan.storage.database.queries.QueryStatement; import com.djrapitops.plan.storage.database.sql.tables.ExtensionGroupsTable; import com.djrapitops.plan.storage.database.sql.tables.ExtensionProviderTable; import com.djrapitops.plan.storage.database.sql.tables.UsersTable; -import org.apache.commons.text.TextStringBuilder; +import com.djrapitops.plan.utilities.dev.Untrusted; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -38,9 +38,10 @@ public class ExtensionUserIdsInGroupQuery extends QueryStatement> { private final String pluginName; private final String groupProvider; private final ServerUUID serverUUID; + @Untrusted private final List inGroups; - public ExtensionUserIdsInGroupQuery(String pluginName, String groupProvider, ServerUUID serverUUID, List inGroups) { + public ExtensionUserIdsInGroupQuery(String pluginName, String groupProvider, ServerUUID serverUUID, @Untrusted List inGroups) { super(buildSQL(inGroups), 100); this.pluginName = pluginName; this.groupProvider = groupProvider; @@ -48,21 +49,19 @@ public class ExtensionUserIdsInGroupQuery extends QueryStatement> { this.inGroups = inGroups; } - private static String buildSQL(Collection inGroups) { - TextStringBuilder dynamicInClauseAllocation = new TextStringBuilder(); - dynamicInClauseAllocation.appendWithSeparators(inGroups.stream().map(group -> "?").toArray(), ","); + private static String buildSQL(@Untrusted Collection inGroups) { return SELECT + DISTINCT + "u." + UsersTable.ID + FROM + ExtensionGroupsTable.TABLE_NAME + " groups" + INNER_JOIN + UsersTable.TABLE_NAME + " u on u." + UsersTable.USER_UUID + "=groups." + ExtensionGroupsTable.USER_UUID + WHERE + ExtensionGroupsTable.PROVIDER_ID + "=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID + - AND + ExtensionGroupsTable.GROUP_NAME + " IN (" + dynamicInClauseAllocation.build() + ")"; + AND + ExtensionGroupsTable.GROUP_NAME + " IN (" + nParameters(inGroups.size()) + ")"; } @Override public void prepare(PreparedStatement statement) throws SQLException { ExtensionProviderTable.set3PluginValuesToStatement(statement, 1, groupProvider, pluginName, serverUUID); int index = 4; - for (String group : inGroups) { + for (@Untrusted String group : inGroups) { setStringOrNull(statement, index, group == null || "null".equalsIgnoreCase(group) ? null : group); index++; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/FinishedSession.java b/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/FinishedSession.java index 6845eee0a..a8b7e2441 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/FinishedSession.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/FinishedSession.java @@ -196,6 +196,7 @@ public class FinishedSession implements DateHolder { getExtraData(PlayerKills.class).orElseGet(PlayerKills::new).toJson() + ';' + getExtraData(MobKillCounter.class).orElseGet(MobKillCounter::new).toJson() + ';' + getExtraData(DeathCounter.class).orElseGet(DeathCounter::new).toJson() + ';' + + // Join address contains @Untrusted data getExtraData(JoinAddress.class).map(JoinAddress::getAddress).orElse(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP) + ';' + getExtraData(PlayerName.class).map(PlayerName::get).orElseGet(playerUUID::toString); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/event/JoinAddress.java b/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/event/JoinAddress.java index f656521dc..e1498a8e9 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/event/JoinAddress.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/gathering/domain/event/JoinAddress.java @@ -17,11 +17,13 @@ package com.djrapitops.plan.gathering.domain.event; import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.apache.commons.lang3.StringUtils; import java.util.Objects; import java.util.function.Supplier; +@Untrusted public class JoinAddress { private final Supplier address; @@ -33,6 +35,7 @@ public class JoinAddress { this.address = address; } + @Untrusted public String getAddress() { return StringUtils.truncate(address.get(), JoinAddressTable.JOIN_ADDRESS_MAX_LENGTH); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/gathering/importing/ImportSystem.java b/Plan/common/src/main/java/com/djrapitops/plan/gathering/importing/ImportSystem.java index 0a439bdc8..1ee0360b8 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/gathering/importing/ImportSystem.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/gathering/importing/ImportSystem.java @@ -18,6 +18,7 @@ package com.djrapitops.plan.gathering.importing; import com.djrapitops.plan.SubSystem; import com.djrapitops.plan.gathering.importing.importers.Importer; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -53,7 +54,7 @@ public class ImportSystem implements SubSystem { importers.put(importer.getName(), importer); } - public Optional getImporter(String name) { + public Optional getImporter(@Untrusted String name) { return Optional.ofNullable(importers.get(name)); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/identification/Identifiers.java b/Plan/common/src/main/java/com/djrapitops/plan/identification/Identifiers.java index f241a179f..c14f5a343 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/identification/Identifiers.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/identification/Identifiers.java @@ -21,6 +21,7 @@ import com.djrapitops.plan.delivery.web.resolver.request.Request; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.objects.ServerQueries; import com.djrapitops.plan.storage.database.queries.objects.UserIdentifierQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.jetbrains.annotations.Nullable; import javax.inject.Inject; @@ -63,55 +64,7 @@ public class Identifiers { )); } - /** - * Obtain UUID of the server. - * - * @param identifier Identifier (name or uuid string) of the server - * @return UUID of the server. - * @throws BadRequestException If the server is not in the database. - */ - public Optional getServerUUID(String identifier) { - Optional parsed = UUIDUtility.parseFromString(identifier).map(ServerUUID::from); - if (parsed.isPresent()) return parsed; - return getServerUUIDFromName(identifier); - } - - private Optional getServerUUIDFromName(String serverName) { - return dbSystem.getDatabase().query(ServerQueries.fetchServerMatchingIdentifier(serverName)) - .map(Server::getUuid); - } - - /** - * Obtain UUID of the player. - * - * @param request for Request, URIQuery needs a 'player' parameter. - * @return UUID of the player. - * @throws BadRequestException If player parameter is not defined or the player is not in the database. - */ - public UUID getPlayerUUID(Request request) { - String playerIdentifier = request.getQuery().get("player") - .orElseThrow(() -> new BadRequestException("'player' parameter was not defined.")).trim(); - - Optional parsed = UUIDUtility.parseFromString(playerIdentifier); - return parsed.orElseGet(() -> getPlayerUUIDFromName(playerIdentifier)); - } - - private UUID getPlayerUUIDFromName(String playerName) { - return dbSystem.getDatabase() - .query(UserIdentifierQueries.fetchPlayerUUIDOf(playerName)) - .orElseThrow(() -> new BadRequestException("Given 'player' was not found in the database.")); - } - - @Nullable - public UUID getPlayerUUID(String name) { - return uuidUtility.getUUIDOf(name); - } - - public Optional getPlayerUserId(UUID playerUUID) { - return dbSystem.getDatabase().query(UserIdentifierQueries.fetchUserId(playerUUID)); - } - - public static Optional getTimestamp(Request request) { + public static Optional getTimestamp(@Untrusted Request request) { try { long currentTime = System.currentTimeMillis(); long timestamp = request.getQuery().get("timestamp") @@ -125,4 +78,52 @@ public class Identifiers { throw new BadRequestException("'timestamp' was not a number: " + nonNumberTimestamp.getMessage()); } } + + /** + * Obtain UUID of the server. + * + * @param identifier Identifier (name or uuid string) of the server + * @return UUID of the server. + * @throws BadRequestException If the server is not in the database. + */ + public Optional getServerUUID(@Untrusted String identifier) { + Optional parsed = UUIDUtility.parseFromString(identifier).map(ServerUUID::from); + if (parsed.isPresent()) return parsed; + return getServerUUIDFromName(identifier); + } + + private Optional getServerUUIDFromName(@Untrusted String serverName) { + return dbSystem.getDatabase().query(ServerQueries.fetchServerMatchingIdentifier(serverName)) + .map(Server::getUuid); + } + + /** + * Obtain UUID of the player. + * + * @param request for Request, URIQuery needs a 'player' parameter. + * @return UUID of the player. + * @throws BadRequestException If player parameter is not defined or the player is not in the database. + */ + public UUID getPlayerUUID(@Untrusted Request request) { + @Untrusted String playerIdentifier = request.getQuery().get("player") + .orElseThrow(() -> new BadRequestException("'player' parameter was not defined.")).trim(); + + Optional parsed = UUIDUtility.parseFromString(playerIdentifier); + return parsed.orElseGet(() -> getPlayerUUIDFromName(playerIdentifier)); + } + + @Nullable + public UUID getPlayerUUID(String name) { + return uuidUtility.getUUIDOf(name); + } + + public Optional getPlayerUserId(UUID playerUUID) { + return dbSystem.getDatabase().query(UserIdentifierQueries.fetchUserId(playerUUID)); + } + + private UUID getPlayerUUIDFromName(@Untrusted String playerName) { + return dbSystem.getDatabase() + .query(UserIdentifierQueries.fetchPlayerUUIDOf(playerName)) + .orElseThrow(() -> new BadRequestException("Given 'player' was not found in the database.")); + } } \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/identification/UUIDUtility.java b/Plan/common/src/main/java/com/djrapitops/plan/identification/UUIDUtility.java index 063ddb1af..592667969 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/identification/UUIDUtility.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/identification/UUIDUtility.java @@ -19,6 +19,7 @@ package com.djrapitops.plan.identification; import com.djrapitops.plan.exceptions.database.DBOpException; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.objects.UserIdentifierQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.logging.ErrorLogger; import net.playeranalytics.plugin.player.UUIDFetcher; import org.jetbrains.annotations.Nullable; @@ -50,18 +51,18 @@ public class UUIDUtility { this.errorLogger = errorLogger; } - public static Optional parseFromString(String uuidString) { + public static Optional parseFromString(@Untrusted String uuidString) { try { return Optional.of(UUID.fromString(uuidString)); - } catch (IllegalArgumentException malformedUUIDException) { + } catch (@Untrusted IllegalArgumentException malformedUUIDException) { return Optional.empty(); } } - public Optional getNameOf(String possiblePlayerUUID) { + public Optional getNameOf(@Untrusted String possiblePlayerUUID) { try { return getNameOf(UUID.fromString(possiblePlayerUUID)); - } catch (IllegalArgumentException notUUID) { + } catch (@Untrusted IllegalArgumentException notUUID) { return Optional.empty(); } } @@ -78,7 +79,7 @@ public class UUIDUtility { * @return UUID of the player */ @Nullable - public UUID getUUIDOf(String playerName) { + public UUID getUUIDOf(@Untrusted String playerName) { if (playerName == null) throw new IllegalArgumentException("Player name can not be null!"); UUID uuid = getUUIDFromString(playerName); if (uuid != null) return uuid; @@ -87,23 +88,23 @@ public class UUIDUtility { .orElse(getUUIDViaUUIDFetcher(playerName)); } - private UUID getUUIDFromString(String playerName) { + private UUID getUUIDFromString(@Untrusted String playerName) { try { return UUID.fromString(playerName); - } catch (IllegalArgumentException ignore) { + } catch (@Untrusted IllegalArgumentException ignore) { return null; } } - private UUID getUUIDViaUUIDFetcher(String playerName) { + private UUID getUUIDViaUUIDFetcher(@Untrusted String playerName) { try { return UUIDFetcher.getUUIDOf(playerName); - } catch (Exception | NoClassDefFoundError ignored) { + } catch (@Untrusted Exception | NoClassDefFoundError ignored) { return null; } } - private Optional getUUIDFromDB(String playerName) { + private Optional getUUIDFromDB(@Untrusted String playerName) { try { return dbSystem.getDatabase().query(UserIdentifierQueries.fetchPlayerUUIDOf(playerName)); } catch (DBOpException e) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/placeholder/OperatorPlaceholders.java b/Plan/common/src/main/java/com/djrapitops/plan/placeholder/OperatorPlaceholders.java index d6011b09b..9d2266201 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/placeholder/OperatorPlaceholders.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/placeholder/OperatorPlaceholders.java @@ -23,6 +23,7 @@ import com.djrapitops.plan.identification.ServerUUID; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.analysis.PlayerCountQueries; import com.djrapitops.plan.storage.database.queries.objects.ServerQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -54,11 +55,11 @@ public class OperatorPlaceholders implements Placeholders { ); } - private ServerUUID getServerUUID(Arguments parameters) { + private ServerUUID getServerUUID(@Untrusted Arguments parameters) { return parameters.get(0).flatMap(this::getServerUUIDForServerIdentifier).orElseGet(serverInfo::getServerUUID); } - private Optional getServerUUIDForServerIdentifier(String serverIdentifier) { + private Optional getServerUUIDForServerIdentifier(@Untrusted String serverIdentifier) { return dbSystem.getDatabase().query(ServerQueries.fetchServerMatchingIdentifier(serverIdentifier)) .map(Server::getUuid); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/placeholder/PlanPlaceholders.java b/Plan/common/src/main/java/com/djrapitops/plan/placeholder/PlanPlaceholders.java index 90bea564d..7b9b5baf9 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/placeholder/PlanPlaceholders.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/placeholder/PlanPlaceholders.java @@ -21,6 +21,7 @@ import com.djrapitops.plan.delivery.domain.container.PlayerContainer; import com.djrapitops.plan.identification.Identifiers; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.containers.ContainerFetchQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -107,21 +108,21 @@ public final class PlanPlaceholders { * value found but the placeholder is registered, * otherwise {@code null} */ - public String onPlaceholderRequest(UUID uuid, String placeholder, List parameters) { + public String onPlaceholderRequest(UUID uuid, @Untrusted String placeholder, @Untrusted List parameters) { for (Entry> entry : rawHandlers.entrySet()) { if (placeholder.startsWith(entry.getKey())) { return Objects.toString(entry.getValue().apply(placeholder)); } } - Arguments arguments = new Arguments(parameters); + @Untrusted Arguments arguments = new Arguments(parameters); StaticPlaceholderLoader staticLoader = staticPlaceholders.get(placeholder); if (staticLoader != null) { return Objects.toString(staticLoader.apply(arguments)); } - Optional givenIdentifier = arguments.get(0); + @Untrusted Optional givenIdentifier = arguments.get(0); Optional foundUUID = givenIdentifier .flatMap(this::getPlayerUUIDForIdentifier); UUID playerUUID = foundUUID.orElse(uuid); @@ -142,7 +143,7 @@ public final class PlanPlaceholders { return null; } - private Optional getPlayerUUIDForIdentifier(String identifier) { + private Optional getPlayerUUIDForIdentifier(@Untrusted String identifier) { return Optional.ofNullable(identifiers.getPlayerUUID(identifier)); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/placeholder/ServerPlaceHolders.java b/Plan/common/src/main/java/com/djrapitops/plan/placeholder/ServerPlaceHolders.java index 9c995e520..671f3ef5f 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/placeholder/ServerPlaceHolders.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/placeholder/ServerPlaceHolders.java @@ -29,6 +29,7 @@ import com.djrapitops.plan.storage.database.queries.analysis.PlayerCountQueries; import com.djrapitops.plan.storage.database.queries.analysis.TopListQueries; import com.djrapitops.plan.storage.database.queries.objects.ServerQueries; import com.djrapitops.plan.storage.database.queries.objects.TPSQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -201,11 +202,11 @@ public class ServerPlaceHolders implements Placeholders { registerDynamicCategoryPlaceholders(placeholders, database); } - private ServerUUID getServerUUID(Arguments parameters) { + private ServerUUID getServerUUID(@Untrusted Arguments parameters) { return parameters.get(0).flatMap(this::getServerUUIDForServerIdentifier).orElseGet(serverInfo::getServerUUID); } - private Optional getServerUUIDForServerIdentifier(String serverIdentifier) { + private Optional getServerUUIDForServerIdentifier(@Untrusted String serverIdentifier) { return dbSystem.getDatabase().query(ServerQueries.fetchServerMatchingIdentifier(serverIdentifier)) .map(Server::getUuid); } @@ -242,7 +243,7 @@ public class ServerPlaceHolders implements Placeholders { } interface QueryCreator { - Query>> apply(Integer number, Long timespan, Arguments parameters); + Query>> apply(Integer number, Long timespan, @Untrusted Arguments parameters); } public static class TopCategoryQuery { @@ -266,7 +267,7 @@ public class ServerPlaceHolders implements Placeholders { return timeSpan; } - public Query>> getQuery(int i, Arguments parameters) { + public Query>> getQuery(int i, @Untrusted Arguments parameters) { return queryCreator.apply(i, timeSpanMillis, parameters); } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/placeholder/SessionPlaceHolders.java b/Plan/common/src/main/java/com/djrapitops/plan/placeholder/SessionPlaceHolders.java index 421ea108c..0d7d70512 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/placeholder/SessionPlaceHolders.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/placeholder/SessionPlaceHolders.java @@ -29,6 +29,7 @@ import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.Database; import com.djrapitops.plan.storage.database.queries.analysis.PlayerCountQueries; import com.djrapitops.plan.storage.database.queries.objects.*; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -219,13 +220,13 @@ public class SessionPlaceHolders implements Placeholders { parameters -> database.query(TPSQueries.fetchPeakPlayerCount(getServerUUID(parameters), now() - TimeUnit.DAYS.toMillis(2L))).map(year).orElse("-")); } - private ServerUUID getServerUUID(Arguments parameters) { + private ServerUUID getServerUUID(@Untrusted Arguments parameters) { return parameters.get(0) .flatMap(this::getServerUUIDForServerIdentifier) .orElseGet(serverInfo::getServerUUID); } - private Optional getServerUUIDForServerIdentifier(String serverIdentifier) { + private Optional getServerUUIDForServerIdentifier(@Untrusted String serverIdentifier) { return dbSystem.getDatabase().query(ServerQueries.fetchServerMatchingIdentifier(serverIdentifier)) .map(Server::getUuid); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/DBType.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/DBType.java index abfe31f37..2c32d9865 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/DBType.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/DBType.java @@ -17,6 +17,7 @@ package com.djrapitops.plan.storage.database; import com.djrapitops.plan.storage.database.sql.building.Sql; +import com.djrapitops.plan.utilities.dev.Untrusted; import java.util.ArrayList; import java.util.List; @@ -80,7 +81,7 @@ public enum DBType { * @param name the name of the {@code DBType} * @return an {@code Optional} */ - public static Optional getForName(String name) { + public static Optional getForName(@Untrusted String name) { for (DBType dbType : DBType.values()) { if (dbType.getName().equalsIgnoreCase(name)) { return Optional.of(dbType); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/ActivityIndexQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/ActivityIndexQueries.java index a96067cee..5413b7b60 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/ActivityIndexQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/analysis/ActivityIndexQueries.java @@ -24,7 +24,7 @@ import com.djrapitops.plan.storage.database.sql.tables.ServerTable; import com.djrapitops.plan.storage.database.sql.tables.SessionsTable; import com.djrapitops.plan.storage.database.sql.tables.UserInfoTable; import com.djrapitops.plan.storage.database.sql.tables.UsersTable; -import com.djrapitops.plan.utilities.Benchmark; +import com.djrapitops.plan.utilities.dev.Benchmark; import java.sql.PreparedStatement; import java.sql.ResultSet; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/Filter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/Filter.java index df7a0e71f..e2e0d2e99 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/Filter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/Filter.java @@ -17,6 +17,7 @@ package com.djrapitops.plan.storage.database.queries.filter; import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto; +import com.djrapitops.plan.utilities.dev.Untrusted; import java.util.*; @@ -42,9 +43,9 @@ public interface Filter { * @return Set of UUIDs this filter applies to * @throws IllegalArgumentException If the arguments are not valid. */ - Set getMatchingUserIds(InputFilterDto query); + Set getMatchingUserIds(@Untrusted InputFilterDto query); - default Result apply(InputFilterDto query) { + default Result apply(@Untrusted InputFilterDto query) { try { return new Result(null, getKind(), getMatchingUserIds(query)); } catch (CompleteSetException allMatch) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/QueryFilters.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/QueryFilters.java index 5c83bede3..39e492503 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/QueryFilters.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/QueryFilters.java @@ -21,6 +21,7 @@ import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.filter.filters.AllPlayersFilter; import com.djrapitops.plan.storage.database.queries.filter.filters.PluginGroupsFilter; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -70,7 +71,7 @@ public class QueryFilters { } } - public Optional getFilter(String kind) { + public Optional getFilter(@Untrusted String kind) { prepareFilters(); return Optional.ofNullable(filters.get(kind)); } @@ -82,25 +83,25 @@ public class QueryFilters { * @return the result object or null if none of the filterQueries could be applied. * @throws BadRequestException If the request kind is not supported or if filter was given bad options. */ - public Filter.Result apply(List filterQueries) { + public Filter.Result apply(@Untrusted List filterQueries) { prepareFilters(); Filter.Result current = null; if (filterQueries.isEmpty()) return allPlayersFilter.apply(null); - for (InputFilterDto inputFilterDto : filterQueries) { + for (@Untrusted InputFilterDto inputFilterDto : filterQueries) { current = apply(current, inputFilterDto); if (current != null && current.isEmpty()) break; } return current; } - private Filter.Result apply(Filter.Result current, InputFilterDto inputFilterDto) { - String kind = inputFilterDto.getKind(); + private Filter.Result apply(Filter.Result current, @Untrusted InputFilterDto inputFilterDto) { + @Untrusted String kind = inputFilterDto.getKind(); Filter filter = getFilter(kind).orElseThrow(() -> new BadRequestException("Filter kind not supported: '" + kind + "'")); return getResult(current, filter, inputFilterDto); } - private Filter.Result getResult(Filter.Result current, Filter filter, InputFilterDto query) { + private Filter.Result getResult(Filter.Result current, Filter filter, @Untrusted InputFilterDto query) { try { return current == null ? filter.apply(query) : current.apply(filter, query); } catch (IllegalArgumentException badOptions) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/ActivityIndexFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/ActivityIndexFilter.java index 6bbf1a909..434598e14 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/ActivityIndexFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/ActivityIndexFilter.java @@ -24,6 +24,7 @@ import com.djrapitops.plan.settings.locale.Locale; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.analysis.NetworkActivityIndexQueries; import com.djrapitops.plan.storage.database.queries.filter.CompleteSetException; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -66,8 +67,8 @@ public class ActivityIndexFilter extends MultiOptionFilter { } @Override - public Set getMatchingUserIds(InputFilterDto query) { - List selected = getSelected(query); + public Set getMatchingUserIds(@Untrusted InputFilterDto query) { + @Untrusted List selected = getSelected(query); String[] options = getOptionsArray(); boolean includeVeryActive = selected.contains(options[0]); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/AllPlayersFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/AllPlayersFilter.java index 9e244117e..39d123588 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/AllPlayersFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/AllPlayersFilter.java @@ -20,6 +20,7 @@ import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.filter.Filter; import com.djrapitops.plan.storage.database.queries.objects.UserIdentifierQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -51,7 +52,7 @@ public class AllPlayersFilter implements Filter { } @Override - public Set getMatchingUserIds(InputFilterDto query) { + public Set getMatchingUserIds(@Untrusted InputFilterDto query) { return dbSystem.getDatabase().query(UserIdentifierQueries.fetchAllUserIds()); } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/BannedFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/BannedFilter.java index 21be9db10..803ce4a70 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/BannedFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/BannedFilter.java @@ -22,6 +22,7 @@ import com.djrapitops.plan.settings.locale.lang.FilterLang; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.filter.CompleteSetException; import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -57,8 +58,8 @@ public class BannedFilter extends MultiOptionFilter { } @Override - public Set getMatchingUserIds(InputFilterDto query) { - List selected = getSelected(query); + public Set getMatchingUserIds(@Untrusted InputFilterDto query) { + @Untrusted List selected = getSelected(query); Set userIds = new HashSet<>(); String[] options = getOptionsArray(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/DateRangeFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/DateRangeFilter.java index 24597c8dc..310df1472 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/DateRangeFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/DateRangeFilter.java @@ -21,6 +21,7 @@ import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.filter.Filter; import com.djrapitops.plan.storage.database.queries.objects.BaseUserQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.java.Maps; import org.apache.commons.lang3.StringUtils; @@ -61,17 +62,17 @@ public abstract class DateRangeFilter implements Filter { .build(); } - protected long getAfter(InputFilterDto query) { + protected long getAfter(@Untrusted InputFilterDto query) { return getTime(query, "afterDate", "afterTime"); } - protected long getBefore(InputFilterDto query) { + protected long getBefore(@Untrusted InputFilterDto query) { return getTime(query, "beforeDate", "beforeTime"); } - private long getTime(InputFilterDto query, String dateKey, String timeKey) { - String date = query.get(dateKey).orElseThrow(() -> new BadRequestException("'" + dateKey + "' not specified in parameters for " + getKind())); - String time = query.get(timeKey).orElseThrow(() -> new BadRequestException("'" + timeKey + "' not specified in parameters for " + getKind())); + private long getTime(@Untrusted InputFilterDto query, String dateKey, String timeKey) { + @Untrusted String date = query.get(dateKey).orElseThrow(() -> new BadRequestException("'" + dateKey + "' not specified in parameters for " + getKind())); + @Untrusted String time = query.get(timeKey).orElseThrow(() -> new BadRequestException("'" + timeKey + "' not specified in parameters for " + getKind())); try { return dateFormat.parse(date + ' ' + time).getTime(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/GeolocationsFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/GeolocationsFilter.java index 3234b3908..96be370f8 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/GeolocationsFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/GeolocationsFilter.java @@ -19,6 +19,7 @@ package com.djrapitops.plan.storage.database.queries.filter.filters; import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.objects.GeoInfoQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -50,7 +51,7 @@ public class GeolocationsFilter extends MultiOptionFilter { } @Override - public Set getMatchingUserIds(InputFilterDto query) { + public Set getMatchingUserIds(@Untrusted InputFilterDto query) { return dbSystem.getDatabase().query(GeoInfoQueries.userIdsOfPlayersWithGeolocations(getSelected(query))); } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/JoinAddressFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/JoinAddressFilter.java index 3083d5c97..d78cc9751 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/JoinAddressFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/JoinAddressFilter.java @@ -19,6 +19,7 @@ package com.djrapitops.plan.storage.database.queries.filter.filters; import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.objects.JoinAddressQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -50,7 +51,7 @@ public class JoinAddressFilter extends MultiOptionFilter { } @Override - public Set getMatchingUserIds(InputFilterDto query) { + public Set getMatchingUserIds(@Untrusted InputFilterDto query) { return dbSystem.getDatabase().query(JoinAddressQueries.userIdsOfPlayersWithJoinAddresses(getSelected(query))); } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/MultiOptionFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/MultiOptionFilter.java index 30033e605..990309231 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/MultiOptionFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/MultiOptionFilter.java @@ -19,6 +19,7 @@ package com.djrapitops.plan.storage.database.queries.filter.filters; import com.djrapitops.plan.delivery.domain.datatransfer.InputFilterDto; import com.djrapitops.plan.storage.database.queries.filter.CompleteSetException; import com.djrapitops.plan.storage.database.queries.filter.Filter; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -31,9 +32,9 @@ public abstract class MultiOptionFilter implements Filter { return new String[]{"selected"}; } - protected List getSelected(InputFilterDto query) { - String selectedJSON = query.get("selected").orElseThrow(IllegalArgumentException::new); - List selected = new Gson().fromJson(selectedJSON, new TypeToken>() {}.getType()); + protected List getSelected(@Untrusted InputFilterDto query) { + @Untrusted String selectedJSON = query.get("selected").orElseThrow(IllegalArgumentException::new); + @Untrusted List selected = new Gson().fromJson(selectedJSON, new TypeToken>() {}.getType()); if (selected.isEmpty()) throw new CompleteSetException(); return selected; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/OperatorsFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/OperatorsFilter.java index 75bd95db1..8c9bf6588 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/OperatorsFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/OperatorsFilter.java @@ -22,6 +22,7 @@ import com.djrapitops.plan.settings.locale.lang.FilterLang; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.filter.CompleteSetException; import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -57,8 +58,8 @@ public class OperatorsFilter extends MultiOptionFilter { } @Override - public Set getMatchingUserIds(InputFilterDto query) { - List selected = getSelected(query); + public Set getMatchingUserIds(@Untrusted InputFilterDto query) { + @Untrusted List selected = getSelected(query); Set userIds = new HashSet<>(); String[] options = getOptionsArray(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PlayedBetweenDateRangeFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PlayedBetweenDateRangeFilter.java index a6b52be96..749278e87 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PlayedBetweenDateRangeFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PlayedBetweenDateRangeFilter.java @@ -21,6 +21,7 @@ import com.djrapitops.plan.identification.ServerUUID; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.objects.ServerQueries; import com.djrapitops.plan.storage.database.queries.objects.SessionQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.google.gson.Gson; import javax.inject.Inject; @@ -47,10 +48,10 @@ public class PlayedBetweenDateRangeFilter extends DateRangeFilter { } @Override - public Set getMatchingUserIds(InputFilterDto query) { + public Set getMatchingUserIds(@Untrusted InputFilterDto query) { long after = getAfter(query); long before = getBefore(query); - List serverNames = getServerNames(query); + @Untrusted List serverNames = getServerNames(query); List serverUUIDs = serverNames.isEmpty() ? Collections.emptyList() : dbSystem.getDatabase().query(ServerQueries.fetchServersMatchingIdentifiers(serverNames)); return dbSystem.getDatabase().query(SessionQueries.userIdsOfPlayedBetween(after, before, serverUUIDs)); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PlayedOnServerFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PlayedOnServerFilter.java index a2fa2513f..6251e3b99 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PlayedOnServerFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PlayedOnServerFilter.java @@ -21,6 +21,7 @@ import com.djrapitops.plan.identification.ServerUUID; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.objects.ServerQueries; import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import javax.inject.Inject; import javax.inject.Singleton; @@ -54,8 +55,8 @@ public class PlayedOnServerFilter extends MultiOptionFilter { } @Override - public Set getMatchingUserIds(InputFilterDto query) { - List serverNames = getSelected(query); + public Set getMatchingUserIds(@Untrusted InputFilterDto query) { + @Untrusted List serverNames = getSelected(query); List serverUUIDs = serverNames.isEmpty() ? Collections.emptyList() : dbSystem.getDatabase().query(ServerQueries.fetchServersMatchingIdentifiers(serverNames)); return dbSystem.getDatabase().query(UserInfoQueries.userIdsOfRegisteredBetween(0, System.currentTimeMillis(), serverUUIDs)); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PluginBooleanGroupFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PluginBooleanGroupFilter.java index 8f157da57..fb11d463a 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PluginBooleanGroupFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PluginBooleanGroupFilter.java @@ -26,7 +26,9 @@ import com.djrapitops.plan.storage.database.queries.QueryAllStatement; import com.djrapitops.plan.storage.database.queries.QueryStatement; import com.djrapitops.plan.storage.database.queries.objects.ServerQueries; import com.djrapitops.plan.storage.database.sql.tables.*; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.Nullable; import javax.inject.Inject; import javax.inject.Singleton; @@ -81,13 +83,13 @@ public class PluginBooleanGroupFilter extends MultiOptionFilter { } private static Query> playersInGroups( - Map selected, + @Untrusted Map selected, Map namesToUUIDs ) { return db -> { Set userIds = new HashSet<>(); for (Map.Entry option : selected.entrySet()) { - PluginBooleanOption pluginBooleanOption = option.getKey(); + @Untrusted PluginBooleanOption pluginBooleanOption = option.getKey(); SelectedBoolean selectedBoolean = option.getValue(); userIds.addAll( db.query(playersInGroup( @@ -103,8 +105,12 @@ public class PluginBooleanGroupFilter extends MultiOptionFilter { } private static Query> playersInGroup( - ServerUUID serverUUID, String pluginName, String providerText, SelectedBoolean selectedBoolean + @Nullable ServerUUID serverUUID, @Untrusted String pluginName, @Untrusted String providerText, SelectedBoolean selectedBoolean ) { + if (serverUUID == null) { + return db -> Collections.emptySet(); + } + String selectUUIDsWithBooleanValues = SELECT + DISTINCT + "u." + UsersTable.ID + " as id" + FROM + ExtensionPluginTable.TABLE_NAME + " plugin" + INNER_JOIN + ExtensionProviderTable.TABLE_NAME + " provider on provider." + ExtensionProviderTable.PLUGIN_ID + "=plugin." + ExtensionPluginTable.ID + @@ -162,12 +168,12 @@ public class PluginBooleanGroupFilter extends MultiOptionFilter { } @Override - public Set getMatchingUserIds(InputFilterDto query) { - Map selectedBooleanOptions = new HashMap<>(); - for (String selected : getSelected(query)) { - String[] optionAndBoolean = StringUtils.split(selected, ":", 2); - PluginBooleanOption pluginBooleanOption = PluginBooleanOption.parse(optionAndBoolean[0].trim()); - String selectedBoolean = optionAndBoolean[1].trim().toUpperCase(); + public Set getMatchingUserIds(@Untrusted InputFilterDto query) { + @Untrusted Map selectedBooleanOptions = new HashMap<>(); + for (@Untrusted String selected : getSelected(query)) { + @Untrusted String[] optionAndBoolean = StringUtils.split(selected, ":", 2); + @Untrusted PluginBooleanOption pluginBooleanOption = PluginBooleanOption.parse(optionAndBoolean[0].trim()); + @Untrusted String selectedBoolean = optionAndBoolean[1].trim().toUpperCase(); selectedBooleanOptions.computeIfPresent(pluginBooleanOption, (key, existing) -> SelectedBoolean.BOTH); selectedBooleanOptions.computeIfAbsent(pluginBooleanOption, key -> SelectedBoolean.valueOf(selectedBoolean)); } @@ -183,6 +189,7 @@ public class PluginBooleanGroupFilter extends MultiOptionFilter { BOTH } + @Untrusted public static class PluginBooleanOption implements Comparable { private final String serverName; private final String pluginName; @@ -194,12 +201,13 @@ public class PluginBooleanGroupFilter extends MultiOptionFilter { this.providerText = providerText; } - public static PluginBooleanOption parse(String fromFormatted) { - String[] split1 = StringUtils.split(fromFormatted, ",", 2); - String[] split2 = StringUtils.split(split1[1], "-", 2); - String serverName = split1[0].trim(); - String pluginName = split2[0].trim(); - String providerName = split2[1].trim(); + @Untrusted + public static PluginBooleanOption parse(@Untrusted String fromFormatted) { + @Untrusted String[] split1 = StringUtils.split(fromFormatted, ",", 2); + @Untrusted String[] split2 = StringUtils.split(split1[1], "-", 2); + @Untrusted String serverName = split1[0].trim(); + @Untrusted String pluginName = split2[0].trim(); + @Untrusted String providerName = split2[1].trim(); return new PluginBooleanOption(serverName, pluginName, providerName); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PluginGroupsFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PluginGroupsFilter.java index ff6191fcb..b0bd413c7 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PluginGroupsFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/PluginGroupsFilter.java @@ -28,6 +28,7 @@ import com.djrapitops.plan.storage.database.sql.tables.ExtensionGroupsTable; import com.djrapitops.plan.storage.database.sql.tables.ExtensionPluginTable; import com.djrapitops.plan.storage.database.sql.tables.ExtensionProviderTable; import com.djrapitops.plan.storage.database.sql.tables.ServerTable; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.java.Maps; import javax.inject.Inject; @@ -67,7 +68,7 @@ public class PluginGroupsFilter extends MultiOptionFilter { } @Override - public Set getMatchingUserIds(InputFilterDto query) { + public Set getMatchingUserIds(@Untrusted InputFilterDto query) { return dbSystem.getDatabase().query( new ExtensionUserIdsInGroupQuery(identifier.getPluginName(), identifier.getProviderName(), identifier.getServerUUID(), getSelected(query)) ); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/RegisteredBetweenDateRangeFilter.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/RegisteredBetweenDateRangeFilter.java index 44c260e2c..063796052 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/RegisteredBetweenDateRangeFilter.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/filter/filters/RegisteredBetweenDateRangeFilter.java @@ -22,6 +22,7 @@ import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.queries.objects.BaseUserQueries; import com.djrapitops.plan.storage.database.queries.objects.ServerQueries; import com.djrapitops.plan.storage.database.queries.objects.UserInfoQueries; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.google.gson.Gson; import javax.inject.Inject; @@ -48,10 +49,10 @@ public class RegisteredBetweenDateRangeFilter extends DateRangeFilter { } @Override - public Set getMatchingUserIds(InputFilterDto query) { + public Set getMatchingUserIds(@Untrusted InputFilterDto query) { long after = getAfter(query); long before = getBefore(query); - List serverNames = getServerNames(query); + @Untrusted List serverNames = getServerNames(query); List serverUUIDs = serverNames.isEmpty() ? Collections.emptyList() : dbSystem.getDatabase().query(ServerQueries.fetchServersMatchingIdentifiers(serverNames)); return dbSystem.getDatabase().query( serverUUIDs.isEmpty() ? BaseUserQueries.userIdsOfRegisteredBetween(after, before) @@ -59,7 +60,7 @@ public class RegisteredBetweenDateRangeFilter extends DateRangeFilter { ); } - private List getServerNames(InputFilterDto query) { + private List getServerNames(@Untrusted InputFilterDto query) { return query.get("servers") .map(serversList -> new Gson().fromJson(serversList, String[].class)) .map(Arrays::asList) diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/GeoInfoQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/GeoInfoQueries.java index 9a096c492..da334b4d4 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/GeoInfoQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/GeoInfoQueries.java @@ -21,10 +21,12 @@ import com.djrapitops.plan.identification.ServerUUID; import com.djrapitops.plan.storage.database.queries.Query; import com.djrapitops.plan.storage.database.queries.QueryAllStatement; import com.djrapitops.plan.storage.database.queries.RowExtractors; +import com.djrapitops.plan.storage.database.sql.building.Sql; import com.djrapitops.plan.storage.database.sql.tables.GeoInfoTable; import com.djrapitops.plan.storage.database.sql.tables.ServerTable; import com.djrapitops.plan.storage.database.sql.tables.UserInfoTable; import com.djrapitops.plan.storage.database.sql.tables.UsersTable; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.java.Lists; import org.apache.commons.text.TextStringBuilder; @@ -166,14 +168,12 @@ public class GeoInfoQueries { return db -> db.queryList(sql, RowExtractors.getString(GeoInfoTable.GEOLOCATION)); } - public static Query> userIdsOfPlayersWithGeolocations(List selected) { + public static Query> userIdsOfPlayersWithGeolocations(@Untrusted List selected) { String sql = SELECT + "u." + UsersTable.ID + FROM + GeoInfoTable.TABLE_NAME + " g" + INNER_JOIN + UsersTable.TABLE_NAME + " u on u.id=g." + GeoInfoTable.USER_ID + WHERE + GeoInfoTable.GEOLOCATION + - " IN ('" + - new TextStringBuilder().appendWithSeparators(selected, "','") + - "')"; - return db -> db.querySet(sql, RowExtractors.getInt(UsersTable.ID)); + " IN (" + Sql.nParameters(selected.size()) + ")"; + return db -> db.querySet(sql, RowExtractors.getInt(UsersTable.ID), selected); } } \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/JoinAddressQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/JoinAddressQueries.java index 8766f0d15..f290497b6 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/JoinAddressQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/JoinAddressQueries.java @@ -26,7 +26,7 @@ import com.djrapitops.plan.storage.database.sql.building.Sql; import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable; import com.djrapitops.plan.storage.database.sql.tables.ServerTable; import com.djrapitops.plan.storage.database.sql.tables.SessionsTable; -import org.apache.commons.text.TextStringBuilder; +import com.djrapitops.plan.utilities.dev.Untrusted; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -104,12 +104,12 @@ public class JoinAddressQueries { }; } - public static Query> userIdsOfPlayersWithJoinAddresses(List joinAddresses) { + public static Query> userIdsOfPlayersWithJoinAddresses(@Untrusted List joinAddresses) { String sql = SELECT + DISTINCT + SessionsTable.USER_ID + FROM + JoinAddressTable.TABLE_NAME + " j" + INNER_JOIN + SessionsTable.TABLE_NAME + " s on s." + SessionsTable.JOIN_ADDRESS_ID + "=j." + JoinAddressTable.ID + WHERE + JoinAddressTable.JOIN_ADDRESS + " IN (" + - new TextStringBuilder().appendWithSeparators(joinAddresses.stream().map(item -> '?').iterator(), ",") + + nParameters(joinAddresses.size()) + ')'; // Don't append addresses directly, SQL injection hazard return db -> db.querySet(sql, RowExtractors.getInt(SessionsTable.USER_ID), joinAddresses.toArray()); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/ServerQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/ServerQueries.java index f5f71c50a..3dac2910b 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/ServerQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/ServerQueries.java @@ -23,6 +23,7 @@ import com.djrapitops.plan.storage.database.queries.QueryAllStatement; import com.djrapitops.plan.storage.database.queries.QueryStatement; import com.djrapitops.plan.storage.database.sql.building.Select; import com.djrapitops.plan.storage.database.sql.tables.ServerTable; +import com.djrapitops.plan.utilities.dev.Untrusted; import com.djrapitops.plan.utilities.java.Maps; import org.apache.commons.lang3.math.NumberUtils; @@ -110,7 +111,7 @@ public class ServerQueries { return fetchServerMatchingIdentifier(serverUUID.toString()); } - public static Query> fetchServerMatchingIdentifier(String identifier) { + public static Query> fetchServerMatchingIdentifier(@Untrusted String identifier) { String sql = SELECT + '*' + FROM + ServerTable.TABLE_NAME + WHERE + "(LOWER(" + ServerTable.SERVER_UUID + ") LIKE LOWER(?)" + OR + "LOWER(" + ServerTable.NAME + ") LIKE LOWER(?)" + @@ -283,7 +284,7 @@ public class ServerQueries { return db -> Maps.reverse(db.query(fetchServerNames())); } - public static Query> fetchServersMatchingIdentifiers(List serverNames) { + public static Query> fetchServersMatchingIdentifiers(@Untrusted List serverNames) { return db -> { Map nameToUUIDMap = db.query(ServerQueries.fetchServerNamesToUUIDs()); return serverNames.stream() diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java index c328b835d..fd03467b2 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/TPSQueries.java @@ -23,7 +23,7 @@ import com.djrapitops.plan.identification.ServerUUID; import com.djrapitops.plan.storage.database.queries.Query; import com.djrapitops.plan.storage.database.queries.QueryStatement; import com.djrapitops.plan.storage.database.sql.tables.ServerTable; -import com.djrapitops.plan.utilities.Benchmark; +import com.djrapitops.plan.utilities.dev.Benchmark; import com.djrapitops.plan.utilities.java.Lists; import java.sql.PreparedStatement; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/UserIdentifierQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/UserIdentifierQueries.java index 330d21345..915c99017 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/UserIdentifierQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/UserIdentifierQueries.java @@ -25,6 +25,7 @@ import com.djrapitops.plan.storage.database.sql.tables.NicknamesTable; import com.djrapitops.plan.storage.database.sql.tables.ServerTable; import com.djrapitops.plan.storage.database.sql.tables.UserInfoTable; import com.djrapitops.plan.storage.database.sql.tables.UsersTable; +import com.djrapitops.plan.utilities.dev.Untrusted; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -125,7 +126,7 @@ public class UserIdentifierQueries { * @param playerName Name of the player, case does not matter. * @return Optional: UUID if found, empty if not. */ - public static Query> fetchPlayerUUIDOf(String playerName) { + public static Query> fetchPlayerUUIDOf(@Untrusted String playerName) { String sql = Select.from(UsersTable.TABLE_NAME, UsersTable.USER_UUID) .where("UPPER(" + UsersTable.USER_NAME + ")=UPPER(?)") .toString(); @@ -172,7 +173,7 @@ public class UserIdentifierQueries { }; } - public static Query> fetchMatchingPlayerNames(String searchFor) { + public static Query> fetchMatchingPlayerNames(@Untrusted String searchFor) { String sql = SELECT + DISTINCT + UsersTable.USER_NAME + FROM + UsersTable.TABLE_NAME + WHERE + "LOWER(" + UsersTable.USER_NAME + ") LIKE LOWER(?)" + diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/WebUserQueries.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/WebUserQueries.java index 307101d27..17c087b3a 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/WebUserQueries.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/queries/objects/WebUserQueries.java @@ -22,6 +22,7 @@ import com.djrapitops.plan.storage.database.queries.Query; import com.djrapitops.plan.storage.database.sql.tables.CookieTable; import com.djrapitops.plan.storage.database.sql.tables.SecurityTable; import com.djrapitops.plan.storage.database.sql.tables.UsersTable; +import com.djrapitops.plan.utilities.dev.Untrusted; import java.sql.ResultSet; import java.sql.SQLException; @@ -43,7 +44,7 @@ public class WebUserQueries { /* Static method class */ } - public static Query> fetchUser(String username) { + public static Query> fetchUser(@Untrusted String username) { String sql = SELECT + '*' + FROM + SecurityTable.TABLE_NAME + LEFT_JOIN + UsersTable.TABLE_NAME + " on " + SecurityTable.LINKED_TO + "=" + UsersTable.USER_UUID + WHERE + SecurityTable.USERNAME + "=?" + LIMIT + "1"; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/transactions/events/CookieChangeTransaction.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/transactions/events/CookieChangeTransaction.java index db8cd309c..1b773ad43 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/transactions/events/CookieChangeTransaction.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/transactions/events/CookieChangeTransaction.java @@ -19,6 +19,7 @@ package com.djrapitops.plan.storage.database.transactions.events; import com.djrapitops.plan.storage.database.sql.tables.CookieTable; import com.djrapitops.plan.storage.database.transactions.ExecStatement; import com.djrapitops.plan.storage.database.transactions.Transaction; +import com.djrapitops.plan.utilities.dev.Untrusted; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -26,10 +27,11 @@ import java.sql.SQLException; public class CookieChangeTransaction extends Transaction { private final String username; + @Untrusted private final String cookie; // Null if removing private final Long expires; - private CookieChangeTransaction(String username, String cookie, Long expires) { + private CookieChangeTransaction(String username, @Untrusted String cookie, Long expires) { this.username = username; this.cookie = cookie; this.expires = expires; @@ -43,7 +45,7 @@ public class CookieChangeTransaction extends Transaction { return new CookieChangeTransaction(username, null, null); } - public static CookieChangeTransaction removeCookie(String cookie) { + public static CookieChangeTransaction removeCookie(@Untrusted String cookie) { return new CookieChangeTransaction(null, cookie, null); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/transactions/events/StoreJoinAddressTransaction.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/transactions/events/StoreJoinAddressTransaction.java index be9b537bf..891358e04 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/database/transactions/events/StoreJoinAddressTransaction.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/database/transactions/events/StoreJoinAddressTransaction.java @@ -22,6 +22,7 @@ import com.djrapitops.plan.storage.database.queries.Query; import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable; import com.djrapitops.plan.storage.database.transactions.ExecStatement; import com.djrapitops.plan.storage.database.transactions.Transaction; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.apache.commons.lang3.StringUtils; import java.sql.PreparedStatement; @@ -33,10 +34,11 @@ import static com.djrapitops.plan.storage.database.sql.building.Sql.*; public class StoreJoinAddressTransaction extends Transaction { + @Untrusted private final Supplier joinAddress; private int newId; - public StoreJoinAddressTransaction(String joinAddress) { + public StoreJoinAddressTransaction(@Untrusted String joinAddress) { this(() -> joinAddress); } @@ -56,12 +58,13 @@ public class StoreJoinAddressTransaction extends Transaction { return new HasMoreThanZeroQueryStatement(sql) { @Override public void prepare(PreparedStatement statement) throws SQLException { - String address = getAddress(); + @Untrusted String address = getAddress(); statement.setString(1, address); } }; } + @Untrusted private String getAddress() { return StringUtils.truncate(joinAddress.get(), JoinAddressTable.JOIN_ADDRESS_MAX_LENGTH); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/file/PlanFiles.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/file/PlanFiles.java index 1e0f3f80f..a3ce8185f 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/file/PlanFiles.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/file/PlanFiles.java @@ -20,6 +20,7 @@ import com.djrapitops.plan.SubSystem; import com.djrapitops.plan.exceptions.EnableException; import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.settings.config.paths.CustomizedFileSettings; +import com.djrapitops.plan.utilities.dev.Untrusted; import dagger.Lazy; import javax.inject.Inject; @@ -90,7 +91,7 @@ public class PlanFiles implements SubSystem { return getFileFromPluginFolder("locale.yml"); } - public File getFileFromPluginFolder(String name) { + public File getFileFromPluginFolder(@Untrusted String name) { return new File(dataFolder, name.replace("/", File.separator)); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java index 1d9e0062c..7b3d9ae30 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/PassEncryptUtil.java @@ -17,6 +17,7 @@ package com.djrapitops.plan.utilities; import com.djrapitops.plan.exceptions.PassEncryptException; +import com.djrapitops.plan.utilities.dev.Untrusted; import org.apache.commons.lang3.StringUtils; import javax.crypto.SecretKeyFactory; @@ -62,7 +63,7 @@ public class PassEncryptUtil { * @return Hash + salt * @throws CannotPerformOperationException If the hash creation fails */ - public static String createHash(String password) { + public static String createHash(@Untrusted String password) { return createHash(password.toCharArray()); } @@ -93,7 +94,7 @@ public class PassEncryptUtil { * @throws CannotPerformOperationException If hashing fails * @throws InvalidHashException If the hash is missing details. */ - public static boolean verifyPassword(String password, String correctHash) { + public static boolean verifyPassword(@Untrusted String password, String correctHash) { return verifyPassword(password.toCharArray(), correctHash); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/Benchmark.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/dev/Benchmark.java similarity index 98% rename from Plan/common/src/main/java/com/djrapitops/plan/utilities/Benchmark.java rename to Plan/common/src/main/java/com/djrapitops/plan/utilities/dev/Benchmark.java index ee67545e1..eaa1a0599 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/Benchmark.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/dev/Benchmark.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with Plan. If not, see . */ -package com.djrapitops.plan.utilities; +package com.djrapitops.plan.utilities.dev; import com.djrapitops.plan.delivery.formatting.Formatter; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/dev/Untrusted.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/dev/Untrusted.java new file mode 100644 index 000000000..922b0f779 --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/dev/Untrusted.java @@ -0,0 +1,31 @@ +/* + * This file is part of Player Analytics (Plan). + * + * Plan is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License v3 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Plan is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Plan. If not, see . + */ +package com.djrapitops.plan.utilities.dev; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for identifying untrusted data that has not been sanitized. + * + * @author AuroraLS3 + */ +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD, ElementType.LOCAL_VARIABLE, ElementType.TYPE_PARAMETER, ElementType.TYPE_USE, ElementType.CONSTRUCTOR, ElementType.TYPE}) +public @interface Untrusted {}