diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index 780fb80e5..e268bf2ca 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -66,6 +66,17 @@ namespace ArchiSteamFarm { private DateTime LastSessionRefreshCheck = DateTime.MinValue; private ulong SteamID; + private string _SteamApiKey; + internal string SteamApiKey => ObtainApiKey().Result; + private enum ESteamApiKeyState : byte { + Unknown = 0, + Invalid = 1, + Registered = 2, + NotRegistered = 3, + AccessDenied = 4, + } + private ESteamApiKeyState SteamApiKeyState; + internal ArchiWebHandler(Bot bot) { if (bot == null) { throw new ArgumentNullException(nameof(bot)); @@ -161,14 +172,14 @@ namespace ArchiSteamFarm { */ internal void DeclineTradeOffer(ulong tradeID) { - if ((tradeID == 0) || string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) { - Bot.ArchiLogger.LogNullError(nameof(tradeID) + " || " + nameof(Bot.BotConfig.SteamApiKey)); + if ((tradeID == 0) || string.IsNullOrEmpty(SteamApiKey)) { + Bot.ArchiLogger.LogNullError(nameof(tradeID) + " || " + nameof(SteamApiKey)); return; } KeyValue response = null; for (byte i = 0; (i < WebBrowser.MaxRetries) && (response == null); i++) { - using (dynamic iEconService = WebAPI.GetInterface(IEconService, Bot.BotConfig.SteamApiKey)) { + using (dynamic iEconService = WebAPI.GetInterface(IEconService, SteamApiKey)) { iEconService.Timeout = Timeout; try { @@ -212,14 +223,14 @@ namespace ArchiSteamFarm { */ internal HashSet GetActiveTradeOffers() { - if (string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) { - Bot.ArchiLogger.LogNullError(nameof(Bot.BotConfig.SteamApiKey)); + if (string.IsNullOrEmpty(SteamApiKey)) { + Bot.ArchiLogger.LogNullError(nameof(SteamApiKey)); return null; } KeyValue response = null; for (byte i = 0; (i < WebBrowser.MaxRetries) && (response == null); i++) { - using (dynamic iEconService = WebAPI.GetInterface(IEconService, Bot.BotConfig.SteamApiKey)) { + using (dynamic iEconService = WebAPI.GetInterface(IEconService, SteamApiKey)) { iEconService.Timeout = Timeout; try { @@ -321,74 +332,105 @@ namespace ArchiSteamFarm { return result; } - internal async Task GetApiKey() { + private async Task UpdateApiKey() { if ( !await RefreshSessionIfNeeded().ConfigureAwait(false) ) { - return null; + return ESteamApiKeyState.Invalid; } - string request = SteamCommunityURL + "/dev/apikey?l=english"; - ushort i = 0; - string ApiKey = null; - do { - HtmlDocument htmlDocument = await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false); - - HtmlNode htmlNode = htmlDocument?.DocumentNode.SelectSingleNode("//div[@id='bodyContents_ex']/p"); - if (htmlNode == null) { - return null; - } - - string text = htmlNode.InnerText; - if (string.IsNullOrEmpty(text)) { - Bot.ArchiLogger.LogNullError(nameof(text)); - return null; - } - int hintIndex = text.IndexOf("Registering for a Steam Web API Key", StringComparison.Ordinal); - if (hintIndex == 0) { - string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); - if ( string.IsNullOrEmpty(sessionID) ) { - Bot.ArchiLogger.LogNullError(nameof(sessionID)); - return null; - } + string request = SteamCommunityURL + "/dev/apikey?l=english"; + + HtmlDocument htmlDocument = await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false); - string registerRequest = SteamCommunityURL + "/dev/registerkey"; - Dictionary data = new Dictionary(4) { + HtmlNode titleNode = htmlDocument?.DocumentNode.SelectSingleNode("//div[@id='mainContents']/h2"); + + if (titleNode == null) { + return ESteamApiKeyState.Invalid; + } + + string title = titleNode.InnerText; + + if (title.IndexOf("Access Denied") == 0) { + return ESteamApiKeyState.AccessDenied; + } + + HtmlNode htmlNode = htmlDocument?.DocumentNode.SelectSingleNode("//div[@id='bodyContents_ex']/p"); + if (htmlNode == null) { + return ESteamApiKeyState.Invalid; + } + + string text = htmlNode.InnerText; + + if (string.IsNullOrEmpty(text)) { + Bot.ArchiLogger.LogNullError(nameof(text)); + return ESteamApiKeyState.Invalid; + } + + int hintIndex = text.IndexOf("Registering for a Steam Web API Key", StringComparison.Ordinal); + if (hintIndex == 0) { + return ESteamApiKeyState.NotRegistered; + } + + int keyIndex = text.IndexOf("Key: ", StringComparison.Ordinal); + if ( keyIndex < 0 ) { + Bot.ArchiLogger.LogNullError(nameof(keyIndex)); + return ESteamApiKeyState.Invalid; + } + + keyIndex += 5; + text = text.Substring(keyIndex); + + if ( text.Length != 32 ) { + Bot.ArchiLogger.LogNullError(nameof(text)); + return ESteamApiKeyState.Invalid; + } + + string allowedChars = "0123456789ABCDEF"; + foreach (char c in text) { + if (!allowedChars.Contains(c.ToString()) ) { + Bot.ArchiLogger.LogNullError(nameof(text)); + return ESteamApiKeyState.Invalid; + } + } + + this._SteamApiKey = text; + + return ESteamApiKeyState.Registered; + } + + private async Task RegisterApiKey() { + string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid"); + if ( string.IsNullOrEmpty(sessionID) ) { + Bot.ArchiLogger.LogNullError(nameof(sessionID)); + return false; + } + + string request = SteamCommunityURL + "/dev/registerkey"; + Dictionary data = new Dictionary(4) { {"domain", "localhost" }, {"agreeToTerms", "agreed"}, {"sessionid", sessionID}, {"Submit", "Register"} }; - await WebBrowser.UrlPostRetry(registerRequest, data).ConfigureAwait(false); - } else { - int keyIndex = text.IndexOf("Key: ", StringComparison.Ordinal); - if ( keyIndex < 0 ) { - Bot.ArchiLogger.LogNullError(nameof(keyIndex)); - return null; - } + return await WebBrowser.UrlPostRetry( request, data).ConfigureAwait(false); + } - keyIndex += 5; - text = text.Substring(keyIndex); - - if ( text.Length != 32 ) { - Bot.ArchiLogger.LogNullError(nameof(text)); - return null; - } - - string allowedChars = "0123456789ABCDEF"; - foreach (char c in text) { - if (!allowedChars.Contains(c.ToString()) ) { - Bot.ArchiLogger.LogNullError(nameof(text)); - return null; - } - } - ApiKey = text; - } - } while (ApiKey == null && ++i < 2); - if (ApiKey == null) { - Bot.ArchiLogger.LogNullError(nameof(ApiKey)); - return null; + private async Task ObtainApiKey() { + switch (SteamApiKeyState) { + case ESteamApiKeyState.Unknown: + SteamApiKeyState = await UpdateApiKey().ConfigureAwait(false); + return await ObtainApiKey().ConfigureAwait(false); + case ESteamApiKeyState.NotRegistered: + await RegisterApiKey().ConfigureAwait(false); + SteamApiKeyState = ESteamApiKeyState.Unknown; + return await ObtainApiKey().ConfigureAwait(false); + case ESteamApiKeyState.Registered: + return _SteamApiKey; + case ESteamApiKeyState.AccessDenied: + return string.Empty; + default: + return null; } - return ApiKey; } internal async Task GetBadgePage(byte page) { @@ -665,14 +707,14 @@ namespace ArchiSteamFarm { } internal Dictionary GetOwnedGames(ulong steamID) { - if ((steamID == 0) || string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) { - Bot.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(Bot.BotConfig.SteamApiKey)); + if ((steamID == 0) || string.IsNullOrEmpty(SteamApiKey)) { + Bot.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(SteamApiKey)); return null; } KeyValue response = null; for (byte i = 0; (i < WebBrowser.MaxRetries) && (response == null); i++) { - using (dynamic iPlayerService = WebAPI.GetInterface(IPlayerService, Bot.BotConfig.SteamApiKey)) { + using (dynamic iPlayerService = WebAPI.GetInterface(IPlayerService, SteamApiKey)) { iPlayerService.Timeout = Timeout; try { diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 533360420..4a8c48f67 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -60,7 +60,7 @@ namespace ArchiSteamFarm { internal readonly string BotName; internal bool HasMobileAuthenticator => BotDatabase?.MobileAuthenticator != null; - internal bool HasValidApiKey => !string.IsNullOrEmpty(BotConfig?.SteamApiKey) && (BotConfig.SteamApiKey.Length == 32); + internal bool HasValidApiKey => !string.IsNullOrEmpty(ArchiWebHandler.SteamApiKey); internal bool IsConnectedAndLoggedOn => (SteamClient?.IsConnected == true) && (SteamClient.SteamID != null); internal bool IsPlayingPossible => !PlayingBlocked && (LibraryLockedBySteamID == 0); diff --git a/ArchiSteamFarm/BotConfig.cs b/ArchiSteamFarm/BotConfig.cs index 3dd52087e..b8b10c623 100644 --- a/ArchiSteamFarm/BotConfig.cs +++ b/ArchiSteamFarm/BotConfig.cs @@ -98,9 +98,6 @@ namespace ArchiSteamFarm { [JsonProperty(Required = Required.DisallowNull)] internal readonly bool ShutdownOnFarmingFinished = false; - [JsonProperty] - internal readonly string SteamApiKey = null; - [JsonProperty(Required = Required.DisallowNull)] internal readonly ulong SteamMasterClanID = 0;