Files
Nebula-Auth/src/NebulaAuth/Model/MaClient.cs
T
achiez 30cf049f23 refactor(auth): redesign Steam audience and web domain authorization model
- Rename AuthorizedDomains to WebDomains
- Introduce explicit Steam audience constants and web audience mappings
- Improve Steam token/domain resolution and cookie installation flow
- Allow mobile-issued tokens with "web" audience to be used for web domains
- Align authorization logic closer to actual Steam audience behavior
- Rename cookie APIs from Add* to Set* where appropriate
2026-05-12 16:36:37 +03:00

196 lines
6.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using AchiesUtilities.Web.Models;
using AchiesUtilities.Web.Proxy;
using NebulaAuth.Model.Entities;
using SteamLib.Api.Mobile;
using SteamLib.Api.Services;
using SteamLib.Api.Trade;
using SteamLib.Authentication;
using SteamLib.Exceptions.Authorization;
using SteamLib.ProtoCore.Services;
using SteamLib.SteamMobile.Confirmations;
using SteamLib.Web;
namespace NebulaAuth.Model;
public static class MaClient
{
private static HttpClientHandler ClientHandler { get; }
private static HttpClient Client { get; }
private static DynamicProxy Proxy { get; }
public static ProxyData? DefaultProxy { get; set; }
static MaClient()
{
Proxy = new DynamicProxy();
var pair = ClientBuilder.BuildMobileClient(Proxy, null);
Client = pair.Client;
ClientHandler = pair.Handler;
}
public static void SetAccount(Mafile? account)
{
ClientHandler.CookieContainer.ClearAllCookies();
if (account == null) return;
ClientHandler.CookieContainer.SetSteamMobileCookies(account.SessionData);
Proxy.SetData(account.Proxy?.Data);
}
public static Task<IEnumerable<Confirmation>> GetConfirmations(Mafile mafile)
{
ValidateMafile(mafile);
SetProxy(mafile);
return SteamMobileConfirmationsApi.GetConfirmations(Client, mafile, mafile.SessionData!.SteamId);
}
public static Task LoginAgain(Mafile mafile, string password, bool savePassword)
{
SetProxy(mafile);
return SessionHandler.LoginAgain(new HttpClientHandlerPair(Client, ClientHandler), mafile, password,
savePassword);
}
public static Task RefreshSession(Mafile mafile)
{
ValidateMafile(mafile, true);
SetProxy(mafile);
return SessionHandler.RefreshMobileToken(new HttpClientHandlerPair(Client, ClientHandler), mafile);
}
public static async Task<bool> SendConfirmation(Mafile mafile, Confirmation confirmation, bool confirm)
{
ValidateMafile(mafile);
SetProxy(mafile);
var res = await SteamMobileConfirmationsApi.SendConfirmation(Client, confirmation, mafile.SessionData!.SteamId,
mafile,
confirm);
if (!res && confirmation.ConfType == ConfirmationType.Trade)
{
Shell.Logger.Warn("Failed to send trade confirmation for {accountName}. Sending ack", mafile.AccountName);
await SteamTradeApi.Acknowledge(Client, mafile.SessionData.SessionId);
await Task.Delay(10);
}
else
{
return res;
}
return await SteamMobileConfirmationsApi.SendConfirmation(Client, confirmation, mafile.SessionData!.SteamId,
mafile,
confirm);
}
public static async Task<bool> SendMultipleConfirmation(Mafile mafile, IEnumerable<Confirmation> confirmations,
bool confirm)
{
var enumerable = confirmations.ToList();
if (enumerable.Count == 0)
{
return false;
}
ValidateMafile(mafile);
SetProxy(mafile);
var res = await SteamMobileConfirmationsApi.SendMultipleConfirmations(Client, enumerable,
mafile.SessionData!.SteamId,
mafile, confirm);
if (!res && enumerable.Any(c => c.ConfType == ConfirmationType.Trade))
{
Shell.Logger.Warn("Failed to send trade confirmations for {accountName}. Sending ack", mafile.AccountName);
await SteamTradeApi.Acknowledge(Client, mafile.SessionData.SessionId);
await Task.Delay(10);
}
else
{
return res;
}
return await SteamMobileConfirmationsApi.SendMultipleConfirmations(Client, enumerable,
mafile.SessionData!.SteamId,
mafile, confirm);
}
public static Task<RemoveAuthenticator_Response> RemoveAuthenticator(Mafile mafile)
{
ValidateMafile(mafile);
SetProxy(mafile);
if (mafile.RevocationCode == null)
{
throw new InvalidOperationException("This mafile does not have R-Code");
}
var token = mafile.SessionData!.GetMobileToken()!;
return SteamMobileApi.RemoveAuthenticator(Client, token.Value.Token, mafile.RevocationCode);
}
private static void SetProxy(Mafile mafile)
{
Proxy.SetData(mafile.Proxy?.Data ?? DefaultProxy);
}
private static void ValidateMafile(Mafile mafile, bool ignoreAccessToken = false)
{
if (mafile.SessionData == null) throw new SessionInvalidException();
if (mafile.SessionData.RefreshToken.IsExpired)
throw new SessionPermanentlyExpiredException();
if (!ignoreAccessToken)
{
var access = mafile.SessionData.GetMobileToken();
if (access == null || access.Value.IsExpired)
throw new SessionPermanentlyExpiredException();
}
}
public static async Task<LoginConfirmationResult> ConfirmLoginRequest(Mafile mafile)
{
ValidateMafile(mafile);
SetProxy(mafile);
var token = mafile.SessionData!.GetMobileToken()!.Value;
var sessions = await AuthenticationServiceApi.GetAuthSessionsForAccount(Client, token.Token);
if (sessions.ClientIds.Count == 0)
{
return new LoginConfirmationResult
{
Error = LoginConfirmationError.NoRequests
};
}
if (sessions.ClientIds.Count > 1)
{
return new LoginConfirmationResult
{
Error = LoginConfirmationError.MoreThanOneRequest
};
}
var clientId = sessions.ClientIds.Single();
var clientInfo = await AuthenticationServiceApi.GetAuthSessionInfo(Client, token.Token, clientId);
var updateReq =
AuthRequestHelper.CreateMobileConfirmationRequest(1, clientId, mafile.SessionData.SteamId.Steam64,
mafile.SharedSecret);
await AuthenticationServiceApi.UpdateAuthSessionWithMobileConfirmation(Client, token.Token, updateReq);
return new LoginConfirmationResult
{
Country = clientInfo.Country,
IP = clientInfo.IP,
Success = true
};
}
public static HttpClientHandlerPair GetHttpClientHandlerPair(Mafile mafile)
{
SetProxy(mafile);
return new HttpClientHandlerPair(Client, ClientHandler);
}
}