From f1b1de441f47c5b61970b0d32abaef7256121b4f Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Mon, 22 Jun 2026 12:17:34 +0200 Subject: [PATCH 1/2] Improve profile update asset validation --- .../Endpoints/UserEndpoints.cs | 115 +++++++++++++----- 1 file changed, 82 insertions(+), 33 deletions(-) diff --git a/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs b/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs index 3a2dc2b3..23315e1e 100644 --- a/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs +++ b/Refresh.Interfaces.Game/Endpoints/UserEndpoints.cs @@ -2,16 +2,21 @@ using Bunkum.Core; using Bunkum.Core.Endpoints; using Bunkum.Core.RateLimit; +using Bunkum.Core.Responses; using Bunkum.Core.Storage; using Bunkum.Listener.Protocol; using Bunkum.Protocols.Http; using Refresh.Common.Constants; using Refresh.Core.Authentication.Permission; using Refresh.Core.Configuration; +using Refresh.Core.Helpers; +using Refresh.Core.Importing; using Refresh.Core.RateLimits.Users; using Refresh.Core.Services; +using Refresh.Core.Types.Assets.Validation; using Refresh.Core.Types.Data; using Refresh.Database; +using Refresh.Database.Models.Assets; using Refresh.Database.Models.Authentication; using Refresh.Database.Models.Users; using Refresh.Interfaces.Game.Endpoints.DataTypes.Response; @@ -73,7 +78,8 @@ public SerializedFriendsList GetFriends(RequestContext context, GameDatabaseCont [NullStatusCode(BadRequest)] [RateLimitSettings(UserModificationEndpointLimits.TimeoutDuration, UserModificationEndpointLimits.GameRequestAmount, UserModificationEndpointLimits.BlockDuration, UserModificationEndpointLimits.GameRequestBucket)] - public string? UpdateUser(RequestContext context, DataContext dataContext, GameUser user, string body, GuidCheckerService guidChecker) + public Response UpdateUser(RequestContext context, DataContext dataContext, GameUser user, string body, GuidCheckerService guidChecker, + AssetImporter importer, AipiService aipi) { SerializedUpdateData? data = null; @@ -83,7 +89,7 @@ public SerializedFriendsList GetFriends(RequestContext context, GameDatabaseCont { XmlSerializer profileSerializer = new(typeof(SerializedUpdateDataProfile)); if (profileSerializer.Deserialize(new StringReader(body)) is not SerializedUpdateDataProfile profileData) - return null; + return BadRequest; data ??= profileData; } @@ -96,7 +102,7 @@ public SerializedFriendsList GetFriends(RequestContext context, GameDatabaseCont { XmlSerializer planetSerializer = new(typeof(SerializedUpdateDataPlanets)); if (planetSerializer.Deserialize(new StringReader(body)) is not SerializedUpdateDataPlanets planetsData) - return null; + return BadRequest; data ??= planetsData; } @@ -108,47 +114,85 @@ public SerializedFriendsList GetFriends(RequestContext context, GameDatabaseCont if (data == null) { dataContext.Database.AddErrorNotification("Profile update failed", "Your profile failed to update because the data could not be read.", user); - return null; + return BadRequest; } if (data.IconHash != null) { - //If the icon is a GUID - if (data.IconHash.StartsWith('g')) - { - //Parse out the GUID - long guid = long.Parse(data.IconHash.AsSpan()[1..]); - - //If its not a valid GUID, block the request - if (data.IconHash.StartsWith('g') && !guidChecker.IsTextureGuid(dataContext.Game, guid)) - { - dataContext.Database.AddErrorNotification("Profile update failed", "Your avatar failed to update because the asset was an invalid GUID.", user); - return null; - } - } - else if (data.IconHash.IsBlankHash()) + ValidatedAssetResult iconResult = ResourceValidationHelper.ValidateReference(new(data.IconHash, dataContext, importer, aipi) { - // 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)) + MustBeTexture = true, + AssetContextTypeStr = "avatar", + }, context.Logger); + data.IconHash = iconResult.NewAssetRef; + + if (iconResult.Status != OK) { - //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); - return null; + if (iconResult.ErrorMessage != null) dataContext.Database.AddErrorNotification("Profile update failed", iconResult.ErrorMessage, user); + return iconResult.Status; } } - if (data.LevelLocations != null && data.LevelLocations.Count > 0) + AssetValidationParameters faceParams = new(null!, dataContext, importer, aipi) { - dataContext.Database.UpdateLevelLocations(data.LevelLocations, user); + MayBeBlank = false, + MayBeGuid = false, + MustBeTexture = true, + AssetContextTypeStr = "image", + }; + + if (data.YayFaceHash != null) + { + faceParams.AssetRef = data.YayFaceHash; + ValidatedAssetResult yayResult = ResourceValidationHelper.ValidateReference(faceParams, context.Logger); + data.YayFaceHash = yayResult.NewAssetRef; + + if (yayResult.Status != OK) return yayResult.Status; // no need to notify, these are always updated in the background } - - if (!string.IsNullOrEmpty(data.PlanetsHash) && data.PlanetsHash != "0" /* Empty planets */ && !dataContext.DataStore.ExistsInStore(data.PlanetsHash)) + + if (data.MehFaceHash != null) { - dataContext.Database.AddErrorNotification("Profile update failed", "Your planets failed to update because the asset was missing on the server.", user); - return null; + faceParams.AssetRef = data.MehFaceHash; + ValidatedAssetResult mehResult = ResourceValidationHelper.ValidateReference(faceParams, context.Logger); + data.MehFaceHash = mehResult.NewAssetRef; + + if (mehResult.Status != OK) return mehResult.Status; + } + + if (data.BooFaceHash != null) + { + faceParams.AssetRef = data.BooFaceHash; + ValidatedAssetResult booResult = ResourceValidationHelper.ValidateReference(faceParams, context.Logger); + data.BooFaceHash = booResult.NewAssetRef; + + if (booResult.Status != OK) return booResult.Status; + } + + if (data.PlanetsHash != null) + { + // Some LBP2 alpha builds like to insert newlines here + data.PlanetsHash = data.PlanetsHash.Replace("\n", ""); + + ValidatedAssetResult planetResult = ResourceValidationHelper.ValidateReference(new(data.PlanetsHash, dataContext, importer) + { + // blank = reset planets, but GUIDs should never happen + MayBeGuid = false, + AssetContextTypeStr = "planet asset", + OnNewAssetRefCallback = delegate(string newRef) { data.PlanetsHash = newRef; } + }, context.Logger); + data.PlanetsHash = planetResult.NewAssetRef; + + if (planetResult.Status != OK) + { + if (planetResult.ErrorMessage != null) dataContext.Database.AddErrorNotification("Planet update failed", planetResult.ErrorMessage, user); + return planetResult.Status; + } + // TODO also read contents and ensure the asset actually contains an earth and a moon + else if (planetResult.AssetInfo != null && planetResult.AssetInfo.AssetType != GameAssetType.Level) + { + if (planetResult.ErrorMessage != null) dataContext.Database.AddErrorNotification("Planet update failed", "The asset was badly formatted.", user); + return BadRequest; + } } // Trim description @@ -157,8 +201,13 @@ public SerializedFriendsList GetFriends(RequestContext context, GameDatabaseCont data.Description = data.Description[..UgcLimits.DescriptionLimit]; } + if (data.LevelLocations != null && data.LevelLocations.Count > 0) + { + dataContext.Database.UpdateLevelLocations(data.LevelLocations, user); + } + dataContext.Database.UpdateUserData(user, data, dataContext.Game); - return string.Empty; + return OK; } private const int PinTimeoutDuration = 480; From bde00d732a3d4a26688e20d7dc1fc444ff6f2f87 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Mon, 22 Jun 2026 12:41:17 +0200 Subject: [PATCH 2/2] Test planet/profile updating --- .../Tests/Planets/PlanetUploadTests.cs | 168 +++++++++++++ .../Tests/Users/UserActionTests.cs | 221 ++++++++++++++++-- 2 files changed, 371 insertions(+), 18 deletions(-) create mode 100644 RefreshTests.GameServer/Tests/Planets/PlanetUploadTests.cs diff --git a/RefreshTests.GameServer/Tests/Planets/PlanetUploadTests.cs b/RefreshTests.GameServer/Tests/Planets/PlanetUploadTests.cs new file mode 100644 index 00000000..eded1786 --- /dev/null +++ b/RefreshTests.GameServer/Tests/Planets/PlanetUploadTests.cs @@ -0,0 +1,168 @@ +using System.Security.Cryptography; +using Refresh.Database.Models.Assets; +using Refresh.Database.Models.Authentication; +using Refresh.Database.Models.Users; +using Refresh.Interfaces.Game.Types.UserData; +using RefreshTests.GameServer.Extensions; + +namespace RefreshTests.GameServer.Tests.Planets; + +public class PlanetUploadTests : GameServerTest +{ + [Test] + public void RejectPlanetsIfGuid() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + SerializedUpdateDataProfile request = new() + { + PlanetsHash = "g34567", + }; + + HttpResponseMessage message = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(message.StatusCode, Is.EqualTo(BadRequest)); + } + + [Test] + public void AllowBlankPlanets() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + SerializedUpdateDataProfile request = new() + { + PlanetsHash = "0", + }; + + HttpResponseMessage message = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(message.StatusCode, Is.EqualTo(OK)); + } + + [Test] + public void AllowHashedPlanets() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + ReadOnlySpan data = "LVLb"u8; + string hash = BitConverter.ToString(SHA1.HashData(data)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(hash, data); + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + SerializedUpdateDataProfile request = new() + { + PlanetsHash = hash, + }; + + HttpResponseMessage message = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(message.StatusCode, Is.EqualTo(OK)); + } + + [Test] + public void AllowHashedPlanetsWithNewline() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + ReadOnlySpan data = "LVLb"u8; + string hash = BitConverter.ToString(SHA1.HashData(data)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(hash, data); + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + SerializedUpdateDataProfile request = new() + { + PlanetsHash = hash + "\n", + }; + + HttpResponseMessage message = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(message.StatusCode, Is.EqualTo(OK)); + } + + [Test] + public void RejectPlanetsIfWrongResourceType() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + ReadOnlySpan data = "PLNb"u8; + string hash = BitConverter.ToString(SHA1.HashData(data)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(hash, data); + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + SerializedUpdateDataProfile request = new() + { + PlanetsHash = hash, + }; + + HttpResponseMessage message = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(message.StatusCode, Is.EqualTo(BadRequest)); + } + + [Test] + public void RejectPlanetsIfNotUploaded() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + ReadOnlySpan data = "LVLb"u8; + string hash = BitConverter.ToString(SHA1.HashData(data)).Replace("-", "").ToLower(); + // Don't upload the asset + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + SerializedUpdateDataProfile request = new() + { + PlanetsHash = hash, + }; + + HttpResponseMessage message = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(message.StatusCode, Is.EqualTo(NotFound)); + } + + [Test] + public void RejectPlanetsIfDisallowed() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + ReadOnlySpan data = "LVLb"u8; + string hash = BitConverter.ToString(SHA1.HashData(data)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(hash, data); + context.Database.DisallowAsset(hash, GameAssetType.Level, "garbage music"); + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + SerializedUpdateDataProfile request = new() + { + PlanetsHash = hash, + }; + + HttpResponseMessage message = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(message.StatusCode, Is.EqualTo(Unauthorized)); + } + + [Test] + public void RejectPlanetsIfInvalidHash() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + SerializedUpdateDataProfile request = new() + { + PlanetsHash = "adserdtfgzhgj", + }; + + HttpResponseMessage message = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(message.StatusCode, Is.EqualTo(BadRequest)); + } +} \ No newline at end of file diff --git a/RefreshTests.GameServer/Tests/Users/UserActionTests.cs b/RefreshTests.GameServer/Tests/Users/UserActionTests.cs index 22a9d6d7..ce2f38e2 100644 --- a/RefreshTests.GameServer/Tests/Users/UserActionTests.cs +++ b/RefreshTests.GameServer/Tests/Users/UserActionTests.cs @@ -1,7 +1,9 @@ -using Refresh.Common.Constants; +using System.Net; +using System.Security.Cryptography; +using Refresh.Common.Constants; +using Refresh.Database.Models.Assets; using Refresh.Database.Models.Authentication; using Refresh.Database.Models.Users; -using Refresh.Interfaces.APIv3.Endpoints.DataTypes.Request; using Refresh.Interfaces.Game.Types.UserData; using RefreshTests.GameServer.Extensions; @@ -49,39 +51,222 @@ public void UserDescriptionGetsTrimmed() } [Test] - [TestCase("")] - [TestCase("0")] - public void CanResetOwnIcon(string newIcon) + public void CanSetAndResetOwnIcon() { using TestContext context = this.GetServer(); GameUser user = context.CreateUser(); using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, user); - // Prepare by setting icon to something - string fakeIcon = "mmmmm"; - context.Database.UpdateUserData(user, new ApiUpdateUserRequest() - { - IconHash = fakeIcon - }); - GameUser? userPrepared = context.Database.GetUserByObjectId(user.UserId); - Assert.That(userPrepared, Is.Not.Null); - Assert.That(userPrepared!.IconHash, Is.EqualTo(fakeIcon)); - - // Now try resetting + // Set to GUID (star sticker here) SerializedUpdateDataPlanets request = new() { - IconHash = newIcon + IconHash = "g18451" }; HttpResponseMessage response = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(response.StatusCode, Is.EqualTo(OK)); + + context.Database.Refresh(); + GameUser? userUpdated = context.Database.GetUserByObjectId(user.UserId); + Assert.That(userUpdated, Is.Not.Null); + Assert.That(userUpdated!.IconHash, Is.EqualTo("g18451")); + + // Set to hash + ReadOnlySpan data = "TEX "u8; + string hash = BitConverter.ToString(SHA1.HashData(data)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(hash, data); + + request.IconHash = hash; + response = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; Assert.That(response, Is.Not.Null); context.Database.Refresh(); + userUpdated = context.Database.GetUserByObjectId(user.UserId); + Assert.That(userUpdated, Is.Not.Null); + Assert.That(userUpdated!.IconHash, Is.EqualTo(hash)); - GameUser? userUpdated = context.Database.GetUserByObjectId(user.UserId); + // Now reset + request.IconHash = ""; + response = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(response, Is.Not.Null); + + context.Database.Refresh(); + userUpdated = context.Database.GetUserByObjectId(user.UserId); Assert.That(userUpdated, Is.Not.Null); Assert.That(userUpdated!.IconHash, Is.EqualTo("0")); } + [Test] + public void RejectIconIfMissing() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + ReadOnlySpan data = "TEX "u8; + string hash = BitConverter.ToString(SHA1.HashData(data)).Replace("-", "").ToLower(); + // Don't upload asset + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + SerializedUpdateDataPlanets request = new() + { + IconHash = hash + }; + HttpResponseMessage response = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(response.StatusCode, Is.EqualTo(NotFound)); + } + + [Test] + public void RejectIconIfInvalidGuid() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + SerializedUpdateDataPlanets request = new() + { + IconHash = "g1087", + }; + HttpResponseMessage response = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(response.StatusCode, Is.EqualTo(BadRequest)); + } + + [Test] + public void RejectDisallowedIcon() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + ReadOnlySpan data = "TEX "u8; + string hash = BitConverter.ToString(SHA1.HashData(data)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(hash, data); + context.Database.DisallowAsset(hash, GameAssetType.Texture, "ugly"); + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + SerializedUpdateDataPlanets request = new() + { + IconHash = hash, + }; + HttpResponseMessage response = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(response.StatusCode, Is.EqualTo(Unauthorized)); + } + + [Test] + public void AcceptValidFaceIcons() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + + ReadOnlySpan yayData = "TEX yay"u8; + string yayHash = BitConverter.ToString(SHA1.HashData(yayData)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(yayHash, yayData); + + ReadOnlySpan mehData = "TEX meh"u8; + string mehHash = BitConverter.ToString(SHA1.HashData(mehData)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(mehHash, mehData); + + ReadOnlySpan booData = "TEX boo"u8; + string booHash = BitConverter.ToString(SHA1.HashData(booData)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(booHash, booData); + + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + // update all of them + SerializedUpdateDataPlanets request = new() + { + YayFaceHash = yayHash, + MehFaceHash = mehHash, + BooFaceHash = booHash, + }; + HttpResponseMessage response = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(response.StatusCode, Is.EqualTo(OK)); + } + + private void TryUpdateProfileWithInvalidFaceIcon(TestContext context, HttpClient client, string invalidHash, HttpStatusCode expectedStatus) + { + ReadOnlySpan yayData = "TEX yay"u8; + string yayHash = BitConverter.ToString(SHA1.HashData(yayData)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(yayHash, yayData); + + ReadOnlySpan mehData = "TEX meh"u8; + string mehHash = BitConverter.ToString(SHA1.HashData(mehData)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(mehHash, mehData); + + ReadOnlySpan booData = "TEX boo"u8; + string booHash = BitConverter.ToString(SHA1.HashData(booData)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(booHash, booData); + + // bad yay icon + SerializedUpdateDataPlanets request = new() + { + YayFaceHash = invalidHash, + MehFaceHash = mehHash, + BooFaceHash = booHash, + }; + + HttpResponseMessage response = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(response.StatusCode, Is.EqualTo(expectedStatus)); + + // bad meh icon + request.YayFaceHash = yayHash; + request.MehFaceHash = invalidHash; + + response = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(response.StatusCode, Is.EqualTo(expectedStatus)); + + // bad boo icon + request.MehFaceHash = mehHash; + request.BooFaceHash = invalidHash; + + response = client.PostAsync($"/lbp/updateUser", new StringContent(request.AsXML())).Result; + Assert.That(response.StatusCode, Is.EqualTo(expectedStatus)); + } + + [Test] + [TestCase("0")] + [TestCase("")] + [TestCase("g18451")] // star sticker texture + [TestCase("g1087")] // sackboy model + [TestCase("INVALID HASH!!!")] + public void RejectFaceIconIfNotHash(string assetRef) + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + this.TryUpdateProfileWithInvalidFaceIcon(context, client, assetRef, BadRequest); + } + + [Test] + public void RejectFaceIconIfMissing() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + ReadOnlySpan badData = "TEX reject"u8; + string badHash = BitConverter.ToString(SHA1.HashData(badData)).Replace("-", "").ToLower(); + // Don't upload asset + + this.TryUpdateProfileWithInvalidFaceIcon(context, client, badHash, NotFound); + } + + [Test] + public void RejectFaceIconIfDisallowed() + { + using TestContext context = this.GetServer(); + GameUser user = context.CreateUser(); + using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, TokenGame.LittleBigPlanet3, TokenPlatform.PS3, user); + + ReadOnlySpan badData = "TEX d"u8; + string badHash = BitConverter.ToString(SHA1.HashData(badData)).Replace("-", "").ToLower(); + context.GetDataStore().WriteToStore(badHash, badData); + context.Database.DisallowAsset(badHash, GameAssetType.Texture, ""); + + this.TryUpdateProfileWithInvalidFaceIcon(context, client, badHash, Unauthorized); + } + [Test] public void DeletingUserDoesNotDisallowEmail() {