diff --git a/CollabVMAuthServer/Cron.cs b/CollabVMAuthServer/Cron.cs new file mode 100644 index 0000000..a006b80 --- /dev/null +++ b/CollabVMAuthServer/Cron.cs @@ -0,0 +1,58 @@ +using Timer = System.Timers.Timer; + +namespace Computernewb.CollabVMAuthServer; + +public static class Cron +{ + private static Timer timer = new Timer(); + + public static async Task Start() + { + #if DEBUG + timer.Interval = 1000 * 60; // 60 seconds + #else + timer.Interval = 1000 * 60 * 10; // 10 minutes + #endif + timer.Elapsed += async (sender, e) => await RunAll(); + await RunAll(); + timer.Start(); + } + + public static void Stop() + { + timer.Stop(); + timer.Interval = 1000 * 60 * 10; + } + + public static async Task RunAll() + { + Utilities.Log(LogLevel.INFO, "Running all cron jobs"); + var t = new List(); + t.Add(PurgeOldSessions()); + if (Program.Config.Registration.EmailVerificationRequired) t.Add(ExpireAccounts()); + await Task.WhenAll(t); + Utilities.Log(LogLevel.INFO, "Finished running all cron jobs"); + } + // Expire unverified accounts after 2 days. Don't purge if the code is null + public static async Task ExpireAccounts() + { + Utilities.Log(LogLevel.INFO, "Purging unverified accounts"); + var minDate = DateTime.UtcNow - TimeSpan.FromDays(2); + int a = await Program.Database.ExecuteNonQuery("DELETE FROM users WHERE email_verified = 0 AND created < @minDate AND email_verification_code IS NOT NULL", + [ + new KeyValuePair("minDate", minDate) + ]); + Utilities.Log(LogLevel.INFO, $"Purged {a} unverified accounts"); + } + + public static async Task PurgeOldSessions() + { + Utilities.Log(LogLevel.INFO, "Purging old sessions"); + var expiryDate = DateTime.UtcNow - TimeSpan.FromDays(Program.Config.Accounts.SessionExpiryDays); + int a = await Program.Database.ExecuteNonQuery("DELETE FROM sessions WHERE last_used < @expiryDate", + [ + new KeyValuePair("expiryDate", expiryDate) + ]); + Utilities.Log(LogLevel.INFO, $"Purged {a} old sessions"); + } +} \ No newline at end of file diff --git a/CollabVMAuthServer/Database.cs b/CollabVMAuthServer/Database.cs index 04b8e5d..d2a3629 100644 --- a/CollabVMAuthServer/Database.cs +++ b/CollabVMAuthServer/Database.cs @@ -518,13 +518,17 @@ public class Database await cmd.ExecuteNonQueryAsync(); } - public async Task ExecuteNonQuery(string query) + public async Task ExecuteNonQuery(string query, KeyValuePair[]? parameters = null) { await using var db = new MySqlConnection(connectionString); await db.OpenAsync(); await using var cmd = db.CreateCommand(); cmd.CommandText = query; - await cmd.ExecuteNonQueryAsync(); + if (parameters != null) foreach (KeyValuePair param in parameters) + { + cmd.Parameters.AddWithValue(param.Key, param.Value); + } + return await cmd.ExecuteNonQueryAsync(); } public async Task SetBanned(string username, bool banned, string? reason) diff --git a/CollabVMAuthServer/HTTP/Routes.cs b/CollabVMAuthServer/HTTP/Routes.cs index 9661329..edc7b58 100644 --- a/CollabVMAuthServer/HTTP/Routes.cs +++ b/CollabVMAuthServer/HTTP/Routes.cs @@ -25,6 +25,15 @@ public static class Routes private static async Task HandleSendReset(HttpContext context) { + if (!Program.Config.SMTP.Enabled) + { + context.Response.StatusCode = 400; + return Results.Json(new SendResetEmailResponse + { + success = false, + error = "Password reset is not supported by this server. Please contact an administrator." + }, Utilities.JsonSerializerOptions); + } // Check payload if (context.Request.ContentType != "application/json") { diff --git a/CollabVMAuthServer/Program.cs b/CollabVMAuthServer/Program.cs index 91e4e04..f57f512 100644 --- a/CollabVMAuthServer/Program.cs +++ b/CollabVMAuthServer/Program.cs @@ -55,6 +55,8 @@ public class Program 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"); + // Init cron + await Cron.Start(); // Create mailer if (!Config.SMTP.Enabled && Config.Registration.EmailVerificationRequired) {