From 9d3bbdb86c3cb1e4a8759e52059835de356f5bcd Mon Sep 17 00:00:00 2001
From: Celeste <130874118+celestebyte@users.noreply.github.com>
Date: Sat, 13 Jul 2024 12:58:52 -0600
Subject: [PATCH] Ban user functionality (#101)
* Add ban functionality
Add properties to set BanDuration on update user and BannedUtil to verify the datetime of the ban applied to the user. Updated the projects from .Net7 to .Net8 (LTS).
* Fix indentation type.
---
Gotrue/User.cs | 16 ++++++++++++++++
GotrueExample/GotrueExample.csproj | 2 +-
GotrueTests/GotrueTests.csproj | 2 +-
GotrueTests/ServiceRoleTests.cs | 24 ++++++++++++++++++++++++
GotrueTests/TestUtils.cs | 11 +++++++++++
5 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/Gotrue/User.cs b/Gotrue/User.cs
index 023fd2ca..a6f24546 100644
--- a/Gotrue/User.cs
+++ b/Gotrue/User.cs
@@ -61,6 +61,9 @@ public class User
[JsonProperty("updated_at")]
public DateTime? UpdatedAt { get; set; }
+ [JsonProperty("banned_until")]
+ public DateTime? BannedUntil { get; set; }
+
[JsonProperty("is_anonymous")]
public bool IsAnonymous { get; set; }
@@ -103,6 +106,19 @@ public class AdminUserAttributes : UserAttributes
///
[JsonProperty("phone_confirm")]
public bool? PhoneConfirm { get; set; }
+
+ ///
+ /// Determines how long a user is banned for.
+ /// This property is ignored when creating a user.
+ /// If you want to create a user banned, first create the user then update it sending this property.
+ /// The format for the ban duration follows a strict sequence of decimal numbers with a unit suffix.
+ /// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
+ /// For example, some possible durations include: '300ms', '2h45m', '1200s'.
+ /// Setting the ban duration to "none" lifts the ban on the user.
+ /// Only a service role can modify.
+ ///
+ [JsonProperty("ban_duration")]
+ public string? BanDuration { get; set; }
}
///
diff --git a/GotrueExample/GotrueExample.csproj b/GotrueExample/GotrueExample.csproj
index 7436345c..b43c349e 100644
--- a/GotrueExample/GotrueExample.csproj
+++ b/GotrueExample/GotrueExample.csproj
@@ -2,7 +2,7 @@
Exe
- net7.0
+ net8.0
diff --git a/GotrueTests/GotrueTests.csproj b/GotrueTests/GotrueTests.csproj
index d965618e..381f7049 100644
--- a/GotrueTests/GotrueTests.csproj
+++ b/GotrueTests/GotrueTests.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net8.0
false
diff --git a/GotrueTests/ServiceRoleTests.cs b/GotrueTests/ServiceRoleTests.cs
index 6973e49c..4c0b8ca7 100644
--- a/GotrueTests/ServiceRoleTests.cs
+++ b/GotrueTests/ServiceRoleTests.cs
@@ -140,6 +140,30 @@ public async Task UpdateUserById()
AreNotEqual(createdUser.Email, updatedUser.Email);
}
+ [TestMethod("Service Role: Ban User by Id")]
+ public async Task BanUserById()
+ {
+ var createdUser = await _client.CreateUser($"{RandomString(12)}@supabase.io", PASSWORD);
+
+ IsNotNull(createdUser);
+
+ int banDurationSeconds = RandomNumber();
+ DateTime bannedUntil = DateTime.UtcNow + TimeSpan.FromSeconds(banDurationSeconds);
+ var updatedUser = await _client.UpdateUserById(createdUser.Id ?? throw new InvalidOperationException(), new AdminUserAttributes { BanDuration = $"{banDurationSeconds}s" });
+
+ IsNotNull(updatedUser);
+
+ AreEqual(createdUser.Id, updatedUser.Id);
+ IsNotNull(updatedUser.BannedUntil);
+ IsTrue((updatedUser.BannedUntil.Value - bannedUntil).Duration().TotalSeconds < 1);
+
+ updatedUser = await _client.UpdateUserById(createdUser.Id ?? throw new InvalidOperationException(), new AdminUserAttributes { BanDuration = "none" });
+ IsNotNull(updatedUser);
+
+ AreEqual(createdUser.Id, updatedUser.Id);
+ IsFalse(updatedUser.BannedUntil.HasValue);
+ }
+
[TestMethod("Service Role: Delete User")]
public async Task DeletesUser()
{
diff --git a/GotrueTests/TestUtils.cs b/GotrueTests/TestUtils.cs
index d155edf1..f1b40dbd 100644
--- a/GotrueTests/TestUtils.cs
+++ b/GotrueTests/TestUtils.cs
@@ -35,6 +35,17 @@ public static string GetRandomPhoneNumber()
return $"+1{inner}";
}
+ ///
+ /// Returns a random number within the limits specified via parameters.
+ ///
+ /// Minimum value. Default 0.
+ /// Maximum value. Default 1000.
+ /// Integer within the range.
+ public static int RandomNumber(int minValue = 0, int maxValue = 1000)
+ {
+ return Random.Next(minValue, maxValue);
+ }
+
public static string GenerateServiceRoleToken()
{
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("37c304f8-51aa-419a-a1af-06154e63707a")); // using GOTRUE_JWT_SECRET