mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-01 14:10:53 +00:00
Further enhance new 2FA, closes #161
This commit is contained in:
@@ -241,16 +241,53 @@ namespace ArchiSteamFarm {
|
||||
Start().Forget();
|
||||
}
|
||||
|
||||
internal async Task AcceptConfirmations(bool accept) {
|
||||
internal async Task AcceptConfirmations(bool accept, Steam.ConfirmationDetails.EType acceptedType = Steam.ConfirmationDetails.EType.Unknown, ulong acceptedSteamID = 0, HashSet<ulong> acceptedTradeIDs = null) {
|
||||
if (BotDatabase.MobileAuthenticator == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
HashSet<MobileAuthenticator.Confirmation> confirmations = await BotDatabase.MobileAuthenticator.GetConfirmations().ConfigureAwait(false);
|
||||
if (confirmations == null) {
|
||||
if ((confirmations == null) || (confirmations.Count == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (acceptedType != Steam.ConfirmationDetails.EType.Unknown) {
|
||||
if (confirmations.RemoveWhere(confirmation => confirmation.Type != acceptedType) > 0) {
|
||||
confirmations.TrimExcess();
|
||||
if (confirmations.Count == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((acceptedSteamID != 0) || ((acceptedTradeIDs != null) && (acceptedTradeIDs.Count > 0))) {
|
||||
HashSet<MobileAuthenticator.Confirmation> ignoredConfirmations = new HashSet<MobileAuthenticator.Confirmation>();
|
||||
// TODO: This could be potentially multi-threaded like below
|
||||
foreach (MobileAuthenticator.Confirmation confirmation in confirmations) {
|
||||
Steam.ConfirmationDetails details = await BotDatabase.MobileAuthenticator.GetConfirmationDetails(confirmation).ConfigureAwait(false);
|
||||
if (details == null) {
|
||||
ignoredConfirmations.Add(confirmation);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((acceptedSteamID != 0) && (acceptedSteamID != details.OtherSteamID64)) {
|
||||
ignoredConfirmations.Add(confirmation);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((acceptedTradeIDs != null) && !acceptedTradeIDs.Contains(details.TradeOfferID)) {
|
||||
ignoredConfirmations.Add(confirmation);
|
||||
}
|
||||
}
|
||||
|
||||
confirmations.ExceptWith(ignoredConfirmations);
|
||||
confirmations.TrimExcess();
|
||||
|
||||
if (confirmations.Count == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await confirmations.ForEachAsync(async confirmation => await BotDatabase.MobileAuthenticator.HandleConfirmation(confirmation, accept).ConfigureAwait(false)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -613,7 +650,7 @@ namespace ArchiSteamFarm {
|
||||
return "Trade offer failed due to error!";
|
||||
}
|
||||
|
||||
await AcceptConfirmations(true).ConfigureAwait(false);
|
||||
await AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, BotConfig.SteamMasterID).ConfigureAwait(false);
|
||||
return "Trade offer sent successfully!";
|
||||
}
|
||||
|
||||
|
||||
@@ -341,9 +341,95 @@ namespace ArchiSteamFarm.JSON {
|
||||
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
|
||||
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
|
||||
internal sealed class ConfirmationDetails {
|
||||
internal enum EType : byte {
|
||||
Unknown,
|
||||
Trade,
|
||||
Market,
|
||||
Other
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "success", Required = Required.Always)]
|
||||
internal bool Success { get; private set; }
|
||||
|
||||
private EType _Type;
|
||||
private EType Type {
|
||||
get {
|
||||
if (_Type != EType.Unknown) {
|
||||
return _Type;
|
||||
}
|
||||
|
||||
if (HtmlDocument == null) {
|
||||
Logging.LogNullError(nameof(HtmlDocument));
|
||||
return EType.Unknown;
|
||||
}
|
||||
|
||||
HtmlNode testNode = HtmlDocument.DocumentNode.SelectSingleNode("//div[@class='mobileconf_listing_prices']");
|
||||
if (testNode != null) {
|
||||
_Type = EType.Market;
|
||||
return _Type;
|
||||
}
|
||||
|
||||
testNode = HtmlDocument.DocumentNode.SelectSingleNode("//div[@class='mobileconf_trade_area']");
|
||||
if (testNode != null) {
|
||||
_Type = EType.Trade;
|
||||
return _Type;
|
||||
}
|
||||
|
||||
_Type = EType.Other;
|
||||
return _Type;
|
||||
}
|
||||
}
|
||||
|
||||
private ulong _TradeOfferID;
|
||||
internal ulong TradeOfferID {
|
||||
get {
|
||||
if (_TradeOfferID != 0) {
|
||||
return _TradeOfferID;
|
||||
}
|
||||
|
||||
if (Type != EType.Trade) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (HtmlDocument == null) {
|
||||
Logging.LogNullError(nameof(HtmlDocument));
|
||||
return 0;
|
||||
}
|
||||
|
||||
HtmlNode htmlNode = HtmlDocument.DocumentNode.SelectSingleNode("//div[@class='tradeoffer']");
|
||||
if (htmlNode == null) {
|
||||
Logging.LogNullError(nameof(htmlNode));
|
||||
return 0;
|
||||
}
|
||||
|
||||
string id = htmlNode.GetAttributeValue("id", null);
|
||||
if (string.IsNullOrEmpty(id)) {
|
||||
Logging.LogNullError(nameof(id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int index = id.IndexOf('_');
|
||||
if (index < 0) {
|
||||
Logging.LogNullError(nameof(index));
|
||||
return 0;
|
||||
}
|
||||
|
||||
index++;
|
||||
if (id.Length <= index) {
|
||||
Logging.LogNullError(nameof(id.Length));
|
||||
return 0;
|
||||
}
|
||||
|
||||
id = id.Substring(index);
|
||||
if (ulong.TryParse(id, out _TradeOfferID) && (_TradeOfferID != 0)) {
|
||||
return _TradeOfferID;
|
||||
}
|
||||
|
||||
Logging.LogNullError(nameof(_TradeOfferID));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private ulong _OtherSteamID64;
|
||||
internal ulong OtherSteamID64 {
|
||||
get {
|
||||
@@ -351,6 +437,10 @@ namespace ArchiSteamFarm.JSON {
|
||||
return _OtherSteamID64;
|
||||
}
|
||||
|
||||
if (Type != EType.Trade) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (OtherSteamID3 == 0) {
|
||||
Logging.LogNullError(nameof(OtherSteamID3));
|
||||
return 0;
|
||||
@@ -371,6 +461,10 @@ namespace ArchiSteamFarm.JSON {
|
||||
return _OtherSteamID3;
|
||||
}
|
||||
|
||||
if (Type != EType.Trade) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (HtmlDocument == null) {
|
||||
Logging.LogNullError(nameof(HtmlDocument));
|
||||
return 0;
|
||||
|
||||
@@ -13,14 +13,16 @@ namespace ArchiSteamFarm {
|
||||
internal sealed class Confirmation {
|
||||
internal readonly uint ID;
|
||||
internal readonly ulong Key;
|
||||
internal readonly Steam.ConfirmationDetails.EType Type;
|
||||
|
||||
internal Confirmation(uint id, ulong key) {
|
||||
if ((id == 0) || (key == 0)) {
|
||||
throw new ArgumentNullException(nameof(id) + " || " + nameof(key));
|
||||
internal Confirmation(uint id, ulong key, Steam.ConfirmationDetails.EType type) {
|
||||
if ((id == 0) || (key == 0) || (type == Steam.ConfirmationDetails.EType.Unknown)) {
|
||||
throw new ArgumentNullException(nameof(id) + " || " + nameof(key) + " || " + nameof(type));
|
||||
}
|
||||
|
||||
ID = id;
|
||||
Key = key;
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,14 +148,14 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
HtmlNodeCollection confirmations = htmlDocument.DocumentNode.SelectNodes("//div[@class='mobileconf_list_entry']");
|
||||
if (confirmations == null) {
|
||||
HtmlNodeCollection confirmationNodes = htmlDocument.DocumentNode.SelectNodes("//div[@class='mobileconf_list_entry']");
|
||||
if (confirmationNodes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HashSet<Confirmation> result = new HashSet<Confirmation>();
|
||||
foreach (HtmlNode confirmation in confirmations) {
|
||||
string idString = confirmation.GetAttributeValue("data-confid", null);
|
||||
foreach (HtmlNode confirmationNode in confirmationNodes) {
|
||||
string idString = confirmationNode.GetAttributeValue("data-confid", null);
|
||||
if (string.IsNullOrEmpty(idString)) {
|
||||
Logging.LogNullError(nameof(idString), Bot.BotName);
|
||||
continue;
|
||||
@@ -165,7 +167,7 @@ namespace ArchiSteamFarm {
|
||||
continue;
|
||||
}
|
||||
|
||||
string keyString = confirmation.GetAttributeValue("data-key", null);
|
||||
string keyString = confirmationNode.GetAttributeValue("data-key", null);
|
||||
if (string.IsNullOrEmpty(keyString)) {
|
||||
Logging.LogNullError(nameof(keyString), Bot.BotName);
|
||||
continue;
|
||||
@@ -177,7 +179,24 @@ namespace ArchiSteamFarm {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.Add(new Confirmation(id, key));
|
||||
HtmlNode descriptionNode = confirmationNode.SelectSingleNode(".//div[@class='mobileconf_list_entry_description']/div");
|
||||
if (descriptionNode == null) {
|
||||
Logging.LogNullError(nameof(descriptionNode), Bot.BotName);
|
||||
continue;
|
||||
}
|
||||
|
||||
Steam.ConfirmationDetails.EType type;
|
||||
|
||||
string description = descriptionNode.InnerText;
|
||||
if (description.Equals("Sell - Market Listing")) {
|
||||
type = Steam.ConfirmationDetails.EType.Market;
|
||||
} else if (description.StartsWith("Trade with ", StringComparison.Ordinal)) {
|
||||
type = Steam.ConfirmationDetails.EType.Trade;
|
||||
} else {
|
||||
type = Steam.ConfirmationDetails.EType.Other;
|
||||
}
|
||||
|
||||
result.Add(new Confirmation(id, key, type));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -94,7 +94,9 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
await tradeOffers.ForEachAsync(ParseTrade).ConfigureAwait(false);
|
||||
await Bot.AcceptConfirmations(true).ConfigureAwait(false);
|
||||
|
||||
HashSet<ulong> tradeIDs = new HashSet<ulong>(tradeOffers.Select(tradeOffer => tradeOffer.TradeOfferID));
|
||||
await Bot.AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, 0, tradeIDs).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task ParseTrade(Steam.TradeOffer tradeOffer) {
|
||||
|
||||
Reference in New Issue
Block a user