forked from collabvm/CollabVMAuthServer
- add mechanism for database upgrades
- add ban reason - add api endpoints for banning - moderators can now list users/bots, and perform basic updates
This commit is contained in:
parent
7e7d9f6e92
commit
130baa8863
15 changed files with 365 additions and 27 deletions
|
@ -8,6 +8,7 @@
|
|||
<PublishAot>false</PublishAot>
|
||||
<RootNamespace>Computernewb.CollabVMAuthServer</RootNamespace>
|
||||
<Company>Computernewb Development Team</Company>
|
||||
<AssemblyVersion>1.1</AssemblyVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -37,6 +37,7 @@ public class Database
|
|||
password_reset_code CHAR(8) DEFAULT NULL,
|
||||
cvm_rank INT UNSIGNED NOT NULL DEFAULT 1,
|
||||
banned BOOLEAN NOT NULL DEFAULT 0,
|
||||
ban_reason TEXT DEFAULT NULL,
|
||||
registration_ip VARBINARY(16) NOT NULL,
|
||||
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
developer BOOLEAN NOT NULL DEFAULT 0
|
||||
|
@ -76,6 +77,13 @@ public class Database
|
|||
)
|
||||
""";
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
cmd.CommandText = """
|
||||
CREATE TABLE IF NOT EXISTS meta (
|
||||
setting VARCHAR(20) NOT NULL PRIMARY KEY,
|
||||
val TEXT NOT NULL
|
||||
)
|
||||
""";
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
|
||||
public async Task<User?> GetUser(string? username = null, string? email = null)
|
||||
|
@ -110,6 +118,7 @@ public class Database
|
|||
PasswordResetCode = reader.IsDBNull("password_reset_code") ? null : reader.GetString("password_reset_code"),
|
||||
Rank = (Rank)reader.GetUInt32("cvm_rank"),
|
||||
Banned = reader.GetBoolean("banned"),
|
||||
BanReason = reader.IsDBNull("ban_reason") ? null : reader.GetString("ban_reason"),
|
||||
RegistrationIP = new IPAddress(reader.GetFieldValue<byte[]>("registration_ip")),
|
||||
Joined = reader.GetDateTime("created"),
|
||||
Developer = reader.GetBoolean("developer")
|
||||
|
@ -363,6 +372,7 @@ public class Database
|
|||
PasswordResetCode = reader.IsDBNull("password_reset_code") ? null : reader.GetString("password_reset_code"),
|
||||
Rank = (Rank)reader.GetUInt32("cvm_rank"),
|
||||
Banned = reader.GetBoolean("banned"),
|
||||
BanReason = reader.IsDBNull("ban_reason") ? null : reader.GetString("ban_reason"),
|
||||
RegistrationIP = new IPAddress(reader.GetFieldValue<byte[]>("registration_ip")),
|
||||
Joined = reader.GetDateTime("created"),
|
||||
Developer = reader.GetBoolean("developer")
|
||||
|
@ -478,4 +488,63 @@ public class Database
|
|||
Created = reader.GetDateTime("created")
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<int> GetDatabaseVersion()
|
||||
{
|
||||
await using var db = new MySqlConnection(connectionString);
|
||||
await db.OpenAsync();
|
||||
await using var cmd = db.CreateCommand();
|
||||
// If `users` table doesn't exist, return -1. This is hacky but I don't know of a better way
|
||||
cmd.CommandText = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'users'";
|
||||
if ((long)(await cmd.ExecuteScalarAsync() ?? 0) == 0)
|
||||
return -1;
|
||||
// If `meta` table doesn't exist, assume version 0
|
||||
cmd.CommandText = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'meta'";
|
||||
if ((long)(await cmd.ExecuteScalarAsync() ?? 0) == 0)
|
||||
return 0;
|
||||
cmd.CommandText = "SELECT val FROM meta WHERE setting = 'db_version'";
|
||||
await using var reader = await cmd.ExecuteReaderAsync();
|
||||
await reader.ReadAsync();
|
||||
return int.Parse(reader.GetString("val"));
|
||||
}
|
||||
|
||||
public async Task SetDatabaseVersion(int version)
|
||||
{
|
||||
await using var db = new MySqlConnection(connectionString);
|
||||
await db.OpenAsync();
|
||||
await using var cmd = db.CreateCommand();
|
||||
cmd.CommandText = "INSERT INTO meta (setting, val) VALUES ('db_version', @version) ON DUPLICATE KEY UPDATE val = @version";
|
||||
cmd.Parameters.AddWithValue("@version", version.ToString());
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
|
||||
public async Task ExecuteNonQuery(string query)
|
||||
{
|
||||
await using var db = new MySqlConnection(connectionString);
|
||||
await db.OpenAsync();
|
||||
await using var cmd = db.CreateCommand();
|
||||
cmd.CommandText = query;
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
|
||||
public async Task SetBanned(string username, bool banned, string? reason)
|
||||
{
|
||||
await using var db = new MySqlConnection(connectionString);
|
||||
await db.OpenAsync();
|
||||
await using var cmd = db.CreateCommand();
|
||||
cmd.CommandText = "UPDATE users SET banned = @banned, ban_reason = @reason WHERE username = @username";
|
||||
cmd.Parameters.AddWithValue("@banned", banned);
|
||||
cmd.Parameters.AddWithValue("@reason", reason);
|
||||
cmd.Parameters.AddWithValue("@username", username);
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
|
||||
public async Task<long> CountUsers()
|
||||
{
|
||||
await using var db = new MySqlConnection(connectionString);
|
||||
await db.OpenAsync();
|
||||
await using var cmd = db.CreateCommand();
|
||||
cmd.CommandText = "SELECT COUNT(*) FROM users";
|
||||
return (long)await cmd.ExecuteScalarAsync();
|
||||
}
|
||||
}
|
33
CollabVMAuthServer/DatabaseUpdate.cs
Normal file
33
CollabVMAuthServer/DatabaseUpdate.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Computernewb.CollabVMAuthServer;
|
||||
|
||||
public static class DatabaseUpdate
|
||||
{
|
||||
public const int CurrentVersion = 1;
|
||||
|
||||
private static ReadOnlyDictionary<int, Func<Database, Task>> Updates = new Dictionary<int, Func<Database, Task>>()
|
||||
{
|
||||
{ 1, async db =>
|
||||
{
|
||||
// Update to version 1
|
||||
// Add ban_reason column to users table
|
||||
await db.ExecuteNonQuery("ALTER TABLE users ADD COLUMN ban_reason TEXT DEFAULT NULL");
|
||||
}},
|
||||
}.AsReadOnly();
|
||||
|
||||
public async static Task Update(Database db)
|
||||
{
|
||||
var version = await db.GetDatabaseVersion();
|
||||
if (version == -1) throw new InvalidOperationException("Uninitialized database cannot be updated");
|
||||
if (version == CurrentVersion) return;
|
||||
if (version > CurrentVersion) throw new InvalidOperationException("Database version is newer than the server supports");
|
||||
Utilities.Log(LogLevel.INFO, $"Updating database from version {version} to {CurrentVersion}");
|
||||
for (int i = version + 1; i <= CurrentVersion; i++)
|
||||
{
|
||||
if (!Updates.TryGetValue(i, out var update)) throw new InvalidOperationException($"No update available for version {i}");
|
||||
await update(db);
|
||||
}
|
||||
await db.SetDatabaseVersion(CurrentVersion);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using Computernewb.CollabVMAuthServer.HTTP.Payloads;
|
||||
using Computernewb.CollabVMAuthServer.HTTP.Responses;
|
||||
|
@ -11,6 +12,160 @@ public static class AdminRoutes
|
|||
app.MapPost("/api/v1/admin/users", (Delegate)HandleAdminUsers);
|
||||
app.MapPost("/api/v1/admin/updateuser", (Delegate)HandleAdminUpdateUser);
|
||||
app.MapPost("/api/v1/admin/updatebot", (Delegate)HandleAdminUpdateBot);
|
||||
app.MapPost("/api/v1/admin/ban", (Delegate)HandleBanUser);
|
||||
app.MapPost("/api/v1/admin/ipban", (Delegate)HandleIPBan);
|
||||
}
|
||||
|
||||
private static async Task<IResult> HandleIPBan(HttpContext context)
|
||||
{
|
||||
// Check payload
|
||||
if (context.Request.ContentType != "application/json")
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
return Results.Json(new IPBanResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Invalid request body"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
IPBanPayload? payload;
|
||||
try
|
||||
{
|
||||
payload = await context.Request.ReadFromJsonAsync<IPBanPayload>();
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
Utilities.Log(LogLevel.DEBUG, $"Failed to parse JSON: {ex.Message}");
|
||||
context.Response.StatusCode = 400;
|
||||
return Results.Json(new IPBanResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Invalid request body"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
if (payload == null || string.IsNullOrWhiteSpace(payload.session) || string.IsNullOrWhiteSpace(payload.ip) || (payload.banned && string.IsNullOrWhiteSpace(payload.reason)) || payload.banned == null || !IPAddress.TryParse(payload.ip, out var ip))
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
return Results.Json(new IPBanResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Invalid request body"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Check token
|
||||
var session = await Program.Database.GetSession(payload.session);
|
||||
if (session == null || Utilities.IsSessionExpired(session))
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
return Results.Json(new IPBanResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Invalid session"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Check rank
|
||||
var user = await Program.Database.GetUser(session.Username)
|
||||
?? throw new Exception("Could not lookup user from session");
|
||||
if (user.Rank != Rank.Admin && user.Rank != Rank.Moderator)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
return Results.Json(new IPBanResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Insufficient permissions"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Set ban
|
||||
if (payload.banned)
|
||||
{
|
||||
await Program.Database.BanIP(ip, payload.reason, user.Username);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Program.Database.UnbanIP(ip);
|
||||
}
|
||||
return Results.Json(new IPBanResponse
|
||||
{
|
||||
success = true
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
|
||||
private static async Task<IResult> HandleBanUser(HttpContext context)
|
||||
{
|
||||
// Check payload
|
||||
if (context.Request.ContentType != "application/json")
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
return Results.Json(new BanUserResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Invalid request body"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
BanUserPayload? payload;
|
||||
try
|
||||
{
|
||||
payload = await context.Request.ReadFromJsonAsync<BanUserPayload>();
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
Utilities.Log(LogLevel.DEBUG, $"Failed to parse JSON: {ex.Message}");
|
||||
context.Response.StatusCode = 400;
|
||||
return Results.Json(new BanUserResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Invalid request body"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
if (payload == null || string.IsNullOrWhiteSpace(payload.token) || string.IsNullOrWhiteSpace(payload.username) || (payload.banned && string.IsNullOrWhiteSpace(payload.reason)) || payload.banned == null)
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
return Results.Json(new BanUserResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Invalid request body"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Check token
|
||||
var session = await Program.Database.GetSession(payload.token);
|
||||
if (session == null || Utilities.IsSessionExpired(session))
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
return Results.Json(new BanUserResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Invalid session"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Check rank
|
||||
var user = await Program.Database.GetUser(session.Username)
|
||||
?? throw new Exception("Could not lookup user from session");
|
||||
if (user.Rank != Rank.Admin && user.Rank != Rank.Moderator)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
return Results.Json(new BanUserResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Insufficient permissions"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Check target user
|
||||
var targetUser = await Program.Database.GetUser(payload.username);
|
||||
if (targetUser == null)
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
return Results.Json(new BanUserResponse
|
||||
{
|
||||
success = false,
|
||||
error = "User not found"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Set ban
|
||||
await Program.Database.SetBanned(targetUser.Username, payload.banned, payload.banned ? payload.reason : null);
|
||||
return Results.Json(new BanUserResponse
|
||||
{
|
||||
success = true
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
|
||||
private static async Task<IResult> HandleAdminUpdateBot(HttpContext context)
|
||||
|
@ -63,7 +218,7 @@ public static class AdminRoutes
|
|||
// Check rank
|
||||
var user = await Program.Database.GetUser(session.Username)
|
||||
?? throw new Exception("Could not lookup user from session");
|
||||
if (user.Rank != Rank.Admin)
|
||||
if (user.Rank != Rank.Admin && user.Rank != Rank.Moderator)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
return Results.Json(new AdminUsersResponse
|
||||
|
@ -93,6 +248,25 @@ public static class AdminRoutes
|
|||
error = "No fields to update"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Moderators cannot promote bots to admin, and can only promote their own bots to moderator
|
||||
else if ((Rank)payload.rank == Rank.Admin && user.Rank == Rank.Moderator)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
return Results.Json(new AdminUpdateBotResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Insufficient permissions"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
if (targetBot.Owner != user.Username && user.Rank == Rank.Moderator)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
return Results.Json(new AdminUpdateBotResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Insufficient permissions"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Check rank
|
||||
int? rank = payload.rank;
|
||||
if (rank != null && rank < 1 || rank > 3)
|
||||
|
@ -193,6 +367,16 @@ public static class AdminRoutes
|
|||
error = "Invalid rank"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Moderators cannot change ranks
|
||||
if (user.Rank == Rank.Moderator && rank != null)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
return Results.Json(new AdminUpdateUserResponse
|
||||
{
|
||||
success = false,
|
||||
error = "Insufficient permissions"
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Check developer
|
||||
bool? developer = payload.developer;
|
||||
// Update rank
|
||||
|
@ -257,7 +441,7 @@ public static class AdminRoutes
|
|||
// Check rank
|
||||
var user = await Program.Database.GetUser(session.Username)
|
||||
?? throw new Exception("Could not lookup user from session");
|
||||
if (user.Rank != Rank.Admin)
|
||||
if (user.Rank != Rank.Admin && user.Rank != Rank.Moderator)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
return Results.Json(new AdminUsersResponse
|
||||
|
@ -293,6 +477,7 @@ public static class AdminRoutes
|
|||
email = user.Email,
|
||||
rank = (int)user.Rank,
|
||||
banned = user.Banned,
|
||||
banReason = user.BanReason ?? "",
|
||||
dateOfBirth = user.DateOfBirth.ToString("yyyy-MM-dd"),
|
||||
dateJoined = user.Joined.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||
registrationIp = user.RegistrationIP.ToString(),
|
||||
|
|
|
@ -63,7 +63,7 @@ public static class DeveloperRoutes
|
|||
// Check developer status
|
||||
var user = await Program.Database.GetUser(session.Username) ??
|
||||
throw new Exception("Unable to get user from session");
|
||||
if (!user.Developer && user.Rank != Rank.Admin)
|
||||
if (!user.Developer && user.Rank != Rank.Admin && user.Rank != Rank.Moderator)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
return Results.Json(new CreateBotResponse
|
||||
|
@ -72,8 +72,8 @@ public static class DeveloperRoutes
|
|||
error = "You must be an approved developer to create and manage bots."
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// owner can only be specified by admins
|
||||
if (payload.owner != null && user.Rank != Rank.Admin)
|
||||
// owner can only be specified by admins and moderators
|
||||
if (payload.owner != null && user.Rank != Rank.Admin && user.Rank != Rank.Moderator)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
return Results.Json(new ListBotsResponse
|
||||
|
@ -84,7 +84,7 @@ public static class DeveloperRoutes
|
|||
}
|
||||
// Get bots
|
||||
// If the user is not an admin, they can only see their own bots
|
||||
var bots = (await Program.Database.ListBots(payload.owner ?? (user.Rank == Rank.Admin ? null : user.Username))).Select(bot => new ListBot
|
||||
var bots = (await Program.Database.ListBots(payload.owner ?? ((user.Rank == Rank.Admin || user.Rank == Rank.Moderator) ? null : user.Username))).Select(bot => new ListBot
|
||||
{
|
||||
id = (int)bot.Id,
|
||||
username = bot.Username,
|
||||
|
|
9
CollabVMAuthServer/HTTP/Payloads/BanUserPayload.cs
Normal file
9
CollabVMAuthServer/HTTP/Payloads/BanUserPayload.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Computernewb.CollabVMAuthServer.HTTP.Payloads;
|
||||
|
||||
public class BanUserPayload
|
||||
{
|
||||
public string token { get; set; }
|
||||
public string username { get; set; }
|
||||
public bool banned { get; set; }
|
||||
public string reason { get; set; }
|
||||
}
|
9
CollabVMAuthServer/HTTP/Payloads/IPBanPayload.cs
Normal file
9
CollabVMAuthServer/HTTP/Payloads/IPBanPayload.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Computernewb.CollabVMAuthServer.HTTP.Payloads;
|
||||
|
||||
public class IPBanPayload
|
||||
{
|
||||
public string session { get; set; }
|
||||
public string ip { get; set; }
|
||||
public bool banned { get; set; }
|
||||
public string reason { get; set; }
|
||||
}
|
|
@ -15,6 +15,7 @@ public class AdminUser
|
|||
public string email { get; set; }
|
||||
public int rank { get; set; }
|
||||
public bool banned { get; set; }
|
||||
public string banReason { get; set; }
|
||||
public string dateOfBirth { get; set; }
|
||||
public string dateJoined { get; set; }
|
||||
public string registrationIp { get; set; }
|
||||
|
|
7
CollabVMAuthServer/HTTP/Responses/BanUserResponse.cs
Normal file
7
CollabVMAuthServer/HTTP/Responses/BanUserResponse.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Computernewb.CollabVMAuthServer.HTTP.Responses;
|
||||
|
||||
public class BanUserResponse
|
||||
{
|
||||
public bool success { get; set; }
|
||||
public string? error { get; set; }
|
||||
}
|
7
CollabVMAuthServer/HTTP/Responses/IPBanResponse.cs
Normal file
7
CollabVMAuthServer/HTTP/Responses/IPBanResponse.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Computernewb.CollabVMAuthServer.HTTP.Responses;
|
||||
|
||||
public class IPBanResponse
|
||||
{
|
||||
public bool success { get; set; }
|
||||
public string? error { get; set; }
|
||||
}
|
|
@ -4,6 +4,8 @@ public class JoinResponse
|
|||
{
|
||||
public bool success { get; set; }
|
||||
public bool clientSuccess { get; set; } = false;
|
||||
public bool? banned { get; set; } = null;
|
||||
public string? banReason { get; set; }
|
||||
public string? error { get; set; }
|
||||
public string? username { get; set; }
|
||||
public Rank? rank { get; set; }
|
||||
|
|
|
@ -556,7 +556,9 @@ public static class Routes
|
|||
{
|
||||
success = true,
|
||||
clientSuccess = false,
|
||||
error = "You are banned"
|
||||
error = "Banned",
|
||||
banned = true,
|
||||
banReason = ban.Reason
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Check if session is valid
|
||||
|
@ -592,7 +594,9 @@ public static class Routes
|
|||
{
|
||||
success = true,
|
||||
clientSuccess = false,
|
||||
error = "You are banned",
|
||||
banned = true,
|
||||
error = "Banned",
|
||||
banReason = user.BanReason
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// Update session
|
||||
|
@ -1026,33 +1030,29 @@ public static class Routes
|
|||
});
|
||||
}
|
||||
// Create the account
|
||||
string? token = null;
|
||||
if (Program.Config.Registration.EmailVerificationRequired)
|
||||
{
|
||||
var code = Program.Random.Next(10000000, 99999999).ToString();
|
||||
await Program.Database.RegisterAccount(payload.username, payload.email, dob, payload.password, false, ip,code);
|
||||
await Program.Mailer.SendVerificationCode(payload.username, payload.email, code);
|
||||
return Results.Json(new RegisterResponse
|
||||
{
|
||||
success = true,
|
||||
verificationRequired = true,
|
||||
email = payload.email,
|
||||
username = payload.username
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Program.Database.RegisterAccount(payload.username, payload.email, dob, payload.password, true, ip, null);
|
||||
var token = Utilities.RandomString(32);
|
||||
token = Utilities.RandomString(32);
|
||||
await Program.Database.CreateSession(payload.username, token, ip);
|
||||
return Results.Json(new RegisterResponse
|
||||
{
|
||||
success = true,
|
||||
verificationRequired = false,
|
||||
email = payload.email,
|
||||
username = payload.username,
|
||||
sessionToken = token
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
// If this is the first user, make them an admin
|
||||
if (await Program.Database.CountUsers() == 1) await Program.Database.UpdateUser(payload.username, newRank: (int)Rank.Admin);
|
||||
return Results.Json(new RegisterResponse
|
||||
{
|
||||
success = true,
|
||||
verificationRequired = Program.Config.Registration.EmailVerificationRequired,
|
||||
email = payload.email,
|
||||
username = payload.username,
|
||||
sessionToken = token
|
||||
}, Utilities.JsonSerializerOptions);
|
||||
}
|
||||
|
||||
private static IResult HandleInfo(HttpContext context)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Net;
|
||||
using System.Reflection;
|
||||
using Computernewb.CollabVMAuthServer.HTTP;
|
||||
using Tomlet;
|
||||
|
||||
|
@ -14,7 +15,8 @@ public class Program
|
|||
public static readonly Random Random = new Random();
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
Utilities.Log(LogLevel.INFO, "CollabVM Authentication Server starting up");
|
||||
var ver = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
Utilities.Log(LogLevel.INFO, $"CollabVM Authentication Server v{ver.Major}.{ver.Minor}.{ver.Revision} starting up");
|
||||
// Read config.toml
|
||||
string configraw;
|
||||
try
|
||||
|
@ -39,8 +41,20 @@ public class Program
|
|||
}
|
||||
// Initialize database
|
||||
Database = new Database(Config.MySQL);
|
||||
await Database.Init();
|
||||
// Get version before initializing
|
||||
int dbversion = await Database.GetDatabaseVersion();
|
||||
Utilities.Log(LogLevel.INFO, "Connected to database");
|
||||
Utilities.Log(LogLevel.INFO, dbversion == -1 ? "Initializing tables..." : $"Database version: {dbversion}");
|
||||
await Database.Init();
|
||||
// If database was version 0, that should now be set, as versioning did not exist then
|
||||
if (dbversion == 0) await Database.SetDatabaseVersion(0);
|
||||
// If database was -1, that means it was just initialized and we should set it to the current version
|
||||
if (dbversion == -1) await Database.SetDatabaseVersion(DatabaseUpdate.CurrentVersion);
|
||||
// Perform any necessary database updates
|
||||
await DatabaseUpdate.Update(Database);
|
||||
var uc = await Database.CountUsers();
|
||||
Utilities.Log(LogLevel.INFO, $"{uc} users in database");
|
||||
if (uc == 0) Utilities.Log(LogLevel.WARN, "No users in database, first user will be promoted to admin");
|
||||
// Create mailer
|
||||
if (!Config.SMTP.Enabled && Config.Registration.EmailVerificationRequired)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ public class User
|
|||
public string? PasswordResetCode { get; set; }
|
||||
public Rank Rank { get; set; }
|
||||
public bool Banned { get; set; }
|
||||
public string? BanReason { get; set; }
|
||||
public IPAddress RegistrationIP { get; set; }
|
||||
public DateTime Joined { get; set; }
|
||||
public bool Developer { get; set; }
|
||||
|
|
|
@ -63,7 +63,7 @@ public static class Utilities
|
|||
case LogLevel.WARN:
|
||||
case LogLevel.ERROR:
|
||||
case LogLevel.FATAL:
|
||||
Console.Error.Write(logstr.ToString());
|
||||
Console.Error.WriteLine(logstr.ToString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue