From fc63c28b052db2f7ad1421d82ff666d08b025052 Mon Sep 17 00:00:00 2001 From: Archi Date: Sat, 17 Dec 2022 03:11:07 +0100 Subject: [PATCH] Use local cache for BadBots in case server is unavailable Bad actors might attempt to DDoS the server in order to refuse the service, fallback to local cache if that happens. --- ArchiSteamFarm/Core/ArchiNet.cs | 20 ++++++++++++++++---- ArchiSteamFarm/Storage/GlobalDatabase.cs | 8 ++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/ArchiSteamFarm/Core/ArchiNet.cs b/ArchiSteamFarm/Core/ArchiNet.cs index e8da5a91c..0a4f49b2c 100644 --- a/ArchiSteamFarm/Core/ArchiNet.cs +++ b/ArchiSteamFarm/Core/ArchiNet.cs @@ -20,7 +20,9 @@ // limitations under the License. using System; +using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using System.Threading.Tasks; using ArchiSteamFarm.Helpers; using ArchiSteamFarm.IPC.Responses; @@ -32,7 +34,7 @@ namespace ArchiSteamFarm.Core; internal static class ArchiNet { internal static Uri URL => new("https://asf.JustArchi.net"); - private static readonly ArchiCacheable> CachedBadBots = new(ResolveCachedBadBots, TimeSpan.FromDays(1)); + private static readonly ArchiCacheable> CachedBadBots = new(ResolveCachedBadBots, TimeSpan.FromDays(1)); internal static async Task FetchBuildChecksum(Version version, string variant) { ArgumentNullException.ThrowIfNull(version); @@ -61,12 +63,16 @@ internal static class ArchiNet { throw new ArgumentOutOfRangeException(nameof(steamID)); } - (_, ImmutableHashSet? badBots) = await CachedBadBots.GetValue(ArchiCacheable>.EFallback.SuccessPreviously).ConfigureAwait(false); + (_, IReadOnlyCollection? badBots) = await CachedBadBots.GetValue(ArchiCacheable>.EFallback.FailedNow).ConfigureAwait(false); return badBots?.Contains(steamID); } - private static async Task<(bool Success, ImmutableHashSet? Result)> ResolveCachedBadBots() { + private static async Task<(bool Success, IReadOnlyCollection? Result)> ResolveCachedBadBots() { + if (ASF.GlobalDatabase == null) { + throw new InvalidOperationException(nameof(ASF.WebBrowser)); + } + if (ASF.WebBrowser == null) { throw new InvalidOperationException(nameof(ASF.WebBrowser)); } @@ -75,6 +81,12 @@ internal static class ArchiNet { ObjectResponse>>? response = await ASF.WebBrowser.UrlGetToJsonObject>>(request).ConfigureAwait(false); - return response?.Content != null ? (true, response.Content.Result) : (false, null); + if (response?.Content?.Result == null) { + return (false, ASF.GlobalDatabase.CachedBadBots); + } + + ASF.GlobalDatabase.CachedBadBots.ReplaceIfNeededWith(response.Content.Result); + + return (true, response.Content.Result); } } diff --git a/ArchiSteamFarm/Storage/GlobalDatabase.cs b/ArchiSteamFarm/Storage/GlobalDatabase.cs index e378950e6..96636f755 100644 --- a/ArchiSteamFarm/Storage/GlobalDatabase.cs +++ b/ArchiSteamFarm/Storage/GlobalDatabase.cs @@ -48,6 +48,9 @@ public sealed class GlobalDatabase : SerializableFile { [PublicAPI] public IReadOnlyDictionary PackagesDataReadOnly => PackagesData; + [JsonProperty(Required = Required.DisallowNull)] + internal readonly ConcurrentHashSet CachedBadBots = new(); + [JsonProperty(Required = Required.DisallowNull)] internal readonly ObservableConcurrentDictionary CardCountsPerGame = new(); @@ -111,6 +114,7 @@ public sealed class GlobalDatabase : SerializableFile { [JsonConstructor] private GlobalDatabase() { + CachedBadBots.OnModified += OnObjectModified; CardCountsPerGame.OnModified += OnObjectModified; ServerListProvider.ServerListUpdated += OnObjectModified; } @@ -165,6 +169,9 @@ public sealed class GlobalDatabase : SerializableFile { [UsedImplicitly] public bool ShouldSerializeBackingLastChangeNumber() => LastChangeNumber != 0; + [UsedImplicitly] + public bool ShouldSerializeCachedBadBots() => CachedBadBots.Count > 0; + [UsedImplicitly] public bool ShouldSerializeCardCountsPerGame() => !CardCountsPerGame.IsEmpty; @@ -183,6 +190,7 @@ public sealed class GlobalDatabase : SerializableFile { protected override void Dispose(bool disposing) { if (disposing) { // Events we registered + CachedBadBots.OnModified -= OnObjectModified; CardCountsPerGame.OnModified -= OnObjectModified; ServerListProvider.ServerListUpdated -= OnObjectModified;