using System; using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; namespace SharpChat.Flashii { public class FlashiiBanInfo { [JsonPropertyName("is_ban")] public bool IsBanned { get; set; } [JsonPropertyName("user_id")] public string UserId { get; set; } [JsonPropertyName("ip_addr")] public string RemoteAddress { get; set; } [JsonPropertyName("is_perma")] public bool IsPermanent { get; set; } [JsonPropertyName("expires")] public DateTimeOffset ExpiresAt { get; set; } // only populated in list request [JsonPropertyName("user_name")] public string UserName { get; set; } [JsonPropertyName("user_colour")] public int UserColourRaw { get; set; } public bool HasExpired => !IsPermanent && DateTimeOffset.UtcNow >= ExpiresAt; public ChatColour UserColour => ChatColour.FromMisuzu(UserColourRaw); private const string CHECK_SIG_FMT = "check#{0}#{1}#{2}#{3}"; private const string REVOKE_SIG_FMT = "revoke#{0}#{1}#{2}"; private const string CREATE_SIG_FMT = "create#{0}#{1}#{2}#{3}#{4}#{5}#{6}#{7}"; private const string LIST_SIG_FMT = "list#{0}"; public static async Task CheckAsync(HttpClient client, string userId = null, string ipAddr = null, bool userIdIsName = false) { if(client == null) throw new ArgumentNullException(nameof(client)); userId ??= string.Empty; ipAddr ??= string.Empty; string userIdIsNameStr = userIdIsName ? "1" : "0"; string now = DateTimeOffset.Now.ToUnixTimeSeconds().ToString(); string url = string.Format(FlashiiUrls.BansCheckURL, Uri.EscapeDataString(userId), Uri.EscapeDataString(ipAddr), Uri.EscapeDataString(now), Uri.EscapeDataString(userIdIsNameStr)); string sig = string.Format(CHECK_SIG_FMT, now, userId, ipAddr, userIdIsNameStr); HttpRequestMessage req = new(HttpMethod.Get, url) { Headers = { { "X-SharpChat-Signature", sig.GetSignedHash() }, }, }; using HttpResponseMessage res = await client.SendAsync(req); return JsonSerializer.Deserialize( await res.Content.ReadAsByteArrayAsync() ); } public static async Task GetListAsync(HttpClient client) { if(client == null) throw new ArgumentNullException(nameof(client)); string now = DateTimeOffset.Now.ToUnixTimeSeconds().ToString(); string url = string.Format(FlashiiUrls.BansListURL, Uri.EscapeDataString(now)); string sig = string.Format(LIST_SIG_FMT, now); HttpRequestMessage req = new(HttpMethod.Get, url) { Headers = { { "X-SharpChat-Signature", sig.GetSignedHash() }, }, }; using HttpResponseMessage res = await client.SendAsync(req); return JsonSerializer.Deserialize( await res.Content.ReadAsByteArrayAsync() ); } public enum RevokeKind { UserId, RemoteAddress, } public async Task RevokeAsync(HttpClient client, RevokeKind kind) { if(client == null) throw new ArgumentNullException(nameof(client)); string type = kind switch { RevokeKind.UserId => "user", RevokeKind.RemoteAddress => "addr", _ => throw new ArgumentException("Invalid kind specified.", nameof(kind)), }; string target = kind switch { RevokeKind.UserId => UserId, RevokeKind.RemoteAddress => RemoteAddress, _ => string.Empty, }; string now = DateTimeOffset.Now.ToUnixTimeSeconds().ToString(); string url = string.Format(FlashiiUrls.BansRevokeURL, Uri.EscapeDataString(type), Uri.EscapeDataString(target), Uri.EscapeDataString(now)); string sig = string.Format(REVOKE_SIG_FMT, now, type, target); HttpRequestMessage req = new(HttpMethod.Delete, url) { Headers = { { "X-SharpChat-Signature", sig.GetSignedHash() }, }, }; using HttpResponseMessage res = await client.SendAsync(req); if(res.StatusCode == HttpStatusCode.NotFound) return false; res.EnsureSuccessStatusCode(); return res.StatusCode == HttpStatusCode.NoContent; } public static async Task CreateAsync( HttpClient client, string targetId, string targetAddr, string modId, string modAddr, TimeSpan duration, string reason ) { if(client == null) throw new ArgumentNullException(nameof(client)); if(string.IsNullOrWhiteSpace(targetAddr)) throw new ArgumentNullException(nameof(targetAddr)); if(string.IsNullOrWhiteSpace(modAddr)) throw new ArgumentNullException(nameof(modAddr)); if(duration <= TimeSpan.Zero) return; modId ??= string.Empty; targetId ??= string.Empty; reason ??= string.Empty; string isPerma = duration == TimeSpan.MaxValue ? "1" : "0"; string durationStr = duration == TimeSpan.MaxValue ? "-1" : duration.TotalSeconds.ToString(); string now = DateTimeOffset.Now.ToUnixTimeSeconds().ToString(); string sig = string.Format( CREATE_SIG_FMT, now, targetId, targetAddr, modId, modAddr, durationStr, isPerma, reason ); HttpRequestMessage req = new(HttpMethod.Post, FlashiiUrls.BansCreateURL) { Headers = { { "X-SharpChat-Signature", sig.GetSignedHash() }, }, Content = new FormUrlEncodedContent(new Dictionary { { "t", now }, { "ui", targetId }, { "ua", targetAddr }, { "mi", modId }, { "ma", modAddr }, { "d", durationStr }, { "p", isPerma }, { "r", reason }, }), }; using HttpResponseMessage res = await client.SendAsync(req); res.EnsureSuccessStatusCode(); } } }