Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to block certain users from registering accounts #380

Merged
merged 2 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions Refresh.GameServer/CommandLineManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ private class Options

[Option('f', "force", Required = false, HelpText = "Force all operations to happen, skipping user consent")]
public bool Force { get; set; }

[Option('b', "disallow_user", Required = false, HelpText = "Disallow a user from registering. Username option is required if this is set.")]
public bool DisallowUser { get; set; }

[Option('r', "reallow_user", Required = false, HelpText = "Re-allow a user to register. Username option is requried if this is set.")]
public bool ReallowUser { get; set; }
}

internal void StartWithArgs(string[] args)
Expand Down Expand Up @@ -99,5 +105,39 @@ private void StartWithOptions(Options options)
Environment.Exit(1);
}
}

if (options.DisallowUser)
{
if (options.Username != null)
{
if (!this._server.DisallowUser(options.Username))
{
Console.WriteLine("User is already disallowed");
Environment.Exit(1);
}
}
else
{
Console.WriteLine("No user was provided, cannot continue.");
Environment.Exit(1);
}
}

if (options.ReallowUser)
{
if (options.Username != null)
{
if (!this._server.ReallowUser(options.Username))
{
Console.WriteLine("User is already allowed");
Environment.Exit(1);
}
}
else
{
Console.WriteLine("No user was provided, cannot continue.");
Environment.Exit(1);
}
}
}
}
35 changes: 35 additions & 0 deletions Refresh.GameServer/Database/GameDatabaseContext.Registration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,39 @@ public void RemoveEmailVerificationCode(EmailVerificationCode code)
this._realm.Remove(code);
});
}

public bool DisallowUser(string username)
{
if (this._realm.Find<DisallowedUser>(username) != null)
return false;

this._realm.Write(() =>
{
this._realm.Add(new DisallowedUser
{
Username = username,
});
});

return true;
}

public bool ReallowUser(string username)
{
DisallowedUser? disallowedUser = this._realm.Find<DisallowedUser>(username);
if (disallowedUser == null)
return false;

this._realm.Write(() =>
{
this._realm.Remove(disallowedUser);
});

return true;
}

public bool IsUserDisallowed(string username)
{
return this._realm.Find<DisallowedUser>(username) != null;
}
}
3 changes: 2 additions & 1 deletion Refresh.GameServer/Database/GameDatabaseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ protected GameDatabaseProvider(IDateTimeProvider time)
this._time = time;
}

protected override ulong SchemaVersion => 117;
protected override ulong SchemaVersion => 118;

protected override string Filename => "refreshGameServer.realm";

Expand Down Expand Up @@ -74,6 +74,7 @@ protected GameDatabaseProvider(IDateTimeProvider time)
typeof(ScreenRect),
typeof(Slot),
typeof(GameReview),
typeof(DisallowedUser)
};

public override void Warmup()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ public ApiResponse<IApiAuthenticationResponse> Register(RequestContext context,
if (!CommonPatterns.EmailAddressRegex().IsMatch(body.EmailAddress))
return new ApiValidationError("The email address given is invalid.");

if (database.IsUserDisallowed(body.Username))
return new ApiAuthenticationError("This username is disallowed from being registered.");

if (database.IsUsernameTaken(body.Username) || database.IsEmailTaken(body.EmailAddress))
{
return new ApiAuthenticationError(
Expand Down
14 changes: 14 additions & 0 deletions Refresh.GameServer/RefreshGameServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,20 @@ public void SetAdminFromEmailAddress(string emailAddress)

context.SetUserRole(user, GameUserRole.Admin);
}

public bool DisallowUser(string username)
{
using GameDatabaseContext context = this.GetContext();

return context.DisallowUser(username);
}

public bool ReallowUser(string username)
{
using GameDatabaseContext context = this.GetContext();

return context.ReallowUser(username);
}

public override void Dispose()
{
Expand Down
9 changes: 9 additions & 0 deletions Refresh.GameServer/Types/UserData/DisallowedUser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Realms;

namespace Refresh.GameServer.Types.UserData;

public partial class DisallowedUser : IRealmObject
{
[PrimaryKey]
public string Username { get; set; }

Check warning on line 8 in Refresh.GameServer/Types/UserData/DisallowedUser.cs

View workflow job for this annotation

GitHub Actions / Build, Test, and Upload Builds

Non-nullable property 'Username' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 8 in Refresh.GameServer/Types/UserData/DisallowedUser.cs

View workflow job for this annotation

GitHub Actions / Build, Test, and Upload Builds

Non-nullable property 'Username' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}
43 changes: 43 additions & 0 deletions RefreshTests.GameServer/Tests/ApiV3/UserApiTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Refresh.GameServer.Authentication;
using Refresh.GameServer.Endpoints.ApiV3.ApiTypes;
using Refresh.GameServer.Endpoints.ApiV3.ApiTypes.Errors;
using Refresh.GameServer.Endpoints.ApiV3.DataTypes.Request.Authentication;
using Refresh.GameServer.Endpoints.ApiV3.DataTypes.Response;
using Refresh.GameServer.Types.UserData;
using RefreshTests.GameServer.Extensions;
Expand All @@ -22,6 +23,48 @@ public void GetsUserByUsername()
Assert.That(response, Is.Not.Null);
response!.AssertErrorIsEqual(ApiNotFoundError.UserMissingError);
}

[Test]
public void RegisterAccount()
{
using TestContext context = this.GetServer();

const string username = "a_lil_guy";

ApiResponse<ApiAuthenticationResponse>? response = context.Http.PostData<ApiAuthenticationResponse>("/api/v3/register", new ApiRegisterRequest
{
Username = username,
EmailAddress = "[email protected]",
PasswordSha512 = "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff",
});
Assert.That(response, Is.Not.EqualTo(null));

context.Database.Refresh();
Assert.That(context.Database.GetUserByUsername(username), Is.Not.EqualTo(null));
}

[Test]
public void CannotRegisterAccountWithDisallowedUsername()
{
using TestContext context = this.GetServer();

const string username = "a_lil_guy";

context.Database.DisallowUser(username);

ApiResponse<ApiAuthenticationResponse>? response = context.Http.PostData<ApiAuthenticationResponse>("/api/v3/register", new ApiRegisterRequest
{
Username = username,
EmailAddress = "[email protected]",
PasswordSha512 = "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff",
});
Assert.That(response, Is.Not.EqualTo(null));
Assert.That(response.Error, Is.Not.EqualTo(null));
Assert.That(response.Error.Name, Is.EqualTo("ApiAuthenticationError"));

context.Database.Refresh();
Assert.That(context.Database.GetUserByUsername(username), Is.EqualTo(null));
}

[Test]
public void GetsUserByUuid()
Expand Down
Loading