Remove galvanic authentication support

... that server is being rewritten
This commit is contained in:
2025-08-10 21:53:58 -04:00
parent 48ca74d2db
commit 1c51b37a7c
6 changed files with 34 additions and 309 deletions

View File

@@ -11,6 +11,7 @@ namespace undead_universal_patch_il2cpp.Core
public static ConfigEntry<bool> SignalRHandshakeFix;
public static ConfigEntry<bool> ImageSignaturePatch;
public static ConfigEntry<bool> RegistrationPatch;
public static ConfigEntry<bool> AFKPatch;
}
public static class GenericConfigDefaults
{
@@ -21,6 +22,7 @@ namespace undead_universal_patch_il2cpp.Core
public static bool SignalRHandshakeFix = false;
public static bool ImageSignaturePatch = false;
public static bool RegistrationPatch = false;
public static bool AFKPatch = false;
}
public static class AssetChangesConfig
{
@@ -70,21 +72,4 @@ namespace undead_universal_patch_il2cpp.Core
public static string ServerAddress = "127.0.0.1";
public static int ServerPort = 5055;
}
public static class GalvanicConfig
{
public static ConfigEntry<bool> Enabled;
public static ConfigEntry<bool> RegenerateKeypair;
public static ConfigEntry<string> Export;
public static ConfigEntry<bool> Import;
}
public static class GalvanicConfigDefaults
{
public static bool Enabled = false;
public static bool RegenerateKeypair = false;
public static string Export = "IDoNotWantToExportMyKeys";
public static bool Import = false;
}
}

View File

@@ -1,239 +0,0 @@
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using System.Text.Json;
using System.IO;
// this entire file could be better
namespace undead_universal_patch_il2cpp.Core
{
public class GalvanicAuth
{
public static void PrepareKeys()
{
PlayerPrefs.DeleteKey("GalvanicPublicKey");
PlayerPrefs.DeleteKey("GalvanicPrivateKey");
using ECDsa ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
byte[] publicKeyBytes = ecdsa.ExportSubjectPublicKeyInfo();
string publicKeyBase64 = Convert.ToBase64String(publicKeyBytes);
byte[] privateKeyBytes = ecdsa.ExportPkcs8PrivateKey();
string privateKeyBase64 = Convert.ToBase64String(privateKeyBytes);
PlayerPrefs.SetString("GalvanicPublicKey", publicKeyBase64);
PlayerPrefs.SetString("GalvanicPrivateKey", privateKeyBase64);
PlayerPrefs.Save();
Plugin.Log.LogInfo("Created new keypair for Galvanic authentication.");
}
public static string GetPubKey()
{
string publicKey = PlayerPrefs.GetString("GalvanicPublicKey", null);
if (string.IsNullOrEmpty(publicKey))
{
Plugin.Log.LogInfo("No keypair found, generating new.");
PrepareKeys();
return GetPubKey();
} else return publicKey;
}
private static ECDsa GetPrivKey()
{
string privateKey = PlayerPrefs.GetString("GalvanicPrivateKey", null);
if (string.IsNullOrEmpty(privateKey))
{
Plugin.Log.LogInfo("No keypair found, generating new.");
PrepareKeys();
return GetPrivKey();
}
byte[] privKeyBytes = Convert.FromBase64String(privateKey);
ECDsa crypt = ECDsa.Create();
crypt.ImportPkcs8PrivateKey(privKeyBytes, out _);
return crypt;
}
public static string SignPayload(string message)
{
using ECDsa ecdsa = GetPrivKey();
if (ecdsa == null) return null;
byte[] payloadBytes = Encoding.UTF8.GetBytes(message);
byte[] signature = ecdsa.SignData(payloadBytes, HashAlgorithmName.SHA256);
return Convert.ToBase64String(signature);
}
public static void Export()
{
File.WriteAllText("./galvanic_keys_export.txt", $"{GetPubKey()}\n{Convert.ToBase64String(GetPrivKey().ExportPkcs8PrivateKey())}");
Plugin.Log.LogWarning("Galvanic Authentication keys were exported.");
}
public static void Import()
{
try
{
string imported = File.ReadAllText("./galvanic_keys_export.txt").ToString();
string privkey = imported.Split("\n")[1];
string pubkey = imported.Split("\n")[0];
if (privkey == null || pubkey == null) throw new Exception("Either imported key was null");
PlayerPrefs.SetString("GalvanicPrivateKey", privkey);
PlayerPrefs.SetString("GalvanicPublicKey", pubkey);
PlayerPrefs.Save();
} catch (Exception err)
{
Plugin.Log.LogError($"Could not import Galvanic Authentication keys: {err}");
}
}
public static ServerInfoRes GetServerInfo()
{
UriBuilder nameserver = new(NameserverConfig.NewUrl.Value);
nameserver.Path = "/info";
nameserver.Query = "";
using HttpClient client = new();
var response = client.GetAsync(nameserver.ToString()).Result;
if (!response.IsSuccessStatusCode) return null;
var str = response.Content.ReadAsStringAsync().Result;
var res = JsonSerializer.Deserialize<ServerInfoRes>(str);
GalvanicCorrosion.Name = res.name;
GalvanicCorrosion.Id = res.id;
GalvanicCorrosion.Motd = res.motd;
GalvanicCorrosion.Patches = res.patches;
return res;
}
}
public static class GalvanicCorrosion
{
public static string Name { get; set; } = "Galvanic Corrosion";
public static string Id { get; set; } = "galvanic-corrosion-default";
public static string Motd { get; set; } = "A Galvanic Corrosion server.";
public static string[] Patches { get; set; } = [];
}
public static class GalvanicWebAuth
{
public static string Token { get; private set; } = null;
public static void TokenExpiry()
{
string url = NameserverConfig.NewUrl.Value;
UriBuilder uri = new(url);
uri.Path = "/user/checkExpired";
uri.Query = "";
HttpClient client = new();
client.DefaultRequestHeaders.Add("GalvanicAuth", Token);
HttpResponseMessage res = client.GetAsync(uri.ToString()).Result;
if (res.IsSuccessStatusCode)
{
bool expired = JsonSerializer.Deserialize<bool>(res.Content.ReadAsStringAsync().Result.ToString());
if (expired) GetToken();
}
}
public static void GetToken()
{
string url = NameserverConfig.NewUrl.Value;
UriBuilder uri = new(url)
{
Path = "/user/auth",
Query = ""
};
var info = GalvanicAuth.GetServerInfo();
Plugin.Log.LogInfo($"Sending authentication request to server ID '{info.id}'");
if (uri.Scheme == "http") Plugin.Log.LogWarning("The server is not secure! Please use HTTPS.");
UserAuthPayload payload = new()
{
timestamp = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds(),
nonce = Guid.NewGuid().ToString(),
server_id = info.id,
};
UserAuthRequest request = new()
{
message = payload,
signature = GalvanicAuth.SignPayload($"{JsonSerializer.Serialize(payload)}"),
client_id = UniqueID.GetUniqueId(),
pubkey = GalvanicAuth.GetPubKey()
};
HttpClient client = new();
HttpResponseMessage res = client.PostAsync(uri.ToString(), new StringContent(JsonSerializer.Serialize(request,
new JsonSerializerOptions {
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}),
Encoding.UTF8,
"application/json")).Result;
if (!res.IsSuccessStatusCode)
{
Plugin.Log.LogError("The GalvanicWeb auth response was not successful.");
return;
}
string str = res.Content.ReadAsStringAsync().Result;
TokenRes token = JsonSerializer.Deserialize<TokenRes>(str);
Token = token.token;
}
}
public static class UniqueID
{
public static string GetUniqueId()
{
if (!PlayerPrefs.HasKey("UniqueId")) SaveUniqueId(GenerateUniqueId());
return PlayerPrefs.GetString("UniqueId");
}
public static void SaveUniqueId(string id)
{
PlayerPrefs.SetString("UniqueId", id);
PlayerPrefs.Save();
}
public static string GenerateUniqueId()
{
byte[] buffer = new byte[128];
new System.Random().NextBytes(buffer);
return Convert.ToBase64String(buffer).Substring(0, 128);
// god help me
}
}
public class ServerInfoRes
{
public string name { get; set; }
public string id { get; set; }
public string motd { get; set; }
public string[] patches { get; set; }
}
class TokenRes
{
public string token { get; set; }
}
class UserAuthPayload
{
public long timestamp { get; set; }
public string nonce { get; set; }
public string server_id { get; set; }
}
class UserAuthRequest
{
public string client_id { get; set; }
public UserAuthPayload message { get; set; }
public string signature { get; set; }
public string pubkey { get; set; }
}
}