diff --git a/src/NebulaAuth/Model/MAAC/PortableMaClient.cs b/src/NebulaAuth/Model/MAAC/PortableMaClient.cs
index 6395256..23555e6 100644
--- a/src/NebulaAuth/Model/MAAC/PortableMaClient.cs
+++ b/src/NebulaAuth/Model/MAAC/PortableMaClient.cs
@@ -62,7 +62,7 @@ public partial class PortableMaClient : ObservableObject, IDisposable
SetStatus(newStatus);
ClientHandler.CookieContainer.ClearAllCookies();
- ClientHandler.CookieContainer.SetSteamMobileCookiesWithMobileToken(sessionData);
+ ClientHandler.CookieContainer.SetSteamMobileCookies(sessionData);
}
diff --git a/src/NebulaAuth/Model/MaClient.cs b/src/NebulaAuth/Model/MaClient.cs
index 115f5e3..74598a2 100644
--- a/src/NebulaAuth/Model/MaClient.cs
+++ b/src/NebulaAuth/Model/MaClient.cs
@@ -38,7 +38,7 @@ public static class MaClient
{
ClientHandler.CookieContainer.ClearAllCookies();
if (account == null) return;
- ClientHandler.CookieContainer.SetSteamMobileCookiesWithMobileToken(account.SessionData);
+ ClientHandler.CookieContainer.SetSteamMobileCookies(account.SessionData);
Proxy.SetData(account.Proxy?.Data);
}
diff --git a/src/NebulaAuth/Model/SessionHandler/SessionHandler_API.cs b/src/NebulaAuth/Model/SessionHandler/SessionHandler_API.cs
index b644462..fe40011 100644
--- a/src/NebulaAuth/Model/SessionHandler/SessionHandler_API.cs
+++ b/src/NebulaAuth/Model/SessionHandler/SessionHandler_API.cs
@@ -30,7 +30,7 @@ public partial class SessionHandler //API
//Trigger PropertyChanged event for PortableMaClient handling session updated from MaClient
mafile.SetSessionData(mafile.SessionData);
await Storage.UpdateMafileAsync(mafile);
- chp.Handler.CookieContainer.SetSteamMobileCookiesWithMobileToken(mafile.SessionData);
+ chp.Handler.CookieContainer.SetSteamMobileCookies(mafile.SessionData);
}
public static async Task LoginAgain(HttpClientHandlerPair chp, Mafile mafile, string password, bool savePassword)
diff --git a/src/SteamLibForked/Authentication/AdmissionHelper.cs b/src/SteamLibForked/Authentication/AdmissionHelper.cs
index 30ab7b2..57ece1c 100644
--- a/src/SteamLibForked/Authentication/AdmissionHelper.cs
+++ b/src/SteamLibForked/Authentication/AdmissionHelper.cs
@@ -54,33 +54,20 @@ public static class AdmissionHelper
return;
}
-
- AddRefreshToken(container, sessionData.RefreshToken);
+ container.SetSteamRefreshToken(sessionData.RefreshToken);
var community = SteamDomains.GetDomainUri(SteamDomain.Community);
container.Add(community, new Cookie(SESSION_ID_COOKIE_NAME, sessionData.SessionId, "/"));
container.Add(community, new Cookie(LANGUAGE_COOKIE_NAME, setLanguage, "/"));
TransferCommunityCookies(container);
- foreach (var domain in SteamDomains.AuthDomains)
+ foreach (var domain in SteamDomains.WebDomains)
{
var token = sessionData.GetToken(domain);
if (token == null) continue;
- AddTokenCookie(container, token.Value);
+ container.SetSteamAccessToken(token.Value);
}
}
- public static void SetDomainCookie(this CookieContainer container, SteamDomain domain, SteamAuthToken token)
- {
- var uri = SteamDomains.GetDomainUri(domain);
- foreach (var cookie in container.GetCookies(uri)
- .Where(c => !c.Expired && c.Name.EqualsIgnoreCase(ACCESS_COOKIE_NAME)))
- {
- cookie.Expired = true;
- }
-
- AddTokenCookie(container, token);
- }
-
///
/// Clear and set new session
///
@@ -95,70 +82,22 @@ public static class AdmissionHelper
return;
}
- AddRefreshToken(container, mobileSession.RefreshToken);
+ container.SetSteamRefreshToken(mobileSession.RefreshToken);
var community = SteamDomains.GetDomainUri(SteamDomain.Community);
container.Add(community, new Cookie("steamid", mobileSession.SteamId.Steam64.ToString()));
container.Add(community, new Cookie(SESSION_ID_COOKIE_NAME, mobileSession.SessionId));
container.Add(community, new Cookie(LANGUAGE_COOKIE_NAME, setLanguage));
TransferCommunityCookies(container);
- foreach (var domain in SteamDomains.AuthDomains)
+ foreach (var domain in SteamDomains.WebDomains)
{
var token = mobileSession.GetToken(domain);
if (token == null) continue;
- AddTokenCookie(container, token.Value);
+ var domainUri = SteamDomains.GetDomainUri(domain);
+ container.SetSteamAccessTokenUnsafe(token.Value, domainUri);
}
}
- ///
- /// Clear and set new session. Not recommended. Uses for domain
- /// instead of its own cookie. It's okay to use it only for confirmations. But
- /// Market, Trading and other pages won't be authorized
- ///
- public static void SetSteamMobileCookiesWithMobileToken(this CookieContainer container,
- IMobileSessionData? mobileSession,
- string setLanguage = "english")
- {
- container.ClearSteamCookies(setLanguage);
- container.AddMinimalMobileCookies();
-
- if (mobileSession == null)
- {
- TransferCommunityCookies(container);
- return;
- }
-
-
- AddRefreshToken(container, mobileSession.RefreshToken);
-
- var community = SteamDomains.GetDomainUri(SteamDomain.Community);
- container.Add(community, new Cookie("steamid", mobileSession.SteamId.Steam64.ToString()));
- container.Add(community, new Cookie(SESSION_ID_COOKIE_NAME, mobileSession.SessionId));
- container.Add(community, new Cookie(LANGUAGE_COOKIE_NAME, setLanguage));
- TransferCommunityCookies(container);
-
- var domainCookieSet = false;
- foreach (var domain in SteamDomains.AllDomains)
- {
- var token = mobileSession.GetToken(domain);
- if (token == null || token.Value.IsExpired) continue;
- if (domain == SteamDomain.Community)
- domainCookieSet = true;
- AddTokenCookie(container, token.Value);
- }
-
- var mobileToken = mobileSession.GetMobileToken();
- if (!domainCookieSet && mobileToken is {IsExpired: false})
- {
- var domain = SteamDomains.GetDomainUri(SteamDomain.Community);
- container.Add(domain, new Cookie(ACCESS_COOKIE_NAME, mobileToken.Value.SignedToken)
- {
- HttpOnly = true,
- Secure = true,
- Expires = mobileToken.Value.Expires.ToLocalDateTime()
- });
- }
- }
public static void AddMinimalMobileCookies(this CookieContainer container)
{
@@ -229,27 +168,93 @@ public static class AdmissionHelper
}
}
- public static void AddRefreshToken(CookieContainer container, SteamAuthToken token)
+ ///
+ /// Sets a Steam refresh token as a cookie to the specified cookie container.
+ ///
+ ///
+ /// The added cookie will have its expiration set according to the token's expiration time. This
+ /// method is typically used to enable authenticated requests to Steam services that require a refresh
+ /// token.
+ ///
+ /// The cookie container to which the Steam refresh token cookie will be added. Cannot be null.
+ ///
+ /// The Steam authentication token to add as a refresh cookie. Must be of type Refresh or
+ /// MobileRefresh.
+ ///
+ /// Thrown if the token is not of type Refresh or MobileRefresh.
+ public static void SetSteamRefreshToken(this CookieContainer container, SteamAuthToken token)
{
if (token.Type is not (SteamAccessTokenType.Refresh or SteamAccessTokenType.MobileRefresh))
throw new ArgumentException(
$"Token must be of type Refresh or MobileRefresh. Provided token has type: {token.Type}",
nameof(token));
- var refreshToken = token.SignedToken;
- container.Add(SteamLoginUri, new Cookie(REFRESH_COOKIE_NAME, refreshToken)
+ SetSteamRefreshTokenUnsafe(container, token, SteamLoginUri);
+ }
+
+ ///
+ /// Sets a Steam refresh token as a cookie to the specified cookie container for the given domain.
+ ///
+ ///
+ /// This method does not perform validation on the input parameters. Callers must ensure that the
+ /// provided values are valid and appropriate for use.
+ ///
+ /// The cookie container to which the refresh token cookie will be added. Cannot be null.
+ ///
+ /// The Steam authentication token containing the signed token value and expiration information. Cannot
+ /// be null.
+ ///
+ /// The URI of the domain for which the refresh token cookie should be set. Cannot be null.
+ public static void SetSteamRefreshTokenUnsafe(CookieContainer container, SteamAuthToken token, Uri domainUri)
+ {
+ container.Add(domainUri, new Cookie(REFRESH_COOKIE_NAME, token.SignedToken)
{
Expires = token.Expires.ToLocalDateTime()
});
}
- public static void AddTokenCookie(CookieContainer container, SteamAuthToken token)
+ ///
+ /// Sets a Steam access token to the specified cookie container for use with Steam web requests.
+ ///
+ ///
+ /// This method is intended for standard web access tokens bound to a specific Steam web domain.
+ /// Mobile tokens are intentionally rejected, since their audiences are capability-based rather
+ /// than domain-based and may grant access to multiple web domains.
+ ///
+ /// The cookie container to which the Steam access token will be added. Cannot be null.
+ ///
+ /// The Steam access token to add. Must be of type AccessToken and associated with a valid Steam
+ /// domain.
+ ///
+ /// Thrown if the token is not of type AccessToken.
+ public static void SetSteamAccessToken(this CookieContainer container, SteamAuthToken token)
{
+ if (token.Type == SteamAccessTokenType.Mobile)
+ throw new ArgumentException(
+ $"Mobile access tokens cannot be added using this method. Use SetSteamAccessTokenUnsafe instead. Provided token has type: {token.Type}",
+ nameof(token));
if (token.Type is not SteamAccessTokenType.AccessToken)
throw new ArgumentException($"Token must be of type AccessToken. Provided token has type: {token.Type}",
nameof(token));
- var domain = SteamDomains.GetDomainUri(token.Domain);
- container.Add(domain, new Cookie(ACCESS_COOKIE_NAME, token.SignedToken)
+ var domainUri = SteamDomains.GetDomainUri(token.Domain);
+ container.SetSteamAccessTokenUnsafe(token, domainUri);
+ }
+
+
+ ///
+ /// Sets a Steam access token as a secure, HTTP-only cookie to the specified cookie container for the given domain.
+ ///
+ ///
+ /// This method does not perform validation on the input parameters and should only be used when
+ /// input values are trusted. The added cookie is marked as secure and HTTP-only, and its expiration is set
+ /// according to the token's expiration time.
+ ///
+ /// The cookie container to which the Steam access token cookie will be added. Cannot be null.
+ /// The Steam access token to add as a cookie. Must contain a valid signed token and expiration.
+ /// The URI of the domain for which the cookie will be set. Cannot be null.
+ public static void SetSteamAccessTokenUnsafe(this CookieContainer container, SteamAuthToken token, Uri domainUri)
+ {
+ container.Add(domainUri, new Cookie(ACCESS_COOKIE_NAME, token.SignedToken)
{
HttpOnly = true,
Secure = true,
@@ -257,7 +262,6 @@ public static class AdmissionHelper
});
}
-
public static bool IsSteamCookie(Cookie cookie)
{
return cookie.Domain.Contains("steamcommunity.com") || cookie.Domain.Contains("steampowered.com") ||
diff --git a/src/SteamLibForked/Core/SteamDomains.cs b/src/SteamLibForked/Core/SteamDomains.cs
index a74737c..5be37e7 100644
--- a/src/SteamLibForked/Core/SteamDomains.cs
+++ b/src/SteamLibForked/Core/SteamDomains.cs
@@ -1,49 +1,43 @@
-using System.Collections.ObjectModel;
-using SteamLibForked.Models.Core;
+using SteamLibForked.Models.Core;
+using System.Collections.Immutable;
namespace SteamLib.Core;
public static class SteamDomains
{
public static IReadOnlyDictionary Domains { get; } =
- new ReadOnlyDictionary(
- new Dictionary
- {
- {SteamDomain.Community, SteamConstants.STEAM_COMMUNITY},
- {SteamDomain.Store, SteamConstants.STEAM_STORE},
- {SteamDomain.Help, SteamConstants.STEAM_HELP},
- {SteamDomain.TV, SteamConstants.STEAM_TV},
- {SteamDomain.Checkout, SteamConstants.STEAM_CHECKOUT},
- {SteamDomain.Login, SteamConstants.STEAM_LOGIN},
- {SteamDomain.API, SteamConstants.STEAM_API}
- });
+ new Dictionary
+ {
+ {SteamDomain.Community, SteamConstants.STEAM_COMMUNITY},
+ {SteamDomain.Store, SteamConstants.STEAM_STORE},
+ {SteamDomain.Help, SteamConstants.STEAM_HELP},
+ {SteamDomain.TV, SteamConstants.STEAM_TV},
+ {SteamDomain.Checkout, SteamConstants.STEAM_CHECKOUT},
+ {SteamDomain.Login, SteamConstants.STEAM_LOGIN},
+ {SteamDomain.API, SteamConstants.STEAM_API}
+ }.ToImmutableDictionary();
public static IReadOnlyDictionary DomainUris { get; }
- = new ReadOnlyDictionary(
- Domains.ToDictionary(x => x.Key, x => new Uri(x.Value))
- );
+ = Domains
+ .ToDictionary(x => x.Key, x => new Uri(x.Value))
+ .ToImmutableDictionary();
- public static IEnumerable AllDomains { get; } =
- [
- SteamDomain.Community,
- SteamDomain.Store,
- SteamDomain.Help,
- SteamDomain.TV,
- SteamDomain.Checkout,
- SteamDomain.Login,
- SteamDomain.API
- ];
-
- public static IEnumerable AuthDomains { get; } =
- [
- SteamDomain.Community,
- SteamDomain.Store,
- SteamDomain.Help,
- SteamDomain.TV,
- SteamDomain.Checkout
- ];
+ ///
+ /// All known public Steam domains.
+ ///
+ public static IEnumerable AllDomains { get; } = ImmutableHashSet.Create(SteamDomain.Community,
+ SteamDomain.Store, SteamDomain.Help, SteamDomain.TV, SteamDomain.Checkout, SteamDomain.Login, SteamDomain.API);
+ ///
+ /// Steam web domains that participate in the standard login authorization flow.
+ ///
+ /// These domains use the web:* audience format and receive
+ /// authentication cookies/tokens during session initialization.
+ ///
+ ///
+ public static IReadOnlySet WebDomains { get; } = ImmutableHashSet.Create(SteamDomain.Community,
+ SteamDomain.Store, SteamDomain.Help, SteamDomain.TV, SteamDomain.Checkout);
public static Uri GetDomainUri(SteamDomain domain)
{
diff --git a/src/SteamLibForked/Models/Core/Session/MobileSessionData.cs b/src/SteamLibForked/Models/Core/Session/MobileSessionData.cs
index 5c228fc..e02b88c 100644
--- a/src/SteamLibForked/Models/Core/Session/MobileSessionData.cs
+++ b/src/SteamLibForked/Models/Core/Session/MobileSessionData.cs
@@ -1,13 +1,14 @@
-using System.Diagnostics.CodeAnalysis;
-using Newtonsoft.Json;
+using Newtonsoft.Json;
+using SteamLib.Core;
using SteamLibForked.Abstractions;
using SteamLibForked.Models.Core;
+using System.Diagnostics.CodeAnalysis;
namespace SteamLibForked.Models.Session;
//WARNING: Any changes here should be reflected in MafileSerializer.cs
-public sealed class MobileSessionData : SessionData, IMobileSessionData
+public class MobileSessionData : SessionData, IMobileSessionData
{
public SteamAuthToken? MobileToken { get; private set; }
@@ -31,26 +32,39 @@ public sealed class MobileSessionData : SessionData, IMobileSessionData
return MobileToken;
}
+ public override SteamAuthToken? GetToken(SteamDomain domain)
+ {
+ var isWeb = SteamDomains.WebDomains.Contains(domain);
+ if (isWeb)
+ {
+ // Mobile-issued tokens usually contain the "web" audience,
+ // so we assume they can also be used for all web:* domains.
+ // See: SteamAuthToken 'TODO' for more details
+ return MobileToken ?? base.GetToken(domain);
+ }
+ return base.GetToken(domain);
+ }
+
[MemberNotNull(nameof(MobileToken))]
- public void SetMobileToken(SteamAuthToken token)
+ public virtual void SetMobileToken(SteamAuthToken token)
{
if (token.Type != SteamAccessTokenType.Mobile)
throw new ArgumentException("Token must be of type MobileAccess", nameof(token))
{
- Data = {{"ActualType", token.Type}}
+ Data = { { "ActualType", token.Type } }
};
MobileToken = token;
}
- public override MobileSessionData Clone()
- {
- return (MobileSessionData) ((ISessionData) this).Clone();
- }
-
object ICloneable.Clone()
{
return new MobileSessionData(SessionId, SteamId, RefreshToken, MobileToken, Tokens);
}
+
+ public override MobileSessionData Clone()
+ {
+ return (MobileSessionData)((ISessionData)this).Clone();
+ }
}
\ No newline at end of file
diff --git a/src/SteamLibForked/Web/ClientBuilder.cs b/src/SteamLibForked/Web/ClientBuilder.cs
index 9118d7a..28640fd 100644
--- a/src/SteamLibForked/Web/ClientBuilder.cs
+++ b/src/SteamLibForked/Web/ClientBuilder.cs
@@ -31,7 +31,7 @@ public static class ClientBuilder
}
else
{
- container.SetSteamMobileCookiesWithMobileToken(sessionData);
+ container.SetSteamMobileCookies(sessionData);
}
//Nebula tweak: