From c594da5acbd6d22f4666fc888f03c59cd77f2184 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Wed, 23 Jan 2019 17:58:37 +0100 Subject: [PATCH] Add 2FA actions to ASF API --- ArchiSteamFarm/Actions.cs | 67 ++++++----- ArchiSteamFarm/Commands.cs | 60 +++++----- .../IPC/Controllers/Api/ASFController.cs | 8 +- .../IPC/Controllers/Api/BotController.cs | 106 ++++++++++++++++-- .../ApiAuthenticationMiddleware.cs | 2 +- ArchiSteamFarm/IPC/Startup.cs | 2 +- ArchiSteamFarm/Statistics.cs | 4 +- ArchiSteamFarm/Trading.cs | 4 +- 8 files changed, 179 insertions(+), 74 deletions(-) rename ArchiSteamFarm/IPC/{Middleware => Integration}/ApiAuthenticationMiddleware.cs (99%) diff --git a/ArchiSteamFarm/Actions.cs b/ArchiSteamFarm/Actions.cs index aad669adb..541dba702 100644 --- a/ArchiSteamFarm/Actions.cs +++ b/ArchiSteamFarm/Actions.cs @@ -57,9 +57,33 @@ namespace ArchiSteamFarm { } [PublicAPI] - public async Task AcceptConfirmations(bool accept, Steam.ConfirmationDetails.EType? acceptedType = null, IReadOnlyCollection acceptedTradeOfferIDs = null, bool waitIfNeeded = false) { + public static (bool Success, string Message) Exit() { + // Schedule the task after some time so user can receive response + Utilities.InBackground( + async () => { + await Task.Delay(1000).ConfigureAwait(false); + await Program.Exit().ConfigureAwait(false); + } + ); + + return (true, Strings.Done); + } + + [PublicAPI] + public async Task<(bool Success, string Token, string Message)> GenerateTwoFactorAuthenticationToken() { if (!Bot.HasMobileAuthenticator) { - return false; + return (false, null, Strings.BotNoASFAuthenticator); + } + + string token = await Bot.BotDatabase.MobileAuthenticator.GenerateToken().ConfigureAwait(false); + + return (true, token, Strings.Success); + } + + [PublicAPI] + public async Task<(bool Success, string Message)> HandleTwoFactorAuthenticationConfirmations(bool accept, Steam.ConfirmationDetails.EType? acceptedType = null, IReadOnlyCollection acceptedTradeOfferIDs = null, bool waitIfNeeded = false) { + if (!Bot.HasMobileAuthenticator) { + return (false, Strings.BotNoASFAuthenticator); } HashSet handledTradeOfferIDs = null; @@ -77,7 +101,9 @@ namespace ArchiSteamFarm { // If we can skip asking for details, we can handle confirmations right away if ((acceptedTradeOfferIDs == null) || (acceptedTradeOfferIDs.Count == 0)) { - return await Bot.BotDatabase.MobileAuthenticator.HandleConfirmations(confirmations, accept).ConfigureAwait(false); + bool result = await Bot.BotDatabase.MobileAuthenticator.HandleConfirmations(confirmations, accept).ConfigureAwait(false); + + return (result, result ? Strings.Success : Strings.WarningFailed); } IList results = await Utilities.InParallel(confirmations.Select(Bot.BotDatabase.MobileAuthenticator.GetConfirmationDetails)).ConfigureAwait(false); @@ -91,7 +117,7 @@ namespace ArchiSteamFarm { } if (!await Bot.BotDatabase.MobileAuthenticator.HandleConfirmations(confirmations, accept).ConfigureAwait(false)) { - return false; + return (false, Strings.WarningFailed); } IEnumerable handledTradeOfferIDsThisRound = results.Where(details => (details != null) && (details.TradeOfferID != 0)).Select(result => result.TradeOfferID); @@ -104,28 +130,15 @@ namespace ArchiSteamFarm { // Check if those are all that we were expected to confirm if (acceptedTradeOfferIDs.All(handledTradeOfferIDs.Contains)) { - return true; + return (true, Strings.Success); } } - return !waitIfNeeded; + return (!waitIfNeeded, waitIfNeeded ? Strings.Success : string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)); } [PublicAPI] - public static (bool Success, string Output) Exit() { - // Schedule the task after some time so user can receive response - Utilities.InBackground( - async () => { - await Task.Delay(1000).ConfigureAwait(false); - await Program.Exit().ConfigureAwait(false); - } - ); - - return (true, Strings.Done); - } - - [PublicAPI] - public async Task<(bool Success, string Output)> Pause(bool permanent, ushort resumeInSeconds = 0) { + public async Task<(bool Success, string Message)> Pause(bool permanent, ushort resumeInSeconds = 0) { if (Bot.CardsFarmer.Paused) { return (false, Strings.BotAutomaticIdlingPausedAlready); } @@ -165,7 +178,7 @@ namespace ArchiSteamFarm { } [PublicAPI] - public static (bool Success, string Output) Restart() { + public static (bool Success, string Message) Restart() { // Schedule the task after some time so user can receive response Utilities.InBackground( async () => { @@ -178,7 +191,7 @@ namespace ArchiSteamFarm { } [PublicAPI] - public (bool Success, string Output) Resume() { + public (bool Success, string Message) Resume() { if (!Bot.CardsFarmer.Paused) { return (false, Strings.BotAutomaticIdlingResumedAlready); } @@ -189,7 +202,7 @@ namespace ArchiSteamFarm { } [PublicAPI] - public async Task<(bool Success, string Output)> SendTradeOffer(uint appID = Steam.Asset.SteamAppID, uint contextID = Steam.Asset.SteamCommunityContextID, ulong targetSteamID = 0, IReadOnlyCollection wantedRealAppIDs = null, IReadOnlyCollection wantedTypes = null) { + public async Task<(bool Success, string Message)> SendTradeOffer(uint appID = Steam.Asset.SteamAppID, uint contextID = Steam.Asset.SteamCommunityContextID, ulong targetSteamID = 0, IReadOnlyCollection wantedRealAppIDs = null, IReadOnlyCollection wantedTypes = null) { if ((appID == 0) || (contextID == 0)) { Bot.ArchiLogger.LogNullError(nameof(appID) + " || " + nameof(contextID)); @@ -240,7 +253,9 @@ namespace ArchiSteamFarm { (bool success, HashSet mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(targetSteamID, inventory, token: Bot.BotConfig.SteamTradeToken).ConfigureAwait(false); if ((mobileTradeOfferIDs != null) && (mobileTradeOfferIDs.Count > 0) && Bot.HasMobileAuthenticator) { - if (!await AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false)) { + (bool twoFactorSuccess, _) = await HandleTwoFactorAuthenticationConfirmations(true, Steam.ConfirmationDetails.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false); + + if (!twoFactorSuccess) { return (false, Strings.BotLootingFailed); } } @@ -256,7 +271,7 @@ namespace ArchiSteamFarm { } [PublicAPI] - public (bool Success, string Output) Start() { + public (bool Success, string Message) Start() { if (Bot.KeepRunning) { return (false, Strings.BotAlreadyRunning); } @@ -268,7 +283,7 @@ namespace ArchiSteamFarm { } [PublicAPI] - public (bool Success, string Output) Stop() { + public (bool Success, string Message) Stop() { if (!Bot.KeepRunning) { return (false, Strings.BotAlreadyStopped); } diff --git a/ArchiSteamFarm/Commands.cs b/ArchiSteamFarm/Commands.cs index e443c64d9..7e98ea475 100644 --- a/ArchiSteamFarm/Commands.cs +++ b/ArchiSteamFarm/Commands.cs @@ -389,13 +389,9 @@ namespace ArchiSteamFarm { return null; } - if (!Bot.HasMobileAuthenticator) { - return FormatBotResponse(Strings.BotNoASFAuthenticator); - } + (bool success, string token, string message) = await Bot.Actions.GenerateTwoFactorAuthenticationToken().ConfigureAwait(false); - string token = await Bot.BotDatabase.MobileAuthenticator.GenerateToken().ConfigureAwait(false); - - return FormatBotResponse(!string.IsNullOrEmpty(token) ? string.Format(Strings.BotAuthenticatorToken, token) : Strings.WarningFailed); + return FormatBotResponse(success ? string.Format(Strings.BotAuthenticatorToken, token) : string.Format(Strings.WarningFailedWithError, message)); } [ItemCanBeNull] @@ -438,9 +434,9 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.BotNoASFAuthenticator); } - bool result = await Bot.Actions.AcceptConfirmations(confirm).ConfigureAwait(false); + (bool success, string message) = await Bot.Actions.HandleTwoFactorAuthenticationConfirmations(confirm).ConfigureAwait(false); - return FormatBotResponse(result ? Strings.Success : Strings.WarningFailed); + return FormatBotResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } [ItemCanBeNull] @@ -589,9 +585,9 @@ namespace ArchiSteamFarm { return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(contextID))); } - (bool success, string output) = await Bot.Actions.SendTradeOffer(appID, contextID).ConfigureAwait(false); + (bool success, string message) = await Bot.Actions.SendTradeOffer(appID, contextID).ConfigureAwait(false); - return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatBotResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } [ItemCanBeNull] @@ -717,9 +713,9 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.TargetBotNotConnected); } - (bool success, string output) = await Bot.Actions.SendTradeOffer(appID, contextID, targetBot.SteamID).ConfigureAwait(false); + (bool success, string message) = await Bot.Actions.SendTradeOffer(appID, contextID, targetBot.SteamID).ConfigureAwait(false); - return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatBotResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } private async Task ResponseAdvancedTransfer(ulong steamID, string targetAppID, string targetContextID, string botNameTo) { @@ -930,9 +926,9 @@ namespace ArchiSteamFarm { return null; } - (bool success, string output) = Actions.Exit(); + (bool success, string message) = Actions.Exit(); - return FormatStaticResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatStaticResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } private async Task ResponseFarm(ulong steamID) { @@ -1381,9 +1377,9 @@ namespace ArchiSteamFarm { return FormatBotResponse(string.Format(Strings.ErrorIsEmpty, nameof(Bot.BotConfig.LootableTypes))); } - (bool success, string output) = await Bot.Actions.SendTradeOffer(wantedTypes: Bot.BotConfig.LootableTypes).ConfigureAwait(false); + (bool success, string message) = await Bot.Actions.SendTradeOffer(wantedTypes: Bot.BotConfig.LootableTypes).ConfigureAwait(false); - return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatBotResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } [ItemCanBeNull] @@ -1442,9 +1438,9 @@ namespace ArchiSteamFarm { realAppIDs.Add(appID); } - (bool success, string output) = await Bot.Actions.SendTradeOffer(wantedTypes: Bot.BotConfig.LootableTypes, wantedRealAppIDs: realAppIDs).ConfigureAwait(false); + (bool success, string message) = await Bot.Actions.SendTradeOffer(wantedTypes: Bot.BotConfig.LootableTypes, wantedRealAppIDs: realAppIDs).ConfigureAwait(false); - return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatBotResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } [ItemCanBeNull] @@ -1694,9 +1690,9 @@ namespace ArchiSteamFarm { return string.Format(Strings.ErrorIsInvalid, nameof(resumeInSecondsText)); } - (bool success, string output) = await Bot.Actions.Pause(permanent, resumeInSeconds).ConfigureAwait(false); + (bool success, string message) = await Bot.Actions.Pause(permanent, resumeInSeconds).ConfigureAwait(false); - return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatBotResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } [ItemCanBeNull] @@ -2197,9 +2193,9 @@ namespace ArchiSteamFarm { return null; } - (bool success, string output) = Actions.Restart(); + (bool success, string message) = Actions.Restart(); - return FormatStaticResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatStaticResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } private string ResponseResume(ulong steamID) { @@ -2213,9 +2209,9 @@ namespace ArchiSteamFarm { return null; } - (bool success, string output) = Bot.Actions.Resume(); + (bool success, string message) = Bot.Actions.Resume(); - return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatBotResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } [ItemCanBeNull] @@ -2250,9 +2246,9 @@ namespace ArchiSteamFarm { return null; } - (bool success, string output) = Bot.Actions.Start(); + (bool success, string message) = Bot.Actions.Start(); - return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatBotResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } [ItemCanBeNull] @@ -2376,9 +2372,9 @@ namespace ArchiSteamFarm { return null; } - (bool success, string output) = Bot.Actions.Stop(); + (bool success, string message) = Bot.Actions.Stop(); - return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatBotResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } [ItemCanBeNull] @@ -2433,9 +2429,9 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.BotSendingTradeToYourself); } - (bool success, string output) = await Bot.Actions.SendTradeOffer(targetSteamID: targetBot.SteamID, wantedTypes: Bot.BotConfig.TransferableTypes).ConfigureAwait(false); + (bool success, string message) = await Bot.Actions.SendTradeOffer(targetSteamID: targetBot.SteamID, wantedTypes: Bot.BotConfig.TransferableTypes).ConfigureAwait(false); - return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatBotResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } [ItemCanBeNull] @@ -2486,9 +2482,9 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.BotSendingTradeToYourself); } - (bool success, string output) = await Bot.Actions.SendTradeOffer(targetSteamID: targetBot.SteamID, wantedTypes: Bot.BotConfig.TransferableTypes, wantedRealAppIDs: realAppIDs).ConfigureAwait(false); + (bool success, string message) = await Bot.Actions.SendTradeOffer(targetSteamID: targetBot.SteamID, wantedTypes: Bot.BotConfig.TransferableTypes, wantedRealAppIDs: realAppIDs).ConfigureAwait(false); - return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); + return FormatBotResponse(success ? message : string.Format(Strings.WarningFailedWithError, message)); } private async Task ResponseTransferByRealAppIDs(ulong steamID, string realAppIDsText, string botNameTo) { diff --git a/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs b/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs index 517fe3ca7..4b53ae56a 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs @@ -82,9 +82,9 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { [HttpPost("Exit")] [ProducesResponseType(typeof(GenericResponse), 200)] public ActionResult ExitPost() { - (bool success, string output) = Actions.Exit(); + (bool success, string message) = Actions.Exit(); - return Ok(new GenericResponse(success, output)); + return Ok(new GenericResponse(success, message)); } /// @@ -93,9 +93,9 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { [HttpPost("Restart")] [ProducesResponseType(typeof(GenericResponse), 200)] public ActionResult RestartPost() { - (bool success, string output) = Actions.Restart(); + (bool success, string message) = Actions.Restart(); - return Ok(new GenericResponse(success, output)); + return Ok(new GenericResponse(success, message)); } /// diff --git a/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs b/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs index 4ed1c4c0a..6fdd56614 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs @@ -249,9 +249,9 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames))); } - IList<(bool Success, string Output)> results = await Utilities.InParallel(bots.Select(bot => bot.Actions.Pause(request.Permanent, request.ResumeInSeconds))).ConfigureAwait(false); + IList<(bool Success, string Message)> results = await Utilities.InParallel(bots.Select(bot => bot.Actions.Pause(request.Permanent, request.ResumeInSeconds))).ConfigureAwait(false); - return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Output)))); + return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Message)))); } /// @@ -317,9 +317,9 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames))); } - IList<(bool Success, string Output)> results = await Utilities.InParallel(bots.Select(bot => Task.Run(bot.Actions.Resume))).ConfigureAwait(false); + IList<(bool Success, string Message)> results = await Utilities.InParallel(bots.Select(bot => Task.Run(bot.Actions.Resume))).ConfigureAwait(false); - return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Output)))); + return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Message)))); } /// @@ -340,9 +340,9 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames))); } - IList<(bool Success, string Output)> results = await Utilities.InParallel(bots.Select(bot => Task.Run(bot.Actions.Start))).ConfigureAwait(false); + IList<(bool Success, string Message)> results = await Utilities.InParallel(bots.Select(bot => Task.Run(bot.Actions.Start))).ConfigureAwait(false); - return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Output)))); + return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Message)))); } /// @@ -363,9 +363,99 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames))); } - IList<(bool Success, string Output)> results = await Utilities.InParallel(bots.Select(bot => Task.Run(bot.Actions.Stop))).ConfigureAwait(false); + IList<(bool Success, string Message)> results = await Utilities.InParallel(bots.Select(bot => Task.Run(bot.Actions.Stop))).ConfigureAwait(false); - return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Output)))); + return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Message)))); + } + + /// + /// Accepts 2FA confirmations of given bots, requires ASF 2FA module to be active on them. + /// + [HttpPost("{botNames:required}/TwoFactorAuthentication/Confirmations/Accept")] + [ProducesResponseType(typeof(GenericResponse>), 200)] + public async Task>>> TwoFactorAuthenticationConfirmationsAcceptPost(string botNames) { + if (string.IsNullOrEmpty(botNames)) { + ASF.ArchiLogger.LogNullError(nameof(botNames)); + + return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames)))); + } + + HashSet bots = Bot.GetBots(botNames); + + if ((bots == null) || (bots.Count == 0)) { + return BadRequest(new GenericResponse>(false, string.Format(Strings.BotNotFound, botNames))); + } + + IList<(bool Success, string Message)> results = await Utilities.InParallel(bots.Select(bot => bot.Actions.HandleTwoFactorAuthenticationConfirmations(true))).ConfigureAwait(false); + + Dictionary result = new Dictionary(bots.Count); + + foreach (Bot bot in bots) { + (bool success, string message) = results[result.Count]; + result[bot.BotName] = new GenericResponse(success, message); + } + + return Ok(new GenericResponse>(result)); + } + + /// + /// Denies 2FA confirmations of given bots, requires ASF 2FA module to be active on them. + /// + [HttpPost("{botNames:required}/TwoFactorAuthentication/Confirmations/Deny")] + [ProducesResponseType(typeof(GenericResponse>), 200)] + public async Task>>> TwoFactorAuthenticationConfirmationsDenyPost(string botNames) { + if (string.IsNullOrEmpty(botNames)) { + ASF.ArchiLogger.LogNullError(nameof(botNames)); + + return BadRequest(new GenericResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames)))); + } + + HashSet bots = Bot.GetBots(botNames); + + if ((bots == null) || (bots.Count == 0)) { + return BadRequest(new GenericResponse>(false, string.Format(Strings.BotNotFound, botNames))); + } + + IList<(bool Success, string Message)> results = await Utilities.InParallel(bots.Select(bot => bot.Actions.HandleTwoFactorAuthenticationConfirmations(true))).ConfigureAwait(false); + + Dictionary result = new Dictionary(bots.Count); + + foreach (Bot bot in bots) { + (bool success, string message) = results[result.Count]; + result[bot.BotName] = new GenericResponse(success, message); + } + + return Ok(new GenericResponse>(result)); + } + + /// + /// Fetches 2FA tokens of given bots, requires ASF 2FA module to be active on them. + /// + [HttpGet("{botNames:required}/TwoFactorAuthentication/Token")] + [ProducesResponseType(typeof(GenericResponse>>), 200)] + public async Task>>>> TwoFactorAuthenticationTokenGet(string botNames) { + if (string.IsNullOrEmpty(botNames)) { + ASF.ArchiLogger.LogNullError(nameof(botNames)); + + return BadRequest(new GenericResponse>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames)))); + } + + HashSet bots = Bot.GetBots(botNames); + + if ((bots == null) || (bots.Count == 0)) { + return BadRequest(new GenericResponse>>(false, string.Format(Strings.BotNotFound, botNames))); + } + + IList<(bool Success, string Token, string Message)> results = await Utilities.InParallel(bots.Select(bot => bot.Actions.GenerateTwoFactorAuthenticationToken())).ConfigureAwait(false); + + Dictionary> result = new Dictionary>(bots.Count); + + foreach (Bot bot in bots) { + (bool success, string token, string message) = results[result.Count]; + result[bot.BotName] = new GenericResponse(success, message, token); + } + + return Ok(new GenericResponse>>(result)); } } } diff --git a/ArchiSteamFarm/IPC/Middleware/ApiAuthenticationMiddleware.cs b/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs similarity index 99% rename from ArchiSteamFarm/IPC/Middleware/ApiAuthenticationMiddleware.cs rename to ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs index d3c658a28..d722178c7 100644 --- a/ArchiSteamFarm/IPC/Middleware/ApiAuthenticationMiddleware.cs +++ b/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs @@ -30,7 +30,7 @@ using JetBrains.Annotations; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; -namespace ArchiSteamFarm.IPC.Middleware { +namespace ArchiSteamFarm.IPC.Integration { [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] internal sealed class ApiAuthenticationMiddleware { internal const string HeadersField = "Authentication"; diff --git a/ArchiSteamFarm/IPC/Startup.cs b/ArchiSteamFarm/IPC/Startup.cs index 841e54ecf..98e7397d1 100644 --- a/ArchiSteamFarm/IPC/Startup.cs +++ b/ArchiSteamFarm/IPC/Startup.cs @@ -21,7 +21,7 @@ using System; using System.IO; -using ArchiSteamFarm.IPC.Middleware; +using ArchiSteamFarm.IPC.Integration; using JetBrains.Annotations; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; diff --git a/ArchiSteamFarm/Statistics.cs b/ArchiSteamFarm/Statistics.cs index da1d54798..448fd6406 100644 --- a/ArchiSteamFarm/Statistics.cs +++ b/ArchiSteamFarm/Statistics.cs @@ -504,7 +504,9 @@ namespace ArchiSteamFarm { (bool success, HashSet mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(listedUser.SteamID, itemsToGive, itemsToReceive, listedUser.TradeToken, true).ConfigureAwait(false); if ((mobileTradeOfferIDs != null) && (mobileTradeOfferIDs.Count > 0) && Bot.HasMobileAuthenticator) { - if (!await Bot.Actions.AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false)) { + (bool twoFactorSuccess, _) = await Bot.Actions.HandleTwoFactorAuthenticationConfirmations(true, Steam.ConfirmationDetails.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false); + + if (!twoFactorSuccess) { Bot.ArchiLogger.LogGenericTrace(Strings.WarningFailed); return false; diff --git a/ArchiSteamFarm/Trading.cs b/ArchiSteamFarm/Trading.cs index 21781675f..b9bf6f8d0 100644 --- a/ArchiSteamFarm/Trading.cs +++ b/ArchiSteamFarm/Trading.cs @@ -418,7 +418,9 @@ namespace ArchiSteamFarm { HashSet mobileTradeOfferIDs = results.Where(result => (result.TradeResult != null) && (result.TradeResult.Result == ParseTradeResult.EResult.Accepted) && result.RequiresMobileConfirmation).Select(result => result.TradeResult.TradeOfferID).ToHashSet(); if (mobileTradeOfferIDs.Count > 0) { - if (!await Bot.Actions.AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false)) { + (bool twoFactorSuccess, _) = await Bot.Actions.HandleTwoFactorAuthenticationConfirmations(true, Steam.ConfirmationDetails.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false); + + if (!twoFactorSuccess) { HandledTradeOfferIDs.ExceptWith(mobileTradeOfferIDs); return;