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.
This commit is contained in:
Archi
2022-12-17 03:11:07 +01:00
parent 7614002501
commit fc63c28b05
2 changed files with 24 additions and 4 deletions

View File

@@ -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<ImmutableHashSet<ulong>> CachedBadBots = new(ResolveCachedBadBots, TimeSpan.FromDays(1));
private static readonly ArchiCacheable<IReadOnlyCollection<ulong>> CachedBadBots = new(ResolveCachedBadBots, TimeSpan.FromDays(1));
internal static async Task<string?> FetchBuildChecksum(Version version, string variant) {
ArgumentNullException.ThrowIfNull(version);
@@ -61,12 +63,16 @@ internal static class ArchiNet {
throw new ArgumentOutOfRangeException(nameof(steamID));
}
(_, ImmutableHashSet<ulong>? badBots) = await CachedBadBots.GetValue(ArchiCacheable<ImmutableHashSet<ulong>>.EFallback.SuccessPreviously).ConfigureAwait(false);
(_, IReadOnlyCollection<ulong>? badBots) = await CachedBadBots.GetValue(ArchiCacheable<IReadOnlyCollection<ulong>>.EFallback.FailedNow).ConfigureAwait(false);
return badBots?.Contains(steamID);
}
private static async Task<(bool Success, ImmutableHashSet<ulong>? Result)> ResolveCachedBadBots() {
private static async Task<(bool Success, IReadOnlyCollection<ulong>? 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<GenericResponse<ImmutableHashSet<ulong>>>? response = await ASF.WebBrowser.UrlGetToJsonObject<GenericResponse<ImmutableHashSet<ulong>>>(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);
}
}

View File

@@ -48,6 +48,9 @@ public sealed class GlobalDatabase : SerializableFile {
[PublicAPI]
public IReadOnlyDictionary<uint, PackageData> PackagesDataReadOnly => PackagesData;
[JsonProperty(Required = Required.DisallowNull)]
internal readonly ConcurrentHashSet<ulong> CachedBadBots = new();
[JsonProperty(Required = Required.DisallowNull)]
internal readonly ObservableConcurrentDictionary<uint, byte> 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;