Add Steam auth, platform validators & name gen
This commit is contained in:
89
RecNet.Infrastructure/Services/Steam/SteamAuthService.cs
Normal file
89
RecNet.Infrastructure/Services/Steam/SteamAuthService.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Extensions.Options;
|
||||
using RecNet.Application.Common.Interfaces;
|
||||
using RecNet.Application.Common.Steam;
|
||||
using SteamApi.Models.Steam.Player;
|
||||
using SteamApi.Models.Steam.Responses;
|
||||
|
||||
namespace RecNet.Infrastructure.Services.Steam;
|
||||
|
||||
public class SteamAuthService(
|
||||
HttpClient httpClient,
|
||||
IOptions<SteamOptions> options) : ISteamAuthService
|
||||
{
|
||||
private readonly SteamOptions _options = options.Value;
|
||||
|
||||
public async Task<SteamAuthResult> AuthorizeAsync(
|
||||
string ticket,
|
||||
uint appId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ticket))
|
||||
return SteamAuthResult.Failure();
|
||||
|
||||
if (appId != _options.AppId)
|
||||
return SteamAuthResult.Failure();
|
||||
|
||||
var steamId = await AuthenticateTicketAsync(ticket, ct);
|
||||
if (steamId is null)
|
||||
return SteamAuthResult.Failure();
|
||||
|
||||
var profile = await GetProfileAsync(steamId, ct);
|
||||
|
||||
return SteamAuthResult.Success(
|
||||
steamId,
|
||||
profile?.PersonaName);
|
||||
}
|
||||
|
||||
private async Task<string?> AuthenticateTicketAsync(
|
||||
string ticket,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var url =
|
||||
"ISteamUserAuth/AuthenticateUserTicket/v0001/" +
|
||||
$"?key={Uri.EscapeDataString(_options.ApiKey)}" +
|
||||
$"&appid={_options.AppId}" +
|
||||
$"&ticket={Uri.EscapeDataString(ticket)}";
|
||||
|
||||
var response = await httpClient.GetAsync(url, ct);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return null;
|
||||
|
||||
var body = await response.Content.ReadFromJsonAsync<SteamResponse<SteamAuthResponse>>(
|
||||
cancellationToken: ct);
|
||||
|
||||
return body?.Response?.Params?.SteamId;
|
||||
}
|
||||
|
||||
private async Task<PlayerSummary?> GetProfileAsync(
|
||||
string steamId,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var url =
|
||||
"ISteamUser/GetPlayerSummaries/v0002/" +
|
||||
$"?key={Uri.EscapeDataString(_options.ApiKey)}" +
|
||||
$"&steamids={Uri.EscapeDataString(steamId)}";
|
||||
|
||||
var response = await httpClient.GetAsync(url, ct);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return null;
|
||||
|
||||
var body = await response.Content.ReadFromJsonAsync<SteamResponse<PlayerSummariesResponse>>(
|
||||
cancellationToken: ct);
|
||||
|
||||
return body?.Response?.Players.FirstOrDefault();
|
||||
}
|
||||
|
||||
private class SteamAuthResponse
|
||||
{
|
||||
[JsonPropertyName("params")]
|
||||
public SteamAuthParamsResponse? Params { get; set; }
|
||||
}
|
||||
|
||||
private class SteamAuthParamsResponse
|
||||
{
|
||||
[JsonPropertyName("steamid")]
|
||||
public required string SteamId { get; set; }
|
||||
}
|
||||
}
|
||||
48
RecNet.Infrastructure/Services/Steam/SteamAuthValidator.cs
Normal file
48
RecNet.Infrastructure/Services/Steam/SteamAuthValidator.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using RecNet.Application.Common.Interfaces;
|
||||
using RecNet.Application.Common.PlatformAuth;
|
||||
using RecNet.Domain.Common;
|
||||
|
||||
namespace RecNet.Infrastructure.Services.Steam;
|
||||
|
||||
public class SteamAuthValidator(ISteamAuthService steamAuthService) : IPlatformAuthValidator
|
||||
{
|
||||
public PlatformType PlatformType
|
||||
=> PlatformType.Steamworks;
|
||||
|
||||
public async Task<PlatformAuthResult> ValidateAsync(
|
||||
string platformAuthentication,
|
||||
string platformId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
var steamParams = JsonSerializer.Deserialize<SteamPlatformAuth>(platformAuthentication);
|
||||
if (steamParams == null)
|
||||
return PlatformAuthResult.Failure("Invalid authentication");
|
||||
|
||||
var result = await steamAuthService.AuthorizeAsync(steamParams.Ticket, steamParams.AppId.AppId, ct);
|
||||
|
||||
if (!result.Succeeded || result.SteamId is null)
|
||||
return PlatformAuthResult.Failure("Invalid authentication");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(platformId) &&
|
||||
platformId != result.SteamId)
|
||||
return PlatformAuthResult.Failure("Nice try");
|
||||
|
||||
return PlatformAuthResult.Success(result.DisplayName);
|
||||
}
|
||||
|
||||
private sealed class SteamPlatformAuth
|
||||
{
|
||||
public required string Ticket { get; set; }
|
||||
|
||||
public required SteamAppIdAuth AppId { get; set; }
|
||||
}
|
||||
|
||||
// Splooty, why did you set it up like this ;-;
|
||||
private sealed class SteamAppIdAuth
|
||||
{
|
||||
[JsonPropertyName("m_AppId")]
|
||||
public required uint AppId { get; set; }
|
||||
}
|
||||
}
|
||||
8
RecNet.Infrastructure/Services/Steam/SteamOptions.cs
Normal file
8
RecNet.Infrastructure/Services/Steam/SteamOptions.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace RecNet.Infrastructure.Services.Steam;
|
||||
|
||||
public class SteamOptions
|
||||
{
|
||||
public string ApiKey { get; set; } = string.Empty;
|
||||
public uint AppId { get; set; } = 480; // Spacewar
|
||||
public string Identity { get; set; } = "recnet";
|
||||
}
|
||||
Reference in New Issue
Block a user