From a4f081c2836f8ae7c82d8d31cff8f38deb187d23 Mon Sep 17 00:00:00 2001 From: Ash-bass Date: Tue, 3 Mar 2026 20:35:35 +0000 Subject: [PATCH] Add Steam ticket auth for auth=steam download URLs Made-with: Cursor --- AcManager.Tools/AcManager.Tools.csproj | 3 +- .../Helpers/CookieAwareWebClient.cs | 7 +++ .../Helpers/SteamTicketProvider.cs | 56 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 AcManager.Tools/Helpers/SteamTicketProvider.cs diff --git a/AcManager.Tools/AcManager.Tools.csproj b/AcManager.Tools/AcManager.Tools.csproj index c79e752b4..d5173d4a2 100644 --- a/AcManager.Tools/AcManager.Tools.csproj +++ b/AcManager.Tools/AcManager.Tools.csproj @@ -1,4 +1,4 @@ - + @@ -503,6 +503,7 @@ + Component diff --git a/AcManager.Tools/Helpers/CookieAwareWebClient.cs b/AcManager.Tools/Helpers/CookieAwareWebClient.cs index bb9522ca7..6035a3618 100644 --- a/AcManager.Tools/Helpers/CookieAwareWebClient.cs +++ b/AcManager.Tools/Helpers/CookieAwareWebClient.cs @@ -191,6 +191,13 @@ protected override WebRequest GetWebRequest(Uri address) { Logging.Debug("Cookies:\n" + cookie); } + if (SteamTicketProvider.UrlRequiresSteamTicket(address.ToString())) { + var ticket = SteamTicketProvider.GetTicketHex(); + if (!string.IsNullOrEmpty(ticket)) { + webRequest.Headers.Set("Authorization", "Bearer " + ticket); + } + } + if (_autoRedirect.HasValue) { webRequest.AllowAutoRedirect = _autoRedirect.Value; } diff --git a/AcManager.Tools/Helpers/SteamTicketProvider.cs b/AcManager.Tools/Helpers/SteamTicketProvider.cs new file mode 100644 index 000000000..a48fac341 --- /dev/null +++ b/AcManager.Tools/Helpers/SteamTicketProvider.cs @@ -0,0 +1,56 @@ +using System; +using FirstFloor.ModernUI.Helpers; +using JetBrains.Annotations; +using Steamworks; + +namespace AcManager.Tools.Helpers { + /// + /// Provides Steam auth tickets for download requests. Used when URLs contain auth=steam + /// to prove identity to servers that validate via Steam (BeginAuthSession or Web API). + /// + public static class SteamTicketProvider { + /// + /// Query param that indicates the server requires a Steam ticket. + /// When present in URL, CM adds Authorization: Bearer <hex-ticket> to the request. + /// + public const string AuthParam = "auth=steam"; + + /// + /// Generates a Steam auth session ticket and returns it as a hex string for Bearer auth. + /// Returns null if Steam is not initialized or ticket generation fails. + /// Uses GetAuthSessionTicket (game session). Compatible with Steamworks.NET 5.x+ (3-param overload). + /// + [CanBeNull] + public static string GetTicketHex() { + try { + if (!SteamAPI.Init()) return null; + + var ticketBuffer = new byte[1024]; + var ticketHandle = SteamUser.GetAuthSessionTicket(ticketBuffer, ticketBuffer.Length, out var ticketSize); + if (ticketHandle == HAuthTicket.Invalid || ticketSize == 0) return null; + + try { + var ticketBytes = new byte[ticketSize]; + Array.Copy(ticketBuffer, ticketBytes, (int)ticketSize); + return BitConverter.ToString(ticketBytes).Replace("-", ""); + } finally { + SteamUser.CancelAuthTicket(ticketHandle); + } + } catch (Exception e) { + Logging.Warning("Steam ticket generation failed: " + e.Message); + return null; + } + } + + /// + /// Checks if the URL contains the auth=steam param (case-insensitive). + /// + public static bool UrlRequiresSteamTicket([NotNull] string url) { + if (string.IsNullOrEmpty(url)) return false; + var queryStart = url.IndexOf('?'); + if (queryStart < 0) return false; + var query = url.Substring(queryStart); + return query.IndexOf(AuthParam, StringComparison.OrdinalIgnoreCase) >= 0; + } + } +}