Skip to content
19 changes: 15 additions & 4 deletions Refresh.Database/GameDatabaseContext.Assets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,20 +111,30 @@ public void SetMainlinePhotoHash(GameAsset asset, string hash) =>
asset.AsMainlinePhotoHash = hash;
});

public bool IsAssetDisallowed(string hash)
{
string hashLower = hash.ToLower();
return this.DisallowedAssets.Any(u => u.AssetHash == hashLower);
}

public DisallowedAsset? GetDisallowedAssetInfo(string hash)
=> this.DisallowedAssets.FirstOrDefault(d => d.AssetHash == hash);
{
string hashLower = hash.ToLower();
return this.DisallowedAssets.FirstOrDefault(d => d.AssetHash == hashLower);
}

/// <returns>
/// The asset's disallowance info + whether the asset wasn't already disallowed before
/// </returns
public (DisallowedAsset, bool) DisallowAsset(string hash, GameAssetType type, string reason)
{
DisallowedAsset? existing = this.GetDisallowedAssetInfo(hash);
string hashLower = hash.ToLower();
DisallowedAsset? existing = this.GetDisallowedAssetInfo(hashLower);
if (existing != null) return (existing, false);

DisallowedAsset disallowed = new()
{
AssetHash = hash,
AssetHash = hashLower,
AssetType = type,
Reason = reason,
DisallowedAt = this._time.Now,
Expand All @@ -137,7 +147,8 @@ public void SetMainlinePhotoHash(GameAsset asset, string hash) =>

public bool ReallowAsset(string hash)
{
DisallowedAsset? existing = this.GetDisallowedAssetInfo(hash);
string hashLower = hash.ToLower();
DisallowedAsset? existing = this.GetDisallowedAssetInfo(hashLower);
if (existing == null) return false;

this.DisallowedAssets.Remove(existing);
Expand Down
58 changes: 37 additions & 21 deletions Refresh.Database/GameDatabaseContext.Registration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,22 +219,29 @@ public void RemoveEmailVerificationCode(EmailVerificationCode code)
}

public bool IsUserDisallowed(string username)
=> this.DisallowedUsers.Any(u => u.Username == username);
{
string lowercaseUsername = username.ToLower();
return this.DisallowedUsers.Any(u => u.UsernameLower == lowercaseUsername);
}

public DisallowedUser? GetDisallowedUserInfo(string username)
=> this.DisallowedUsers.FirstOrDefault(d => d.Username == username);
{
string lowercaseUsername = username.ToLower();
return this.DisallowedUsers.FirstOrDefault(d => d.UsernameLower == lowercaseUsername);
}

public DatabaseList<DisallowedUser> GetDisallowedUsers(int skip, int count)
=> new(this.DisallowedUsers.OrderByDescending(d => d.DisallowedAt), skip, count);

public (DisallowedUser, bool) DisallowUser(string username, string reason)
{
DisallowedUser? existing = this.GetDisallowedUserInfo(username);
string lowercaseUsername = username.ToLower();
DisallowedUser? existing = this.GetDisallowedUserInfo(lowercaseUsername);
if (existing != null) return (existing, false);

DisallowedUser disallowed = new()
{
Username = username,
UsernameLower = lowercaseUsername,
Reason = reason,
DisallowedAt = this._time.Now,
};
Expand All @@ -246,7 +253,8 @@ public DatabaseList<DisallowedUser> GetDisallowedUsers(int skip, int count)

public bool ReallowUser(string username)
{
DisallowedUser? disallowedUser = this.GetDisallowedUserInfo(username);
string lowercaseUsername = username.ToLower();
DisallowedUser? disallowedUser = this.GetDisallowedUserInfo(lowercaseUsername);
if (disallowedUser == null)
return false;

Expand All @@ -257,22 +265,29 @@ public bool ReallowUser(string username)
}

public bool IsEmailAddressDisallowed(string emailAddress)
=> this.DisallowedEmailAddresses.Any(u => u.Address == emailAddress);
{
string emailAddressLower = emailAddress.ToLowerInvariant();
return this.DisallowedEmailAddresses.Any(u => u.AddressLower == emailAddressLower);
}

public DisallowedEmailAddress? GetDisallowedEmailAddressInfo(string emailAddress)
=> this.DisallowedEmailAddresses.FirstOrDefault(d => d.Address == emailAddress);
{
string emailAddressLower = emailAddress.ToLowerInvariant();
return this.DisallowedEmailAddresses.FirstOrDefault(d => d.AddressLower == emailAddressLower);
}

public DatabaseList<DisallowedEmailAddress> GetDisallowedEmailAddresses(int skip, int count)
=> new(this.DisallowedEmailAddresses.OrderByDescending(d => d.DisallowedAt), skip, count);

public (DisallowedEmailAddress, bool) DisallowEmailAddress(string emailAddress, string reason)
{
DisallowedEmailAddress? existing = this.GetDisallowedEmailAddressInfo(emailAddress);
string emailAddressLower = emailAddress.ToLowerInvariant();
DisallowedEmailAddress? existing = this.GetDisallowedEmailAddressInfo(emailAddressLower);
if (existing != null) return (existing, false);

DisallowedEmailAddress disallowed = new()
{
Address = emailAddress,
AddressLower = emailAddressLower,
Reason = reason,
DisallowedAt = this._time.Now,
};
Expand All @@ -284,7 +299,8 @@ public DatabaseList<DisallowedEmailAddress> GetDisallowedEmailAddresses(int skip

public bool ReallowEmailAddress(string emailAddress)
{
DisallowedEmailAddress? disallowed = this.GetDisallowedEmailAddressInfo(emailAddress);
string emailAddressLower = emailAddress.ToLowerInvariant();
DisallowedEmailAddress? disallowed = this.GetDisallowedEmailAddressInfo(emailAddressLower);
if (disallowed == null)
return false;

Expand All @@ -294,33 +310,33 @@ public bool ReallowEmailAddress(string emailAddress)
return true;
}

private string GetEmailDomainFromAddress(string emailAddress)
=> emailAddress.Split('@').Last();
private string GetLowercaseEmailDomainFromAddress(string emailAddress)
=> emailAddress.Split('@').Last().ToLowerInvariant();

public bool IsEmailDomainDisallowed(string emailAddress)
{
string emailDomain = this.GetEmailDomainFromAddress(emailAddress);
return this.DisallowedEmailDomains.Any(u => u.Domain == emailDomain);
string emailDomainLower = this.GetLowercaseEmailDomainFromAddress(emailAddress);
return this.DisallowedEmailDomains.Any(u => u.DomainLower == emailDomainLower);
}

public DisallowedEmailDomain? GetDisallowedEmailDomainInfo(string emailAddress)
{
string emailDomain = this.GetEmailDomainFromAddress(emailAddress);
return this.DisallowedEmailDomains.FirstOrDefault(d => d.Domain == emailDomain);
string emailDomainLower = this.GetLowercaseEmailDomainFromAddress(emailAddress);
return this.DisallowedEmailDomains.FirstOrDefault(d => d.DomainLower == emailDomainLower);
}

public DatabaseList<DisallowedEmailDomain> GetDisallowedEmailDomains(int skip, int count)
=> new(this.DisallowedEmailDomains.OrderByDescending(d => d.DisallowedAt), skip, count);

public (DisallowedEmailDomain, bool) DisallowEmailDomain(string emailAddress, string reason)
{
string emailDomain = this.GetEmailDomainFromAddress(emailAddress);
DisallowedEmailDomain? existing = this.GetDisallowedEmailDomainInfo(emailDomain);
string emailDomainLower = this.GetLowercaseEmailDomainFromAddress(emailAddress);
DisallowedEmailDomain? existing = this.GetDisallowedEmailDomainInfo(emailDomainLower);
if (existing != null) return (existing, false);

DisallowedEmailDomain disallowed = new()
{
Domain = emailDomain,
DomainLower = emailDomainLower,
Reason = reason,
DisallowedAt = this._time.Now,
};
Expand All @@ -332,8 +348,8 @@ public DatabaseList<DisallowedEmailDomain> GetDisallowedEmailDomains(int skip, i

public bool ReallowEmailDomain(string emailAddress)
{
string emailDomain = this.GetEmailDomainFromAddress(emailAddress);
DisallowedEmailDomain? disallowedDomain = this.GetDisallowedEmailDomainInfo(emailDomain);
string emailDomainLower = this.GetLowercaseEmailDomainFromAddress(emailAddress);
DisallowedEmailDomain? disallowedDomain = this.GetDisallowedEmailDomainInfo(emailDomainLower);
if (disallowedDomain == null)
return false;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace Refresh.Database.Migrations
{
/// <inheritdoc />
[DbContext(typeof(GameDatabaseContext))]
[Migration("20260527172459_DisallowEntitiesCaseInsensitively")]
public partial class DisallowEntitiesCaseInsensitively : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
// Remove case-insensitively duplicate entries before lowercasing primary keys to not cause duplicate keys
// Email Addresses
migrationBuilder.Sql
("""
DELETE FROM "DisallowedEmailAddresses"
WHERE "Address" NOT IN (
SELECT min("Address")
FROM "DisallowedEmailAddresses"
GROUP BY lower("Address")
)
""");
// for some reason, Postgres won't actually execute these separately if we use semicolons, so we have to do separate method calls
migrationBuilder.Sql
("""
UPDATE "DisallowedEmailAddresses" SET "Address" = lower("Address");
""");

// Email Domains
migrationBuilder.Sql
("""
DELETE FROM "DisallowedEmailDomains"
WHERE "Domain" NOT IN (
SELECT min("Domain")
FROM "DisallowedEmailDomains"
GROUP BY lower("Domain")
)
""");
migrationBuilder.Sql
("""
UPDATE "DisallowedEmailDomains" SET "Domain" = lower("Domain");
""");

// Usernames
migrationBuilder.Sql
("""
DELETE FROM "DisallowedUsers"
WHERE "Username" NOT IN (
SELECT min("Username")
FROM "DisallowedUsers"
GROUP BY lower("Username")
)
""");
migrationBuilder.Sql
("""
UPDATE "DisallowedUsers" SET "Username" = lower("Username");
""");

// Assets
migrationBuilder.Sql
("""
DELETE FROM "DisallowedAssets"
WHERE "AssetHash" NOT IN (
SELECT min("AssetHash")
FROM "DisallowedAssets"
GROUP BY lower("AssetHash")
)
""");
migrationBuilder.Sql
("""
UPDATE "DisallowedAssets" SET "AssetHash" = lower("AssetHash");
""");
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace Refresh.Database.Migrations
{
/// <inheritdoc />
[DbContext(typeof(GameDatabaseContext))]
[Migration("20260606101615_RenameDisallowancePKsForClarity")]
public partial class RenameDisallowancePKsForClarity : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "Username",
table: "DisallowedUsers",
newName: "UsernameLower");

migrationBuilder.RenameColumn(
name: "Domain",
table: "DisallowedEmailDomains",
newName: "DomainLower");

migrationBuilder.RenameColumn(
name: "Address",
table: "DisallowedEmailAddresses",
newName: "AddressLower");
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "UsernameLower",
table: "DisallowedUsers",
newName: "Username");

migrationBuilder.RenameColumn(
name: "DomainLower",
table: "DisallowedEmailDomains",
newName: "Domain");

migrationBuilder.RenameColumn(
name: "AddressLower",
table: "DisallowedEmailAddresses",
newName: "Address");
}
}
}
18 changes: 9 additions & 9 deletions Refresh.Database/Migrations/GameDatabaseContextModelSnapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1532,7 +1532,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)

modelBuilder.Entity("Refresh.Database.Models.Users.DisallowedEmailAddress", b =>
{
b.Property<string>("Address")
b.Property<string>("AddressLower")
.HasColumnType("text");

b.Property<DateTimeOffset>("DisallowedAt")
Expand All @@ -1541,14 +1541,14 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<string>("Reason")
.HasColumnType("text");

b.HasKey("Address");
b.HasKey("AddressLower");

b.ToTable("DisallowedEmailAddresses");
});

modelBuilder.Entity("Refresh.Database.Models.Users.DisallowedEmailDomain", b =>
{
b.Property<string>("Domain")
b.Property<string>("DomainLower")
.HasColumnType("text");

b.Property<DateTimeOffset>("DisallowedAt")
Expand All @@ -1557,14 +1557,14 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<string>("Reason")
.HasColumnType("text");

b.HasKey("Domain");
b.HasKey("DomainLower");

b.ToTable("DisallowedEmailDomains");
});

modelBuilder.Entity("Refresh.Database.Models.Users.DisallowedUser", b =>
{
b.Property<string>("Username")
b.Property<string>("UsernameLower")
.HasColumnType("text");

b.Property<DateTimeOffset>("DisallowedAt")
Expand All @@ -1573,7 +1573,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<string>("Reason")
.HasColumnType("text");

b.HasKey("Username");
b.HasKey("UsernameLower");

b.ToTable("DisallowedUsers");
});
Expand Down Expand Up @@ -1602,12 +1602,12 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<byte>("Entity")
.HasColumnType("smallint");

b.Property<int>("UploadCount")
.HasColumnType("integer");

b.Property<DateTimeOffset>("ExpiryDate")
.HasColumnType("timestamp with time zone");

b.Property<int>("UploadCount")
.HasColumnType("integer");

b.HasKey("UserId", "Entity");

b.ToTable("EntityUploadRateLimits");
Expand Down
Loading
Loading