From 47b42d6fc0ea4a9b6b32e6320019d4c7980a6659 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Wed, 11 Nov 2020 19:51:52 +0100 Subject: [PATCH] More code cleanups --- ArchiSteamFarm/ASF.cs | 238 +++++++--- ArchiSteamFarm/Actions.cs | 60 ++- ArchiSteamFarm/ArchiCryptoHelper.cs | 115 +++-- ArchiSteamFarm/ArchiHandler.cs | 230 ++++++++-- ArchiSteamFarm/ArchiWebHandler.cs | 416 ++++++++++++------ ArchiSteamFarm/Bot.cs | 8 +- .../IPC/Controllers/Api/BotController.cs | 10 +- 7 files changed, 760 insertions(+), 317 deletions(-) diff --git a/ArchiSteamFarm/ASF.cs b/ArchiSteamFarm/ASF.cs index f5599f2ed..8f852f221 100644 --- a/ArchiSteamFarm/ASF.cs +++ b/ArchiSteamFarm/ASF.cs @@ -23,6 +23,8 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; +using System.ComponentModel; +using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; @@ -77,7 +79,7 @@ namespace ArchiSteamFarm { [PublicAPI] public static bool IsOwner(ulong steamID) { if (steamID == 0) { - throw new ArgumentNullException(nameof(steamID)); + throw new ArgumentOutOfRangeException(nameof(steamID)); } return (steamID == GlobalConfig?.SteamOwnerID) || (Debugging.IsDebugBuild && (steamID == SharedInfo.ArchiSteamID)); @@ -85,7 +87,7 @@ namespace ArchiSteamFarm { internal static string GetFilePath(EFileType fileType) { if (!Enum.IsDefined(typeof(EFileType), fileType)) { - throw new ArgumentNullException(nameof(fileType)); + throw new InvalidEnumArgumentException(nameof(fileType), (int) fileType, typeof(EFileType)); } return fileType switch { @@ -97,7 +99,7 @@ namespace ArchiSteamFarm { internal static async Task Init() { if (GlobalConfig == null) { - throw new ArgumentNullException(nameof(GlobalConfig)); + throw new InvalidOperationException(nameof(GlobalConfig)); } if (!PluginsCore.InitPlugins()) { @@ -144,15 +146,15 @@ namespace ArchiSteamFarm { // The only purpose of using hashingAlgorithm below is to cut on a potential size of the resource name - paths can be really long, and we almost certainly have some upper limit on the resource name we can allocate // At the same time it'd be the best if we avoided all special characters, such as '/' found e.g. in base64, as we can't be sure that it's not a prohibited character in regards to native OS implementation - // Because of that, MD5 is sufficient for our case, as it generates alphanumeric characters only, and is barely 128-bit long. We don't need any kind of complex cryptography or collision detection here, any hashing algorithm will do, and the shorter the better + // Because of that, SHA256 is sufficient for our case, as it generates alphanumeric characters only, and is barely 256-bit long. We don't need any kind of complex cryptography or collision detection here, any hashing algorithm will do, and the shorter the better string networkGroupText = ""; if (!string.IsNullOrEmpty(Program.NetworkGroup)) { - using MD5 hashingAlgorithm = MD5.Create(); + using SHA256CryptoServiceProvider hashingAlgorithm = new SHA256CryptoServiceProvider(); networkGroupText = "-" + BitConverter.ToString(hashingAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(Program.NetworkGroup!))).Replace("-", ""); } else if (!string.IsNullOrEmpty(globalConfig.WebProxyText)) { - using MD5 hashingAlgorithm = MD5.Create(); + using SHA256CryptoServiceProvider hashingAlgorithm = new SHA256CryptoServiceProvider(); networkGroupText = "-" + BitConverter.ToString(hashingAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(globalConfig.WebProxyText!))).Replace("-", ""); } @@ -184,9 +186,21 @@ namespace ArchiSteamFarm { GlobalDatabase = globalDatabase; } + internal static bool IsValidBotName(string botName) { + if (string.IsNullOrEmpty(botName)) { + throw new ArgumentNullException(nameof(botName)); + } + + if (botName[0] == '.') { + return false; + } + + return !botName.Equals(SharedInfo.ASF, StringComparison.OrdinalIgnoreCase); + } + internal static async Task RestartOrExit() { if (GlobalConfig == null) { - throw new ArgumentNullException(nameof(GlobalConfig)); + throw new InvalidOperationException(nameof(GlobalConfig)); } if (Program.RestartAllowed && GlobalConfig.AutoRestart) { @@ -201,8 +215,12 @@ namespace ArchiSteamFarm { } internal static async Task Update(bool updateOverride = false) { - if ((GlobalConfig == null) || (WebBrowser == null)) { - throw new ArgumentNullException(nameof(GlobalConfig) + " || " + nameof(WebBrowser)); + if (GlobalConfig == null) { + throw new InvalidOperationException(nameof(GlobalConfig)); + } + + if (WebBrowser == null) { + throw new InvalidOperationException(nameof(WebBrowser)); } if (!SharedInfo.BuildInfo.CanUpdate || (GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None)) { @@ -250,7 +268,7 @@ namespace ArchiSteamFarm { Version newVersion = new Version(releaseResponse.Tag!); - ArchiLogger.LogGenericInfo(string.Format(Strings.UpdateVersionInfo, SharedInfo.Version, newVersion)); + ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.UpdateVersionInfo, SharedInfo.Version, newVersion)); if (SharedInfo.Version >= newVersion) { if (SharedInfo.Version > newVersion) { @@ -294,7 +312,7 @@ namespace ArchiSteamFarm { ArchiLogger.LogGenericInfo(releaseResponse.ChangelogPlainText!); } - ArchiLogger.LogGenericInfo(string.Format(Strings.UpdateDownloadingNewVersion, newVersion, binaryAsset.Size / 1024 / 1024)); + ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.UpdateDownloadingNewVersion, newVersion, binaryAsset.Size / 1024 / 1024)); Progress progressReporter = new Progress(); @@ -355,8 +373,12 @@ namespace ArchiSteamFarm { } private static async Task CanHandleWriteEvent(string filePath) { - if (string.IsNullOrEmpty(filePath) || (LastWriteEvents == null)) { - throw new ArgumentNullException(nameof(filePath) + " || " + nameof(LastWriteEvents)); + if (string.IsNullOrEmpty(filePath)) { + throw new ArgumentNullException(nameof(filePath)); + } + + if (LastWriteEvents == null) { + throw new InvalidOperationException(nameof(LastWriteEvents)); } // Save our event in dictionary @@ -388,7 +410,7 @@ namespace ArchiSteamFarm { } if (Bot.BotsComparer == null) { - throw new ArgumentNullException(nameof(Bot.BotsComparer)); + throw new InvalidOperationException(nameof(Bot.BotsComparer)); } FileSystemWatcher = new FileSystemWatcher(SharedInfo.ConfigDirectory) { NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite }; @@ -403,18 +425,6 @@ namespace ArchiSteamFarm { FileSystemWatcher.EnableRaisingEvents = true; } - private static bool IsValidBotName(string botName) { - if (string.IsNullOrEmpty(botName)) { - throw new ArgumentNullException(nameof(botName)); - } - - if (botName[0] == '.') { - return false; - } - - return !botName.Equals(SharedInfo.ASF, StringComparison.OrdinalIgnoreCase); - } - private static void LoadAssembliesRecursively(Assembly assembly, HashSet? loadedAssembliesNames = null) { if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); @@ -433,20 +443,32 @@ namespace ArchiSteamFarm { } private static async void OnChanged(object sender, FileSystemEventArgs e) { - if ((sender == null) || (e == null)) { - throw new ArgumentNullException(nameof(sender) + " || " + nameof(e)); + if (sender == null) { + throw new ArgumentNullException(nameof(sender)); + } + + if (e == null) { + throw new ArgumentNullException(nameof(e)); } if (string.IsNullOrEmpty(e.Name)) { - throw new ArgumentNullException(nameof(e.Name)); + throw new InvalidOperationException(nameof(e.Name)); + } + + if (string.IsNullOrEmpty(e.FullPath)) { + throw new InvalidOperationException(nameof(e.FullPath)); } await OnChangedFile(e.Name, e.FullPath).ConfigureAwait(false); } private static async Task OnChangedConfigFile(string name, string fullPath) { - if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) { - throw new ArgumentNullException(nameof(name) + " || " + nameof(fullPath)); + if (string.IsNullOrEmpty(name)) { + throw new ArgumentNullException(nameof(name)); + } + + if (string.IsNullOrEmpty(fullPath)) { + throw new ArgumentNullException(nameof(fullPath)); } await OnCreatedConfigFile(name, fullPath).ConfigureAwait(false); @@ -457,7 +479,7 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(name)); } - if (!name.Equals(SharedInfo.IPCConfigFile) || (GlobalConfig?.IPC != true)) { + if (!name.Equals(SharedInfo.IPCConfigFile, StringComparison.OrdinalIgnoreCase) || (GlobalConfig?.IPC != true)) { return; } @@ -471,8 +493,12 @@ namespace ArchiSteamFarm { } private static async Task OnChangedFile(string name, string fullPath) { - if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) { - throw new ArgumentNullException(nameof(name) + " || " + nameof(fullPath)); + if (string.IsNullOrEmpty(name)) { + throw new ArgumentNullException(nameof(name)); + } + + if (string.IsNullOrEmpty(fullPath)) { + throw new ArgumentNullException(nameof(fullPath)); } string extension = Path.GetExtension(name); @@ -491,28 +517,44 @@ namespace ArchiSteamFarm { } private static async Task OnChangedKeysFile(string name, string fullPath) { - if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) { - throw new ArgumentNullException(nameof(name) + " || " + nameof(fullPath)); + if (string.IsNullOrEmpty(name)) { + throw new ArgumentNullException(nameof(name)); + } + + if (string.IsNullOrEmpty(fullPath)) { + throw new ArgumentNullException(nameof(fullPath)); } await OnCreatedKeysFile(name, fullPath).ConfigureAwait(false); } private static async void OnCreated(object sender, FileSystemEventArgs e) { - if ((sender == null) || (e == null)) { - throw new ArgumentNullException(nameof(sender) + " || " + nameof(e)); + if (sender == null) { + throw new ArgumentNullException(nameof(sender)); + } + + if (e == null) { + throw new ArgumentNullException(nameof(e)); } if (string.IsNullOrEmpty(e.Name)) { - throw new ArgumentNullException(nameof(e.Name)); + throw new InvalidOperationException(nameof(e.Name)); + } + + if (string.IsNullOrEmpty(e.FullPath)) { + throw new InvalidOperationException(nameof(e.FullPath)); } await OnCreatedFile(e.Name, e.FullPath).ConfigureAwait(false); } private static async Task OnCreatedConfigFile(string name, string fullPath) { - if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) { - throw new ArgumentNullException(nameof(name) + " || " + nameof(fullPath)); + if (string.IsNullOrEmpty(name)) { + throw new ArgumentNullException(nameof(name)); + } + + if (string.IsNullOrEmpty(fullPath)) { + throw new ArgumentNullException(nameof(fullPath)); } string extension = Path.GetExtension(name); @@ -530,8 +572,12 @@ namespace ArchiSteamFarm { } private static async Task OnCreatedFile(string name, string fullPath) { - if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) { - throw new ArgumentNullException(nameof(name) + " || " + nameof(fullPath)); + if (string.IsNullOrEmpty(name)) { + throw new ArgumentNullException(nameof(name)); + } + + if (string.IsNullOrEmpty(fullPath)) { + throw new ArgumentNullException(nameof(fullPath)); } string extension = Path.GetExtension(name); @@ -550,8 +596,16 @@ namespace ArchiSteamFarm { } private static async Task OnCreatedJsonFile(string name, string fullPath) { - if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath) || (Bot.Bots == null)) { - throw new ArgumentNullException(nameof(name) + " || " + nameof(fullPath) + " || " + nameof(Bot.Bots)); + if (string.IsNullOrEmpty(name)) { + throw new ArgumentNullException(nameof(name)); + } + + if (string.IsNullOrEmpty(fullPath)) { + throw new ArgumentNullException(nameof(fullPath)); + } + + if (Bot.Bots == null) { + throw new InvalidOperationException(nameof(Bot.Bots)); } string botName = Path.GetFileNameWithoutExtension(name); @@ -581,14 +635,22 @@ namespace ArchiSteamFarm { await Bot.RegisterBot(botName).ConfigureAwait(false); if (Bot.Bots.Count > MaximumRecommendedBotsCount) { - ArchiLogger.LogGenericWarning(string.Format(Strings.WarningExcessiveBotsCount, MaximumRecommendedBotsCount)); + ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningExcessiveBotsCount, MaximumRecommendedBotsCount)); } } } private static async Task OnCreatedKeysFile(string name, string fullPath) { - if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath) || (Bot.Bots == null)) { - throw new ArgumentNullException(nameof(name) + " || " + nameof(fullPath) + " || " + nameof(Bot.Bots)); + if (string.IsNullOrEmpty(name)) { + throw new ArgumentNullException(nameof(name)); + } + + if (string.IsNullOrEmpty(fullPath)) { + throw new ArgumentNullException(nameof(fullPath)); + } + + if (Bot.Bots == null) { + throw new InvalidOperationException(nameof(Bot.Bots)); } string botName = Path.GetFileNameWithoutExtension(name); @@ -609,20 +671,32 @@ namespace ArchiSteamFarm { } private static async void OnDeleted(object sender, FileSystemEventArgs e) { - if ((sender == null) || (e == null)) { - throw new ArgumentNullException(nameof(sender) + " || " + nameof(e)); + if (sender == null) { + throw new ArgumentNullException(nameof(sender)); + } + + if (e == null) { + throw new ArgumentNullException(nameof(e)); } if (string.IsNullOrEmpty(e.Name)) { - throw new ArgumentNullException(nameof(e.Name)); + throw new InvalidOperationException(nameof(e.Name)); + } + + if (string.IsNullOrEmpty(e.FullPath)) { + throw new InvalidOperationException(nameof(e.FullPath)); } await OnDeletedFile(e.Name, e.FullPath).ConfigureAwait(false); } private static async Task OnDeletedConfigFile(string name, string fullPath) { - if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) { - throw new ArgumentNullException(nameof(name) + " || " + nameof(fullPath)); + if (string.IsNullOrEmpty(name)) { + throw new ArgumentNullException(nameof(name)); + } + + if (string.IsNullOrEmpty(fullPath)) { + throw new ArgumentNullException(nameof(fullPath)); } string extension = Path.GetExtension(name); @@ -640,8 +714,12 @@ namespace ArchiSteamFarm { } private static async Task OnDeletedFile(string name, string fullPath) { - if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) { - throw new ArgumentNullException(nameof(name) + " || " + nameof(fullPath)); + if (string.IsNullOrEmpty(name)) { + throw new ArgumentNullException(nameof(name)); + } + + if (string.IsNullOrEmpty(fullPath)) { + throw new ArgumentNullException(nameof(fullPath)); } string extension = Path.GetExtension(name); @@ -656,8 +734,16 @@ namespace ArchiSteamFarm { } private static async Task OnDeletedJsonConfigFile(string name, string fullPath) { - if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath) || (Bot.Bots == null)) { - throw new ArgumentNullException(nameof(name) + " || " + nameof(fullPath) + " || " + nameof(Bot.Bots)); + if (string.IsNullOrEmpty(name)) { + throw new ArgumentNullException(nameof(name)); + } + + if (string.IsNullOrEmpty(fullPath)) { + throw new ArgumentNullException(nameof(fullPath)); + } + + if (Bot.Bots == null) { + throw new InvalidOperationException(nameof(Bot.Bots)); } string botName = Path.GetFileNameWithoutExtension(name); @@ -709,12 +795,28 @@ namespace ArchiSteamFarm { } private static async void OnRenamed(object sender, RenamedEventArgs e) { - if ((sender == null) || (e == null)) { - throw new ArgumentNullException(nameof(sender) + " || " + nameof(e)); + if (sender == null) { + throw new ArgumentNullException(nameof(sender)); } - if (string.IsNullOrEmpty(e.OldName) || string.IsNullOrEmpty(e.Name)) { - throw new ArgumentNullException(nameof(e.OldName) + " || " + nameof(e.Name)); + if (e == null) { + throw new ArgumentNullException(nameof(e)); + } + + if (string.IsNullOrEmpty(e.OldName)) { + throw new InvalidOperationException(nameof(e.OldName)); + } + + if (string.IsNullOrEmpty(e.OldFullPath)) { + throw new InvalidOperationException(nameof(e.OldFullPath)); + } + + if (string.IsNullOrEmpty(e.Name)) { + throw new InvalidOperationException(nameof(e.Name)); + } + + if (string.IsNullOrEmpty(e.FullPath)) { + throw new InvalidOperationException(nameof(e.FullPath)); } await OnDeletedFile(e.OldName, e.OldFullPath).ConfigureAwait(false); @@ -730,7 +832,7 @@ namespace ArchiSteamFarm { IEnumerable servers = await GlobalDatabase.ServerListProvider.FetchServerListAsync().ConfigureAwait(false); if (servers?.Any() != true) { - ArchiLogger.LogGenericInfo(string.Format(Strings.Initializing, nameof(SteamDirectory))); + ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.Initializing, nameof(SteamDirectory))); SteamConfiguration steamConfiguration = SteamConfiguration.Create(builder => builder.WithProtocolTypes(GlobalConfig.SteamProtocols).WithCellID(GlobalDatabase.CellID).WithServerListProvider(GlobalDatabase.ServerListProvider).WithHttpClientFactory(() => WebBrowser.GenerateDisposableHttpClient())); @@ -762,7 +864,7 @@ namespace ArchiSteamFarm { } if (botNames.Count > MaximumRecommendedBotsCount) { - ArchiLogger.LogGenericWarning(string.Format(Strings.WarningExcessiveBotsCount, MaximumRecommendedBotsCount)); + ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningExcessiveBotsCount, MaximumRecommendedBotsCount)); await Task.Delay(10000).ConfigureAwait(false); } @@ -788,7 +890,7 @@ namespace ArchiSteamFarm { autoUpdatePeriod // Period ); - ArchiLogger.LogGenericInfo(string.Format(Strings.AutoUpdateCheckInfo, autoUpdatePeriod.ToHumanReadable())); + ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.AutoUpdateCheckInfo, autoUpdatePeriod.ToHumanReadable())); } Version? newVersion = await Update().ConfigureAwait(false); @@ -801,8 +903,12 @@ namespace ArchiSteamFarm { } private static bool UpdateFromArchive(ZipArchive archive, string targetDirectory) { - if ((archive == null) || string.IsNullOrEmpty(targetDirectory)) { - throw new ArgumentNullException(nameof(archive) + " || " + nameof(targetDirectory)); + if (archive == null) { + throw new ArgumentNullException(nameof(archive)); + } + + if (string.IsNullOrEmpty(targetDirectory)) { + throw new ArgumentNullException(nameof(targetDirectory)); } if (SharedInfo.HomeDirectory == AppContext.BaseDirectory) { diff --git a/ArchiSteamFarm/Actions.cs b/ArchiSteamFarm/Actions.cs index f617339ba..3504b143b 100644 --- a/ArchiSteamFarm/Actions.cs +++ b/ArchiSteamFarm/Actions.cs @@ -21,6 +21,8 @@ using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Net.Http; using System.Threading; @@ -58,8 +60,12 @@ namespace ArchiSteamFarm { [PublicAPI] public static string? Encrypt(ArchiCryptoHelper.ECryptoMethod cryptoMethod, string stringToEncrypt) { - if (!Enum.IsDefined(typeof(ArchiCryptoHelper.ECryptoMethod), cryptoMethod) || string.IsNullOrEmpty(stringToEncrypt)) { - throw new ArgumentNullException(nameof(cryptoMethod) + " || " + nameof(stringToEncrypt)); + if (!Enum.IsDefined(typeof(ArchiCryptoHelper.ECryptoMethod), cryptoMethod)) { + throw new InvalidEnumArgumentException(nameof(cryptoMethod), (int) cryptoMethod, typeof(ArchiCryptoHelper.ECryptoMethod)); + } + + if (string.IsNullOrEmpty(stringToEncrypt)) { + throw new ArgumentNullException(nameof(stringToEncrypt)); } return ArchiCryptoHelper.Encrypt(cryptoMethod, stringToEncrypt); @@ -128,7 +134,7 @@ namespace ArchiSteamFarm { } } - if ((acceptedCreatorIDs != null) && (acceptedCreatorIDs.Count > 0)) { + if (acceptedCreatorIDs?.Count > 0) { if (confirmations.RemoveWhere(confirmation => !acceptedCreatorIDs.Contains(confirmation.Creator)) > 0) { if (confirmations.Count == 0) { continue; @@ -142,7 +148,7 @@ namespace ArchiSteamFarm { handledConfirmationsCount += (ushort) confirmations.Count; - if ((acceptedCreatorIDs != null) && (acceptedCreatorIDs.Count > 0)) { + if (acceptedCreatorIDs?.Count > 0) { IEnumerable handledCreatorIDsThisRound = confirmations.Select(confirmation => confirmation.Creator).Where(acceptedCreatorIDs.Contains!); if (handledCreatorIDs != null) { @@ -153,18 +159,22 @@ namespace ArchiSteamFarm { // Check if those are all that we were expected to confirm if (handledCreatorIDs.SetEquals(acceptedCreatorIDs)) { - return (true, string.Format(Strings.BotHandledConfirmations, handledConfirmationsCount)); + return (true, string.Format(CultureInfo.CurrentCulture, Strings.BotHandledConfirmations, handledConfirmationsCount)); } } } - return (!waitIfNeeded, !waitIfNeeded ? string.Format(Strings.BotHandledConfirmations, handledConfirmationsCount) : string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + return (!waitIfNeeded, !waitIfNeeded ? string.Format(CultureInfo.CurrentCulture, Strings.BotHandledConfirmations, handledConfirmationsCount) : string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); } [PublicAPI] public static string Hash(ArchiCryptoHelper.EHashingMethod hashingMethod, string stringToHash) { - if (!Enum.IsDefined(typeof(ArchiCryptoHelper.EHashingMethod), hashingMethod) || string.IsNullOrEmpty(stringToHash)) { - throw new ArgumentNullException(nameof(hashingMethod) + " || " + nameof(stringToHash)); + if (!Enum.IsDefined(typeof(ArchiCryptoHelper.EHashingMethod), hashingMethod)) { + throw new InvalidEnumArgumentException(nameof(hashingMethod), (int) hashingMethod, typeof(ArchiCryptoHelper.EHashingMethod)); + } + + if (string.IsNullOrEmpty(stringToHash)) { + throw new ArgumentNullException(nameof(stringToHash)); } return ArchiCryptoHelper.Hash(hashingMethod, stringToHash); @@ -254,8 +264,12 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task<(bool Success, string Message)> SendInventory(IReadOnlyCollection items, ulong targetSteamID = 0, string? tradeToken = null, ushort itemsPerTrade = Trading.MaxItemsPerTrade) { - if ((items == null) || (items.Count == 0) || (itemsPerTrade < 2)) { - throw new ArgumentNullException(nameof(items) + " || " + nameof(itemsPerTrade)); + if ((items == null) || (items.Count == 0)) { + throw new ArgumentNullException(nameof(items)); + } + + if (itemsPerTrade < 2) { + throw new ArgumentOutOfRangeException(nameof(itemsPerTrade)); } if (!Bot.IsConnectedAndLoggedOn) { @@ -272,6 +286,8 @@ namespace ArchiSteamFarm { if (string.IsNullOrEmpty(tradeToken) && !string.IsNullOrEmpty(Bot.BotConfig.SteamTradeToken)) { tradeToken = Bot.BotConfig.SteamTradeToken; } + } else if (!new SteamID(targetSteamID).IsIndividualAccount) { + throw new ArgumentOutOfRangeException(nameof(targetSteamID)); } if (targetSteamID == Bot.SteamID) { @@ -292,7 +308,7 @@ namespace ArchiSteamFarm { (bool success, HashSet? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(targetSteamID, items, token: tradeToken, itemsPerTrade: itemsPerTrade).ConfigureAwait(false); - if ((mobileTradeOfferIDs != null) && (mobileTradeOfferIDs.Count > 0) && Bot.HasMobileAuthenticator) { + if ((mobileTradeOfferIDs?.Count > 0) && Bot.HasMobileAuthenticator) { (bool twoFactorSuccess, _) = await HandleTwoFactorAuthenticationConfirmations(true, MobileAuthenticator.Confirmation.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false); if (!twoFactorSuccess) { @@ -305,8 +321,12 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task<(bool Success, string Message)> SendInventory(uint appID = Steam.Asset.SteamAppID, ulong contextID = Steam.Asset.SteamCommunityContextID, ulong targetSteamID = 0, string? tradeToken = null, Func? filterFunction = null, ushort itemsPerTrade = Trading.MaxItemsPerTrade) { - if ((appID == 0) || (contextID == 0) || (itemsPerTrade < 2)) { - throw new ArgumentNullException(nameof(appID) + " || " + nameof(contextID) + " || " + nameof(itemsPerTrade)); + if (appID == 0) { + throw new ArgumentOutOfRangeException(nameof(appID)); + } + + if (contextID == 0) { + throw new ArgumentOutOfRangeException(nameof(contextID)); } if (!Bot.IsConnectedAndLoggedOn) { @@ -336,17 +356,17 @@ namespace ArchiSteamFarm { } catch (HttpRequestException e) { Bot.ArchiLogger.LogGenericWarningException(e); - return (false, string.Format(Strings.WarningFailedWithError, e.Message)); + return (false, string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message)); } catch (Exception e) { Bot.ArchiLogger.LogGenericException(e); - return (false, string.Format(Strings.WarningFailedWithError, e.Message)); + return (false, string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message)); } finally { TradingSemaphore.Release(); } if (inventory.Count == 0) { - return (false, string.Format(Strings.ErrorIsEmpty, nameof(inventory))); + return (false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(inventory))); } return await SendInventory(inventory, targetSteamID, tradeToken, itemsPerTrade).ConfigureAwait(false); @@ -416,7 +436,7 @@ namespace ArchiSteamFarm { foreach (ulong giftCardID in giftCardIDs.Where(gid => !HandledGifts.Contains(gid))) { HandledGifts.Add(giftCardID); - Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.BotAcceptingGift, giftCardID)); + Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.BotAcceptingGift, giftCardID)); await LimitGiftsRequestsAsync().ConfigureAwait(false); bool result = await Bot.ArchiWebHandler.AcceptDigitalGiftCard(giftCardID).ConfigureAwait(false); @@ -440,7 +460,7 @@ namespace ArchiSteamFarm { foreach (ulong guestPassID in guestPassIDs.Where(guestPassID => !HandledGifts.Contains(guestPassID))) { HandledGifts.Add(guestPassID); - Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.BotAcceptingGift, guestPassID)); + Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.BotAcceptingGift, guestPassID)); await LimitGiftsRequestsAsync().ConfigureAwait(false); ArchiHandler.RedeemGuestPassResponseCallback? response = await Bot.ArchiHandler.RedeemGuestPass(guestPassID).ConfigureAwait(false); @@ -449,7 +469,7 @@ namespace ArchiSteamFarm { if (response.Result == EResult.OK) { Bot.ArchiLogger.LogGenericInfo(Strings.Success); } else { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, response.Result)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Result)); } } else { Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); @@ -473,7 +493,7 @@ namespace ArchiSteamFarm { private static async Task LimitGiftsRequestsAsync() { if (ASF.GiftsSemaphore == null) { - throw new ArgumentNullException(nameof(ASF.GiftsSemaphore)); + throw new InvalidOperationException(nameof(ASF.GiftsSemaphore)); } byte giftsLimiterDelay = ASF.GlobalConfig?.GiftsLimiterDelay ?? GlobalConfig.DefaultGiftsLimiterDelay; diff --git a/ArchiSteamFarm/ArchiCryptoHelper.cs b/ArchiSteamFarm/ArchiCryptoHelper.cs index 57cb97a04..a741699d1 100644 --- a/ArchiSteamFarm/ArchiCryptoHelper.cs +++ b/ArchiSteamFarm/ArchiCryptoHelper.cs @@ -21,6 +21,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Runtime.InteropServices; using System.Security.Cryptography; @@ -47,50 +48,74 @@ namespace ArchiSteamFarm { private static byte[] EncryptionKey = Encoding.UTF8.GetBytes(nameof(ArchiSteamFarm)); - internal static string? Decrypt(ECryptoMethod cryptoMethod, string encrypted) { - if (!Enum.IsDefined(typeof(ECryptoMethod), cryptoMethod) || string.IsNullOrEmpty(encrypted)) { - throw new ArgumentNullException(nameof(cryptoMethod) + " || " + nameof(encrypted)); + internal static string? Decrypt(ECryptoMethod cryptoMethod, string encryptedString) { + if (!Enum.IsDefined(typeof(ECryptoMethod), cryptoMethod)) { + throw new InvalidEnumArgumentException(nameof(cryptoMethod), (int) cryptoMethod, typeof(ECryptoMethod)); + } + + if (string.IsNullOrEmpty(encryptedString)) { + throw new ArgumentNullException(nameof(encryptedString)); } return cryptoMethod switch { - ECryptoMethod.PlainText => encrypted, - ECryptoMethod.AES => DecryptAES(encrypted), - ECryptoMethod.ProtectedDataForCurrentUser => DecryptProtectedDataForCurrentUser(encrypted), + ECryptoMethod.PlainText => encryptedString, + ECryptoMethod.AES => DecryptAES(encryptedString), + ECryptoMethod.ProtectedDataForCurrentUser => DecryptProtectedDataForCurrentUser(encryptedString), _ => throw new ArgumentOutOfRangeException(nameof(cryptoMethod)) }; } - internal static string? Encrypt(ECryptoMethod cryptoMethod, string decrypted) { - if (!Enum.IsDefined(typeof(ECryptoMethod), cryptoMethod) || string.IsNullOrEmpty(decrypted)) { - throw new ArgumentNullException(nameof(cryptoMethod) + " || " + nameof(decrypted)); + internal static string? Encrypt(ECryptoMethod cryptoMethod, string decryptedString) { + if (!Enum.IsDefined(typeof(ECryptoMethod), cryptoMethod)) { + throw new InvalidEnumArgumentException(nameof(cryptoMethod), (int) cryptoMethod, typeof(ECryptoMethod)); + } + + if (string.IsNullOrEmpty(decryptedString)) { + throw new ArgumentNullException(nameof(decryptedString)); } return cryptoMethod switch { - ECryptoMethod.PlainText => decrypted, - ECryptoMethod.AES => EncryptAES(decrypted), - ECryptoMethod.ProtectedDataForCurrentUser => EncryptProtectedDataForCurrentUser(decrypted), + ECryptoMethod.PlainText => decryptedString, + ECryptoMethod.AES => EncryptAES(decryptedString), + ECryptoMethod.ProtectedDataForCurrentUser => EncryptProtectedDataForCurrentUser(decryptedString), _ => throw new ArgumentOutOfRangeException(nameof(cryptoMethod)) }; } - internal static string Hash(EHashingMethod hashingMethod, string password) { - if (!Enum.IsDefined(typeof(EHashingMethod), hashingMethod) || string.IsNullOrEmpty(password)) { - throw new ArgumentNullException(nameof(hashingMethod) + " || " + nameof(password)); + internal static string Hash(EHashingMethod hashingMethod, string stringToHash) { + if (!Enum.IsDefined(typeof(EHashingMethod), hashingMethod)) { + throw new InvalidEnumArgumentException(nameof(hashingMethod), (int) hashingMethod, typeof(EHashingMethod)); + } + + if (string.IsNullOrEmpty(stringToHash)) { + throw new ArgumentNullException(nameof(stringToHash)); } if (hashingMethod == EHashingMethod.PlainText) { - return password; + return stringToHash; } - byte[] passwordBytes = Encoding.UTF8.GetBytes(password); + byte[] passwordBytes = Encoding.UTF8.GetBytes(stringToHash); byte[] hashBytes = Hash(passwordBytes, EncryptionKey, DefaultHashLength, hashingMethod); return Convert.ToBase64String(hashBytes); } internal static byte[] Hash(byte[] password, byte[] salt, byte hashLength, EHashingMethod hashingMethod) { - if ((password == null) || (salt == null) || (hashLength == 0) || !Enum.IsDefined(typeof(EHashingMethod), hashingMethod)) { - throw new ArgumentNullException(nameof(password) + " || " + nameof(salt) + " || " + nameof(hashLength) + " || " + nameof(hashingMethod)); + if ((password == null) || (password.Length == 0)) { + throw new ArgumentNullException(nameof(password)); + } + + if ((salt == null) || (salt.Length == 0)) { + throw new ArgumentNullException(nameof(salt)); + } + + if (hashLength == 0) { + throw new ArgumentOutOfRangeException(nameof(hashLength)); + } + + if (!Enum.IsDefined(typeof(EHashingMethod), hashingMethod)) { + throw new InvalidEnumArgumentException(nameof(hashingMethod), (int) hashingMethod, typeof(EHashingMethod)); } switch (hashingMethod) { @@ -107,12 +132,20 @@ namespace ArchiSteamFarm { } } - internal static string? RecoverSteamParentalCode(byte[] passwordHash, byte[] salt, EHashingMethod steamParentalAlgorithm) { - if ((passwordHash == null) || (salt == null) || !Enum.IsDefined(typeof(EHashingMethod), steamParentalAlgorithm)) { - throw new ArgumentNullException(nameof(passwordHash) + " || " + nameof(salt) + " || " + nameof(steamParentalAlgorithm)); + internal static string? RecoverSteamParentalCode(byte[] passwordHash, byte[] salt, EHashingMethod hashingMethod) { + if ((passwordHash == null) || (passwordHash.Length == 0)) { + throw new ArgumentNullException(nameof(passwordHash)); } - byte[]? password = SteamParentalCodes.AsParallel().FirstOrDefault(passwordToTry => Hash(passwordToTry, salt, (byte) passwordHash.Length, steamParentalAlgorithm).SequenceEqual(passwordHash)); + if ((salt == null) || (salt.Length == 0)) { + throw new ArgumentNullException(nameof(salt)); + } + + if (!Enum.IsDefined(typeof(EHashingMethod), hashingMethod)) { + throw new InvalidEnumArgumentException(nameof(hashingMethod), (int) hashingMethod, typeof(EHashingMethod)); + } + + byte[]? password = SteamParentalCodes.AsParallel().FirstOrDefault(passwordToTry => Hash(passwordToTry, salt, (byte) passwordHash.Length, hashingMethod).SequenceEqual(passwordHash)); return password != null ? Encoding.UTF8.GetString(password) : null; } @@ -125,9 +158,9 @@ namespace ArchiSteamFarm { EncryptionKey = Encoding.UTF8.GetBytes(key); } - private static string? DecryptAES(string encrypted) { - if (string.IsNullOrEmpty(encrypted)) { - throw new ArgumentNullException(nameof(encrypted)); + private static string? DecryptAES(string encryptedString) { + if (string.IsNullOrEmpty(encryptedString)) { + throw new ArgumentNullException(nameof(encryptedString)); } try { @@ -137,7 +170,7 @@ namespace ArchiSteamFarm { key = sha256.ComputeHash(EncryptionKey); } - byte[] decryptedData = Convert.FromBase64String(encrypted); + byte[] decryptedData = Convert.FromBase64String(encryptedString); decryptedData = CryptoHelper.SymmetricDecrypt(decryptedData, key); return Encoding.UTF8.GetString(decryptedData); @@ -148,9 +181,9 @@ namespace ArchiSteamFarm { } } - private static string? DecryptProtectedDataForCurrentUser(string encrypted) { - if (string.IsNullOrEmpty(encrypted)) { - throw new ArgumentNullException(nameof(encrypted)); + private static string? DecryptProtectedDataForCurrentUser(string encryptedString) { + if (string.IsNullOrEmpty(encryptedString)) { + throw new ArgumentNullException(nameof(encryptedString)); } if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -159,8 +192,8 @@ namespace ArchiSteamFarm { try { byte[] decryptedData = ProtectedData.Unprotect( - Convert.FromBase64String(encrypted), - EncryptionKey, // This is used as salt only and it's fine that it's known + Convert.FromBase64String(encryptedString), + EncryptionKey, DataProtectionScope.CurrentUser ); @@ -172,9 +205,9 @@ namespace ArchiSteamFarm { } } - private static string? EncryptAES(string decrypted) { - if (string.IsNullOrEmpty(decrypted)) { - throw new ArgumentNullException(nameof(decrypted)); + private static string? EncryptAES(string decryptedString) { + if (string.IsNullOrEmpty(decryptedString)) { + throw new ArgumentNullException(nameof(decryptedString)); } try { @@ -184,7 +217,7 @@ namespace ArchiSteamFarm { key = sha256.ComputeHash(EncryptionKey); } - byte[] encryptedData = Encoding.UTF8.GetBytes(decrypted); + byte[] encryptedData = Encoding.UTF8.GetBytes(decryptedString); encryptedData = CryptoHelper.SymmetricEncrypt(encryptedData, key); return Convert.ToBase64String(encryptedData); @@ -195,9 +228,9 @@ namespace ArchiSteamFarm { } } - private static string? EncryptProtectedDataForCurrentUser(string decrypted) { - if (string.IsNullOrEmpty(decrypted)) { - throw new ArgumentNullException(nameof(decrypted)); + private static string? EncryptProtectedDataForCurrentUser(string decryptedString) { + if (string.IsNullOrEmpty(decryptedString)) { + throw new ArgumentNullException(nameof(decryptedString)); } if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -206,8 +239,8 @@ namespace ArchiSteamFarm { try { byte[] encryptedData = ProtectedData.Protect( - Encoding.UTF8.GetBytes(decrypted), - EncryptionKey, // This is used as salt only and it's fine that it's known + Encoding.UTF8.GetBytes(decryptedString), + EncryptionKey, DataProtectionScope.CurrentUser ); diff --git a/ArchiSteamFarm/ArchiHandler.cs b/ArchiSteamFarm/ArchiHandler.cs index 6b145f0bf..4c6e5ea7b 100644 --- a/ArchiSteamFarm/ArchiHandler.cs +++ b/ArchiSteamFarm/ArchiHandler.cs @@ -21,7 +21,9 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.IO; using System.Linq; using System.Net; @@ -48,11 +50,11 @@ namespace ArchiSteamFarm { internal DateTime LastPacketReceived { get; private set; } internal ArchiHandler(ArchiLogger archiLogger, SteamUnifiedMessages steamUnifiedMessages) { - if ((archiLogger == null) || (steamUnifiedMessages == null)) { - throw new ArgumentNullException(nameof(archiLogger) + " || " + nameof(steamUnifiedMessages)); + if (steamUnifiedMessages == null) { + throw new ArgumentNullException(nameof(steamUnifiedMessages)); } - ArchiLogger = archiLogger; + ArchiLogger = archiLogger ?? throw new ArgumentNullException(nameof(archiLogger)); UnifiedChatRoomService = steamUnifiedMessages.CreateService(); UnifiedClanChatRoomsService = steamUnifiedMessages.CreateService(); UnifiedEconService = steamUnifiedMessages.CreateService(); @@ -62,8 +64,12 @@ namespace ArchiSteamFarm { } public override void HandleMsg(IPacketMsg packetMsg) { - if ((packetMsg == null) || (Client == null)) { - throw new ArgumentNullException(nameof(packetMsg) + " || " + nameof(Client)); + if (packetMsg == null) { + throw new ArgumentNullException(nameof(packetMsg)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } LastPacketReceived = DateTime.UtcNow; @@ -113,8 +119,20 @@ namespace ArchiSteamFarm { } internal void AckChatMessage(ulong chatGroupID, ulong chatID, uint timestamp) { - if ((chatGroupID == 0) || (chatID == 0) || (timestamp == 0)) { - throw new ArgumentNullException(nameof(chatGroupID) + " || " + nameof(chatID) + " || " + nameof(timestamp)); + if (chatGroupID == 0) { + throw new ArgumentOutOfRangeException(nameof(chatGroupID)); + } + + if (chatID == 0) { + throw new ArgumentOutOfRangeException(nameof(chatID)); + } + + if (timestamp == 0) { + throw new ArgumentOutOfRangeException(nameof(timestamp)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -131,8 +149,16 @@ namespace ArchiSteamFarm { } internal void AckMessage(ulong steamID, uint timestamp) { - if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount || (timestamp == 0)) { - throw new ArgumentNullException(nameof(steamID) + " || " + nameof(timestamp)); + if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) { + throw new ArgumentOutOfRangeException(nameof(steamID)); + } + + if (timestamp == 0) { + throw new ArgumentOutOfRangeException(nameof(timestamp)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -149,7 +175,11 @@ namespace ArchiSteamFarm { internal void AcknowledgeClanInvite(ulong steamID, bool acceptInvite) { if ((steamID == 0) || !new SteamID(steamID).IsClanAccount) { - throw new ArgumentNullException(nameof(steamID)); + throw new ArgumentOutOfRangeException(nameof(steamID)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -168,7 +198,11 @@ namespace ArchiSteamFarm { internal async Task AddFriend(ulong steamID) { if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) { - throw new ArgumentNullException(nameof(steamID)); + throw new ArgumentOutOfRangeException(nameof(steamID)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -192,7 +226,11 @@ namespace ArchiSteamFarm { internal async Task GetClanChatGroupID(ulong steamID) { if ((steamID == 0) || !new SteamID(steamID).IsClanAccount) { - throw new ArgumentNullException(nameof(steamID)); + throw new ArgumentOutOfRangeException(nameof(steamID)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -224,6 +262,10 @@ namespace ArchiSteamFarm { } internal async Task GetLevel() { + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); + } + if (!Client.IsConnected) { return null; } @@ -249,6 +291,10 @@ namespace ArchiSteamFarm { } internal async Task?> GetMyChatGroupIDs() { + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); + } + if (!Client.IsConnected) { return null; } @@ -275,6 +321,10 @@ namespace ArchiSteamFarm { } internal async Task GetPrivacySettings() { + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); + } + if (!Client.IsConnected) { return null; } @@ -301,6 +351,10 @@ namespace ArchiSteamFarm { } internal async Task GetTradeToken() { + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); + } + if (!Client.IsConnected) { return null; } @@ -328,7 +382,11 @@ namespace ArchiSteamFarm { internal async Task GetTwoFactorDeviceIdentifier(ulong steamID) { if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) { - throw new ArgumentNullException(nameof(steamID)); + throw new ArgumentOutOfRangeException(nameof(steamID)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -360,7 +418,11 @@ namespace ArchiSteamFarm { internal async Task JoinChatRoomGroup(ulong chatGroupID) { if (chatGroupID == 0) { - throw new ArgumentNullException(nameof(chatGroupID)); + throw new ArgumentOutOfRangeException(nameof(chatGroupID)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -387,6 +449,10 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(gameIDs)); } + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); + } + if (!Client.IsConnected) { return; } @@ -432,7 +498,11 @@ namespace ArchiSteamFarm { internal async Task RedeemGuestPass(ulong guestPassID) { if (guestPassID == 0) { - throw new ArgumentNullException(nameof(guestPassID)); + throw new ArgumentOutOfRangeException(nameof(guestPassID)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -460,6 +530,10 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(key)); } + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); + } + if (!Client.IsConnected) { return null; } @@ -482,7 +556,11 @@ namespace ArchiSteamFarm { internal async Task RemoveFriend(ulong steamID) { if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) { - throw new ArgumentNullException(nameof(steamID)); + throw new ArgumentOutOfRangeException(nameof(steamID)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -505,6 +583,10 @@ namespace ArchiSteamFarm { } internal void RequestItemAnnouncements() { + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); + } + if (!Client.IsConnected) { return; } @@ -514,8 +596,16 @@ namespace ArchiSteamFarm { } internal async Task SendMessage(ulong steamID, string message) { - if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount || string.IsNullOrEmpty(message)) { - throw new ArgumentNullException(nameof(steamID) + " || " + nameof(message)); + if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) { + throw new ArgumentOutOfRangeException(nameof(steamID)); + } + + if (string.IsNullOrEmpty(message)) { + throw new ArgumentNullException(nameof(message)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -543,8 +633,20 @@ namespace ArchiSteamFarm { } internal async Task SendMessage(ulong chatGroupID, ulong chatID, string message) { - if ((chatGroupID == 0) || (chatID == 0) || string.IsNullOrEmpty(message)) { - throw new ArgumentNullException(nameof(chatGroupID) + " || " + nameof(chatID) + " || " + nameof(message)); + if (chatGroupID == 0) { + throw new ArgumentOutOfRangeException(nameof(chatGroupID)); + } + + if (chatID == 0) { + throw new ArgumentOutOfRangeException(nameof(chatID)); + } + + if (string.IsNullOrEmpty(message)) { + throw new ArgumentNullException(nameof(message)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -572,7 +674,11 @@ namespace ArchiSteamFarm { internal async Task SendTypingStatus(ulong steamID) { if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) { - throw new ArgumentNullException(nameof(steamID)); + throw new ArgumentOutOfRangeException(nameof(steamID)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -599,7 +705,11 @@ namespace ArchiSteamFarm { internal void SetCurrentMode(uint chatMode) { if (chatMode == 0) { - throw new ArgumentNullException(nameof(chatMode)); + throw new ArgumentOutOfRangeException(nameof(chatMode)); + } + + if (Client == null) { + throw new InvalidOperationException(nameof(Client)); } if (!Client.IsConnected) { @@ -612,14 +722,18 @@ namespace ArchiSteamFarm { [SuppressMessage("ReSharper", "MemberCanBeInternal")] public sealed class PurchaseResponseCallback : CallbackMsg { - public readonly Dictionary? Items; + public Dictionary? Items { get; } public EPurchaseResultDetail PurchaseResultDetail { get; internal set; } public EResult Result { get; internal set; } internal PurchaseResponseCallback(EResult result, EPurchaseResultDetail purchaseResult) { - if (!Enum.IsDefined(typeof(EResult), result) || !Enum.IsDefined(typeof(EPurchaseResultDetail), purchaseResult)) { - throw new ArgumentNullException(nameof(result) + " || " + nameof(purchaseResult)); + if (!Enum.IsDefined(typeof(EResult), result)) { + throw new InvalidEnumArgumentException(nameof(result), (int) result, typeof(EResult)); + } + + if (!Enum.IsDefined(typeof(EPurchaseResultDetail), purchaseResult)) { + throw new InvalidEnumArgumentException(nameof(purchaseResult), (int) purchaseResult, typeof(EPurchaseResultDetail)); } Result = result; @@ -627,8 +741,12 @@ namespace ArchiSteamFarm { } internal PurchaseResponseCallback(JobID jobID, CMsgClientPurchaseResponse msg) { - if ((jobID == null) || (msg == null)) { - throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); + if (jobID == null) { + throw new ArgumentNullException(nameof(jobID)); + } + + if (msg == null) { + throw new ArgumentNullException(nameof(msg)); } JobID = jobID; @@ -693,8 +811,12 @@ namespace ArchiSteamFarm { internal readonly Dictionary Notifications; internal UserNotificationsCallback(JobID jobID, CMsgClientUserNotifications msg) { - if ((jobID == null) || (msg == null)) { - throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); + if (jobID == null) { + throw new ArgumentNullException(nameof(jobID)); + } + + if (msg == null) { + throw new ArgumentNullException(nameof(msg)); } JobID = jobID; @@ -723,7 +845,7 @@ namespace ArchiSteamFarm { case EUserNotification.Trading: break; default: - ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(type), type)); + ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(type), type)); break; } @@ -733,8 +855,12 @@ namespace ArchiSteamFarm { } internal UserNotificationsCallback(JobID jobID, CMsgClientItemAnnouncements msg) { - if ((jobID == null) || (msg == null)) { - throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); + if (jobID == null) { + throw new ArgumentNullException(nameof(jobID)); + } + + if (msg == null) { + throw new ArgumentNullException(nameof(msg)); } JobID = jobID; @@ -742,8 +868,12 @@ namespace ArchiSteamFarm { } internal UserNotificationsCallback(JobID jobID, CMsgClientCommentNotifications msg) { - if ((jobID == null) || (msg == null)) { - throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); + if (jobID == null) { + throw new ArgumentNullException(nameof(jobID)); + } + + if (msg == null) { + throw new ArgumentNullException(nameof(msg)); } JobID = jobID; @@ -770,8 +900,12 @@ namespace ArchiSteamFarm { internal readonly bool PlayingBlocked; internal PlayingSessionStateCallback(JobID jobID, CMsgClientPlayingSessionState msg) { - if ((jobID == null) || (msg == null)) { - throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); + if (jobID == null) { + throw new ArgumentNullException(nameof(jobID)); + } + + if (msg == null) { + throw new ArgumentNullException(nameof(msg)); } JobID = jobID; @@ -783,8 +917,12 @@ namespace ArchiSteamFarm { internal readonly EResult Result; internal RedeemGuestPassResponseCallback(JobID jobID, CMsgClientRedeemGuestPassResponse msg) { - if ((jobID == null) || (msg == null)) { - throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); + if (jobID == null) { + throw new ArgumentNullException(nameof(jobID)); + } + + if (msg == null) { + throw new ArgumentNullException(nameof(msg)); } JobID = jobID; @@ -796,8 +934,12 @@ namespace ArchiSteamFarm { internal readonly ulong LibraryLockedBySteamID; internal SharedLibraryLockStatusCallback(JobID jobID, CMsgClientSharedLibraryLockStatus msg) { - if ((jobID == null) || (msg == null)) { - throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); + if (jobID == null) { + throw new ArgumentNullException(nameof(jobID)); + } + + if (msg == null) { + throw new ArgumentNullException(nameof(msg)); } JobID = jobID; @@ -814,8 +956,12 @@ namespace ArchiSteamFarm { internal readonly string VanityURL; internal VanityURLChangedCallback(JobID jobID, CMsgClientVanityURLChangedNotification msg) { - if ((jobID == null) || (msg == null)) { - throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); + if (jobID == null) { + throw new ArgumentNullException(nameof(jobID)); + } + + if (msg == null) { + throw new ArgumentNullException(nameof(msg)); } JobID = jobID; diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index 0449bc8c6..00fe47706 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -23,6 +23,8 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; +using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; @@ -65,10 +67,10 @@ namespace ArchiSteamFarm { private static readonly ConcurrentDictionary CachedCardCountsForGame = new ConcurrentDictionary(); [PublicAPI] - public readonly ArchiCacheable CachedApiKey; + public ArchiCacheable CachedApiKey { get; } [PublicAPI] - public readonly WebBrowser WebBrowser; + public WebBrowser WebBrowser { get; } private readonly Bot Bot; private readonly SemaphoreSlim SessionSemaphore = new SemaphoreSlim(1, 1); @@ -113,8 +115,16 @@ namespace ArchiSteamFarm { [PublicAPI] public async IAsyncEnumerable GetInventoryAsync(ulong steamID = 0, uint appID = Steam.Asset.SteamAppID, ulong contextID = Steam.Asset.SteamCommunityContextID) { - if ((appID == 0) || (contextID == 0) || (ASF.InventorySemaphore == null)) { - throw new ArgumentNullException(nameof(appID) + " || " + nameof(contextID) + " || " + nameof(ASF.InventorySemaphore)); + if (appID == 0) { + throw new ArgumentOutOfRangeException(nameof(appID)); + } + + if (contextID == 0) { + throw new ArgumentOutOfRangeException(nameof(contextID)); + } + + if (ASF.InventorySemaphore == null) { + throw new InvalidOperationException(nameof(ASF.InventorySemaphore)); } if (steamID == 0) { @@ -132,7 +142,7 @@ namespace ArchiSteamFarm { steamID = Bot.SteamID; } else if (!new SteamID(steamID).IsIndividualAccount) { - throw new NotSupportedException(string.Format(Strings.ErrorObjectIsNull, nameof(steamID))); + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(steamID))); } string request = "/inventory/" + steamID + "/" + appID + "/" + contextID + "?count=" + MaxItemsInSingleInventoryRequest + "&l=english"; @@ -148,11 +158,11 @@ namespace ArchiSteamFarm { WebBrowser.ObjectResponse? response = await UrlGetToJsonObjectWithSession(SteamCommunityURL, request + (startAssetID > 0 ? "&start_assetid=" + startAssetID : "")).ConfigureAwait(false); if (response?.Content == null) { - throw new HttpRequestException(string.Format(Strings.ErrorObjectIsNull, nameof(response))); + throw new HttpRequestException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(response))); } if (response.Content.Result != EResult.OK) { - throw new HttpRequestException(!string.IsNullOrEmpty(response.Content.Error) ? string.Format(Strings.WarningFailedWithError, response.Content.Error) : Strings.WarningFailed); + throw new HttpRequestException(!string.IsNullOrEmpty(response.Content.Error) ? string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content.Error) : Strings.WarningFailed); } if (response.Content.TotalInventoryCount == 0) { @@ -161,14 +171,14 @@ namespace ArchiSteamFarm { } if ((response.Content.Assets == null) || (response.Content.Assets.Count == 0) || (response.Content.Descriptions == null) || (response.Content.Descriptions.Count == 0)) { - throw new NotSupportedException(string.Format(Strings.ErrorObjectIsNull, nameof(response.Content.Assets) + " || " + nameof(response.Content.Descriptions))); + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(response.Content.Assets) + " || " + nameof(response.Content.Descriptions))); } Dictionary<(ulong ClassID, ulong InstanceID), Steam.InventoryResponse.Description> descriptions = new Dictionary<(ulong ClassID, ulong InstanceID), Steam.InventoryResponse.Description>(); foreach (Steam.InventoryResponse.Description description in response.Content.Descriptions) { if (description.ClassID == 0) { - throw new NotSupportedException(string.Format(Strings.ErrorObjectIsNull, nameof(description.ClassID))); + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(description.ClassID))); } (ulong ClassID, ulong InstanceID) key = (description.ClassID, description.InstanceID); @@ -206,7 +216,7 @@ namespace ArchiSteamFarm { } if (response.Content.LastAssetID == 0) { - throw new NotSupportedException(string.Format(Strings.ErrorObjectIsNull, nameof(response.Content.LastAssetID))); + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(response.Content.LastAssetID))); } startAssetID = response.Content.LastAssetID; @@ -279,7 +289,7 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task?> GetOwnedGames(ulong steamID) { if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) { - throw new ArgumentNullException(nameof(steamID)); + throw new ArgumentOutOfRangeException(nameof(steamID)); } (bool success, string? steamApiKey) = await CachedApiKey.GetValue().ConfigureAwait(false); @@ -316,7 +326,7 @@ namespace ArchiSteamFarm { } if (response == null) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); return null; } @@ -357,8 +367,16 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task<(bool Success, HashSet? MobileTradeOfferIDs)> SendTradeOffer(ulong steamID, IReadOnlyCollection? itemsToGive = null, IReadOnlyCollection? itemsToReceive = null, string? token = null, bool forcedSingleOffer = false, ushort itemsPerTrade = Trading.MaxItemsPerTrade) { - if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount || (((itemsToGive == null) || (itemsToGive.Count == 0)) && ((itemsToReceive == null) || (itemsToReceive.Count == 0))) || (itemsPerTrade < 2)) { - throw new ArgumentNullException(nameof(steamID) + " || (" + nameof(itemsToGive) + " && " + nameof(itemsToReceive) + ") || " + nameof(itemsPerTrade)); + if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) { + throw new ArgumentOutOfRangeException(nameof(steamID)); + } + + if (((itemsToGive == null) || (itemsToGive.Count == 0)) && ((itemsToReceive == null) || (itemsToReceive.Count == 0))) { + throw new ArgumentException(nameof(itemsToGive) + " && " + nameof(itemsToReceive)); + } + + if (itemsPerTrade <= 2) { + throw new ArgumentOutOfRangeException(nameof(itemsPerTrade)); } Steam.TradeOfferSendRequest singleTrade = new Steam.TradeOfferSendRequest(); @@ -399,7 +417,7 @@ namespace ArchiSteamFarm { // Extra entry for sessionID Dictionary data = new Dictionary(6, StringComparer.Ordinal) { - { "partner", steamID.ToString() }, + { "partner", steamID.ToString(CultureInfo.InvariantCulture) }, { "serverid", "1" }, { "trade_offer_create_params", !string.IsNullOrEmpty(token) ? new JObject { { "trade_offer_access_token", token } }.ToString(Formatting.None) : "" }, { "tradeoffermessage", "Sent by " + SharedInfo.PublicIdentifier + "/" + SharedInfo.Version } @@ -426,13 +444,17 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task UrlGetToHtmlDocumentWithSession(string host, string request, IReadOnlyCollection>? headers = null, string? referer = null, WebBrowser.ERequestOptions requestOptions = WebBrowser.ERequestOptions.None, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) { - if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(request)) { - throw new ArgumentNullException(nameof(host) + " || " + nameof(request)); + if (string.IsNullOrEmpty(host)) { + throw new ArgumentNullException(nameof(host)); + } + + if (string.IsNullOrEmpty(request)) { + throw new ArgumentNullException(nameof(request)); } if (maxTries == 0) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -447,7 +469,7 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -466,7 +488,7 @@ namespace ArchiSteamFarm { if (!Initialized) { Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -484,14 +506,14 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } // Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) { - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); return await UrlGetToHtmlDocumentWithSession(host, request, headers, referer, requestOptions, checkSessionPreemptively, --maxTries).ConfigureAwait(false); } @@ -501,13 +523,17 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task?> UrlGetToJsonObjectWithSession(string host, string request, IReadOnlyCollection>? headers = null, string? referer = null, WebBrowser.ERequestOptions requestOptions = WebBrowser.ERequestOptions.None, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) where T : class { - if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(request)) { - throw new ArgumentNullException(nameof(host) + " || " + nameof(request)); + if (string.IsNullOrEmpty(host)) { + throw new ArgumentNullException(nameof(host)); + } + + if (string.IsNullOrEmpty(request)) { + throw new ArgumentNullException(nameof(request)); } if (maxTries == 0) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return default; } @@ -522,7 +548,7 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -541,7 +567,7 @@ namespace ArchiSteamFarm { if (!Initialized) { Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return default; } @@ -559,14 +585,14 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } // Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) { - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); return await UrlGetToJsonObjectWithSession(host, request, headers, referer, requestOptions, checkSessionPreemptively, --maxTries).ConfigureAwait(false); } @@ -576,13 +602,17 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task UrlGetToXmlDocumentWithSession(string host, string request, IReadOnlyCollection>? headers = null, string? referer = null, WebBrowser.ERequestOptions requestOptions = WebBrowser.ERequestOptions.None, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) { - if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(request)) { - throw new ArgumentNullException(nameof(host) + " || " + nameof(request)); + if (string.IsNullOrEmpty(host)) { + throw new ArgumentNullException(nameof(host)); + } + + if (string.IsNullOrEmpty(request)) { + throw new ArgumentNullException(nameof(request)); } if (maxTries == 0) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -597,7 +627,7 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -616,7 +646,7 @@ namespace ArchiSteamFarm { if (!Initialized) { Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -634,14 +664,14 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } // Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) { - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); return await UrlGetToXmlDocumentWithSession(host, request, headers, referer, requestOptions, checkSessionPreemptively, --maxTries).ConfigureAwait(false); } @@ -651,13 +681,17 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task UrlHeadWithSession(string host, string request, IReadOnlyCollection>? headers = null, string? referer = null, WebBrowser.ERequestOptions requestOptions = WebBrowser.ERequestOptions.None, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) { - if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(request)) { - throw new ArgumentNullException(nameof(host) + " || " + nameof(request)); + if (string.IsNullOrEmpty(host)) { + throw new ArgumentNullException(nameof(host)); + } + + if (string.IsNullOrEmpty(request)) { + throw new ArgumentNullException(nameof(request)); } if (maxTries == 0) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return false; } @@ -672,7 +706,7 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return false; } @@ -691,7 +725,7 @@ namespace ArchiSteamFarm { if (!Initialized) { Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return false; } @@ -709,14 +743,14 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return false; } // Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) { - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); return await UrlHeadWithSession(host, request, headers, referer, requestOptions, checkSessionPreemptively, --maxTries).ConfigureAwait(false); } @@ -726,13 +760,21 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task UrlPostToHtmlDocumentWithSession(string host, string request, IReadOnlyCollection>? headers = null, IDictionary? data = null, string? referer = null, WebBrowser.ERequestOptions requestOptions = WebBrowser.ERequestOptions.None, ESession session = ESession.Lowercase, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) { - if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(request) || !Enum.IsDefined(typeof(ESession), session)) { - throw new ArgumentNullException(nameof(host) + " || " + nameof(request) + " || " + nameof(session)); + if (string.IsNullOrEmpty(host)) { + throw new ArgumentNullException(nameof(host)); + } + + if (string.IsNullOrEmpty(request)) { + throw new ArgumentNullException(nameof(request)); + } + + if (!Enum.IsDefined(typeof(ESession), session)) { + throw new InvalidEnumArgumentException(nameof(session), (int) session, typeof(ESession)); } if (maxTries == 0) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -747,7 +789,7 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -766,7 +808,7 @@ namespace ArchiSteamFarm { if (!Initialized) { Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -807,14 +849,14 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } // Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) { - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); return await UrlPostToHtmlDocumentWithSession(host, request, headers, data, referer, requestOptions, session, checkSessionPreemptively, --maxTries).ConfigureAwait(false); } @@ -824,13 +866,21 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task?> UrlPostToJsonObjectWithSession(string host, string request, IReadOnlyCollection>? headers = null, IDictionary? data = null, string? referer = null, WebBrowser.ERequestOptions requestOptions = WebBrowser.ERequestOptions.None, ESession session = ESession.Lowercase, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) where T : class { - if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(request) || !Enum.IsDefined(typeof(ESession), session)) { - throw new ArgumentNullException(nameof(host) + " || " + nameof(request) + " || " + nameof(session)); + if (string.IsNullOrEmpty(host)) { + throw new ArgumentNullException(nameof(host)); + } + + if (string.IsNullOrEmpty(request)) { + throw new ArgumentNullException(nameof(request)); + } + + if (!Enum.IsDefined(typeof(ESession), session)) { + throw new InvalidEnumArgumentException(nameof(session), (int) session, typeof(ESession)); } if (maxTries == 0) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -845,7 +895,7 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -864,7 +914,7 @@ namespace ArchiSteamFarm { if (!Initialized) { Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -905,14 +955,14 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } // Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) { - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); return await UrlPostToJsonObjectWithSession(host, request, headers, data, referer, requestOptions, session, checkSessionPreemptively, --maxTries).ConfigureAwait(false); } @@ -922,13 +972,21 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task?> UrlPostToJsonObjectWithSession(string host, string request, IReadOnlyCollection>? headers = null, ICollection>? data = null, string? referer = null, WebBrowser.ERequestOptions requestOptions = WebBrowser.ERequestOptions.None, ESession session = ESession.Lowercase, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) where T : class { - if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(request) || !Enum.IsDefined(typeof(ESession), session)) { - throw new ArgumentNullException(nameof(host) + " || " + nameof(request) + " || " + nameof(session)); + if (string.IsNullOrEmpty(host)) { + throw new ArgumentNullException(nameof(host)); + } + + if (string.IsNullOrEmpty(request)) { + throw new ArgumentNullException(nameof(request)); + } + + if (!Enum.IsDefined(typeof(ESession), session)) { + throw new InvalidEnumArgumentException(nameof(session), (int) session, typeof(ESession)); } if (maxTries == 0) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -943,7 +1001,7 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -962,7 +1020,7 @@ namespace ArchiSteamFarm { if (!Initialized) { Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } @@ -1006,14 +1064,14 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return null; } // Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) { - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); return await UrlPostToJsonObjectWithSession(host, request, headers, data, referer, requestOptions, session, checkSessionPreemptively, --maxTries).ConfigureAwait(false); } @@ -1023,13 +1081,21 @@ namespace ArchiSteamFarm { [PublicAPI] public async Task UrlPostWithSession(string host, string request, IReadOnlyCollection>? headers = null, IDictionary? data = null, string? referer = null, WebBrowser.ERequestOptions requestOptions = WebBrowser.ERequestOptions.None, ESession session = ESession.Lowercase, bool checkSessionPreemptively = true, byte maxTries = WebBrowser.MaxTries) { - if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(request) || !Enum.IsDefined(typeof(ESession), session)) { - throw new ArgumentNullException(nameof(host) + " || " + nameof(request) + " || " + nameof(session)); + if (string.IsNullOrEmpty(host)) { + throw new ArgumentNullException(nameof(host)); + } + + if (string.IsNullOrEmpty(request)) { + throw new ArgumentNullException(nameof(request)); + } + + if (!Enum.IsDefined(typeof(ESession), session)) { + throw new InvalidEnumArgumentException(nameof(session), (int) session, typeof(ESession)); } if (maxTries == 0) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return false; } @@ -1044,7 +1110,7 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return false; } @@ -1063,7 +1129,7 @@ namespace ArchiSteamFarm { if (!Initialized) { Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return false; } @@ -1104,14 +1170,14 @@ namespace ArchiSteamFarm { } Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, host + request)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, host + request)); return false; } // Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case if (await IsProfileUri(response.FinalUri).ConfigureAwait(false)) { - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); return await UrlPostWithSession(host, request, headers, data, referer, requestOptions, session, checkSessionPreemptively, --maxTries).ConfigureAwait(false); } @@ -1121,8 +1187,16 @@ namespace ArchiSteamFarm { [PublicAPI] public static async Task WebLimitRequest(string service, Func> function) where T : class { - if (string.IsNullOrEmpty(service) || (function == null) || (ASF.WebLimitingSemaphores == null)) { - throw new ArgumentNullException(nameof(service) + " || " + nameof(function) + " || " + nameof(ASF.WebLimitingSemaphores)); + if (string.IsNullOrEmpty(service)) { + throw new ArgumentNullException(nameof(service)); + } + + if (function == null) { + throw new ArgumentNullException(nameof(function)); + } + + if (ASF.WebLimitingSemaphores == null) { + throw new InvalidOperationException(nameof(ASF.WebLimitingSemaphores)); } ushort webLimiterDelay = ASF.GlobalConfig?.WebLimiterDelay ?? GlobalConfig.DefaultWebLimiterDelay; @@ -1132,7 +1206,7 @@ namespace ArchiSteamFarm { } if (!ASF.WebLimitingSemaphores.TryGetValue(service, out (ICrossProcessSemaphore RateLimitingSemaphore, SemaphoreSlim OpenConnectionsSemaphore) limiters)) { - ASF.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(service), service)); + ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(service), service)); if (!ASF.WebLimitingSemaphores.TryGetValue(nameof(ArchiWebHandler), out limiters)) { ASF.ArchiLogger.LogNullError(nameof(limiters)); @@ -1165,7 +1239,7 @@ namespace ArchiSteamFarm { internal async Task AcceptDigitalGiftCard(ulong giftCardID) { if (giftCardID == 0) { - throw new ArgumentNullException(nameof(giftCardID)); + throw new ArgumentOutOfRangeException(nameof(giftCardID)); } const string request = "/gifts/0/resolvegiftcard"; @@ -1173,7 +1247,7 @@ namespace ArchiSteamFarm { // Extra entry for sessionID Dictionary data = new Dictionary(3, StringComparer.Ordinal) { { "accept", "1" }, - { "giftcardid", giftCardID.ToString() } + { "giftcardid", giftCardID.ToString(CultureInfo.InvariantCulture) } }; WebBrowser.ObjectResponse? response = await UrlPostToJsonObjectWithSession(SteamStoreURL, request, data: data).ConfigureAwait(false); @@ -1193,14 +1267,14 @@ namespace ArchiSteamFarm { internal async Task<(bool Success, bool RequiresMobileConfirmation)> AcceptTradeOffer(ulong tradeID, byte maxTries = WebBrowser.MaxTries) { if (tradeID == 0) { - throw new ArgumentNullException(nameof(tradeID)); + throw new ArgumentOutOfRangeException(nameof(tradeID)); } string request = "/tradeoffer/" + tradeID + "/accept"; if (maxTries == 0) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, SteamCommunityURL + request)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, SteamCommunityURL + request)); return (false, false); } @@ -1210,7 +1284,7 @@ namespace ArchiSteamFarm { // Extra entry for sessionID Dictionary data = new Dictionary(3, StringComparer.Ordinal) { { "serverid", "1" }, - { "tradeofferid", tradeID.ToString() } + { "tradeofferid", tradeID.ToString(CultureInfo.InvariantCulture) } }; WebBrowser.ObjectResponse? response = await UrlPostToJsonObjectWithSession(SteamCommunityURL, request, data: data, referer: referer, requestOptions: WebBrowser.ERequestOptions.ReturnServerErrors).ConfigureAwait(false); @@ -1226,7 +1300,7 @@ namespace ArchiSteamFarm { } // This is actually client error with a reason, so it doesn't make sense to retry - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningFailedWithError, response.Content!.ErrorText)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content!.ErrorText)); return (false, false); } @@ -1236,7 +1310,7 @@ namespace ArchiSteamFarm { internal async Task AddFreeLicense(uint subID) { if (subID == 0) { - throw new ArgumentNullException(nameof(subID)); + throw new ArgumentOutOfRangeException(nameof(subID)); } const string request = "/checkout/addfreelicense"; @@ -1244,7 +1318,7 @@ namespace ArchiSteamFarm { // Extra entry for sessionID Dictionary data = new Dictionary(3, StringComparer.Ordinal) { { "action", "add_to_cart" }, - { "subid", subID.ToString() } + { "subid", subID.ToString(CultureInfo.InvariantCulture) } }; using WebBrowser.HtmlDocumentResponse? response = await UrlPostToHtmlDocumentWithSession(SteamStoreURL, request, data: data).ConfigureAwait(false); @@ -1269,7 +1343,7 @@ namespace ArchiSteamFarm { // Extra entry for sessionID Dictionary data = new Dictionary(3, StringComparer.Ordinal) { - { "eCommentPermission", ((byte) userPrivacy.CommentPermission).ToString() }, + { "eCommentPermission", ((byte) userPrivacy.CommentPermission).ToString(CultureInfo.InvariantCulture) }, { "Privacy", JsonConvert.SerializeObject(userPrivacy.Settings) } }; @@ -1290,20 +1364,20 @@ namespace ArchiSteamFarm { internal async Task ClearFromDiscoveryQueue(uint appID) { if (appID == 0) { - throw new ArgumentNullException(nameof(appID)); + throw new ArgumentOutOfRangeException(nameof(appID)); } string request = "/app/" + appID; // Extra entry for sessionID - Dictionary data = new Dictionary(2, StringComparer.Ordinal) { { "appid_to_clear_from_queue", appID.ToString() } }; + Dictionary data = new Dictionary(2, StringComparer.Ordinal) { { "appid_to_clear_from_queue", appID.ToString(CultureInfo.InvariantCulture) } }; return await UrlPostWithSession(SteamStoreURL, request, data: data).ConfigureAwait(false); } internal async Task DeclineTradeOffer(ulong tradeID) { if (tradeID == 0) { - throw new ArgumentNullException(nameof(tradeID)); + throw new ArgumentOutOfRangeException(nameof(tradeID)); } (bool success, string? steamApiKey) = await CachedApiKey.GetValue().ConfigureAwait(false); @@ -1339,7 +1413,7 @@ namespace ArchiSteamFarm { } if (response == null) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); return false; } @@ -1397,7 +1471,7 @@ namespace ArchiSteamFarm { } if (response == null) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); return null; } @@ -1505,7 +1579,7 @@ namespace ArchiSteamFarm { if (itemsToGive.Count > 0) { if (!ParseItems(descriptions, itemsToGive, tradeOffer.ItemsToGive)) { - Bot.ArchiLogger.LogGenericError(string.Format(Strings.ErrorParsingObject, nameof(itemsToGive))); + Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorParsingObject, nameof(itemsToGive))); return null; } @@ -1515,7 +1589,7 @@ namespace ArchiSteamFarm { if (itemsToReceive.Count > 0) { if (!ParseItems(descriptions, itemsToReceive, tradeOffer.ItemsToReceive)) { - Bot.ArchiLogger.LogGenericError(string.Format(Strings.ErrorParsingObject, nameof(itemsToReceive))); + Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorParsingObject, nameof(itemsToReceive))); return null; } @@ -1550,7 +1624,7 @@ namespace ArchiSteamFarm { } if (response == null) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); return null; } @@ -1558,7 +1632,7 @@ namespace ArchiSteamFarm { List apps = response["apps"].Children; if (apps.Count == 0) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorIsEmpty, nameof(apps))); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(apps))); return null; } @@ -1580,7 +1654,7 @@ namespace ArchiSteamFarm { internal async Task GetBadgePage(byte page) { if (page == 0) { - throw new ArgumentNullException(nameof(page)); + throw new ArgumentOutOfRangeException(nameof(page)); } string request = "/my/badges?l=english&p=" + page; @@ -1592,7 +1666,7 @@ namespace ArchiSteamFarm { internal async Task GetCardCountForGame(uint appID) { if (appID == 0) { - throw new ArgumentNullException(nameof(appID)); + throw new ArgumentOutOfRangeException(nameof(appID)); } if (CachedCardCountsForGame.TryGetValue(appID, out byte result)) { @@ -1622,8 +1696,16 @@ namespace ArchiSteamFarm { } internal async Task GetConfirmationsPage(string deviceID, string confirmationHash, uint time) { - if (string.IsNullOrEmpty(deviceID) || string.IsNullOrEmpty(confirmationHash) || (time == 0)) { - throw new ArgumentNullException(nameof(deviceID) + " || " + nameof(confirmationHash) + " || " + nameof(time)); + if (string.IsNullOrEmpty(deviceID)) { + throw new ArgumentNullException(nameof(deviceID)); + } + + if (string.IsNullOrEmpty(confirmationHash)) { + throw new ArgumentNullException(nameof(confirmationHash)); + } + + if (time == 0) { + throw new ArgumentOutOfRangeException(nameof(time)); } if (!Initialized) { @@ -1672,13 +1754,13 @@ namespace ArchiSteamFarm { } if (giftCardIDText.Length <= 13) { - Bot.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, nameof(giftCardIDText))); + Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(giftCardIDText))); return null; } if (!ulong.TryParse(giftCardIDText.Substring(13), out ulong giftCardID) || (giftCardID == 0)) { - Bot.ArchiLogger.LogGenericError(string.Format(Strings.ErrorParsingObject, nameof(giftCardID))); + Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorParsingObject, nameof(giftCardID))); return null; } @@ -1737,7 +1819,7 @@ namespace ArchiSteamFarm { internal async Task GetGameCardsPage(uint appID) { if (appID == 0) { - throw new ArgumentNullException(nameof(appID)); + throw new ArgumentOutOfRangeException(nameof(appID)); } string request = "/my/gamecards/" + appID + "?l=english"; @@ -1770,7 +1852,7 @@ namespace ArchiSteamFarm { } if (response == null) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); return 0; } @@ -1788,7 +1870,7 @@ namespace ArchiSteamFarm { internal async Task GetTradeHoldDurationForTrade(ulong tradeID) { if (tradeID == 0) { - throw new ArgumentNullException(nameof(tradeID)); + throw new ArgumentOutOfRangeException(nameof(tradeID)); } string request = "/tradeoffer/" + tradeID + "?l=english"; @@ -1843,7 +1925,7 @@ namespace ArchiSteamFarm { internal async Task GetTradeHoldDurationForUser(ulong steamID, string? tradeToken = null) { if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) { - throw new ArgumentNullException(nameof(steamID)); + throw new ArgumentOutOfRangeException(nameof(steamID)); } (bool success, string? steamApiKey) = await CachedApiKey.GetValue().ConfigureAwait(false); @@ -1883,7 +1965,7 @@ namespace ArchiSteamFarm { } if (response == null) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); return null; } @@ -1900,8 +1982,24 @@ namespace ArchiSteamFarm { } internal async Task HandleConfirmation(string deviceID, string confirmationHash, uint time, ulong confirmationID, ulong confirmationKey, bool accept) { - if (string.IsNullOrEmpty(deviceID) || string.IsNullOrEmpty(confirmationHash) || (time == 0) || (confirmationID == 0) || (confirmationKey == 0)) { - throw new ArgumentNullException(nameof(deviceID) + " || " + nameof(confirmationHash) + " || " + nameof(time) + " || " + nameof(confirmationID) + " || " + nameof(confirmationKey)); + if (string.IsNullOrEmpty(deviceID)) { + throw new ArgumentNullException(nameof(deviceID)); + } + + if (string.IsNullOrEmpty(confirmationHash)) { + throw new ArgumentNullException(nameof(confirmationHash)); + } + + if (time == 0) { + throw new ArgumentOutOfRangeException(nameof(time)); + } + + if (confirmationID == 0) { + throw new ArgumentOutOfRangeException(nameof(confirmationID)); + } + + if (confirmationKey == 0) { + throw new ArgumentOutOfRangeException(nameof(confirmationKey)); } if (!Initialized) { @@ -1926,8 +2024,20 @@ namespace ArchiSteamFarm { } internal async Task HandleConfirmations(string deviceID, string confirmationHash, uint time, IReadOnlyCollection confirmations, bool accept) { - if (string.IsNullOrEmpty(deviceID) || string.IsNullOrEmpty(confirmationHash) || (time == 0) || (confirmations == null) || (confirmations.Count == 0)) { - throw new ArgumentNullException(nameof(deviceID) + " || " + nameof(confirmationHash) + " || " + nameof(time) + " || " + nameof(confirmations)); + if (string.IsNullOrEmpty(deviceID)) { + throw new ArgumentNullException(nameof(deviceID)); + } + + if (string.IsNullOrEmpty(confirmationHash)) { + throw new ArgumentNullException(nameof(confirmationHash)); + } + + if (time == 0) { + throw new ArgumentOutOfRangeException(nameof(time)); + } + + if ((confirmations == null) || (confirmations.Count == 0)) { + throw new ArgumentNullException(nameof(confirmations)); } if (!Initialized) { @@ -1948,18 +2058,18 @@ namespace ArchiSteamFarm { // Extra entry for sessionID List> data = new List>(8 + (confirmations.Count * 2)) { - new KeyValuePair("a", Bot.SteamID.ToString()), + new KeyValuePair("a", Bot.SteamID.ToString(CultureInfo.InvariantCulture)), new KeyValuePair("k", confirmationHash), new KeyValuePair("m", "android"), new KeyValuePair("op", accept ? "allow" : "cancel"), new KeyValuePair("p", deviceID), - new KeyValuePair("t", time.ToString()), + new KeyValuePair("t", time.ToString(CultureInfo.InvariantCulture)), new KeyValuePair("tag", "conf") }; foreach (MobileAuthenticator.Confirmation confirmation in confirmations) { - data.Add(new KeyValuePair("cid[]", confirmation.ID.ToString())); - data.Add(new KeyValuePair("ck[]", confirmation.Key.ToString())); + data.Add(new KeyValuePair("cid[]", confirmation.ID.ToString(CultureInfo.InvariantCulture))); + data.Add(new KeyValuePair("ck[]", confirmation.Key.ToString(CultureInfo.InvariantCulture))); } WebBrowser.ObjectResponse? response = await UrlPostToJsonObjectWithSession(SteamCommunityURL, request, data: data).ConfigureAwait(false); @@ -1968,8 +2078,16 @@ namespace ArchiSteamFarm { } internal async Task Init(ulong steamID, EUniverse universe, string webAPIUserNonce, string? parentalCode = null) { - if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount || (universe == EUniverse.Invalid) || !Enum.IsDefined(typeof(EUniverse), universe) || string.IsNullOrEmpty(webAPIUserNonce)) { - throw new ArgumentNullException(nameof(steamID) + " || " + nameof(universe) + " || " + nameof(webAPIUserNonce)); + if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) { + throw new ArgumentOutOfRangeException(nameof(steamID)); + } + + if ((universe == EUniverse.Invalid) || !Enum.IsDefined(typeof(EUniverse), universe)) { + throw new InvalidEnumArgumentException(nameof(universe), (int) universe, typeof(EUniverse)); + } + + if (string.IsNullOrEmpty(webAPIUserNonce)) { + throw new ArgumentNullException(nameof(webAPIUserNonce)); } byte[]? publicKey = KeyDictionary.GetPublicKey(universe); @@ -1997,7 +2115,7 @@ namespace ArchiSteamFarm { byte[] encryptedLoginKey = CryptoHelper.SymmetricEncrypt(loginKey, sessionKey); // We're now ready to send the data to Steam API - Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.LoggingIn, ISteamUserAuth)); + Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.LoggingIn, ISteamUserAuth)); KeyValue? response; @@ -2051,7 +2169,7 @@ namespace ArchiSteamFarm { return false; } - string sessionID = Convert.ToBase64String(Encoding.UTF8.GetBytes(steamID.ToString())); + string sessionID = Convert.ToBase64String(Encoding.UTF8.GetBytes(steamID.ToString(CultureInfo.InvariantCulture))); WebBrowser.CookieContainer.Add(new Cookie("sessionid", sessionID, "/", "." + SteamCommunityHost)); WebBrowser.CookieContainer.Add(new Cookie("sessionid", sessionID, "/", "." + SteamHelpHost)); @@ -2075,7 +2193,7 @@ namespace ArchiSteamFarm { Bot.ArchiLogger.LogGenericInfo(Strings.Success); // Unlock Steam Parental if needed - if ((parentalCode != null) && (parentalCode.Length == 4)) { + if (parentalCode?.Length == BotConfig.SteamParentalCodeLength) { if (!await UnlockParentalAccount(parentalCode).ConfigureAwait(false)) { return false; } @@ -2089,7 +2207,7 @@ namespace ArchiSteamFarm { internal async Task JoinGroup(ulong groupID) { if ((groupID == 0) || !new SteamID(groupID).IsClanAccount) { - throw new ArgumentNullException(nameof(groupID)); + throw new ArgumentOutOfRangeException(nameof(groupID)); } string request = "/gid/" + groupID; @@ -2102,7 +2220,7 @@ namespace ArchiSteamFarm { internal async Task MarkInventory() { if (ASF.InventorySemaphore == null) { - throw new ArgumentNullException(nameof(ASF.InventorySemaphore)); + throw new InvalidOperationException(nameof(ASF.InventorySemaphore)); } // We aim to have a maximum of 2 tasks, one already working, and one waiting in the queue @@ -2185,8 +2303,12 @@ namespace ArchiSteamFarm { } internal async Task UnpackBooster(uint appID, ulong itemID) { - if ((appID == 0) || (itemID == 0)) { - throw new ArgumentNullException(nameof(appID) + " || " + nameof(itemID)); + if (appID == 0) { + throw new ArgumentOutOfRangeException(nameof(appID)); + } + + if (itemID == 0) { + throw new ArgumentOutOfRangeException(nameof(itemID)); } string? profileURL = await GetAbsoluteProfileURL().ConfigureAwait(false); @@ -2201,8 +2323,8 @@ namespace ArchiSteamFarm { // Extra entry for sessionID Dictionary data = new Dictionary(3, StringComparer.Ordinal) { - { "appid", appID.ToString() }, - { "communityitemid", itemID.ToString() } + { "appid", appID.ToString(CultureInfo.InvariantCulture) }, + { "communityitemid", itemID.ToString(CultureInfo.InvariantCulture) } }; WebBrowser.ObjectResponse? response = await UrlPostToJsonObjectWithSession(SteamCommunityURL, request, data: data).ConfigureAwait(false); @@ -2293,7 +2415,7 @@ namespace ArchiSteamFarm { return false; } - return uri.AbsolutePath.Equals(profileURL); + return uri.AbsolutePath.Equals(profileURL, StringComparison.OrdinalIgnoreCase); } private async Task IsSessionExpired() { @@ -2349,12 +2471,20 @@ namespace ArchiSteamFarm { throw new ArgumentNullException(nameof(uri)); } - return uri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal) || uri.Host.Equals("lostauth"); + return uri.AbsolutePath.StartsWith("/login", StringComparison.OrdinalIgnoreCase) || uri.Host.Equals("lostauth", StringComparison.OrdinalIgnoreCase); } private static bool ParseItems(IReadOnlyDictionary<(uint AppID, ulong ClassID, ulong InstanceID), Steam.InventoryResponse.Description> descriptions, IReadOnlyCollection input, ICollection output) { - if ((descriptions == null) || (input == null) || (input.Count == 0) || (output == null)) { - throw new ArgumentNullException(nameof(descriptions) + " || " + nameof(input) + " || " + nameof(output)); + if (descriptions == null) { + throw new ArgumentNullException(nameof(descriptions)); + } + + if ((input == null) || (input.Count == 0)) { + throw new ArgumentNullException(nameof(input)); + } + + if (output == null) { + throw new ArgumentNullException(nameof(output)); } foreach (KeyValue item in input) { @@ -2517,7 +2647,7 @@ namespace ArchiSteamFarm { return (false, null); default: // We got an unhandled error, this should never happen - Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(result.State), result.State)); + Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(result.State), result.State)); return (false, null); } @@ -2544,15 +2674,19 @@ namespace ArchiSteamFarm { } private async Task UnlockParentalAccountForService(string serviceURL, string parentalCode, byte maxTries = WebBrowser.MaxTries) { - if (string.IsNullOrEmpty(serviceURL) || string.IsNullOrEmpty(parentalCode)) { - throw new ArgumentNullException(nameof(serviceURL) + " || " + nameof(parentalCode)); + if (string.IsNullOrEmpty(serviceURL)) { + throw new ArgumentNullException(nameof(serviceURL)); + } + + if (string.IsNullOrEmpty(parentalCode)) { + throw new ArgumentNullException(nameof(parentalCode)); } const string request = "/parental/ajaxunlock"; if (maxTries == 0) { - Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, serviceURL + request)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.ErrorFailingRequest, serviceURL + request)); return false; } @@ -2580,7 +2714,7 @@ namespace ArchiSteamFarm { // Under special brain-damaged circumstances, Steam might just return our own profile as a response to the request, for absolutely no reason whatsoever - just try again in this case if (await IsProfileUri(response.FinalUri, false).ConfigureAwait(false)) { - Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); + Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.WarningWorkaroundTriggered, nameof(IsProfileUri))); return await UnlockParentalAccountForService(serviceURL, parentalCode, --maxTries).ConfigureAwait(false); } diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index db15c2c0b..59ba8004f 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -1195,7 +1195,7 @@ namespace ArchiSteamFarm { HashSet? customHandlers = await PluginsCore.OnBotSteamHandlersInit(bot).ConfigureAwait(false); - if ((customHandlers != null) && (customHandlers.Count > 0)) { + if (customHandlers?.Count > 0) { foreach (ClientMsgHandler customHandler in customHandlers) { bot.SteamClient.AddHandler(customHandler); } @@ -3236,11 +3236,11 @@ namespace ArchiSteamFarm { BotDatabase.RemoveGameToRedeemInBackground(key!); // If user omitted the name or intentionally provided the same name as key, replace it with the Steam result - if (name!.Equals(key) && (result.Items != null) && (result.Items.Count > 0)) { + if (name!.Equals(key) && (result.Items?.Count > 0)) { name = string.Join(", ", result.Items.Values); } - string logEntry = name + DefaultBackgroundKeysRedeemerSeparator + "[" + result.PurchaseResultDetail + "]" + ((result.Items != null) && (result.Items.Count > 0) ? DefaultBackgroundKeysRedeemerSeparator + string.Join(", ", result.Items) : "") + DefaultBackgroundKeysRedeemerSeparator + key; + string logEntry = name + DefaultBackgroundKeysRedeemerSeparator + "[" + result.PurchaseResultDetail + "]" + (result.Items?.Count > 0 ? DefaultBackgroundKeysRedeemerSeparator + string.Join(", ", result.Items) : "") + DefaultBackgroundKeysRedeemerSeparator + key; string filePath = GetFilePath(redeemed ? EFileType.KeysToRedeemUsed : EFileType.KeysToRedeemUnused); @@ -3373,7 +3373,7 @@ namespace ArchiSteamFarm { return (true, null); } - if ((steamParentalCode != null) && (steamParentalCode.Length == BotConfig.SteamParentalCodeLength)) { + if (steamParentalCode?.Length == BotConfig.SteamParentalCodeLength) { byte i = 0; byte[] password = new byte[steamParentalCode.Length]; diff --git a/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs b/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs index a6009a4d5..f1e07507c 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs @@ -111,7 +111,11 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { request.BotConfig.ShouldSerializeHelperProperties = false; request.BotConfig.ShouldSerializeSensitiveDetails = true; - HashSet bots = botNames.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Where(botName => botName != SharedInfo.ASF).ToHashSet(Bot.BotsComparer); + HashSet bots = botNames.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToHashSet(Bot.BotsComparer); + + if (bots.Any(botName => !ASF.IsValidBotName(botName))) { + return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(botNames)))); + } Dictionary result = new Dictionary(bots.Count, Bot.BotsComparer); @@ -374,7 +378,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { throw new InvalidOperationException(nameof(Bot.Bots)); } - if (string.IsNullOrEmpty(request.NewName) || request.NewName!.Equals(SharedInfo.ASF, StringComparison.OrdinalIgnoreCase) || Bot.Bots.ContainsKey(request.NewName)) { + if (string.IsNullOrEmpty(request.NewName) || !ASF.IsValidBotName(request.NewName!) || Bot.Bots.ContainsKey(request.NewName!)) { return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(request.NewName)))); } @@ -382,7 +386,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botName))); } - bool result = await bot.Rename(request.NewName).ConfigureAwait(false); + bool result = await bot.Rename(request.NewName!).ConfigureAwait(false); return Ok(new GenericResponse(result)); }