From 2c2dccec2aa8a7e1781a6cd3ae1ea0d2ec9dc653 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Fri, 15 Jul 2016 16:13:36 +0200 Subject: [PATCH] EXPERIMENTAL: Move 2FA to multi-confirmations, closes #295 Some further tests would be cool to do --- ArchiSteamFarm/ArchiWebHandler.cs | 23 +++++++++++++---------- ArchiSteamFarm/Bot.cs | 22 +++++++--------------- ArchiSteamFarm/JSON/Steam.cs | 10 +++++----- ArchiSteamFarm/MobileAuthenticator.cs | 11 ++++++----- 4 files changed, 31 insertions(+), 35 deletions(-) diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index fcf59f89f..672e7e4f2 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -300,9 +300,9 @@ namespace ArchiSteamFarm { return await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false); } - internal async Task GetConfirmationDetails(string deviceID, string confirmationHash, uint time, uint confirmationID) { - if (string.IsNullOrEmpty(deviceID) || string.IsNullOrEmpty(confirmationHash) || (time == 0) || (confirmationID == 0)) { - Logging.LogNullError(nameof(deviceID) + " || " + nameof(confirmationHash) + " || " + nameof(time) + " || " + nameof(confirmationID), Bot.BotName); + internal async Task GetConfirmationDetails(string deviceID, string confirmationHash, uint time, MobileAuthenticator.Confirmation confirmation) { + if (string.IsNullOrEmpty(deviceID) || string.IsNullOrEmpty(confirmationHash) || (time == 0) || (confirmation == null)) { + Logging.LogNullError(nameof(deviceID) + " || " + nameof(confirmationHash) + " || " + nameof(time) + " || " + nameof(confirmation), Bot.BotName); return null; } @@ -310,7 +310,7 @@ namespace ArchiSteamFarm { return null; } - string request = SteamCommunityURL + "/mobileconf/details/" + confirmationID + "?p=" + deviceID + "&a=" + SteamID + "&k=" + WebUtility.UrlEncode(confirmationHash) + "&t=" + time + "&m=android&tag=conf"; + string request = SteamCommunityURL + "/mobileconf/details/" + confirmation.ID + "?p=" + deviceID + "&a=" + SteamID + "&k=" + WebUtility.UrlEncode(confirmationHash) + "&t=" + time + "&m=android&tag=conf"; string json = await WebBrowser.UrlGetToContentRetry(request).ConfigureAwait(false); if (string.IsNullOrEmpty(json)) { @@ -331,13 +331,13 @@ namespace ArchiSteamFarm { return null; } - response.ConfirmationID = confirmationID; + response.Confirmation = confirmation; return response; } - internal async Task HandleConfirmation(string deviceID, string confirmationHash, uint time, uint confirmationID, ulong confirmationKey, bool accept) { - if (string.IsNullOrEmpty(deviceID) || string.IsNullOrEmpty(confirmationHash) || (time == 0) || (confirmationID == 0) || (confirmationKey == 0)) { - Logging.LogNullError(nameof(deviceID) + " || " + nameof(confirmationHash) + " || " + nameof(time) + " || " + nameof(confirmationID) + " || " + nameof(confirmationKey), Bot.BotName); + internal async Task HandleConfirmations(string deviceID, string confirmationHash, uint time, HashSet confirmations, bool accept) { + if (string.IsNullOrEmpty(deviceID) || string.IsNullOrEmpty(confirmationHash) || (time == 0) || (confirmations == null) || (confirmations.Count == 0)) { + Logging.LogNullError(nameof(deviceID) + " || " + nameof(confirmationHash) + " || " + nameof(time) + " || " + nameof(confirmations), Bot.BotName); return false; } @@ -345,9 +345,12 @@ namespace ArchiSteamFarm { return false; } - string request = SteamCommunityURL + "/mobileconf/ajaxop?op=" + (accept ? "allow" : "cancel") + "&p=" + deviceID + "&a=" + SteamID + "&k=" + WebUtility.UrlEncode(confirmationHash) + "&t=" + time + "&m=android&tag=conf&cid=" + confirmationID + "&ck=" + confirmationKey; + StringBuilder request = new StringBuilder(SteamCommunityURL + "/mobileconf/multiajaxop?op=" + (accept ? "allow" : "cancel") + "&p=" + deviceID + "&a=" + SteamID + "&k=" + WebUtility.UrlEncode(confirmationHash) + "&t=" + time + "&m=android&tag=conf"); + foreach (MobileAuthenticator.Confirmation confirmation in confirmations) { + request.Append("&cid[]=" + confirmation.ID + "&ck[]=" + confirmation.Key); + } - string json = await WebBrowser.UrlGetToContentRetry(request).ConfigureAwait(false); + string json = await WebBrowser.UrlGetToContentRetry(request.ToString()).ConfigureAwait(false); if (string.IsNullOrEmpty(json)) { return false; } diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 609aa46fc..86077d7f3 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -271,28 +271,20 @@ namespace ArchiSteamFarm { if ((acceptedSteamID != 0) || ((acceptedTradeIDs != null) && (acceptedTradeIDs.Count > 0))) { Steam.ConfirmationDetails[] detailsResults = await Task.WhenAll(confirmations.Select(BotDatabase.MobileAuthenticator.GetConfirmationDetails)).ConfigureAwait(false); - HashSet ignoredConfirmationIDs = new HashSet(); - foreach (Steam.ConfirmationDetails details in detailsResults.Where(details => (details != null) && ( + HashSet ignoredConfirmations = new HashSet(detailsResults.Where(details => (details != null) && ( ((acceptedSteamID != 0) && (details.OtherSteamID64 != 0) && (acceptedSteamID != details.OtherSteamID64)) || ((acceptedTradeIDs != null) && (details.TradeOfferID != 0) && !acceptedTradeIDs.Contains(details.TradeOfferID)) - ))) { - ignoredConfirmationIDs.Add(details.ConfirmationID); - } + )).Select(details => details.Confirmation)); - if (ignoredConfirmationIDs.Count > 0) { - if (confirmations.RemoveWhere(confirmation => ignoredConfirmationIDs.Contains(confirmation.ID)) > 0) { - if (confirmations.Count == 0) { - return; - } + if (ignoredConfirmations.Count > 0) { + confirmations.ExceptWith(ignoredConfirmations); + if (confirmations.Count == 0) { + return; } } } - // This could be done in parallel, but for some reason Steam allows only one confirmation being accepted at the time - // Therefore, even though no physical barrier stops us from doing so, we execute this synchronously - foreach (MobileAuthenticator.Confirmation confirmation in confirmations) { - await BotDatabase.MobileAuthenticator.HandleConfirmation(confirmation, accept).ConfigureAwait(false); - } + await BotDatabase.MobileAuthenticator.HandleConfirmations(confirmations, accept).ConfigureAwait(false); } internal async Task RefreshSession() { diff --git a/ArchiSteamFarm/JSON/Steam.cs b/ArchiSteamFarm/JSON/Steam.cs index 9647f3161..ac06665b4 100644 --- a/ArchiSteamFarm/JSON/Steam.cs +++ b/ArchiSteamFarm/JSON/Steam.cs @@ -367,17 +367,17 @@ namespace ArchiSteamFarm.JSON { Other } - private uint _ConfirmationID; - internal uint ConfirmationID { - get { return _ConfirmationID; } + private MobileAuthenticator.Confirmation _Confirmation; + internal MobileAuthenticator.Confirmation Confirmation { + get { return _Confirmation; } set { - if (value == 0) { + if (value == null) { Logging.LogNullError(nameof(value)); return; } - _ConfirmationID = value; + _Confirmation = value; } } diff --git a/ArchiSteamFarm/MobileAuthenticator.cs b/ArchiSteamFarm/MobileAuthenticator.cs index 2f65e411a..6107ddfff 100644 --- a/ArchiSteamFarm/MobileAuthenticator.cs +++ b/ArchiSteamFarm/MobileAuthenticator.cs @@ -25,6 +25,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading; @@ -94,9 +95,9 @@ namespace ArchiSteamFarm { DeviceID = deviceID; } - internal async Task HandleConfirmation(Confirmation confirmation, bool accept) { - if (confirmation == null) { - Logging.LogNullError(nameof(confirmation), Bot.BotName); + internal async Task HandleConfirmations(HashSet confirmations, bool accept) { + if ((confirmations == null) || (confirmations.Count == 0)) { + Logging.LogNullError(nameof(confirmations), Bot.BotName); return false; } @@ -108,7 +109,7 @@ namespace ArchiSteamFarm { string confirmationHash = GenerateConfirmationKey(time, "conf"); if (!string.IsNullOrEmpty(confirmationHash)) { - return await Bot.ArchiWebHandler.HandleConfirmation(DeviceID, confirmationHash, time, confirmation.ID, confirmation.Key, accept).ConfigureAwait(false); + return await Bot.ArchiWebHandler.HandleConfirmations(DeviceID, confirmationHash, time, confirmations, accept).ConfigureAwait(false); } Logging.LogNullError(nameof(confirmationHash), Bot.BotName); @@ -133,7 +134,7 @@ namespace ArchiSteamFarm { return null; } - Steam.ConfirmationDetails response = await Bot.ArchiWebHandler.GetConfirmationDetails(DeviceID, confirmationHash, time, confirmation.ID).ConfigureAwait(false); + Steam.ConfirmationDetails response = await Bot.ArchiWebHandler.GetConfirmationDetails(DeviceID, confirmationHash, time, confirmation).ConfigureAwait(false); if ((response == null) || !response.Success) { return null; }