backend refactor yay!!! 1.4.0
This commit is contained in:
21
Core/AssetChanges/AGRoomChanges.cs
Normal file
21
Core/AssetChanges/AGRoomChanges.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core.AssetChanges;
|
||||
|
||||
public class RecChange
|
||||
{
|
||||
[JsonPropertyName("Key")]
|
||||
public string RecKey { get; set; }
|
||||
|
||||
[JsonPropertyName("Value")]
|
||||
public dynamic RecValue { get; set; }
|
||||
}
|
||||
|
||||
public static class AGRoomChanges
|
||||
{
|
||||
public static string name = "AGRoomObjectChanges";
|
||||
public static DediConfig<Dictionary<string, List<RecChange>>> config = new(name, "[]", null);
|
||||
}
|
||||
91
Core/Config.cs
Normal file
91
Core/Config.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using BepInEx.Configuration;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core
|
||||
{
|
||||
public static class GenericConfig
|
||||
{
|
||||
public static ConfigEntry<bool> PatchDebug;
|
||||
public static ConfigEntry<bool> LogAllRequests;
|
||||
public static ConfigEntry<bool> CertificatePatch;
|
||||
public static ConfigEntry<bool> HilePatch;
|
||||
public static ConfigEntry<bool> SignalRHandshakeFix;
|
||||
public static ConfigEntry<bool> ImageSignaturePatch;
|
||||
public static ConfigEntry<bool> RegistrationPatch;
|
||||
}
|
||||
public static class GenericConfigDefaults
|
||||
{
|
||||
public static bool PatchDebug = false;
|
||||
public static bool LogAllRequests = false;
|
||||
public static bool CertificatePatch = false;
|
||||
public static bool HilePatch = false;
|
||||
public static bool SignalRHandshakeFix = false;
|
||||
public static bool ImageSignaturePatch = false;
|
||||
public static bool RegistrationPatch = false;
|
||||
}
|
||||
public static class AssetChangesConfig
|
||||
{
|
||||
public static ConfigEntry<bool> AGRoomChanges;
|
||||
}
|
||||
public static class AssetChangesConfigDefaults
|
||||
{
|
||||
public static bool AGRoomChanges = false;
|
||||
}
|
||||
public static class GameManagerConfig
|
||||
{
|
||||
public static ConfigEntry<bool> StaticGameTeamConfig;
|
||||
public static ConfigEntry<bool> AnyGameFreeSpawn;
|
||||
}
|
||||
public static class GameManagerConfigDefaults
|
||||
{
|
||||
public static bool StaticGameTeamConfig;
|
||||
public static bool AnyGameFreeSpawn;
|
||||
}
|
||||
public static class NameserverConfig
|
||||
{
|
||||
public static ConfigEntry<bool> Rewrite;
|
||||
public static ConfigEntry<string> NewUrl;
|
||||
}
|
||||
public static class NameserverConfigDefaults
|
||||
{
|
||||
public static bool Rewrite = false;
|
||||
public static string NewUrl = "https://example.com/nameserver";
|
||||
}
|
||||
public static class PhotonConfig
|
||||
{
|
||||
public static ConfigEntry<bool> PatchPhotonIds;
|
||||
public static ConfigEntry<bool> PunLogging;
|
||||
public static ConfigEntry<bool> SelfHosted;
|
||||
public static ConfigEntry<string> AppID;
|
||||
public static ConfigEntry<string> VoiceAppID;
|
||||
public static ConfigEntry<string> ServerAddress;
|
||||
public static ConfigEntry<int> ServerPort;
|
||||
}
|
||||
public static class PhotonConfigDefaults
|
||||
{
|
||||
public static bool PatchPhotonIds = false;
|
||||
public static bool PunLogging = false;
|
||||
public static bool SelfHosted = false;
|
||||
public static string AppID = "replace-me-please";
|
||||
public static string VoiceAppID = "replace-me-please";
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
49
Core/DediConfig.cs
Normal file
49
Core/DediConfig.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core;
|
||||
|
||||
public class DediConfig<T>
|
||||
{
|
||||
private readonly string _default;
|
||||
public readonly string _name;
|
||||
public readonly string path;
|
||||
private T? cached;
|
||||
private bool loaded = false;
|
||||
private readonly JsonSerializerOptions? _options;
|
||||
|
||||
public DediConfig(string name, string def, JsonSerializerOptions? options)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Name cannot be invalid");
|
||||
|
||||
_name = name;
|
||||
path = $"BepInEx/config/Undead.{name}.json";
|
||||
_default = def;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
private string GetAlways() {
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
File.WriteAllText(path, _default);
|
||||
return _default;
|
||||
}
|
||||
return File.ReadAllText(path);
|
||||
}
|
||||
public T Get()
|
||||
{
|
||||
if (loaded) return cached;
|
||||
|
||||
string data = GetAlways();
|
||||
cached = JsonSerializer.Deserialize<T>(data, _options == null ? new JsonSerializerOptions()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
AllowTrailingCommas = true
|
||||
} : _options);
|
||||
|
||||
loaded = true;
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
239
Core/Galvanic.cs
Normal file
239
Core/Galvanic.cs
Normal file
@@ -0,0 +1,239 @@
|
||||
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; }
|
||||
}
|
||||
}
|
||||
9
Core/GameManager/GameManSpawns.cs
Normal file
9
Core/GameManager/GameManSpawns.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core.UndeadGameManager;
|
||||
|
||||
public static class GameFreeSpawns
|
||||
{
|
||||
static readonly string name = "GameFreeSpawns";
|
||||
public static DediConfig<List<string>> config = new(name, "[]", null);
|
||||
}
|
||||
19
Core/GameManager/TeamConfigurator.cs
Normal file
19
Core/GameManager/TeamConfigurator.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core.UndeadGameManager;
|
||||
|
||||
public class TeamConfiguration
|
||||
{
|
||||
public int Size { get; set; }
|
||||
}
|
||||
public class GameConfiguration
|
||||
{
|
||||
public string GameName { get; set; }
|
||||
public List<TeamConfiguration> TeamConfigurations { get; set; }
|
||||
}
|
||||
|
||||
public static class TeamConfigurator
|
||||
{
|
||||
static readonly string name = "TeamConfigurator";
|
||||
public static DediConfig<List<GameConfiguration>> config = new(name, "[]", null);
|
||||
}
|
||||
11
Core/Util.cs
Normal file
11
Core/Util.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core
|
||||
{
|
||||
public class Util
|
||||
{
|
||||
public static string LocalInstanceGuid { set; get; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user