Decompiled source of FusionWhitelist v1.0.0

FusionWhitelist.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using BoneLib.BoneMenu;
using FusionWhitelist;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.Utilities;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "Fusion Whitelist", "1.0.0", "lawsms", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("FusionWhitelist")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FusionWhitelist")]
[assembly: AssemblyTitle("FusionWhitelist")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FusionWhitelist
{
	public class Core : MelonMod
	{
		public override void OnInitializeMelon()
		{
			WhitelistManager.Load();
			WhitelistMenu.Setup();
			LabFusionBridge.Subscribe();
			MelonLogger.Msg("[FusionWhitelist] Initialized. Whitelist enforcement is " + (WhitelistManager.Data.Enabled ? "ENABLED" : "DISABLED") + ".");
		}

		public override void OnDeinitializeMelon()
		{
			LabFusionBridge.Unsubscribe();
		}
	}
	public class WhitelistData
	{
		public bool Enabled { get; set; }

		public List<string> SteamIds { get; set; } = new List<string>();
	}
	public static class WhitelistManager
	{
		private static readonly HashSet<ulong> _lookup = new HashSet<ulong>();

		public static WhitelistData Data { get; private set; } = new WhitelistData();

		private static string FilePath => Path.Combine(MelonEnvironment.UserDataDirectory, "FusionWhitelist.json");

		public static IReadOnlyCollection<ulong> AllIds => _lookup;

		public static void Load()
		{
			try
			{
				if (File.Exists(FilePath))
				{
					WhitelistData whitelistData = JsonSerializer.Deserialize<WhitelistData>(File.ReadAllText(FilePath));
					if (whitelistData != null)
					{
						Data = whitelistData;
					}
				}
				else
				{
					Data = new WhitelistData();
					Save();
				}
			}
			catch (Exception value)
			{
				MelonLogger.Error($"[FusionWhitelist] Failed to load whitelist file, using defaults. {value}");
				Data = new WhitelistData();
			}
			RebuildLookup();
		}

		public static void Save()
		{
			try
			{
				string contents = JsonSerializer.Serialize(Data, new JsonSerializerOptions
				{
					WriteIndented = true
				});
				Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
				File.WriteAllText(FilePath, contents);
			}
			catch (Exception value)
			{
				MelonLogger.Error($"[FusionWhitelist] Failed to save whitelist file. {value}");
			}
		}

		private static void RebuildLookup()
		{
			_lookup.Clear();
			foreach (string steamId in Data.SteamIds)
			{
				if (ulong.TryParse(steamId, out var result))
				{
					_lookup.Add(result);
				}
			}
		}

		public static bool TryAdd(string rawSteamId, out string message)
		{
			if (!TryParseSteamId(rawSteamId, out var id, out message))
			{
				return false;
			}
			if (_lookup.Contains(id))
			{
				message = $"SteamID {id} is already whitelisted.";
				return false;
			}
			_lookup.Add(id);
			Data.SteamIds.Add(id.ToString());
			Save();
			message = $"Added {id} to the whitelist.";
			return true;
		}

		public static bool TryAddBulk(string rawBlock, out string message)
		{
			if (string.IsNullOrWhiteSpace(rawBlock))
			{
				message = "Input is empty.";
				return false;
			}
			string[] array = rawBlock.Split(new char[6] { ',', ';', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				if (!TryParseSteamId(array2[i], out var id, out var _))
				{
					num2++;
					continue;
				}
				if (_lookup.Contains(id))
				{
					num3++;
					continue;
				}
				_lookup.Add(id);
				Data.SteamIds.Add(id.ToString());
				num++;
			}
			if (num > 0)
			{
				Save();
			}
			message = $"Added {num}, skipped {num3} duplicate(s), skipped {num2} invalid.";
			return num > 0;
		}

		public static void Reload()
		{
			Load();
		}

		public static bool TryRemove(string rawSteamId, out string message)
		{
			if (!TryParseSteamId(rawSteamId, out var id, out message))
			{
				return false;
			}
			if (!_lookup.Contains(id))
			{
				message = $"SteamID {id} is not on the whitelist.";
				return false;
			}
			_lookup.Remove(id);
			Data.SteamIds.RemoveAll((string s) => s == id.ToString());
			Save();
			message = $"Removed {id} from the whitelist.";
			return true;
		}

		public static bool IsWhitelisted(ulong steamId)
		{
			return _lookup.Contains(steamId);
		}

		public static void SetEnabled(bool enabled)
		{
			Data.Enabled = enabled;
			Save();
		}

		public static bool TryParseSteamId(string raw, out ulong id, out string message)
		{
			id = 0uL;
			message = string.Empty;
			if (string.IsNullOrWhiteSpace(raw))
			{
				message = "SteamID field is empty.";
				return false;
			}
			raw = raw.Trim();
			if (!ulong.TryParse(raw, out id))
			{
				message = "'" + raw + "' is not a valid numeric SteamID64.";
				return false;
			}
			if (id < 76561197960265728L)
			{
				message = "'" + raw + "' does not look like a valid SteamID64.";
				return false;
			}
			return true;
		}
	}
	public static class WhitelistMenu
	{
		private static Page _page;

		private static FunctionElement _statusElement;

		private static FunctionElement _listHeaderElement;

		private static readonly List<FunctionElement> _listEntries = new List<FunctionElement>();

		private static string _pendingSteamId = string.Empty;

		public static void Setup()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			_page = Page.Root.CreatePage("Fusion Whitelist", Color.cyan, 20, true);
			_page.CreateBool("Enable Whitelist", Color.yellow, WhitelistManager.Data.Enabled, (Action<bool>)delegate(bool newValue)
			{
				WhitelistManager.SetEnabled(newValue);
				RefreshStatus();
				MelonLogger.Msg($"[FusionWhitelist] Whitelist enforcement set to {newValue}.");
			});
			_page.CreateString("SteamID Input", Color.white, _pendingSteamId, (Action<string>)delegate(string newValue)
			{
				_pendingSteamId = newValue;
			});
			_page.CreateFunction("Add to Whitelist", Color.green, (Action)delegate
			{
				if (WhitelistManager.TryAddBulk(_pendingSteamId, out var message))
				{
					MelonLogger.Msg("[FusionWhitelist] " + message);
				}
				else
				{
					MelonLogger.Warning("[FusionWhitelist] " + message);
				}
				RefreshList();
			});
			_page.CreateFunction("Remove from Whitelist", Color.red, (Action)delegate
			{
				if (WhitelistManager.TryRemove(_pendingSteamId, out var message))
				{
					MelonLogger.Msg("[FusionWhitelist] " + message);
				}
				else
				{
					MelonLogger.Warning("[FusionWhitelist] " + message);
				}
				RefreshList();
			});
			_page.CreateFunction("Reload Whitelist from File", Color.cyan, (Action)delegate
			{
				WhitelistManager.Reload();
				MelonLogger.Msg("[FusionWhitelist] Reloaded whitelist from disk.");
				RefreshList();
			});
			_statusElement = _page.CreateFunction("Status: " + (WhitelistManager.Data.Enabled ? "ENABLED" : "DISABLED"), Color.white, (Action)null);
			_listHeaderElement = _page.CreateFunction("--- Whitelisted SteamIDs ---", Color.gray, (Action)delegate
			{
				PrintListToConsole();
			});
			RefreshList();
		}

		private static void RefreshStatus()
		{
			if (_statusElement != null)
			{
				((Element)_statusElement).ElementName = "Status: " + (WhitelistManager.Data.Enabled ? "ENABLED" : "DISABLED");
			}
		}

		private static void RefreshList()
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			RefreshStatus();
			foreach (FunctionElement listEntry in _listEntries)
			{
				_page.Remove((Element)(object)listEntry);
			}
			_listEntries.Clear();
			foreach (ulong item2 in WhitelistManager.AllIds.OrderBy((ulong x) => x))
			{
				FunctionElement item = _page.CreateFunction(item2.ToString(), Color.white, (Action)null);
				_listEntries.Add(item);
			}
			PrintListToConsole();
		}

		private static void PrintListToConsole()
		{
			MelonLogger.Msg("[FusionWhitelist] ---- Current Whitelist ----");
			if (WhitelistManager.AllIds.Count == 0)
			{
				MelonLogger.Msg("[FusionWhitelist] (empty)");
			}
			else
			{
				foreach (ulong item in WhitelistManager.AllIds.OrderBy((ulong x) => x))
				{
					MelonLogger.Msg($"[FusionWhitelist]   {item}");
				}
			}
			MelonLogger.Msg("[FusionWhitelist] ---------------------------");
		}
	}
	public static class LabFusionBridge
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UserAccessEvent <0>__CheckShouldAllowConnection;
		}

		public static void Subscribe()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			object obj = <>O.<0>__CheckShouldAllowConnection;
			if (obj == null)
			{
				UserAccessEvent val = CheckShouldAllowConnection;
				<>O.<0>__CheckShouldAllowConnection = val;
				obj = (object)val;
			}
			MultiplayerHooking.OnShouldAllowConnection += (UserAccessEvent)obj;
		}

		public static void Unsubscribe()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			object obj = <>O.<0>__CheckShouldAllowConnection;
			if (obj == null)
			{
				UserAccessEvent val = CheckShouldAllowConnection;
				<>O.<0>__CheckShouldAllowConnection = val;
				obj = (object)val;
			}
			MultiplayerHooking.OnShouldAllowConnection -= (UserAccessEvent)obj;
		}

		private static bool CheckShouldAllowConnection(PlayerID playerId, out string reason)
		{
			reason = string.Empty;
			try
			{
				if (playerId == null)
				{
					return true;
				}
				if (!NetworkInfo.IsHost)
				{
					return true;
				}
				if (IsLocalHost(playerId))
				{
					return true;
				}
				if (!WhitelistManager.Data.Enabled)
				{
					return true;
				}
				ulong platformID = playerId.PlatformID;
				if (WhitelistManager.IsWhitelisted(platformID))
				{
					MelonLogger.Msg($"[FusionWhitelist] Player {platformID} is whitelisted, allowing connection.");
					return true;
				}
				MelonLogger.Warning($"[FusionWhitelist] Player {platformID} is NOT whitelisted. Rejecting connection.");
				reason = "You are not whitelisted on this server.";
				return false;
			}
			catch (Exception value)
			{
				MelonLogger.Error($"[FusionWhitelist] Exception in CheckShouldAllowConnection: {value}");
				return true;
			}
		}

		private static bool IsLocalHost(PlayerID playerId)
		{
			return playerId.IsHost;
		}

		public static void KickPlayer(PlayerID playerId)
		{
			NetworkHelper.KickUser(playerId);
		}
	}
}