using System.Reflection;
using System.Text.Json;
using System.Text.Json.Nodes;
using HarmonyLib;
using SPTarkov.Reflection.Patching;
using SPTarkov.Server.Core.Routers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Launcher;
using SPTarkov.Server.Core.Callbacks;
using SPTarkov.Server.Core.Controllers;
using System.Threading;
namespace PersonalAuthMod;
///
/// AsyncLocal to pass the password from the patch to the router
///
public static class AuthContext
{
private static readonly AsyncLocal _currentPassword = new();
private static readonly AsyncLocal _currentSessionID = new();
public static string? CurrentPassword
{
get => _currentPassword.Value;
set => _currentPassword.Value = value;
}
public static string? CurrentSessionID
{
get => _currentSessionID.Value;
set => _currentSessionID.Value = value;
}
}
///
/// Patch HttpRouter.HandleRoute to capture session ID globally before deserialization happens.
///
public class HttpRouterHandleRoutePatch : AbstractPatch
{
protected override MethodBase GetTargetMethod()
{
return typeof(HttpRouter).GetMethod("HandleRoute", BindingFlags.NonPublic | BindingFlags.Instance)!;
}
[PatchPrefix]
public static void Prefix(MongoId sessionID)
{
// Capture the session ID for other patches (like profile filtering)
AuthContext.CurrentSessionID = sessionID.ToString();
}
}
///
/// Patch LauncherCallbacks.Login to enforce database authentication.
/// Returns true to let the original method execute and fetch the MongoId from memory.
/// Returns false if DB verification fails, aborting the original method.
///
public class LauncherCallbacksLoginPatch : AbstractPatch
{
protected override MethodBase GetTargetMethod()
{
return typeof(LauncherCallbacks).GetMethod(nameof(LauncherCallbacks.Login))!;
}
[PatchPrefix]
public static bool Prefix(string url, LoginRequestData info, MongoId sessionID, ref ValueTask __result)
{
if (string.IsNullOrWhiteSpace(info.Username) || string.IsNullOrWhiteSpace(info.Password))
{
__result = new ValueTask("FAILED");
return false;
}
if (!PersonalAuthMod.Instance!.DbManager.ValidateCredentials(info.Username, info.Password))
{
Console.WriteLine($"[PersonalAuthMod] Login FAILED for user: {info.Username} (Invalid credentials via DB)");
__result = new ValueTask("FAILED");
return false;
}
Console.WriteLine($"[PersonalAuthMod] Login SUCCESS for user: {info.Username}, Validated by DB.");
return true;
}
}
///
/// Patch LauncherCallbacks.Register to enforce database registration.
/// Returns true to let the original method execute and create the account in SaveServer.
/// Returns false if DB registration fails (e.g. user exists).
///
public class LauncherCallbacksRegisterPatch : AbstractPatch
{
protected override MethodBase GetTargetMethod()
{
return typeof(LauncherCallbacks).GetMethod(nameof(LauncherCallbacks.Register))!;
}
[PatchPrefix]
public static bool Prefix(string url, RegisterData info, MongoId sessionID, ref ValueTask __result)
{
if (string.IsNullOrWhiteSpace(info.Username) || string.IsNullOrWhiteSpace(info.Password))
{
__result = new ValueTask("FAILED");
return false;
}
if (!PersonalAuthMod.Instance!.DbManager.RegisterUser(info.Username, info.Password))
{
Console.WriteLine($"[PersonalAuthMod] Register FAILED for user: {info.Username} (Already exists or DB error)");
__result = new ValueTask("FAILED");
return false;
}
Console.WriteLine($"[PersonalAuthMod] Register SUCCESS for user: {info.Username}");
return true;
}
}