Skip to content

Commit bde5a43

Browse files
committed
Properly organize role-specific config settings, separate timed level limit for trusted users
1 parent ef7a165 commit bde5a43

12 files changed

Lines changed: 215 additions & 77 deletions

File tree

Refresh.Core/Configuration/GameServerConfig.cs

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,102 @@
11
using System.Diagnostics.CodeAnalysis;
22
using Bunkum.Core.Configuration;
33
using Microsoft.CSharp.RuntimeBinder;
4-
using Refresh.Database.Models.Assets;
5-
using Refresh.Database.Models.Users;
64

75
namespace Refresh.Core.Configuration;
86

97
[SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global")]
108
[SuppressMessage("ReSharper", "RedundantDefaultMemberInitializer")]
119
public class GameServerConfig : Config
1210
{
13-
public override int CurrentConfigVersion => 26;
11+
public override int CurrentConfigVersion => 27;
1412
public override int Version { get; set; } = 0;
1513

1614
protected override void Migrate(int oldVer, dynamic oldConfig)
1715
{
18-
if (oldVer < 18)
16+
// In version 27, various (mostly already role-specific) perms, like blocked assets and read-only mode, were moved to dedicated child objects,
17+
// to better split them between certain roles.
18+
if (oldVer < 27)
1919
{
20-
// Asset safety level was added in config version 2, so dont try to migrate if we are coming from an older version than that
21-
if (oldVer >= 2)
20+
this.NormalUserPermissions = new();
21+
this.TrustedUserPermissions = new();
22+
23+
if (oldVer >= 18)
2224
{
23-
int oldSafetyLevel = (int)oldConfig.MaximumAssetSafetyLevel;
24-
this.BlockedAssetFlags = new ConfigAssetFlags
25-
{
26-
Dangerous = oldSafetyLevel < 3,
27-
Modded = oldSafetyLevel < 2,
28-
Media = oldSafetyLevel < 1,
29-
};
30-
}
25+
this.NormalUserPermissions.BlockedAssetFlags.Dangerous = (bool)oldConfig.BlockedAssetFlags.Dangerous;
26+
this.NormalUserPermissions.BlockedAssetFlags.Media = (bool)oldConfig.BlockedAssetFlags.Media;
27+
this.NormalUserPermissions.BlockedAssetFlags.Modded = (bool)oldConfig.BlockedAssetFlags.Modded;
3128

32-
// Asset safety level for trusted users was added in config version 12, so dont try to migrate if we are coming from a version older than that
33-
if (oldVer >= 12)
29+
this.TrustedUserPermissions.BlockedAssetFlags.Dangerous = (bool)oldConfig.BlockedAssetFlagsForTrustedUsers.Dangerous;
30+
this.TrustedUserPermissions.BlockedAssetFlags.Media = (bool)oldConfig.BlockedAssetFlagsForTrustedUsers.Media;
31+
this.TrustedUserPermissions.BlockedAssetFlags.Modded = (bool)oldConfig.BlockedAssetFlagsForTrustedUsers.Modded;
32+
}
33+
else
3434
{
35-
// There was no version bump for trusted users being added, so we just have to catch this error :/
36-
try
35+
// Asset safety level was added in config version 2, so dont try to migrate if we are coming from an older version than that
36+
if (oldVer >= 2)
3737
{
38-
int oldTrustedSafetyLevel = (int)oldConfig.MaximumAssetSafetyLevelForTrustedUsers;
39-
this.BlockedAssetFlagsForTrustedUsers = new ConfigAssetFlags
38+
int oldSafetyLevel = (int)oldConfig.MaximumAssetSafetyLevel;
39+
this.NormalUserPermissions.BlockedAssetFlags = new ConfigAssetFlags
4040
{
41-
Dangerous = oldTrustedSafetyLevel < 3,
42-
Modded = oldTrustedSafetyLevel < 2,
43-
Media = oldTrustedSafetyLevel < 1,
41+
Dangerous = oldSafetyLevel < 3,
42+
Modded = oldSafetyLevel < 2,
43+
Media = oldSafetyLevel < 1,
4444
};
4545
}
46-
catch (RuntimeBinderException)
46+
47+
// Asset safety level for trusted users was added in config version 12, so dont try to migrate if we are coming from a version older than that
48+
if (oldVer >= 12)
4749
{
48-
this.BlockedAssetFlagsForTrustedUsers = this.BlockedAssetFlags;
50+
// There was no version bump for trusted users being added, so we just have to catch this error :/
51+
try
52+
{
53+
int oldTrustedSafetyLevel = (int)oldConfig.MaximumAssetSafetyLevelForTrustedUsers;
54+
this.TrustedUserPermissions.BlockedAssetFlags = new ConfigAssetFlags
55+
{
56+
Dangerous = oldTrustedSafetyLevel < 3,
57+
Modded = oldTrustedSafetyLevel < 2,
58+
Media = oldTrustedSafetyLevel < 1,
59+
};
60+
}
61+
catch (RuntimeBinderException)
62+
{
63+
this.TrustedUserPermissions.BlockedAssetFlags = this.NormalUserPermissions.BlockedAssetFlags;
64+
}
4965
}
5066
}
67+
68+
// Timed level upload limits were added in version 19.
69+
if (oldVer >= 19)
70+
{
71+
this.NormalUserPermissions.TimedLevelUploadLimits.Enabled = (bool)oldConfig.TimedLevelUploadLimits.Enabled;
72+
this.NormalUserPermissions.TimedLevelUploadLimits.TimeSpanHours = (int)oldConfig.TimedLevelUploadLimits.TimeSpanHours;
73+
this.NormalUserPermissions.TimedLevelUploadLimits.LevelQuota = (int)oldConfig.TimedLevelUploadLimits.LevelQuota;
74+
75+
this.TrustedUserPermissions.TimedLevelUploadLimits.Enabled = (bool)oldConfig.TimedLevelUploadLimits.Enabled;
76+
this.TrustedUserPermissions.TimedLevelUploadLimits.TimeSpanHours = (int)oldConfig.TimedLevelUploadLimits.TimeSpanHours;
77+
this.TrustedUserPermissions.TimedLevelUploadLimits.LevelQuota = (int)oldConfig.TimedLevelUploadLimits.LevelQuota;
78+
}
79+
80+
// Read-only mode was added for both normal and trusted users in version 20.
81+
if (oldVer >= 20)
82+
{
83+
this.NormalUserPermissions.ReadOnlyMode = (bool)oldConfig.ReadOnlyMode;
84+
this.TrustedUserPermissions.ReadOnlyMode = (bool)oldConfig.ReadonlyModeForTrustedUsers;
85+
}
5186
}
5287
}
5388

5489
public string LicenseText { get; set; } = "Welcome to Refresh!";
5590

56-
public ConfigAssetFlags BlockedAssetFlags { get; set; } = new(AssetFlags.Dangerous | AssetFlags.Modded);
57-
/// <seealso cref="GameUserRole.Trusted"/>
58-
public ConfigAssetFlags BlockedAssetFlagsForTrustedUsers { get; set; } = new(AssetFlags.Dangerous | AssetFlags.Modded);
91+
/// <summary>
92+
/// Role-specific permissions for normal users and below
93+
/// </summary>
94+
public RolePermissions NormalUserPermissions = new();
95+
/// <summary>
96+
/// Role-specific permissions for trusted users and above
97+
/// </summary>
98+
public RolePermissions TrustedUserPermissions = new();
99+
59100
public bool AllowUsersToUseIpAuthentication { get; set; } = false;
60101
public bool PermitPsnLogin { get; set; } = true;
61102
public bool PermitRpcnLogin { get; set; } = true;
@@ -97,20 +138,10 @@ protected override void Migrate(int oldVer, dynamic oldConfig)
97138
/// </summary>
98139
public string GameConfigStorageUrl { get; set; } = "https://refresh.example.com/lbp";
99140
public bool AllowInvalidTextureGuids { get; set; } = false;
100-
public bool ReadOnlyMode { get; set; } = false;
101-
/// <seealso cref="GameUserRole.Trusted"/>
102-
public bool ReadonlyModeForTrustedUsers { get; set; } = false;
103141
/// <summary>
104142
/// The amount of data the user is allowed to upload before all resource uploads get blocked, defaults to 100mb.
105143
/// </summary>
106144
public int UserFilesizeQuota { get; set; } = 100 * 1_048_576;
107-
108-
public TimedLevelUploadLimitProperties TimedLevelUploadLimits { get; set; } = new()
109-
{
110-
Enabled = false,
111-
TimeSpanHours = 24,
112-
LevelQuota = 10,
113-
};
114145

115146
/// <summary>
116147
/// Whether to print the room state whenever a `FindBestRoom` match returns no results
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using Refresh.Database.Models.Assets;
2+
3+
namespace Refresh.Core.Configuration;
4+
5+
public class RolePermissions
6+
{
7+
public RolePermissions() {}
8+
9+
public bool ReadOnlyMode { get; set; } = false;
10+
public ConfigAssetFlags BlockedAssetFlags { get; set; } = new(AssetFlags.Dangerous | AssetFlags.Modded);
11+
public TimedLevelUploadLimitProperties TimedLevelUploadLimits = new()
12+
{
13+
Enabled = false,
14+
TimeSpanHours = 24,
15+
LevelQuota = 10,
16+
};
17+
}

Refresh.Core/Extensions/GameUserExtensions.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,7 @@ public static class GameUserExtensions
77
{
88
public static bool IsWriteBlocked(this GameUser user, GameServerConfig config)
99
{
10-
if (config.ReadOnlyMode && user.Role != GameUserRole.Admin)
11-
{
12-
return user.Role < GameUserRole.Trusted || config.ReadonlyModeForTrustedUsers;
13-
}
14-
15-
return false;
10+
return GetRolePermissionsForUser(user, config).ReadOnlyMode;
1611
}
1712

1813
public static bool MayModifyUser(this GameUser user, GameUser targetUser)
@@ -27,4 +22,12 @@ public static bool MayModifyUser(this GameUser user, GameUser targetUser)
2722

2823
return true;
2924
}
25+
26+
public static RolePermissions GetRolePermissionsForUser(this GameUser user, GameServerConfig config)
27+
{
28+
if (user.Role >= GameUserRole.Trusted)
29+
return config.TrustedUserPermissions;
30+
31+
return config.NormalUserPermissions;
32+
}
3033
}

Refresh.Interfaces.APIv3/Endpoints/InstanceApiEndpoints.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ public ApiResponse<ApiInstanceResponse> GetInstanceInformation(RequestContext co
6262
SoftwareSourceUrl = "https://github.com/LittleBigRefresh/Refresh",
6363
SoftwareLicenseName = "AGPL-3.0",
6464
SoftwareLicenseUrl = "https://www.gnu.org/licenses/agpl-3.0.txt",
65-
BlockedAssetFlags = gameConfig.BlockedAssetFlags,
66-
BlockedAssetFlagsForTrustedUsers = gameConfig.BlockedAssetFlagsForTrustedUsers,
65+
BlockedAssetFlags = gameConfig.NormalUserPermissions.BlockedAssetFlags,
66+
BlockedAssetFlagsForTrustedUsers = gameConfig.TrustedUserPermissions.BlockedAssetFlags,
6767
Announcements = ApiGameAnnouncementResponse.FromOldList(database.GetAnnouncements(), dataContext),
6868
MaintenanceModeEnabled = gameConfig.MaintenanceMode,
6969
RichPresenceConfiguration = ApiRichPresenceConfigurationResponse.FromOld(RichPresenceConfiguration.Create(

Refresh.Interfaces.Game/Endpoints/Levels/PublishEndpoints.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,16 @@ public Response StartPublish(RequestContext context,
119119
GameLevelRequest body,
120120
DataContext dataContext,
121121
GameServerConfig config,
122-
IDateTimeProvider dateTimeProvider)
122+
IDateTimeProvider dateTimeProvider,
123+
GameUser user)
123124
{
124125
if (dataContext.User!.IsWriteBlocked(config))
125126
{
126127
dataContext.Database.AddPublishFailNotification("The server is in read-only mode.", body.Title, dataContext.User!);
127128
return Unauthorized;
128129
}
129130

130-
if (IsTimedLevelLimitReached(dataContext, dataContext.User!, body.Title, config.TimedLevelUploadLimits, dateTimeProvider.Now))
131+
if (IsTimedLevelLimitReached(dataContext, dataContext.User!, body.Title, user.GetRolePermissionsForUser(config).TimedLevelUploadLimits, dateTimeProvider.Now))
131132
return Unauthorized;
132133

133134
//If verifying the request fails, return BadRequest
@@ -182,7 +183,8 @@ public Response PublishLevel(RequestContext context,
182183
if (user.IsWriteBlocked(config))
183184
return Unauthorized;
184185

185-
if (IsTimedLevelLimitReached(dataContext, user, body.Title, config.TimedLevelUploadLimits, dateTimeProvider.Now))
186+
TimedLevelUploadLimitProperties timedLevelLimit = user.GetRolePermissionsForUser(config).TimedLevelUploadLimits;
187+
if (IsTimedLevelLimitReached(dataContext, user, body.Title, timedLevelLimit, dateTimeProvider.Now))
186188
return Unauthorized;
187189

188190
//If verifying the request fails, return BadRequest
@@ -256,9 +258,9 @@ public Response PublishLevel(RequestContext context,
256258

257259
// Only increment if the level can be uploaded (right after the previous checks + adding the level),
258260
// don't want to increment for failed uploads
259-
if (config.TimedLevelUploadLimits.Enabled)
261+
if (timedLevelLimit.Enabled)
260262
{
261-
dataContext.Database.IncrementTimedLevelLimit(user, config.TimedLevelUploadLimits.TimeSpanHours);
263+
dataContext.Database.IncrementTimedLevelLimit(user, timedLevelLimit.TimeSpanHours);
262264
}
263265

264266
// Update the modded status of the level

Refresh.Interfaces.Game/Endpoints/ResourceEndpoints.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ public Response UploadAsset(RequestContext context, string hash, string type, by
6666

6767
gameAsset.UploadDate = DateTimeOffset.FromUnixTimeSeconds(Math.Clamp(gameAsset.UploadDate.ToUnixTimeSeconds(), timeProvider.EarliestDate, timeProvider.TimestampSeconds));
6868

69-
AssetFlags blockedAssetFlags = config.BlockedAssetFlags.ToAssetFlags();
70-
if (user.Role >= GameUserRole.Trusted)
71-
blockedAssetFlags = config.BlockedAssetFlagsForTrustedUsers.ToAssetFlags();
69+
AssetFlags blockedAssetFlags = user.GetRolePermissionsForUser(config).BlockedAssetFlags.ToAssetFlags();
7270

7371
// Don't block any assets uploaded from PSP, else block any unwanted assets,
7472
// For example, if the "blocked asset flags" has the "Media" bit set, and so does the asset,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Refresh.Core.Configuration;
2+
using Refresh.Database.Models.Assets;
3+
4+
namespace RefreshTests.GameServer.GameServer;
5+
6+
public class TestGameServerConfig : GameServerConfig
7+
{
8+
public void TestMigration()
9+
{
10+
this.Migrate(this.Version, this);
11+
}
12+
13+
// Various attributes to migrate from
14+
public ConfigAssetFlags BlockedAssetFlags { get; set; } = new(AssetFlags.Dangerous | AssetFlags.Modded);
15+
public ConfigAssetFlags BlockedAssetFlagsForTrustedUsers { get; set; } = new(AssetFlags.Dangerous | AssetFlags.Modded);
16+
public bool ReadOnlyMode { get; set; } = false;
17+
public bool ReadonlyModeForTrustedUsers { get; set; } = false;
18+
public TimedLevelUploadLimitProperties TimedLevelUploadLimits { get; set; } = new()
19+
{
20+
Enabled = false,
21+
TimeSpanHours = 24,
22+
LevelQuota = 10,
23+
};
24+
25+
public int MaximumAssetSafetyLevel { get; set; } = 0;
26+
public int MaximumAssetSafetyLevelForTrustedUsers { get; set; } = 0;
27+
}

RefreshTests.GameServer/Tests/Assets/AssetUploadTests.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public void CannotUploadAssetWhenBlocked(bool psp)
7171
{
7272
using TestContext context = this.GetServer();
7373

74-
context.Server.Value.GameServerConfig.ReadOnlyMode = true;
74+
context.Server.Value.GameServerConfig.NormalUserPermissions.ReadOnlyMode = true;
7575

7676
context.Server.Value.Server.AddService<ImportService>();
7777
GameUser user = context.CreateUser();
@@ -95,8 +95,8 @@ public void TrustedCanUploadAssetWhenBlocked(bool psp)
9595
{
9696
using TestContext context = this.GetServer();
9797
context.Server.Value.Server.AddService<ImportService>();
98-
context.Server.Value.GameServerConfig.ReadOnlyMode = true;
99-
context.Server.Value.GameServerConfig.ReadonlyModeForTrustedUsers = false;
98+
context.Server.Value.GameServerConfig.NormalUserPermissions.ReadOnlyMode = true;
99+
context.Server.Value.GameServerConfig.TrustedUserPermissions.ReadOnlyMode = false;
100100

101101
GameUser user = context.CreateUser();
102102
context.Database.SetUserRole(user, GameUserRole.Trusted);
@@ -121,8 +121,8 @@ public void AdminCanUploadAssetWhenBlocked(bool psp)
121121
{
122122
using TestContext context = this.GetServer();
123123
context.Server.Value.Server.AddService<ImportService>();
124-
context.Server.Value.GameServerConfig.ReadOnlyMode = true;
125-
context.Server.Value.GameServerConfig.ReadonlyModeForTrustedUsers = true;
124+
context.Server.Value.GameServerConfig.NormalUserPermissions.ReadOnlyMode = true;
125+
context.Server.Value.GameServerConfig.TrustedUserPermissions.ReadOnlyMode = true;
126126

127127
GameUser user = context.CreateUser();
128128
context.Database.SetUserRole(user, GameUserRole.Admin);
@@ -146,13 +146,13 @@ public void TrustedCanUploadAssetWithSafetyLevel()
146146
{
147147
using TestContext context = this.GetServer();
148148
context.Server.Value.Server.AddService<ImportService>();
149-
context.Server.Value.GameServerConfig.BlockedAssetFlags = new ConfigAssetFlags
149+
context.Server.Value.GameServerConfig.NormalUserPermissions.BlockedAssetFlags = new ConfigAssetFlags
150150
{
151151
Modded = true,
152152
Media = true,
153153
Dangerous = true,
154154
};
155-
context.Server.Value.GameServerConfig.BlockedAssetFlagsForTrustedUsers = new ConfigAssetFlags
155+
context.Server.Value.GameServerConfig.TrustedUserPermissions.BlockedAssetFlags = new ConfigAssetFlags
156156
{
157157
Dangerous = true,
158158
Modded = true,
@@ -178,13 +178,13 @@ public void NormalUserCantUploadAssetWithSafetyLevel()
178178
{
179179
using TestContext context = this.GetServer();
180180
context.Server.Value.Server.AddService<ImportService>();
181-
context.Server.Value.GameServerConfig.BlockedAssetFlags = new ConfigAssetFlags
181+
context.Server.Value.GameServerConfig.NormalUserPermissions.BlockedAssetFlags = new ConfigAssetFlags
182182
{
183183
Dangerous = true,
184184
Modded = true,
185185
Media = true,
186186
};
187-
context.Server.Value.GameServerConfig.BlockedAssetFlagsForTrustedUsers = new ConfigAssetFlags
187+
context.Server.Value.GameServerConfig.TrustedUserPermissions.BlockedAssetFlags = new ConfigAssetFlags
188188
{
189189
Dangerous = true,
190190
Modded = true,
@@ -209,7 +209,7 @@ public void PspCantUploadMediaAssetWhileBlocked()
209209
{
210210
using TestContext context = this.GetServer();
211211
context.Server.Value.Server.AddService<ImportService>();
212-
context.Server.Value.GameServerConfig.BlockedAssetFlags = new ConfigAssetFlags
212+
context.Server.Value.GameServerConfig.NormalUserPermissions.BlockedAssetFlags = new ConfigAssetFlags
213213
{
214214
Dangerous = true,
215215
Modded = true,
@@ -236,7 +236,7 @@ public void PspCanUploadNormalAssetWhileBlocked()
236236
{
237237
using TestContext context = this.GetServer();
238238
context.Server.Value.Server.AddService<ImportService>();
239-
context.Server.Value.GameServerConfig.BlockedAssetFlags = new ConfigAssetFlags
239+
context.Server.Value.GameServerConfig.NormalUserPermissions.BlockedAssetFlags = new ConfigAssetFlags
240240
{
241241
Dangerous = true,
242242
Modded = true,

0 commit comments

Comments
 (0)