diff --git a/Projects/UOContent/Accounting/AccountHandler.cs b/Projects/UOContent/Accounting/AccountHandler.cs index 642660d05..583091ed7 100644 --- a/Projects/UOContent/Accounting/AccountHandler.cs +++ b/Projects/UOContent/Accounting/AccountHandler.cs @@ -241,13 +241,15 @@ namespace Server.Misc { res = DeleteResultType.CharBeingPlayed; } - else if (RestrictDeletion && Core.Now < m.Created + DeleteDelay) + else if (acct.AccessLevel == AccessLevel.Player && RestrictDeletion && Core.Now < m.Created + DeleteDelay) { res = DeleteResultType.CharTooYoung; } - else if (m.AccessLevel == AccessLevel.Player && + // Don't need to check current location, if netstate is null, they're logged out + else if ( + m.AccessLevel == AccessLevel.Player && Region.Find(m.LogoutLocation, m.LogoutMap).IsPartOf() - ) // Don't need to check current location, if netstate is null, they're logged out + ) { res = DeleteResultType.BadRequest; } @@ -265,7 +267,6 @@ namespace Server.Misc state.SendCharacterDeleteResult(res); state.SendCharacterListUpdate(acct); - } public static bool CanCreate(IPAddress ip) => diff --git a/Projects/UOContent/Misc/AccountPrompt.cs b/Projects/UOContent/Misc/AccountPrompt.cs index 0e537c0d5..1483f022e 100644 --- a/Projects/UOContent/Misc/AccountPrompt.cs +++ b/Projects/UOContent/Misc/AccountPrompt.cs @@ -27,6 +27,9 @@ namespace Server.Misc a.AccessLevel = AccessLevel.Owner; Console.WriteLine("Account created."); + + ServerAccess.AddProtectedAccount(a, true); + Console.WriteLine("Added {0} to the protected accounts list.", a.Username); } else { diff --git a/Projects/UOContent/Misc/PacketThrottles.cs b/Projects/UOContent/Misc/PacketThrottles.cs index d2b666ed9..dda06aab8 100644 --- a/Projects/UOContent/Misc/PacketThrottles.cs +++ b/Projects/UOContent/Misc/PacketThrottles.cs @@ -10,7 +10,7 @@ namespace Server.Network { // Delay in milliseconds private static readonly int[] Delays = new int[0x100]; - private static string ThrottlesConfiguration = "Configuration/throttles.json"; + private const string ThrottlesConfiguration = "Configuration/throttles.json"; public static void Initialize() { diff --git a/Projects/UOContent/Misc/ServerAccess.cs b/Projects/UOContent/Misc/ServerAccess.cs new file mode 100644 index 000000000..433055b86 --- /dev/null +++ b/Projects/UOContent/Misc/ServerAccess.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json.Serialization; +using Server.Accounting; +using Server.Json; +using Server.Logging; + +namespace Server.Misc; + +public static class ServerAccess +{ + private static readonly ILogger logger = LogFactory.GetLogger(typeof(ServerAccess)); + private const string _serverAccessConfigurationPath = "Configuration/server-access.json"; + public static ServerAccessConfiguration ServerAccessConfiguration { get; private set; } + + public static void SaveConfiguration() + { + var path = Path.Join(Core.BaseDirectory, _serverAccessConfigurationPath); + JsonConfig.Serialize(path, ServerAccessConfiguration); + } + + public static void AddProtectedAccount(Account acct, bool save = false) + { + ServerAccessConfiguration.ProtectedAccounts.Add(acct.Username.ToLower()); + + if (save) + { + SaveConfiguration(); + } + } + + public static void RemoveProtectedAccount(Account acct, bool save = false) + { + ServerAccessConfiguration.ProtectedAccounts.Remove(acct.Username.ToLower()); + + if (save) + { + SaveConfiguration(); + } + } + + public static void Configure() + { + var path = Path.Join(Core.BaseDirectory, _serverAccessConfigurationPath); + + if (!File.Exists(path)) + { + return; + } + + ServerAccessConfiguration = JsonConfig.Deserialize(path); + var protectedAccounts = string.Join(", ", ServerAccessConfiguration.ProtectedAccounts); + logger.Information("Protected accounts registered: {0}", protectedAccounts); + } + + public static void Initialize() + { + EventSink.AccountLogin += EventSink_ResetProtectedAccount; + } + + public static void EventSink_ResetProtectedAccount(AccountLoginEventArgs e) + { + var username = e.Username.ToLower(); + if (!ServerAccessConfiguration.ProtectedAccounts.Contains(username)) + { + return; + } + + var account = Accounts.GetAccount(username); + if (account is not { Banned: true, AccessLevel: >= AccessLevel.Owner }) + { + return; + } + + account.Banned = false; + account.AccessLevel = AccessLevel.Owner; + + logger.Warning("Protected account \"{0}\" has been reset.", username); + + if (ServerAccessConfiguration.NewPasswordOnReset) + { + var password = Guid.NewGuid().ToString(); + logger.Warning("Protected account \"{0}\" password reset to \"{1}\"", username, password); + account.SetPassword(password); + } + + e.Accepted = true; + } +} + +public record ServerAccessConfiguration +{ + [JsonPropertyName("newPasswordOnReset")] + public bool NewPasswordOnReset { get; init; } + + [JsonPropertyName("protectedAccounts")] + public HashSet ProtectedAccounts { get; init; } +}