beatsaber-scoretracker/Mod/API/Authentication.cs

146 lines
4.5 KiB
C#
Raw Permalink Normal View History

2024-08-07 07:26:12 +00:00
using ScoreTracker.Configuration;
using System;
2024-08-07 04:19:39 +00:00
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ScoreTracker.API
{
2024-08-15 17:22:16 +00:00
internal class SigninResponse
2024-08-07 07:26:12 +00:00
{
2024-08-15 17:22:16 +00:00
public bool Success { get; set; }
public string Response { get; set; }
}
internal class Authentication
{
private static bool _signedIn = false;
private static string _authToken;
2024-08-07 07:26:12 +00:00
/// <summary>
2024-08-15 17:22:16 +00:00
/// Validate the auth token and sign in if necessary
2024-08-07 07:26:12 +00:00
/// </summary>
2024-08-15 17:22:16 +00:00
public static async Task<SigninResponse> ValidateAndSignIn()
2024-08-07 07:26:12 +00:00
{
2024-08-15 17:22:16 +00:00
if (_signedIn && await ValidateAuthToken())
2024-08-07 07:26:12 +00:00
{
2024-08-15 17:22:16 +00:00
return new SigninResponse
{
Success = true,
Response = null
}; // Already signed in
2024-08-07 07:26:12 +00:00
}
2024-08-15 17:22:16 +00:00
bool success = false;
string response = null;
await LoginUser(
2024-08-07 07:26:12 +00:00
token => {
2024-08-15 17:22:16 +00:00
success = true;
2024-08-07 07:26:12 +00:00
Request.PersistHeaders(new Dictionary<string, string>
{
{ "Authorization", $"Bearer {token}" }
});
},
reason =>
{
2024-08-15 17:22:16 +00:00
response = reason;
2024-08-07 07:26:12 +00:00
Request.HttpClient.DefaultRequestHeaders.Clear(); // Clear headers
}
);
2024-08-15 17:22:16 +00:00
return new SigninResponse
{
Success = success,
Response = response
};
2024-08-07 04:19:39 +00:00
}
/// <summary>
/// Get the steam ticket and user info
/// </summary>
/// <returns>the steam ticket</returns>
private static async Task<string> GetSteamTicket()
{
Plugin.Log.Info("Getting steam ticket...");
return (await new SteamPlatformUserModel().GetUserAuthToken()).token;
}
/// <summary>
/// Login the user
/// </summary>
/// <param name="onSuccess">callback for successful login, returns the token</param>
/// <param name="onFail">callback for failed login</param>
/// <returns>an IEnumerator</returns>
public static async Task LoginUser(Action<string> onSuccess, Action<string> onFail)
{
if (_signedIn && !string.IsNullOrEmpty(_authToken))
{
onSuccess(_authToken);
return;
}
var ticketTask = GetSteamTicket();
await Task.Run(() => ticketTask.Wait());
var ticket = ticketTask.Result;
if (string.IsNullOrEmpty(ticket))
{
Plugin.Log.Error("Login failed :( no steam auth token");
onFail("No Steam Auth Token");
return;
}
Plugin.Log.Info("Logging in...");
2024-08-07 07:26:12 +00:00
var request = await Request.PostJsonAsync($"{PluginConfig.Instance.ApiUrl}/auth/login", new Dictionary<object, object> {
2024-08-07 04:19:39 +00:00
{ "ticket", ticket }
}, false);
if (request.IsSuccessStatusCode)
{
var authToken = request.Headers.GetValues("Authorization").First();
Plugin.Log.Info($"Login successful! auth token: {authToken}");
onSuccess(authToken);
_signedIn = true;
_authToken = authToken;
}
else
{
Plugin.Log.Error($"Login failed! body: {request.StatusCode}");
onFail($"Login failed: {request.StatusCode}");
_signedIn = false;
_authToken = null;
}
}
/// <summary>
/// Validates the auth token and logs out if it's invalid
/// </summary>
/// <returns>whether the token is valid</returns>
public static async Task<bool> ValidateAuthToken()
{
if (!_signedIn || string.IsNullOrEmpty(_authToken)) // If we're not signed in, return false
{
return false;
}
2024-08-07 07:26:12 +00:00
var request = await Request.PostJsonAsync($"{PluginConfig.Instance.ApiUrl}/auth/validate", new Dictionary<object, object> {
2024-08-07 04:19:39 +00:00
{ "token", _authToken }
}, false);
if (request.IsSuccessStatusCode)
{
return true;
}
else
{
_signedIn = false;
_authToken = null;
return false;
}
}
}
}