diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 8ba7ab93f..c5e3f5e17 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -1450,7 +1450,45 @@ namespace ArchiSteamFarm { ArchiLogger.LogGenericInfo(Strings.BotAuthenticatorConverting); try { - MobileAuthenticator authenticator = JsonConvert.DeserializeObject(await RuntimeCompatibility.File.ReadAllTextAsync(maFilePath).ConfigureAwait(false)); + string json = await RuntimeCompatibility.File.ReadAllTextAsync(maFilePath).ConfigureAwait(false); + + if (string.IsNullOrEmpty(json)) { + ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsEmpty, nameof(json))); + + return; + } + + MobileAuthenticator authenticator = JsonConvert.DeserializeObject(json); + + if (authenticator == null) { + ArchiLogger.LogNullError(nameof(authenticator)); + + return; + } + + if (!authenticator.HasValidDeviceID) { + ArchiLogger.LogGenericWarning(Strings.BotAuthenticatorInvalidDeviceID); + + if (string.IsNullOrEmpty(DeviceID)) { + string deviceID = Program.GetUserInput(ASF.EUserInputType.DeviceID, BotName); + + if (string.IsNullOrEmpty(deviceID)) { + return; + } + + SetUserInput(ASF.EUserInputType.DeviceID, deviceID); + } + + if (!MobileAuthenticator.IsValidDeviceID(DeviceID)) { + ArchiLogger.LogGenericWarning(Strings.BotAuthenticatorInvalidDeviceID); + + return; + } + + authenticator.CorrectDeviceID(DeviceID); + } + + authenticator.Init(this); await BotDatabase.SetMobileAuthenticator(authenticator).ConfigureAwait(false); File.Delete(maFilePath); } catch (Exception e) { @@ -1459,32 +1497,6 @@ namespace ArchiSteamFarm { return; } - if (BotDatabase.MobileAuthenticator == null) { - ArchiLogger.LogNullError(nameof(BotDatabase.MobileAuthenticator)); - - return; - } - - BotDatabase.MobileAuthenticator.Init(this); - - if (!BotDatabase.MobileAuthenticator.HasCorrectDeviceID) { - ArchiLogger.LogGenericWarning(Strings.BotAuthenticatorInvalidDeviceID); - - if (string.IsNullOrEmpty(DeviceID)) { - string deviceID = Program.GetUserInput(ASF.EUserInputType.DeviceID, BotName); - - if (string.IsNullOrEmpty(deviceID)) { - await BotDatabase.SetMobileAuthenticator().ConfigureAwait(false); - - return; - } - - SetUserInput(ASF.EUserInputType.DeviceID, deviceID); - } - - await BotDatabase.CorrectMobileAuthenticatorDeviceID(DeviceID).ConfigureAwait(false); - } - ArchiLogger.LogGenericInfo(Strings.BotAuthenticatorImportFinished); } diff --git a/ArchiSteamFarm/BotDatabase.cs b/ArchiSteamFarm/BotDatabase.cs index 7b6ba4987..b43452ad9 100644 --- a/ArchiSteamFarm/BotDatabase.cs +++ b/ArchiSteamFarm/BotDatabase.cs @@ -137,18 +137,6 @@ namespace ArchiSteamFarm { } } - internal async Task CorrectMobileAuthenticatorDeviceID(string deviceID) { - if (string.IsNullOrEmpty(deviceID) || (MobileAuthenticator == null)) { - ASF.ArchiLogger.LogNullError(nameof(deviceID) + " || " + nameof(MobileAuthenticator)); - - return; - } - - if (MobileAuthenticator.CorrectDeviceID(deviceID)) { - await Save().ConfigureAwait(false); - } - } - internal static async Task CreateOrLoad(string filePath) { if (string.IsNullOrEmpty(filePath)) { ASF.ArchiLogger.LogNullError(nameof(filePath)); diff --git a/ArchiSteamFarm/MobileAuthenticator.cs b/ArchiSteamFarm/MobileAuthenticator.cs index 623b383eb..d27709c5f 100644 --- a/ArchiSteamFarm/MobileAuthenticator.cs +++ b/ArchiSteamFarm/MobileAuthenticator.cs @@ -45,8 +45,7 @@ namespace ArchiSteamFarm { private static DateTime LastSteamTimeCheck; private static int? SteamTimeDifference; - // "ERROR" is being used by SteamDesktopAuthenticator - internal bool HasCorrectDeviceID => !string.IsNullOrEmpty(DeviceID) && !DeviceID.Equals("ERROR"); + internal bool HasValidDeviceID => !string.IsNullOrEmpty(DeviceID) && IsValidDeviceID(DeviceID); #pragma warning disable 649 [JsonProperty(PropertyName = "identity_secret", Required = Required.Always)] @@ -65,20 +64,20 @@ namespace ArchiSteamFarm { private MobileAuthenticator() { } - internal bool CorrectDeviceID(string deviceID) { + internal void CorrectDeviceID(string deviceID) { if (string.IsNullOrEmpty(deviceID)) { Bot.ArchiLogger.LogNullError(nameof(deviceID)); - return false; + return; } - if (!string.IsNullOrEmpty(DeviceID) && DeviceID.Equals(deviceID)) { - return false; + if (!IsValidDeviceID(deviceID)) { + Bot.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, nameof(deviceID))); + + return; } DeviceID = deviceID; - - return true; } internal async Task GenerateToken() { @@ -100,7 +99,7 @@ namespace ArchiSteamFarm { return null; } - if (!HasCorrectDeviceID) { + if (!HasValidDeviceID) { Bot.ArchiLogger.LogGenericError(Strings.ErrorMobileAuthenticatorInvalidDeviceID); return null; @@ -128,7 +127,7 @@ namespace ArchiSteamFarm { } internal async Task> GetConfirmations(Steam.ConfirmationDetails.EType acceptedType = Steam.ConfirmationDetails.EType.Unknown) { - if (!HasCorrectDeviceID) { + if (!HasValidDeviceID) { Bot.ArchiLogger.LogGenericError(Strings.ErrorMobileAuthenticatorInvalidDeviceID); return null; @@ -228,7 +227,7 @@ namespace ArchiSteamFarm { return false; } - if (!HasCorrectDeviceID) { + if (!HasValidDeviceID) { Bot.ArchiLogger.LogGenericError(Strings.ErrorMobileAuthenticatorInvalidDeviceID); return false; @@ -278,6 +277,26 @@ namespace ArchiSteamFarm { internal void Init(Bot bot) => Bot = bot ?? throw new ArgumentNullException(nameof(bot)); + internal static bool IsValidDeviceID(string deviceID) { + if (string.IsNullOrEmpty(deviceID)) { + ASF.ArchiLogger.LogNullError(nameof(deviceID)); + + return false; + } + + // To the best of my knowledge, Steam uses android identifier even on iOS and other devices right now + // If we ever need to correct this, we also need to clean up other places + const string deviceIdentifier = "android:"; + + if (!deviceID.StartsWith(deviceIdentifier, StringComparison.Ordinal) || (deviceID.Length != deviceIdentifier.Length + 36)) { + return false; + } + + string hash = deviceID.Substring(deviceIdentifier.Length).Replace("-", ""); + + return (hash.Length == 32) && Utilities.IsValidHexadecimalString(hash); + } + private string GenerateConfirmationHash(uint time, string tag = null) { if (time == 0) { Bot.ArchiLogger.LogNullError(nameof(time)); diff --git a/ArchiSteamFarm/Utilities.cs b/ArchiSteamFarm/Utilities.cs index 90c97639e..839b79b47 100644 --- a/ArchiSteamFarm/Utilities.cs +++ b/ArchiSteamFarm/Utilities.cs @@ -180,17 +180,55 @@ namespace ArchiSteamFarm { return false; } - const byte split = 16; - - for (byte i = 0; i < text.Length; i += split) { - string textPart = string.Join("", text.Skip(i).Take(split)); - - if (!ulong.TryParse(textPart, NumberStyles.HexNumber, null, out _)) { - return false; - } + if (text.Length % 2 != 0) { + return false; } - return true; + // ulong is 64-bits wide, each hexadecimal character is 4-bits wide, so we split each 16 + const byte split = 16; + + string lastHex; + + if (text.Length >= split) { + StringBuilder hex = new StringBuilder(split); + + foreach (char character in text) { + hex.Append(character); + + if (hex.Length < split) { + continue; + } + + if (!ulong.TryParse(hex.ToString(), NumberStyles.HexNumber, null, out _)) { + return false; + } + + hex.Clear(); + } + + if (hex.Length == 0) { + return true; + } + + lastHex = hex.ToString(); + } else { + lastHex = text; + } + + switch (lastHex.Length) { + case 2: + + return byte.TryParse(lastHex, NumberStyles.HexNumber, null, out _); + case 4: + + return ushort.TryParse(lastHex, NumberStyles.HexNumber, null, out _); + case 8: + + return uint.TryParse(lastHex, NumberStyles.HexNumber, null, out _); + default: + + return false; + } } internal static int RandomNext() {