From 933426638dc15bac58085e385d185be34d4f5396 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Fri, 26 Dec 2025 22:16:39 +0100 Subject: [PATCH 1/3] Allow resetting own avatar --- Refresh.Common/Extensions/StringExtensions.cs | 9 +++++++++ Refresh.Interfaces.APIv3/Endpoints/UserApiEndpoints.cs | 6 +++--- Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs | 9 +++------ 3 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 Refresh.Common/Extensions/StringExtensions.cs diff --git a/Refresh.Common/Extensions/StringExtensions.cs b/Refresh.Common/Extensions/StringExtensions.cs new file mode 100644 index 00000000..4773aa54 --- /dev/null +++ b/Refresh.Common/Extensions/StringExtensions.cs @@ -0,0 +1,9 @@ +namespace Refresh.Common.Extensions; + +public static class StringExtensions +{ + public static bool IsHashBlank(this string? hash) + { + return string.IsNullOrWhiteSpace(hash) || hash == "0"; + } +} \ No newline at end of file diff --git a/Refresh.Interfaces.APIv3/Endpoints/UserApiEndpoints.cs b/Refresh.Interfaces.APIv3/Endpoints/UserApiEndpoints.cs index f13fe7a2..55b136c5 100644 --- a/Refresh.Interfaces.APIv3/Endpoints/UserApiEndpoints.cs +++ b/Refresh.Interfaces.APIv3/Endpoints/UserApiEndpoints.cs @@ -62,13 +62,13 @@ public ApiResponse UpdateUser(RequestContext contex GameUser user, ApiUpdateUserRequest body, IDataStore dataStore, DataContext dataContext, IntegrationConfig integrationConfig, SmtpService smtpService) { - if (body.IconHash != null && database.GetAssetFromHash(body.IconHash) == null) + if (body.IconHash != null && !body.IconHash.IsHashBlank() && database.GetAssetFromHash(body.IconHash) == null) return ApiNotFoundError.Instance; - if (body.VitaIconHash != null && database.GetAssetFromHash(body.VitaIconHash) == null) + if (body.VitaIconHash != null && !body.VitaIconHash.IsHashBlank() && database.GetAssetFromHash(body.VitaIconHash) == null) return ApiNotFoundError.Instance; - if (body.BetaIconHash != null && database.GetAssetFromHash(body.BetaIconHash) == null) + if (body.BetaIconHash != null && !body.BetaIconHash.IsHashBlank() && database.GetAssetFromHash(body.BetaIconHash) == null) return ApiNotFoundError.Instance; if (body.EmailAddress != null && !smtpService.CheckEmailDomainValidity(body.EmailAddress)) diff --git a/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs b/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs index a679dd19..8f2d516b 100644 --- a/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs +++ b/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs @@ -115,14 +115,11 @@ public SerializedFriendsList GetFriends(RequestContext context, GameDatabaseCont return null; } } - else + else if (!data.IconHash.IsHashBlank() && !dataContext.DataStore.ExistsInStore(data.IconHash)) { //If the asset does not exist on the server, block the request - if (!dataContext.DataStore.ExistsInStore(data.IconHash)) - { - dataContext.Database.AddErrorNotification("Profile update failed", "Your avatar failed to update because the asset was missing on the server.", user); - return null; - } + dataContext.Database.AddErrorNotification("Profile update failed", "Your avatar failed to update because the asset was missing on the server.", user); + return null; } } From 36df973655cb432b3159e0283c9d46000bd1d6e9 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 27 Dec 2025 12:55:46 +0100 Subject: [PATCH 2/3] Fix bad method naming, force blank avatars to have a specific value --- Refresh.Common/Extensions/StringExtensions.cs | 2 +- .../Endpoints/UserApiEndpoints.cs | 45 +++++++++++++++---- .../Endpoints/UserEndpoints.cs | 8 +++- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/Refresh.Common/Extensions/StringExtensions.cs b/Refresh.Common/Extensions/StringExtensions.cs index 4773aa54..0e93ed44 100644 --- a/Refresh.Common/Extensions/StringExtensions.cs +++ b/Refresh.Common/Extensions/StringExtensions.cs @@ -2,7 +2,7 @@ namespace Refresh.Common.Extensions; public static class StringExtensions { - public static bool IsHashBlank(this string? hash) + public static bool IsBlankHash(this string? hash) { return string.IsNullOrWhiteSpace(hash) || hash == "0"; } diff --git a/Refresh.Interfaces.APIv3/Endpoints/UserApiEndpoints.cs b/Refresh.Interfaces.APIv3/Endpoints/UserApiEndpoints.cs index 55b136c5..fd930258 100644 --- a/Refresh.Interfaces.APIv3/Endpoints/UserApiEndpoints.cs +++ b/Refresh.Interfaces.APIv3/Endpoints/UserApiEndpoints.cs @@ -62,14 +62,43 @@ public ApiResponse UpdateUser(RequestContext contex GameUser user, ApiUpdateUserRequest body, IDataStore dataStore, DataContext dataContext, IntegrationConfig integrationConfig, SmtpService smtpService) { - if (body.IconHash != null && !body.IconHash.IsHashBlank() && database.GetAssetFromHash(body.IconHash) == null) - return ApiNotFoundError.Instance; - - if (body.VitaIconHash != null && !body.VitaIconHash.IsHashBlank() && database.GetAssetFromHash(body.VitaIconHash) == null) - return ApiNotFoundError.Instance; - - if (body.BetaIconHash != null && !body.BetaIconHash.IsHashBlank() && database.GetAssetFromHash(body.BetaIconHash) == null) - return ApiNotFoundError.Instance; + // If any icon is requested to be reset, force its hash to be a specific value, + // to not allow uncontrolled values which would still count as blank/empty hash (e.g. unlimited whitespaces) + if (body.IconHash != null) + { + if (body.IconHash.IsBlankHash()) + { + body.IconHash = "0"; + } + else if (database.GetAssetFromHash(body.IconHash) == null) + { + return ApiNotFoundError.Instance; + } + } + + if (body.VitaIconHash != null) + { + if (body.VitaIconHash.IsBlankHash()) + { + body.VitaIconHash = "0"; + } + else if (database.GetAssetFromHash(body.VitaIconHash) == null) + { + return ApiNotFoundError.Instance; + } + } + + if (body.BetaIconHash != null) + { + if (body.BetaIconHash.IsBlankHash()) + { + body.BetaIconHash = "0"; + } + else if (database.GetAssetFromHash(body.BetaIconHash) == null) + { + return ApiNotFoundError.Instance; + } + } if (body.EmailAddress != null && !smtpService.CheckEmailDomainValidity(body.EmailAddress)) return ApiValidationError.EmailDoesNotActuallyExistError; diff --git a/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs b/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs index 8f2d516b..89af490f 100644 --- a/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs +++ b/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs @@ -115,7 +115,13 @@ public SerializedFriendsList GetFriends(RequestContext context, GameDatabaseCont return null; } } - else if (!data.IconHash.IsHashBlank() && !dataContext.DataStore.ExistsInStore(data.IconHash)) + else if (data.IconHash.IsBlankHash()) + { + // Force hash to be a specific value if the icon is supposed to be reset/default to a PSN avatar, + // to not allow uncontrolled values which would still count as blank/empty hash (e.g. unlimited whitespaces) + data.IconHash = "0"; + } + else if (!dataContext.DataStore.ExistsInStore(data.IconHash)) { //If the asset does not exist on the server, block the request dataContext.Database.AddErrorNotification("Profile update failed", "Your avatar failed to update because the asset was missing on the server.", user); From 1dfc46040d4f3934299a7df70239c51de8b6581f Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 27 Dec 2025 12:56:40 +0100 Subject: [PATCH 3/3] Don't look up asset in database if hash is empty --- Refresh.Database/GameDatabaseContext.Assets.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Refresh.Database/GameDatabaseContext.Assets.cs b/Refresh.Database/GameDatabaseContext.Assets.cs index 2e548c3c..a208e34b 100644 --- a/Refresh.Database/GameDatabaseContext.Assets.cs +++ b/Refresh.Database/GameDatabaseContext.Assets.cs @@ -10,7 +10,7 @@ public partial class GameDatabaseContext // Assets public GameAsset? GetAssetFromHash(string hash) { - if (hash == "0" || hash.StartsWith('g')) return null; + if (hash.IsBlankHash() || hash.StartsWith('g')) return null; return this.GameAssetsIncluded .FirstOrDefault(a => a.AssetHash == hash);