Skip to content

Commit

Permalink
Allow new 'trusted' users to upload assets during read-only mode (#392)
Browse files Browse the repository at this point in the history
We haven't heard back from the NCMEC yet, so here's a band-aid solution
to let people upload things for the time being.

Requires a change to add the new role in refresh-web.
  • Loading branch information
jvyden authored Apr 6, 2024
2 parents 6e32464 + 930dae3 commit 5c2249d
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 4 deletions.
3 changes: 3 additions & 0 deletions Refresh.GameServer/Configuration/GameServerConfig.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using Bunkum.Core.Configuration;
using Refresh.GameServer.Types.Assets;
using Refresh.GameServer.Types.Roles;

namespace Refresh.GameServer.Configuration;

Expand All @@ -27,6 +28,8 @@ protected override void Migrate(int oldVer, dynamic oldConfig) {}
public string WebExternalUrl { get; set; } = "https://refresh.example.com";
public bool AllowInvalidTextureGuids { get; set; } = false;
public bool BlockAssetUploads { get; set; } = false;
/// <seealso cref="GameUserRole.Trusted"/>
public bool BlockAssetUploadsForTrustedUsers { get; set; } = false;
/// <summary>
/// The amount of data the user is allowed to upload before all resource uploads get blocked, defaults to 100mb.
/// </summary>
Expand Down
10 changes: 8 additions & 2 deletions Refresh.GameServer/Endpoints/ApiV3/ResourceApiEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,15 @@ public ApiResponse<ApiGameAssetResponse> UploadImageAsset(RequestContext context
[DocSummary("The SHA1 hash of the asset")] string hash,
byte[] body, GameUser user)
{
//If we block asset uploads, return unauthorized, unless the user is an admin
// If we're blocking asset uploads, throw unless the user is an admin.
// We also have the ability to block asset uploads for trusted users (when they would normally bypass this)
if (config.BlockAssetUploads && user.Role != GameUserRole.Admin)
return ApiAuthenticationError.NoPermissionsForCreation;
{
if (user.Role < GameUserRole.Trusted || config.BlockAssetUploadsForTrustedUsers)
{
return ApiAuthenticationError.NoPermissionsForCreation;
}
}

if (!CommonPatterns.Sha1Regex().IsMatch(hash)) return ApiValidationError.HashInvalidError;

Expand Down
10 changes: 8 additions & 2 deletions Refresh.GameServer/Endpoints/Game/ResourceEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ public class ResourceEndpoints : EndpointGroup
public Response UploadAsset(RequestContext context, string hash, string type, byte[] body, IDataStore dataStore,
GameDatabaseContext database, GameUser user, AssetImporter importer, GameServerConfig config, IDateTimeProvider timeProvider, Token token)
{
//If we block asset uploads, return unauthorized, unless the user is an admin
// If we're blocking asset uploads, throw unless the user is an admin.
// We also have the ability to block asset uploads for trusted users (when they would normally bypass this)
if (config.BlockAssetUploads && user.Role != GameUserRole.Admin)
return Unauthorized;
{
if (user.Role < GameUserRole.Trusted || config.BlockAssetUploadsForTrustedUsers)
{
return Unauthorized;
}
}

if (!CommonPatterns.Sha1Regex().IsMatch(hash)) return BadRequest;

Expand Down
4 changes: 4 additions & 0 deletions Refresh.GameServer/Types/Roles/GameUserRole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public enum GameUserRole : sbyte
/// </summary>
Admin = 127,
/// <summary>
/// A user with special permissions. May upload assets when asset uploads are otherwise disabled.
/// </summary>
Trusted = 1,
/// <summary>
/// A standard user. Can play the game, log in, play levels, review them, etc.
/// </summary>
User = 0,
Expand Down
53 changes: 53 additions & 0 deletions RefreshTests.GameServer/Tests/Assets/AssetUploadTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Refresh.GameServer.Authentication;
using Refresh.GameServer.Services;
using Refresh.GameServer.Types.Lists;
using Refresh.GameServer.Types.Roles;
using Refresh.GameServer.Types.UserData;
using RefreshTests.GameServer.Extensions;

Expand Down Expand Up @@ -87,6 +88,58 @@ public void CannotUploadAssetWhenBlocked(bool psp)
HttpResponseMessage response = client.PostAsync("/lbp/upload/" + hash, new ByteArrayContent(data.ToArray())).Result;
Assert.That(response.StatusCode, Is.EqualTo(Unauthorized));
}

[TestCase(false)]
[TestCase(true)]
public void TrustedCanUploadAssetWhenBlocked(bool psp)
{
using TestContext context = this.GetServer();
context.Server.Value.Server.AddService<ImportService>();
context.Server.Value.GameServerConfig.BlockAssetUploads = true;
context.Server.Value.GameServerConfig.BlockAssetUploadsForTrustedUsers = false;

GameUser user = context.CreateUser();
context.Database.SetUserRole(user, GameUserRole.Trusted);

using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, user);
if(psp)
client.DefaultRequestHeaders.UserAgent.TryParseAdd("LBPPSP CLIENT");

ReadOnlySpan<byte> data = "TEX a"u8;

string hash = BitConverter.ToString(SHA1.HashData(data))
.Replace("-", "")
.ToLower();

HttpResponseMessage response = client.PostAsync("/lbp/upload/" + hash, new ByteArrayContent(data.ToArray())).Result;
Assert.That(response.StatusCode, Is.EqualTo(OK));
}

[TestCase(false)]
[TestCase(true)]
public void AdminCanUploadAssetWhenBlocked(bool psp)
{
using TestContext context = this.GetServer();
context.Server.Value.Server.AddService<ImportService>();
context.Server.Value.GameServerConfig.BlockAssetUploads = true;
context.Server.Value.GameServerConfig.BlockAssetUploadsForTrustedUsers = true;

GameUser user = context.CreateUser();
context.Database.SetUserRole(user, GameUserRole.Admin);

using HttpClient client = context.GetAuthenticatedClient(TokenType.Game, user);
if(psp)
client.DefaultRequestHeaders.UserAgent.TryParseAdd("LBPPSP CLIENT");

ReadOnlySpan<byte> data = "TEX a"u8;

string hash = BitConverter.ToString(SHA1.HashData(data))
.Replace("-", "")
.ToLower();

HttpResponseMessage response = client.PostAsync("/lbp/upload/" + hash, new ByteArrayContent(data.ToArray())).Result;
Assert.That(response.StatusCode, Is.EqualTo(OK));
}

[Test]
public void CantUploadAssetWithInvalidHash()
Expand Down

0 comments on commit 5c2249d

Please sign in to comment.