using System; using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; using Newtonsoft.Json; using SteamAuth; using SteamKit2; using SteamKit2.Authentication; var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapPost("/login", async (HttpContext http) => { var req = await GetRequestBodyAsync(http); if (req == null) { http.Response.StatusCode = 400; await http.Response.WriteAsync("invalid request"); return; } if (!File.Exists(req.MaFilePath)) { http.Response.StatusCode = 400; await http.Response.WriteAsync("maFile not found"); return; } SteamGuardAccount? account; try { var contents = await File.ReadAllTextAsync(req.MaFilePath); account = JsonConvert.DeserializeObject(contents); } catch (Exception ex) { http.Response.StatusCode = 500; await http.Response.WriteAsync("failed to read maFile: " + ex.Message); return; } try { // Start SteamClient and authenticate using the maFile-provided SteamGuardAccount SteamClient steamClient = new SteamClient(); steamClient.Connect(); var timeoutMs = 15000; var waited = 0; while (!steamClient.IsConnected && waited < timeoutMs) { await Task.Delay(200); waited += 200; } if (!steamClient.IsConnected) { http.Response.StatusCode = 500; await http.Response.WriteAsync("failed to connect to steam network"); return; } CredentialsAuthSession authSession = await steamClient.Authentication.BeginAuthSessionViaCredentialsAsync(new AuthSessionDetails { Username = req.Username, Password = req.Password, IsPersistentSession = false, // PlatformType and ClientOSType are optional; omit to avoid enum symbol differences across SteamKit2 versions. Authenticator = new FileAuthenticator(account), }); var pollResponse = await authSession.PollingWaitForResultAsync(); var sessionData = new SessionData() { SteamID = authSession.SteamID.ConvertToUInt64(), AccessToken = pollResponse.AccessToken, RefreshToken = pollResponse.RefreshToken, }; // Serialize cookies var uri = new Uri("https://steamcommunity.com"); var cookies = sessionData.GetCookies().GetCookies(uri).Cast().Select(c => new { name = c.Name, value = c.Value, domain = c.Domain, path = c.Path, expires = c.Expires == DateTime.MinValue ? null : (DateTime?)c.Expires }).ToArray(); var resp = new { session = new { steamId = sessionData.SteamID, accessToken = sessionData.AccessToken, refreshToken = sessionData.RefreshToken, sessionId = sessionData.SessionID }, cookies = cookies }; http.Response.ContentType = "application/json"; await http.Response.WriteAsync(JsonConvert.SerializeObject(resp, Formatting.Indented)); return; } catch (Exception ex) { http.Response.StatusCode = 500; await http.Response.WriteAsync("login failed: " + ex.Message); return; } }); app.Run(); async Task GetRequestBodyAsync(HttpContext http) { try { using var sr = new StreamReader(http.Request.Body); var body = await sr.ReadToEndAsync(); if (string.IsNullOrWhiteSpace(body)) return null; return JsonConvert.DeserializeObject(body); } catch { return null; } } record LoginRequest(string Username, string Password, string MaFilePath); internal class FileAuthenticator : IAuthenticator { private readonly SteamGuardAccount? account; private int deviceCodesGenerated = 0; public FileAuthenticator(SteamGuardAccount? account) { this.account = account; } public Task AcceptDeviceConfirmationAsync() { return Task.FromResult(false); } public async Task GetDeviceCodeAsync(bool previousCodeWasIncorrect) { if (previousCodeWasIncorrect) { if (deviceCodesGenerated > 2) throw new Exception("failed to generate device code from maFile"); await Task.Delay(30000); } if (account == null) return null; deviceCodesGenerated++; var code = await account.GenerateSteamGuardCodeAsync(); return code ?? ""; } public Task GetEmailCodeAsync(string email, bool previousCodeWasIncorrect) { // This implementation does not support interactive email codes. return Task.FromResult(string.Empty); } }