From 6ffa0948a494798a138d3689dff0e3e9500525c5 Mon Sep 17 00:00:00 2001 From: Yaakov Date: Fri, 24 Mar 2023 15:00:27 +1100 Subject: [PATCH] Implement -qr CLI arg to log in with a QR code --- DepotDownloader/DepotDownloader.csproj | 1 + DepotDownloader/DownloadConfig.cs | 2 + DepotDownloader/Program.cs | 38 ++++++++------- DepotDownloader/Steam3Session.cs | 64 ++++++++++++++++++++++++-- 4 files changed, 83 insertions(+), 22 deletions(-) diff --git a/DepotDownloader/DepotDownloader.csproj b/DepotDownloader/DepotDownloader.csproj index c64d0054..a2e07dd3 100644 --- a/DepotDownloader/DepotDownloader.csproj +++ b/DepotDownloader/DepotDownloader.csproj @@ -12,6 +12,7 @@ + diff --git a/DepotDownloader/DownloadConfig.cs b/DepotDownloader/DownloadConfig.cs index bcb46cb1..1022aac4 100644 --- a/DepotDownloader/DownloadConfig.cs +++ b/DepotDownloader/DownloadConfig.cs @@ -26,5 +26,7 @@ namespace DepotDownloader // A Steam LoginID to allow multiple concurrent connections public uint? LoginID { get; set; } + + public bool UseQrCode { get; set; } } } diff --git a/DepotDownloader/Program.cs b/DepotDownloader/Program.cs index 9c07fbbd..baae3e8e 100644 --- a/DepotDownloader/Program.cs +++ b/DepotDownloader/Program.cs @@ -47,6 +47,7 @@ namespace DepotDownloader var username = GetParameter(args, "-username") ?? GetParameter(args, "-user"); var password = GetParameter(args, "-password") ?? GetParameter(args, "-pass"); ContentDownloader.Config.RememberPassword = HasParameter(args, "-remember-password"); + ContentDownloader.Config.UseQrCode = HasParameter(args, "-qr"); ContentDownloader.Config.DownloadManifestOnly = HasParameter(args, "-manifest-only"); @@ -268,27 +269,30 @@ namespace DepotDownloader static bool InitializeSteam(string username, string password) { - if (username != null && password == null && (!ContentDownloader.Config.RememberPassword || !AccountSettingsStore.Instance.LoginTokens.ContainsKey(username))) + if (!ContentDownloader.Config.UseQrCode) { - do + if (username != null && password == null && (!ContentDownloader.Config.RememberPassword || !AccountSettingsStore.Instance.LoginTokens.ContainsKey(username))) { - Console.Write("Enter account password for \"{0}\": ", username); - if (Console.IsInputRedirected) + do { - password = Console.ReadLine(); - } - else - { - // Avoid console echoing of password - password = Util.ReadPassword(); - } + Console.Write("Enter account password for \"{0}\": ", username); + if (Console.IsInputRedirected) + { + password = Console.ReadLine(); + } + else + { + // Avoid console echoing of password + password = Util.ReadPassword(); + } - Console.WriteLine(); - } while (string.Empty == password); - } - else if (username == null) - { - Console.WriteLine("No username given. Using anonymous account with dedicated server subscription."); + Console.WriteLine(); + } while (string.Empty == password); + } + else if (username == null) + { + Console.WriteLine("No username given. Using anonymous account with dedicated server subscription."); + } } return ContentDownloader.InitializeSteam3(username, password); diff --git a/DepotDownloader/Steam3Session.cs b/DepotDownloader/Steam3Session.cs index d88feccc..e30ff64e 100644 --- a/DepotDownloader/Steam3Session.cs +++ b/DepotDownloader/Steam3Session.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using QRCoder; using SteamKit2; using SteamKit2.Authentication; using SteamKit2.Internal; @@ -72,7 +73,7 @@ namespace DepotDownloader { this.logonDetails = details; - this.authenticatedUser = details.Username != null; + this.authenticatedUser = details.Username != null || ContentDownloader.Config.UseQrCode; this.credentials = new Credentials(); this.bConnected = false; this.bConnecting = false; @@ -114,7 +115,7 @@ namespace DepotDownloader Console.Write("Connecting to Steam3..."); - if (authenticatedUser) + if (details.Username != null) { var fi = new FileInfo(String.Format("{0}.sentryFile", logonDetails.Username)); if (AccountSettingsStore.Instance.SentryData != null && AccountSettingsStore.Instance.SentryData.ContainsKey(logonDetails.Username)) @@ -488,7 +489,10 @@ namespace DepotDownloader } else { - Console.WriteLine("Logging '{0}' into Steam3...", logonDetails.Username); + if (logonDetails.Username != null) + { + Console.WriteLine("Logging '{0}' into Steam3...", logonDetails.Username); + } if (logonDetails.Username != null && logonDetails.Password != null && logonDetails.AccessToken is null) { @@ -504,8 +508,6 @@ namespace DepotDownloader var result = await session.PollingWaitForResultAsync(); - DebugLog.WriteLine(nameof(Steam3Session), "Completed authentication initialization, got access token."); - // Assume that we get back the same username, no need to reset it. logonDetails.Password = null; logonDetails.AccessToken = result.RefreshToken; @@ -519,6 +521,46 @@ namespace DepotDownloader Abort(false); } } + else if (ContentDownloader.Config.UseQrCode) + { + Console.WriteLine("Logging in with QR code..."); + + try + { + var session = await steamClient.Authentication.BeginAuthSessionViaQRAsync(new AuthSessionDetails + { + IsPersistentSession = ContentDownloader.Config.RememberPassword, + Authenticator = new UserConsoleAuthenticator(), + }); + + // Steam will periodically refresh the challenge url, so we need a new QR code. + session.ChallengeURLChanged = () => + { + Console.WriteLine(); + Console.WriteLine("The QR code has changed:"); + + DisplayQrCode(session.ChallengeURL); + }; + + // Draw initial QR code immediately + DisplayQrCode(session.ChallengeURL); + + var result = await session.PollingWaitForResultAsync(); + + logonDetails.Username = result.AccountName; + logonDetails.Password = null; + logonDetails.AccessToken = result.RefreshToken; + + AccountSettingsStore.Instance.LoginTokens[result.AccountName] = result.RefreshToken; + AccountSettingsStore.Save(); + } + catch (Exception ex) + { + Console.Error.WriteLine("Failed to authenticate with Steam: " + ex.Message); + Abort(false); + } + } + steamUser.LogOn(logonDetails); } } @@ -701,5 +743,17 @@ namespace DepotDownloader // send off our response steamUser.SendMachineAuthResponse(authResponse); } + + private static void DisplayQrCode(string challengeUrl) + { + // Encode the link as a QR code + var qrGenerator = new QRCodeGenerator(); + var qrCodeData = qrGenerator.CreateQrCode(challengeUrl, QRCodeGenerator.ECCLevel.L); + var qrCode = new AsciiQRCode(qrCodeData); + var qrCodeAsAsciiArt = qrCode.GetGraphic(1, drawQuietZones: false); + + Console.WriteLine("Use the Steam Mobile App to sign in with this QR code:"); + Console.WriteLine(qrCodeAsAsciiArt); + } } }