Skip to content

Commit 7a27d41

Browse files
authored
Merge branch 'main' into announcements
2 parents f8092a2 + cc54039 commit 7a27d41

29 files changed

+654
-157
lines changed

Refresh.Core/Configuration/GameServerConfig.cs

Lines changed: 81 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,116 @@
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 more cleanly split the perms between certain roles, and to make their enforcement easier.
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+
// filesize quota limit was added during version 11, but the version wasn't bumped, so catch error to be safe
24+
if (oldVer >= 11)
2225
{
23-
int oldSafetyLevel = (int)oldConfig.MaximumAssetSafetyLevel;
24-
this.BlockedAssetFlags = new ConfigAssetFlags
26+
try
27+
{
28+
this.NormalUserPermissions.UserFilesizeQuota = (int)oldConfig.UserFilesizeQuota;
29+
this.TrustedUserPermissions.UserFilesizeQuota = (int)oldConfig.UserFilesizeQuota;
30+
}
31+
catch (RuntimeBinderException)
2532
{
26-
Dangerous = oldSafetyLevel < 3,
27-
Modded = oldSafetyLevel < 2,
28-
Media = oldSafetyLevel < 1,
29-
};
33+
// do nothing
34+
}
3035
}
3136

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)
37+
if (oldVer >= 18)
3438
{
35-
// There was no version bump for trusted users being added, so we just have to catch this error :/
36-
try
39+
this.NormalUserPermissions.BlockedAssetFlags.Dangerous = (bool)oldConfig.BlockedAssetFlags.Dangerous;
40+
this.NormalUserPermissions.BlockedAssetFlags.Media = (bool)oldConfig.BlockedAssetFlags.Media;
41+
this.NormalUserPermissions.BlockedAssetFlags.Modded = (bool)oldConfig.BlockedAssetFlags.Modded;
42+
43+
this.TrustedUserPermissions.BlockedAssetFlags.Dangerous = (bool)oldConfig.BlockedAssetFlagsForTrustedUsers.Dangerous;
44+
this.TrustedUserPermissions.BlockedAssetFlags.Media = (bool)oldConfig.BlockedAssetFlagsForTrustedUsers.Media;
45+
this.TrustedUserPermissions.BlockedAssetFlags.Modded = (bool)oldConfig.BlockedAssetFlagsForTrustedUsers.Modded;
46+
}
47+
else
48+
{
49+
// Asset safety level was added in config version 2, so dont try to migrate if we are coming from an older version than that
50+
if (oldVer >= 2)
3751
{
38-
int oldTrustedSafetyLevel = (int)oldConfig.MaximumAssetSafetyLevelForTrustedUsers;
39-
this.BlockedAssetFlagsForTrustedUsers = new ConfigAssetFlags
52+
int oldSafetyLevel = (int)oldConfig.MaximumAssetSafetyLevel;
53+
this.NormalUserPermissions.BlockedAssetFlags = new ConfigAssetFlags
4054
{
41-
Dangerous = oldTrustedSafetyLevel < 3,
42-
Modded = oldTrustedSafetyLevel < 2,
43-
Media = oldTrustedSafetyLevel < 1,
55+
Dangerous = oldSafetyLevel < 3,
56+
Modded = oldSafetyLevel < 2,
57+
Media = oldSafetyLevel < 1,
4458
};
4559
}
46-
catch (RuntimeBinderException)
60+
61+
// 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
62+
if (oldVer >= 12)
4763
{
48-
this.BlockedAssetFlagsForTrustedUsers = this.BlockedAssetFlags;
64+
// There was no version bump for trusted users being added, so we just have to catch this error :/
65+
try
66+
{
67+
int oldTrustedSafetyLevel = (int)oldConfig.MaximumAssetSafetyLevelForTrustedUsers;
68+
this.TrustedUserPermissions.BlockedAssetFlags = new ConfigAssetFlags
69+
{
70+
Dangerous = oldTrustedSafetyLevel < 3,
71+
Modded = oldTrustedSafetyLevel < 2,
72+
Media = oldTrustedSafetyLevel < 1,
73+
};
74+
}
75+
catch (RuntimeBinderException)
76+
{
77+
this.TrustedUserPermissions.BlockedAssetFlags = this.NormalUserPermissions.BlockedAssetFlags;
78+
}
4979
}
5080
}
81+
82+
// Timed level upload limits were added in version 19.
83+
if (oldVer >= 19)
84+
{
85+
this.NormalUserPermissions.TimedLevelUploadLimits.Enabled = (bool)oldConfig.TimedLevelUploadLimits.Enabled;
86+
this.NormalUserPermissions.TimedLevelUploadLimits.TimeSpanHours = (int)oldConfig.TimedLevelUploadLimits.TimeSpanHours;
87+
this.NormalUserPermissions.TimedLevelUploadLimits.LevelQuota = (int)oldConfig.TimedLevelUploadLimits.LevelQuota;
88+
89+
this.TrustedUserPermissions.TimedLevelUploadLimits.Enabled = (bool)oldConfig.TimedLevelUploadLimits.Enabled;
90+
this.TrustedUserPermissions.TimedLevelUploadLimits.TimeSpanHours = (int)oldConfig.TimedLevelUploadLimits.TimeSpanHours;
91+
this.TrustedUserPermissions.TimedLevelUploadLimits.LevelQuota = (int)oldConfig.TimedLevelUploadLimits.LevelQuota;
92+
}
93+
94+
// Read-only mode was added for both normal and trusted users in version 20.
95+
if (oldVer >= 20)
96+
{
97+
this.NormalUserPermissions.ReadOnlyMode = (bool)oldConfig.ReadOnlyMode;
98+
this.TrustedUserPermissions.ReadOnlyMode = (bool)oldConfig.ReadonlyModeForTrustedUsers;
99+
}
51100
}
52101
}
53102

54103
public string LicenseText { get; set; } = "Welcome to Refresh!";
55104

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);
105+
/// <summary>
106+
/// Role-specific permissions for normal users and below
107+
/// </summary>
108+
public RolePermissions NormalUserPermissions = new();
109+
/// <summary>
110+
/// Role-specific permissions for trusted users and above
111+
/// </summary>
112+
public RolePermissions TrustedUserPermissions = new();
113+
59114
public bool AllowUsersToUseIpAuthentication { get; set; } = false;
60115
public bool PermitPsnLogin { get; set; } = true;
61116
public bool PermitRpcnLogin { get; set; } = true;
@@ -97,20 +152,6 @@ protected override void Migrate(int oldVer, dynamic oldConfig)
97152
/// </summary>
98153
public string GameConfigStorageUrl { get; set; } = "https://refresh.example.com/lbp";
99154
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;
103-
/// <summary>
104-
/// The amount of data the user is allowed to upload before all resource uploads get blocked, defaults to 100mb.
105-
/// </summary>
106-
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-
};
114155

115156
/// <summary>
116157
/// Whether to print the room state whenever a `FindBestRoom` match returns no results
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
18+
/// <summary>
19+
/// The amount of data the user is allowed to upload before all resource uploads get blocked, defaults to 100mb.
20+
/// </summary>
21+
public int UserFilesizeQuota { get; set; } = 100 * 1_048_576;
22+
}

Refresh.Core/Extensions/GameUserExtensions.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,8 @@ 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+
if (user.Role == GameUserRole.Admin) return false;
11+
return GetRolePermissionsForUser(user, config).ReadOnlyMode;
1612
}
1713

1814
public static bool MayModifyUser(this GameUser user, GameUser targetUser)
@@ -27,4 +23,12 @@ public static bool MayModifyUser(this GameUser user, GameUser targetUser)
2723

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

Refresh.Database/GameDatabaseContext.Pins.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ private IEnumerable<PinProgressRelation> GetPinProgressesByUser(GameUser user, b
169169
public DatabaseList<PinProgressRelation> GetPinProgressesByUser(GameUser user, bool isBeta, TokenPlatform platform, int skip, int count)
170170
=> new(this.GetPinProgressesByUser(user, isBeta, platform), skip, count);
171171

172+
public IQueryable<PinProgressRelation> GetAllPinProgressesByUserAndId(GameUser user, long pinId)
173+
=> this.PinProgressRelations.Where(p => p.PublisherId == user.UserId && p.PinId == pinId);
174+
172175
public PinProgressRelation? GetUserPinProgress(long pinId, GameUser user, bool isBeta, TokenPlatform platform)
173176
=> this.PinProgressRelations.FirstOrDefault(p => p.PinId == pinId && p.PublisherId == user.UserId
174177
&& (p.IsBeta == isBeta && p.Platform == platform || p.Platform == TokenPlatform.Website));

Refresh.Database/GameDatabaseContext.Registration.cs

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public bool IsEmailTaken(string emailAddress)
115115
{
116116
return this.GameUsers.Any(u => u.EmailAddress == emailAddress) ||
117117
this.QueuedRegistrations.Any(r => r.EmailAddress == emailAddress) ||
118-
this.IsEmailDisallowed(emailAddress);
118+
this.IsEmailAddressDisallowed(emailAddress);
119119
}
120120

121121
public void AddRegistrationToQueue(string username, string emailAddress, string passwordBcrypt)
@@ -253,34 +253,71 @@ public bool IsUserDisallowed(string username)
253253
return this.DisallowedUsers.FirstOrDefault(u => u.Username == username) != null;
254254
}
255255

256-
public bool DisallowEmail(string email)
256+
public bool DisallowEmailAddress(string emailAddress)
257257
{
258-
if (this.IsEmailDisallowed(email))
258+
if (this.IsEmailAddressDisallowed(emailAddress))
259259
return false;
260260

261-
this.DisallowedEmails.Add(new()
261+
this.DisallowedEmailAddresses.Add(new()
262262
{
263-
Email = email,
263+
Address = emailAddress,
264264
});
265265
this.SaveChanges();
266266

267267
return true;
268268
}
269269

270-
public bool ReallowEmail(string email)
270+
public bool ReallowEmailAddress(string emailAddress)
271271
{
272-
DisallowedEmail? disallowedEmail = this.DisallowedEmails.FirstOrDefault(u => u.Email == email);
273-
if (disallowedEmail == null)
272+
DisallowedEmailAddress? DisallowedEmailAddress = this.DisallowedEmailAddresses.FirstOrDefault(u => u.Address == emailAddress);
273+
if (DisallowedEmailAddress == null)
274274
return false;
275275

276-
this.DisallowedEmails.Remove(disallowedEmail);
276+
this.DisallowedEmailAddresses.Remove(DisallowedEmailAddress);
277277
this.SaveChanges();
278278

279279
return true;
280280
}
281281

282-
public bool IsEmailDisallowed(string email)
282+
public bool IsEmailAddressDisallowed(string emailAddress)
283283
{
284-
return this.DisallowedEmails.Any(u => u.Email == email);
284+
return this.DisallowedEmailAddresses.Any(u => u.Address == emailAddress);
285+
}
286+
287+
private string GetEmailDomainFromAddress(string emailAddress)
288+
=> emailAddress.Split('@').Last();
289+
290+
public bool DisallowEmailDomain(string emailAddress)
291+
{
292+
string emailDomain = this.GetEmailDomainFromAddress(emailAddress);
293+
if (this.IsEmailDomainDisallowed(emailDomain))
294+
return false;
295+
296+
this.DisallowedEmailDomains.Add(new()
297+
{
298+
Domain = emailDomain,
299+
});
300+
this.SaveChanges();
301+
302+
return true;
303+
}
304+
305+
public bool ReallowEmailDomain(string emailAddress)
306+
{
307+
string emailDomain = this.GetEmailDomainFromAddress(emailAddress);
308+
DisallowedEmailDomain? disallowedDomain = this.DisallowedEmailDomains.FirstOrDefault(u => u.Domain == emailDomain);
309+
if (disallowedDomain == null)
310+
return false;
311+
312+
this.DisallowedEmailDomains.Remove(disallowedDomain);
313+
this.SaveChanges();
314+
315+
return true;
316+
}
317+
318+
public bool IsEmailDomainDisallowed(string emailAddress)
319+
{
320+
string emailDomain = this.GetEmailDomainFromAddress(emailAddress);
321+
return this.DisallowedEmailDomains.Any(u => u.Domain == emailDomain);
285322
}
286323
}

Refresh.Database/GameDatabaseContext.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ public partial class GameDatabaseContext : DbContext, IDatabaseContext
6464
internal DbSet<AssetDependencyRelation> AssetDependencyRelations { get; set; }
6565
internal DbSet<GameReview> GameReviews { get; set; }
6666
internal DbSet<DisallowedUser> DisallowedUsers { get; set; }
67-
internal DbSet<DisallowedEmail> DisallowedEmails { get; set; }
67+
internal DbSet<DisallowedEmailAddress> DisallowedEmailAddresses { get; set; }
68+
internal DbSet<DisallowedEmailDomain> DisallowedEmailDomains { get; set; }
6869
internal DbSet<RateReviewRelation> RateReviewRelations { get; set; }
6970
internal DbSet<TagLevelRelation> TagLevelRelations { get; set; }
7071
internal DbSet<GamePlaylist> GamePlaylists { get; set; }
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using Microsoft.EntityFrameworkCore.Infrastructure;
2+
using Microsoft.EntityFrameworkCore.Migrations;
3+
4+
#nullable disable
5+
6+
namespace Refresh.Database.Migrations
7+
{
8+
/// <inheritdoc />
9+
[DbContext(typeof(GameDatabaseContext))]
10+
[Migration("20260331143640_AddAbilityToDisallowEmailDomains")]
11+
public partial class AddAbilityToDisallowEmailDomains : Migration
12+
{
13+
/// <inheritdoc />
14+
protected override void Up(MigrationBuilder migrationBuilder)
15+
{
16+
migrationBuilder.RenameTable(name: "DisallowedEmails", newName: "DisallowedEmailAddresses");
17+
migrationBuilder.DropPrimaryKey(name: "PK_DisallowedEmails", table: "DisallowedEmailAddresses");
18+
migrationBuilder.RenameColumn(name: "Email", table: "DisallowedEmailAddresses", newName: "Address");
19+
migrationBuilder.AddPrimaryKey(name: "PK_DisallowedEmailAddresses", table: "DisallowedEmailAddresses", column: "Address");
20+
21+
migrationBuilder.CreateTable(
22+
name: "DisallowedEmailDomains",
23+
columns: table => new
24+
{
25+
Domain = table.Column<string>(type: "text", nullable: false)
26+
},
27+
constraints: table =>
28+
{
29+
table.PrimaryKey("PK_DisallowedEmailDomains", x => x.Domain);
30+
});
31+
}
32+
33+
/// <inheritdoc />
34+
protected override void Down(MigrationBuilder migrationBuilder)
35+
{
36+
migrationBuilder.DropTable(
37+
name: "DisallowedEmailDomains");
38+
39+
migrationBuilder.RenameTable(name: "DisallowedEmailAddresses", newName: "DisallowedEmails");
40+
migrationBuilder.DropPrimaryKey(name: "PK_DisallowedEmailAddresses", table: "DisallowedEmails");
41+
migrationBuilder.RenameColumn(name: "Address", table: "DisallowedEmails", newName: "Email");
42+
migrationBuilder.AddPrimaryKey(name: "PK_DisallowedEmails", table: "DisallowedEmails", column: "Email");
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)