Can get a list of all appIds and depotids owned by the user

This commit is contained in:
Timothy Baldridge 2022-01-08 15:03:39 -07:00
parent bf843f9289
commit ac1f4a7427
6 changed files with 180 additions and 5 deletions

View File

@ -65,6 +65,7 @@ internal class Program
services.AddSingleton<IVerb, ForceHeal>(); services.AddSingleton<IVerb, ForceHeal>();
services.AddSingleton<IVerb, MirrorFile>(); services.AddSingleton<IVerb, MirrorFile>();
services.AddSingleton<IVerb, SteamLogin>(); services.AddSingleton<IVerb, SteamLogin>();
services.AddSingleton<IVerb, SteamAppDumpInfo>();
services.AddSingleton<IUserInterventionHandler, UserInterventionHandler>(); services.AddSingleton<IUserInterventionHandler, UserInterventionHandler>();
}).Build(); }).Build();

View File

@ -0,0 +1,57 @@
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Wabbajack.DTOs;
using Wabbajack.Networking.Http.Interfaces;
using Wabbajack.Networking.Steam;
namespace Wabbajack.CLI.Verbs;
public class SteamAppDumpInfo : IVerb
{
private readonly ILogger<SteamAppDumpInfo> _logger;
private readonly Client _client;
private readonly ITokenProvider<SteamLoginState> _token;
private readonly DepotDownloader _downloader;
public SteamAppDumpInfo(ILogger<SteamAppDumpInfo> logger, Client steamClient, ITokenProvider<SteamLoginState> token,
DepotDownloader downloader)
{
_logger = logger;
_client = steamClient;
_token = token;
_downloader = downloader;
}
public Command MakeCommand()
{
var command = new Command("steam-app-dump-info");
command.Description = "Dumps information to the console about the given app";
command.Add(new Option<string>(new[] {"-g", "-game", "-gameName"}, "Wabbajack game name"));
command.Handler = CommandHandler.Create(Run);
return command;
}
public async Task<int> Run(string gameName)
{
if (!GameRegistry.TryGetByFuzzyName(gameName, out var game))
{
_logger.LogError("Can't find game {GameName} in game registry", gameName);
return 1;
}
await _client.Login();
if (!await _downloader.AccountHasAccess((uint) game.SteamIDs.First()))
{
_logger.LogError("Your account does not have access to this Steam App");
return 1;
}
return 0;
}
}

View File

@ -1,6 +1,8 @@
using System.Collections.Concurrent;
using System.Security; using System.Security;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using SteamKit2; using SteamKit2;
using SteamKit2.Internal;
using Wabbajack.DTOs.Interventions; using Wabbajack.DTOs.Interventions;
using Wabbajack.Networking.Http.Interfaces; using Wabbajack.Networking.Http.Interfaces;
using Wabbajack.Networking.Steam.UserInterventions; using Wabbajack.Networking.Steam.UserInterventions;
@ -26,6 +28,16 @@ public class Client : IDisposable
private bool _isLoggedIn; private bool _isLoggedIn;
private bool _haveSigFile; private bool _haveSigFile;
public TaskCompletionSource _licenseRequest = new();
private readonly SteamApps _steamApps;
public SteamApps.LicenseListCallback.License[] Licenses { get; private set; }
public ConcurrentDictionary<uint, ulong> PackageTokens { get; } = new();
public ConcurrentDictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo?> PackageInfos { get; } = new();
public Client(ILogger<Client> logger, HttpClient client, ITokenProvider<SteamLoginState> token, public Client(ILogger<Client> logger, HttpClient client, ITokenProvider<SteamLoginState> token,
IUserInterventionHandler interventionHandler) IUserInterventionHandler interventionHandler)
{ {
@ -47,6 +59,7 @@ public class Client : IDisposable
_manager = new CallbackManager(_client); _manager = new CallbackManager(_client);
_steamUser = _client.GetHandler<SteamUser>()!; _steamUser = _client.GetHandler<SteamUser>()!;
_steamApps = _client.GetHandler<SteamApps>()!;
_manager.Subscribe<SteamClient.ConnectedCallback>( OnConnected ); _manager.Subscribe<SteamClient.ConnectedCallback>( OnConnected );
_manager.Subscribe<SteamClient.DisconnectedCallback>( OnDisconnected ); _manager.Subscribe<SteamClient.DisconnectedCallback>( OnDisconnected );
@ -54,6 +67,8 @@ public class Client : IDisposable
_manager.Subscribe<SteamUser.LoggedOnCallback>( OnLoggedOn ); _manager.Subscribe<SteamUser.LoggedOnCallback>( OnLoggedOn );
_manager.Subscribe<SteamUser.LoggedOffCallback>( OnLoggedOff ); _manager.Subscribe<SteamUser.LoggedOffCallback>( OnLoggedOff );
_manager.Subscribe<SteamApps.LicenseListCallback>(OnLicenseList);
_manager.Subscribe<SteamUser.UpdateMachineAuthCallback>( OnUpdateMachineAuthCallback ); _manager.Subscribe<SteamUser.UpdateMachineAuthCallback>( OnUpdateMachineAuthCallback );
_isConnected = false; _isConnected = false;
@ -74,6 +89,17 @@ public class Client : IDisposable
.Start(); .Start();
} }
private void OnLicenseList(SteamApps.LicenseListCallback obj)
{
if (obj.Result != EResult.OK)
{
_licenseRequest.TrySetException(new SteamException("While getting licenses", obj.Result, EResult.Invalid));
}
_logger.LogInformation("Got {LicenseCount} licenses from Steam", obj.LicenseList.Count);
Licenses = obj.LicenseList.ToArray();
_licenseRequest.TrySetResult();
}
private void OnUpdateMachineAuthCallback(SteamUser.UpdateMachineAuthCallback callback) private void OnUpdateMachineAuthCallback(SteamUser.UpdateMachineAuthCallback callback)
{ {
Task.Run(async () => Task.Run(async () =>
@ -192,13 +218,14 @@ public class Client : IDisposable
_isConnected = true; _isConnected = true;
_steamUser.LogOn(new SteamUser.LogOnDetails() _steamUser.LogOn(new SteamUser.LogOnDetails
{ {
Username = state.User, Username = state.User,
Password = state.Password, Password = state.Password,
AuthCode = _authCode, AuthCode = _authCode,
TwoFactorCode = _twoFactorCode, TwoFactorCode = _twoFactorCode,
SentryFileHash = sentryHash SentryFileHash = sentryHash,
RequestSteam2Ticket = true
}); });
}); });
} }
@ -218,12 +245,57 @@ public class Client : IDisposable
_cancellationSource.Dispose(); _cancellationSource.Dispose();
} }
public Task Login(TaskCompletionSource? tcs = null) public async Task Login(TaskCompletionSource? tcs = null)
{ {
_loginTask = tcs ?? new TaskCompletionSource(); _loginTask = tcs ?? new TaskCompletionSource();
_logger.LogInformation("Attempting login"); _logger.LogInformation("Attempting login");
_client.Connect(); _client.Connect();
return _loginTask.Task; await _loginTask.Task;
await _licenseRequest.Task;
}
public async Task<Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo?>> GetPackageInfos(IEnumerable<uint> packageIds)
{
var packages = packageIds.Where(id => !PackageInfos.ContainsKey(id)).ToList();
if (packages.Count > 0)
{
var packageRequests = new List<SteamApps.PICSRequest>();
foreach (var package in packages)
{
var request = new SteamApps.PICSRequest(package);
if (PackageTokens.TryGetValue(package, out var token))
{
request.AccessToken = token;
}
packageRequests.Add(request);
}
_logger.LogInformation("Requesting {Count} package infos", packageRequests.Count);
var results = await _steamApps.PICSGetProductInfo(new List<SteamApps.PICSRequest>(), packageRequests);
if (results.Failed)
throw new SteamException("Exception getting product info", EResult.Invalid, EResult.Invalid);
foreach (var packageInfo in results.Results!)
{
foreach (var package in packageInfo.Packages.Select(v => v.Value))
{
PackageInfos[package.ID] = package;
}
foreach (var package in packageInfo.UnknownPackages)
{
PackageInfos[package] = null;
}
}
}
return packages.Distinct().ToDictionary(p => p, p => PackageInfos[p]);
} }
} }

View File

@ -0,0 +1,32 @@
using Microsoft.Extensions.Logging;
namespace Wabbajack.Networking.Steam;
public class DepotDownloader
{
private readonly ILogger<DepotDownloader> _logger;
private readonly Client _steamClient;
public DepotDownloader(ILogger<DepotDownloader> logger, Client client)
{
_logger = logger;
_steamClient = client;
}
public async Task<bool> AccountHasAccess(uint depotId)
{
var packages = _steamClient.Licenses.Select(l => l.PackageID);
var infos = await _steamClient.GetPackageInfos(packages);
foreach (var info in infos.Where(i => i.Value != null))
{
if (info.Value!.KeyValues["appids"].Children.Any(child => child.AsUnsignedInteger() == depotId))
return true;
if (info.Value!.KeyValues["depotids"].Children.Any(child => child.AsUnsignedInteger() == depotId))
return true;
}
return false;
}
}

View File

@ -0,0 +1,13 @@
using Microsoft.Extensions.DependencyInjection;
using Wabbajack.Networking.Steam;
namespace Wabbajack.Networking.NexusApi;
public static class ServiceExtensions
{
public static void AddSteam(this IServiceCollection services)
{
services.AddSingleton<Client>();
services.AddSingleton<DepotDownloader>();
}
}

View File

@ -107,7 +107,7 @@ public static class ServiceExtensions
service.AddSingleton<HttpClient>(); service.AddSingleton<HttpClient>();
service.AddAllSingleton<IHttpDownloader, SingleThreadedDownloader>(); service.AddAllSingleton<IHttpDownloader, SingleThreadedDownloader>();
service.AddSingleton<Wabbajack.Networking.Steam.Client>(); service.AddSteam();
service.AddSingleton<Client>(); service.AddSingleton<Client>();
service.AddSingleton<WriteOnlyClient>(); service.AddSingleton<WriteOnlyClient>();