/*************************************************************************
* ModernUO *
* Copyright 2019-2026 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: LoginAllowlistConfiguration.cs *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
*************************************************************************/
using System;
using System.IO;
using System.Text.Json.Serialization;
using Server.Json;
namespace Server.Network;
///
/// Loads the from Configuration/login-allowlist.json (matching
/// the per-feature JSON config pattern used by BlocklistConfiguration). Loaded once; a missing file
/// writes a template so operators have something to edit.
///
public static class LoginAllowlistConfiguration
{
private const string _path = "Configuration/login-allowlist.json";
public static LoginAllowlistSettings Settings { get; private set; }
public static void Load()
{
var path = Path.Join(Core.BaseDirectory, _path);
if (File.Exists(path))
{
Settings = JsonConfig.Deserialize(path);
}
else
{
Settings = new LoginAllowlistSettings();
Save();
}
}
private static void Save()
{
JsonConfig.Serialize(Path.Join(Core.BaseDirectory, _path), Settings);
}
}
///
/// Bound configuration for : which addresses have recently proven they carry a
/// real player, how long that proof counts, and how much misbehaviour revokes it.
///
///
/// The recency window is the point. Consumer addresses are reassigned constantly, and on CGNAT the same
/// address fronts a different subscriber week to week, so a list without a TTL becomes a list of strangers.
///
public record LoginAllowlistSettings
{
/// Whether successful logins are recorded and consulted at all. Disabled makes the list inert.
[JsonPropertyName("enabled")]
public bool Enabled { get; set; } = true;
///
/// Where the list is persisted. A relative path resolves against .
/// Plain text, one address unix-seconds pair per line, so it can be read and edited by hand.
/// Set to "" to disable.
///
[JsonPropertyName("file")]
public string File { get; set; } = "Configuration/login-allowlist.txt";
///
/// How long a successful login allowlists its address; dropped on the next flush after that. 90 days
/// covers a player who takes a season off without carrying a reassigned address indefinitely.
///
[JsonPropertyName("ttl")]
public TimeSpan Ttl { get; set; } = TimeSpan.FromDays(90);
///
/// How often a changed list is written out. A crash loses at most this much, and an entry is re-earned by
/// the next login.
///
[JsonPropertyName("flushInterval")]
public TimeSpan FlushInterval { get; set; } = TimeSpan.FromMinutes(1);
///
/// How many suppressed contributions inside revoke an address's entry. Past
/// this it escalates like anything else until it earns a new entry by logging in again.
///
///
/// Generous on purpose: local defences never stop applying, so a high threshold only delays the external
/// ban. A bad line might trip a gate a few times an hour; a host being used to flood burns through this
/// in seconds. Set to 0 to never revoke.
///
[JsonPropertyName("escalateAfterStrikes")]
public int EscalateAfterStrikes { get; set; } = 10;
/// Rolling window the strike count is measured over. A quiet hour clears the tally.
[JsonPropertyName("strikeWindow")]
public TimeSpan StrikeWindow { get; set; } = TimeSpan.FromHours(1);
}