Decompiled source of AutoServerPassword v1.0.2

plugins\AutoServerPassword.dll

Decompiled 2 weeks 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.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: IgnoresAccessChecksTo("gui_framework")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Allifreyr")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyProduct("AutoServerPassword")]
[assembly: AssemblyTitle("AutoServerPassword")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.0")]
[module: UnverifiableCode]
[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 AutoServerPassword
{
	public static class PasswordManagerGui
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static WindowFunction <0>__DrawWindowContents;
		}

		private const int WindowId = 4281168;

		private static Rect _windowRect = new Rect(70f, 90f, 540f, 440f);

		private static Vector2 _scrollPosition;

		private static string _filterText = "";

		private static readonly HashSet<string> _revealedPasswords = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static bool _confirmClearAll;

		private static string _statusMessage = "";

		private static float _statusMessageTimer;

		public static bool Visible { get; set; }

		public static void Toggle()
		{
			Visible = !Visible;
			if (Visible)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
				_confirmClearAll = false;
				_statusMessage = "";
			}
		}

		public static void Draw()
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			if (Visible)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
				((Rect)(ref _windowRect)).x = Mathf.Clamp(((Rect)(ref _windowRect)).x, 0f, Mathf.Max(0f, (float)Screen.width - ((Rect)(ref _windowRect)).width));
				((Rect)(ref _windowRect)).y = Mathf.Clamp(((Rect)(ref _windowRect)).y, 0f, Mathf.Max(0f, (float)Screen.height - ((Rect)(ref _windowRect)).height));
				Rect windowRect = _windowRect;
				object obj = <>O.<0>__DrawWindowContents;
				if (obj == null)
				{
					WindowFunction val = DrawWindowContents;
					<>O.<0>__DrawWindowContents = val;
					obj = (object)val;
				}
				_windowRect = GUI.Window(4281168, windowRect, (WindowFunction)obj, "AutoServerPassword — Saved Server Passwords");
			}
		}

		private static void DrawWindowContents(int id)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Event.current.type == 4 && (int)Event.current.keyCode == 27)
			{
				Visible = false;
				Event.current.Use();
				return;
			}
			GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width - 30f, 25f));
			if (GUI.Button(new Rect(((Rect)(ref _windowRect)).width - 25f, 3f, 22f, 20f), "X"))
			{
				Visible = false;
				return;
			}
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			if (!string.IsNullOrEmpty(_statusMessage))
			{
				_statusMessageTimer -= Time.unscaledDeltaTime;
				if (_statusMessageTimer <= 0f)
				{
					_statusMessage = "";
				}
				else
				{
					GUILayout.Space(2f);
					GUI.color = Color.cyan;
					GUILayout.Label(_statusMessage, Array.Empty<GUILayoutOption>());
					GUI.color = Color.white;
				}
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			bool flag = GUILayout.Toggle(PluginConfig.AutoSubmit.Value, "Auto-Submit", Array.Empty<GUILayoutOption>());
			if (flag != PluginConfig.AutoSubmit.Value)
			{
				PluginConfig.AutoSubmit.Value = flag;
			}
			bool flag2 = GUILayout.Toggle(PluginConfig.HidePasswordDialog.Value, "Hide Dialog", Array.Empty<GUILayoutOption>());
			if (flag2 != PluginConfig.HidePasswordDialog.Value)
			{
				PluginConfig.HidePasswordDialog.Value = flag2;
			}
			bool flag3 = GUILayout.Toggle(PluginConfig.AutoSave.Value, "Auto-Save", Array.Empty<GUILayoutOption>());
			if (flag3 != PluginConfig.AutoSave.Value)
			{
				PluginConfig.AutoSave.Value = flag3;
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Search:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			_filterText = GUILayout.TextField(_filterText, Array.Empty<GUILayoutOption>());
			if (!string.IsNullOrEmpty(_filterText) && GUILayout.Button("Clear", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }))
			{
				_filterText = "";
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(4f);
			IReadOnlyList<SavedServerEntry> readOnlyList = ServerPasswordManager.GetAllSavedServers();
			if (!string.IsNullOrWhiteSpace(_filterText))
			{
				readOnlyList = readOnlyList.Where((SavedServerEntry s) => (!string.IsNullOrEmpty(s.ServerName) && s.ServerName.IndexOf(_filterText, StringComparison.OrdinalIgnoreCase) >= 0) || (!string.IsNullOrEmpty(s.ServerKey) && s.ServerKey.IndexOf(_filterText, StringComparison.OrdinalIgnoreCase) >= 0) || (s.Aliases != null && s.Aliases.Any((string a) => a.IndexOf(_filterText, StringComparison.OrdinalIgnoreCase) >= 0))).ToList();
			}
			_scrollPosition = GUILayout.BeginScrollView(_scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(260f) });
			if (readOnlyList.Count == 0)
			{
				GUILayout.Space(20f);
				GUILayout.Label("<color=#CCCCCC><i>No saved server passwords found.\nWhen you connect to a password-protected server, it will be automatically saved here.</i></color>", Array.Empty<GUILayoutOption>());
			}
			else
			{
				for (int num = 0; num < readOnlyList.Count; num++)
				{
					DrawServerCard(readOnlyList[num], num);
				}
			}
			GUILayout.EndScrollView();
			GUILayout.Space(6f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (!_confirmClearAll)
			{
				if (GUILayout.Button("Clear All", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
				{
					_confirmClearAll = true;
				}
			}
			else
			{
				GUI.color = Color.red;
				if (GUILayout.Button("CONFIRM CLEAR?", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) }))
				{
					ServerPasswordManager.ClearAllPasswords();
					_confirmClearAll = false;
					SetStatus("All saved server passwords cleared.");
				}
				GUI.color = Color.white;
				if (GUILayout.Button("Cancel", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
				{
					_confirmClearAll = false;
				}
			}
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Reload", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
			{
				ServerPasswordManager.LoadFromDisk();
				SetStatus("Reloaded passwords from disk.");
			}
			if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
			{
				Visible = false;
			}
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
		}

		private static void DrawServerCard(SavedServerEntry entry, int index)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			string text = ((!string.IsNullOrEmpty(entry.ServerName)) ? entry.ServerName : entry.ServerKey);
			GUILayout.Label("<b><color=#FFD700>" + text + "</color></b>", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			GUI.color = new Color(1f, 0.4f, 0.4f, 1f);
			if (GUILayout.Button("Delete", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
			{
				ServerPasswordManager.RemoveSavedPassword(entry.ServerKey);
				SetStatus("Removed saved password for " + text + ".");
			}
			GUI.color = Color.white;
			GUILayout.EndHorizontal();
			GUILayout.Label("<color=#AAAAAA>Key: " + entry.ServerKey + "</color>", Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			bool flag = _revealedPasswords.Contains(entry.ServerKey);
			string text2 = (flag ? entry.Password : new string('•', Math.Max(6, entry.Password.Length)));
			GUILayout.Label("Password:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			GUILayout.TextField(text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
			if (GUILayout.Button(flag ? "Hide" : "Show", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }))
			{
				if (flag)
				{
					_revealedPasswords.Remove(entry.ServerKey);
				}
				else
				{
					_revealedPasswords.Add(entry.ServerKey);
				}
			}
			if (GUILayout.Button("Copy", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }))
			{
				GUIUtility.systemCopyBuffer = entry.Password;
				SetStatus("Password copied to clipboard!");
			}
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			GUILayout.Label($"<color=#888888><size=10>Last used: {entry.LastUsed:yyyy-MM-dd HH:mm}</size></color>", Array.Empty<GUILayoutOption>());
			GUILayout.EndVertical();
			GUILayout.Space(2f);
		}

		private static void SetStatus(string message)
		{
			_statusMessage = message;
			_statusMessageTimer = 3.5f;
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "JoinServer")]
	public static class Patch_FejdStartup_JoinServer
	{
		[HarmonyPrefix]
		public unsafe static void Prefix(FejdStartup __instance)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (!PluginConfig.Enabled.Value)
			{
				return;
			}
			try
			{
				ServerJoinData serverToJoin = __instance.GetServerToJoin();
				ServerPasswordManager.LastJoiningServerData = ((object)(*(ServerJoinData*)(&serverToJoin))/*cast due to .constrained prefix*/).ToString();
				ServerPasswordManager.LastJoiningServerName = MultiBackendMatchmaking.GetServerName(serverToJoin);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[AutoServerPassword] Error capturing joining server data: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "RPC_ClientHandshake")]
	public static class Patch_ZNet_RPC_ClientHandshake
	{
		[HarmonyPrefix]
		public static bool Prefix(ZNet __instance, ZRpc rpc, bool needPassword, string serverPasswordSalt)
		{
			if (__instance.IsServer() || !PluginConfig.Enabled.Value)
			{
				return true;
			}
			if (!needPassword)
			{
				return true;
			}
			try
			{
				ServerIdentifiers serverIdentifiers = ServerPasswordManager.CollectCurrentIdentifiers(__instance, rpc);
				if (PluginConfig.AutoSubmit.Value && ServerPasswordManager.TryFindSavedPassword(serverIdentifiers, out var matchedEntry, out var matchedKey))
				{
					string serverKey = matchedEntry.ServerKey;
					if (!ServerPasswordManager.IsFailedThisSession(serverKey))
					{
						string text = ((!string.IsNullOrEmpty(matchedEntry.ServerName)) ? matchedEntry.ServerName : serverKey);
						Plugin.Log.LogInfo((object)("[AutoServerPassword] Server '" + text + "' requires a password. Found saved password (matched key: '" + matchedKey + "'). Auto-submitting..."));
						ZNet.m_serverPasswordSalt = serverPasswordSalt;
						((Component)__instance.m_connectingDialog).gameObject.SetActive(false);
						ServerPasswordManager.RecordActiveAttempt(serverKey, matchedEntry.Password, isAuto: true, serverIdentifiers);
						if (PluginConfig.HidePasswordDialog.Value)
						{
							((Component)__instance.m_passwordDialog).gameObject.SetActive(false);
						}
						else
						{
							((Component)__instance.m_passwordDialog).gameObject.SetActive(true);
							GuiInputField componentInChildren = ((Component)__instance.m_passwordDialog).GetComponentInChildren<GuiInputField>();
							if ((Object)(object)componentInChildren != (Object)null)
							{
								((TMP_InputField)componentInChildren).text = matchedEntry.Password;
							}
						}
						__instance.m_tempPasswordRPC = rpc;
						__instance.OnPasswordEntered(matchedEntry.Password);
						return false;
					}
					Plugin.Log.LogWarning((object)("[AutoServerPassword] Saved password for '" + serverKey + "' previously failed this session. Prompting for new password."));
				}
				else
				{
					Plugin.Log.LogInfo((object)"[AutoServerPassword] Server requires password, but no saved password was found. Displaying password prompt.");
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[AutoServerPassword] Error in RPC_ClientHandshake: {arg}");
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnPasswordEntered")]
	public static class Patch_ZNet_OnPasswordEntered
	{
		[HarmonyPrefix]
		public static void Prefix(ZNet __instance, string pwd)
		{
			if (__instance.IsServer() || !PluginConfig.Enabled.Value)
			{
				return;
			}
			try
			{
				if (!string.IsNullOrEmpty(pwd) && !ServerPasswordManager.HasActiveAutoAttempt)
				{
					ServerIdentifiers serverIdentifiers = ServerPasswordManager.CollectCurrentIdentifiers(__instance, __instance.m_tempPasswordRPC);
					string primaryServerKey = serverIdentifiers.PrimaryServerKey;
					string text = ((!string.IsNullOrEmpty(serverIdentifiers.ServerName)) ? serverIdentifiers.ServerName : primaryServerKey);
					Plugin.Log.LogInfo((object)("[AutoServerPassword] User entered password for '" + text + "'. Waiting to confirm connection..."));
					ServerPasswordManager.RecordActiveAttempt(primaryServerKey, pwd, isAuto: false, serverIdentifiers);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[AutoServerPassword] Error in OnPasswordEntered: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	public static class Patch_ZNet_RPC_PeerInfo
	{
		[HarmonyPostfix]
		public static void Postfix(ZNet __instance, ZRpc rpc)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			if (__instance.IsServer() || !PluginConfig.Enabled.Value)
			{
				return;
			}
			try
			{
				if ((int)ZNet.GetConnectionStatus() == 2)
				{
					ServerPasswordManager.OnConnectionSuccess(__instance, rpc);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[AutoServerPassword] Error in RPC_PeerInfo: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "RPC_Error")]
	public static class Patch_ZNet_RPC_Error
	{
		[HarmonyPrefix]
		public static void Prefix(ZNet __instance, ZRpc rpc, int error)
		{
			if (__instance.IsServer() || !PluginConfig.Enabled.Value)
			{
				return;
			}
			try
			{
				if (error == 6)
				{
					ServerPasswordManager.OnPasswordError(__instance, rpc);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[AutoServerPassword] Error in RPC_Error: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "ShowConnectError")]
	public static class Patch_FejdStartup_ShowConnectError
	{
		[HarmonyPostfix]
		public static void Postfix(FejdStartup __instance, ConnectionStatus statusOverride)
		{
			if (!PluginConfig.Enabled.Value)
			{
				return;
			}
			try
			{
				if (ServerPasswordManager.WasAutoPasswordPurged && (Object)(object)__instance.m_connectionFailedError != (Object)null)
				{
					string text = ((!string.IsNullOrEmpty(ServerPasswordManager.PurgedServerName)) ? ServerPasswordManager.PurgedServerName : "the server");
					TMP_Text connectionFailedError = __instance.m_connectionFailedError;
					connectionFailedError.text = connectionFailedError.text + "\n\n<color=#FFCC00>AutoServerPassword: Saved password for " + text + " was incorrect (or changed) and has been removed.\nClick Join to enter the new password.</color>";
					ServerPasswordManager.WasAutoPasswordPurged = false;
					ServerPasswordManager.PurgedServerName = null;
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[AutoServerPassword] Error in ShowConnectError: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(ServerListElement), "UpdateTextAndIcons")]
	public static class Patch_ServerListElement_UpdateTextAndIcons
	{
		private static readonly Color SavedPasswordLockColor = new Color(0.35f, 1f, 0.45f, 1f);

		[HarmonyPostfix]
		public static void Postfix(ServerListElement __instance, ref ServerListEntryData serverEntry)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (!PluginConfig.Enabled.Value || !PluginConfig.HighlightSavedInServerList.Value)
			{
				return;
			}
			try
			{
				if (!((ServerListEntryData)(ref serverEntry)).IsPasswordProtected || !((Object)(object)__instance.m_private != (Object)null))
				{
					return;
				}
				Image component = ((Component)__instance.m_private).GetComponent<Image>();
				if (ServerPasswordManager.HasSavedPassword(serverEntry.m_joinData))
				{
					if ((Object)(object)component != (Object)null)
					{
						((Graphic)component).color = SavedPasswordLockColor;
					}
					if ((Object)(object)__instance.m_tooltip != (Object)null && !string.IsNullOrEmpty(__instance.m_tooltip.m_text) && !__instance.m_tooltip.m_text.Contains("Password Saved"))
					{
						UITooltip tooltip = __instance.m_tooltip;
						tooltip.m_text += "\n<color=#55FF55>Password Saved (Auto-login enabled)</color>";
					}
				}
				else if ((Object)(object)component != (Object)null)
				{
					((Graphic)component).color = Color.white;
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Update")]
	public static class Patch_Game_Update
	{
		[HarmonyPostfix]
		public static void Postfix()
		{
			if (PluginConfig.Enabled.Value)
			{
				ServerPasswordManager.TryDisplayQueuedNotification();
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnDestroy")]
	public static class Patch_ZNet_OnDestroy
	{
		[HarmonyPostfix]
		public static void Postfix()
		{
			ServerPasswordManager.ClearActiveAttempt();
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	public static class Patch_Terminal_InitTerminal
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ConsoleEvent <0>__HandleSavedPasswordsCommand;
		}

		[HarmonyPostfix]
		public static void Postfix()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			object obj = <>O.<0>__HandleSavedPasswordsCommand;
			if (obj == null)
			{
				ConsoleEvent val = HandleSavedPasswordsCommand;
				<>O.<0>__HandleSavedPasswordsCommand = val;
				obj = (object)val;
			}
			new ConsoleCommand("savedpasswords", "Manage saved server passwords. Subcommands: list, list --show, remove <name/key>, clear", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static void HandleSavedPasswordsCommand(ConsoleEventArgs args)
		{
			Terminal context = args.Context;
			if ((Object)(object)context == (Object)null)
			{
				return;
			}
			if (args.Length < 2 || string.Equals(args[1], "list", StringComparison.OrdinalIgnoreCase))
			{
				bool flag = args.Length >= 3 && string.Equals(args[2], "--show", StringComparison.OrdinalIgnoreCase);
				IReadOnlyList<SavedServerEntry> allSavedServers = ServerPasswordManager.GetAllSavedServers();
				if (allSavedServers.Count == 0)
				{
					context.AddString("AutoServerPassword: No saved server passwords found.");
					return;
				}
				context.AddString($"AutoServerPassword: {allSavedServers.Count} saved server password(s):");
				for (int i = 0; i < allSavedServers.Count; i++)
				{
					SavedServerEntry savedServerEntry = allSavedServers[i];
					string text = (flag ? savedServerEntry.Password : MaskPassword(savedServerEntry.Password));
					string text2 = ((!string.IsNullOrEmpty(savedServerEntry.ServerName)) ? ("\"" + savedServerEntry.ServerName + "\"") : "(unnamed)");
					context.AddString($"[{i + 1}] {text2} (Key: {savedServerEntry.ServerKey}) -> Password: [{text}] (Last used: {savedServerEntry.LastUsed:yyyy-MM-dd HH:mm})");
				}
			}
			else if (string.Equals(args[1], "remove", StringComparison.OrdinalIgnoreCase))
			{
				if (args.Length < 3)
				{
					context.AddString("Usage: savedpasswords remove <server_name_or_key>");
					return;
				}
				string text3 = string.Join(" ", args.Args.Skip(2));
				if (ServerPasswordManager.RemoveSavedPassword(text3))
				{
					context.AddString("AutoServerPassword: Removed saved password for '" + text3 + "'.");
				}
				else
				{
					context.AddString("AutoServerPassword: No saved password found matching '" + text3 + "'.");
				}
			}
			else if (string.Equals(args[1], "clear", StringComparison.OrdinalIgnoreCase))
			{
				ServerPasswordManager.ClearAllPasswords();
				context.AddString("AutoServerPassword: All saved server passwords have been cleared.");
			}
			else
			{
				context.AddString("Unknown subcommand. Usage: savedpasswords [list / list --show / remove <target> / clear]");
			}
		}

		private static string MaskPassword(string pw)
		{
			if (string.IsNullOrEmpty(pw))
			{
				return "";
			}
			if (pw.Length <= 2)
			{
				return new string('*', pw.Length);
			}
			return pw[0] + new string('*', Math.Max(1, pw.Length - 2)) + pw[pw.Length - 1];
		}
	}
	[BepInPlugin("Allifreyr.AutoServerPassword", "AutoServerPassword", "1.0.2")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "Allifreyr.AutoServerPassword";

		public const string PluginName = "AutoServerPassword";

		public const string PluginVersion = "1.0.2";

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal static Harmony Harmony { get; private set; }

		private void Awake()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			PluginConfig.Bind(((BaseUnityPlugin)this).Config);
			ServerPasswordManager.Initialize();
			Harmony = new Harmony("Allifreyr.AutoServerPassword");
			Harmony.PatchAll(Assembly.GetExecutingAssembly());
			Log.LogInfo((object)string.Format("{0} {1} loaded successfully. Press {2} to open password manager.", "AutoServerPassword", "1.0.2", PluginConfig.ToggleHotkey.Value));
		}

		private void Update()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (!PluginConfig.Enabled.Value)
			{
				PasswordManagerGui.Visible = false;
				return;
			}
			KeyboardShortcut value = PluginConfig.ToggleHotkey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				value = PluginConfig.ToggleHotkey.Value;
				if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
				{
					PasswordManagerGui.Toggle();
				}
			}
			value = PluginConfig.ConsoleHotkey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
			{
				value = PluginConfig.ConsoleHotkey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					ToggleConsole();
				}
			}
		}

		private void OnGUI()
		{
			if (PluginConfig.Enabled.Value)
			{
				PasswordManagerGui.Draw();
			}
		}

		private void ToggleConsole()
		{
			if ((Object)(object)Console.instance != (Object)null && (Object)(object)((Terminal)Console.instance).m_chatWindow != (Object)null)
			{
				bool flag = !((Component)((Terminal)Console.instance).m_chatWindow).gameObject.activeSelf;
				((Component)((Terminal)Console.instance).m_chatWindow).gameObject.SetActive(flag);
				if (flag && (Object)(object)((Terminal)Console.instance).m_input != (Object)null)
				{
					((Terminal)Console.instance).m_input.ActivateInputField();
				}
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Instance = null;
		}
	}
	public static class PluginConfig
	{
		public static ConfigEntry<bool> Enabled { get; private set; }

		public static ConfigEntry<KeyboardShortcut> ToggleHotkey { get; private set; }

		public static ConfigEntry<KeyboardShortcut> ConsoleHotkey { get; private set; }

		public static ConfigEntry<bool> AutoSubmit { get; private set; }

		public static ConfigEntry<bool> HidePasswordDialog { get; private set; }

		public static ConfigEntry<bool> AutoSave { get; private set; }

		public static ConfigEntry<bool> PurgeOnWrongPassword { get; private set; }

		public static ConfigEntry<bool> ShowNotifications { get; private set; }

		public static ConfigEntry<bool> HighlightSavedInServerList { get; private set; }

		public static void Bind(ConfigFile config)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			Enabled = config.Bind<bool>("General", "Enabled", true, "Master switch to enable or disable the AutoServerPassword mod.");
			ToggleHotkey = config.Bind<KeyboardShortcut>("General", "ToggleHotkey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Key to toggle the AutoServerPassword in-game manager window. Change this to any key to avoid conflicts with dev console mods.");
			ConsoleHotkey = config.Bind<KeyboardShortcut>("General", "ConsoleHotkey", new KeyboardShortcut((KeyCode)0, Array.Empty<KeyCode>()), "Optional alternate key to toggle Valheim's developer console. Useful if a dev console mod overrides or conflicts with F5.");
			AutoSubmit = config.Bind<bool>("General", "AutoSubmit", true, "Automatically submit the saved password when connecting to a known server.");
			HidePasswordDialog = config.Bind<bool>("General", "HidePasswordDialog", true, "If true, the password prompt dialog will not render when a saved password is automatically entered.");
			AutoSave = config.Bind<bool>("General", "AutoSave", true, "Automatically save the password for a server after successfully connecting with it.");
			PurgeOnWrongPassword = config.Bind<bool>("General", "PurgeOnWrongPassword", true, "Automatically remove the saved password if the server rejects it (e.g. if the server password changed), so you are prompted next time.");
			ShowNotifications = config.Bind<bool>("UI", "ShowNotifications", true, "Show an in-game HUD notification when a password is auto-submitted or saved.");
			HighlightSavedInServerList = config.Bind<bool>("UI", "HighlightSavedInServerList", true, "In the server browser list, tint the lock icon green and note in tooltip for servers that have saved passwords.");
		}
	}
	public class SavedServerEntry
	{
		public string ServerKey { get; set; } = "";

		public string ServerName { get; set; } = "";

		public string Password { get; set; } = "";

		public List<string> Aliases { get; set; } = new List<string>();

		public DateTime LastUsed { get; set; } = DateTime.UtcNow;

		public DateTime LastSaved { get; set; } = DateTime.UtcNow;
	}
	public class ServerIdentifiers
	{
		public string PrimaryServerKey { get; set; } = "";

		public string ServerStringNoBackend { get; set; } = "";

		public string SocketEndpoint { get; set; } = "";

		public string SocketHost { get; set; } = "";

		public string ServerHost { get; set; } = "";

		public string JoinData { get; set; } = "";

		public string ServerName { get; set; } = "";

		public IEnumerable<string> GetAllKeys()
		{
			HashSet<string> seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			AddIfValid(PrimaryServerKey);
			AddIfValid(SocketEndpoint);
			AddIfValid(ServerStringNoBackend);
			AddIfValid(ServerHost);
			AddIfValid(JoinData);
			AddIfValid(SocketHost);
			return seen;
			void AddIfValid(string key)
			{
				if (!string.IsNullOrWhiteSpace(key))
				{
					seen.Add(key.Trim());
				}
			}
		}
	}
	public class InFlightAttempt
	{
		public string ServerKey { get; set; } = "";

		public string Password { get; set; } = "";

		public bool IsAuto { get; set; }

		public ServerIdentifiers Identifiers { get; set; }
	}
	public static class ServerPasswordManager
	{
		private static readonly object _lock = new object();

		private static Dictionary<string, SavedServerEntry> _servers = new Dictionary<string, SavedServerEntry>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> _failedThisSession = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static InFlightAttempt _activeAttempt;

		private static string _queuedNotification;

		public static bool WasAutoPasswordPurged { get; set; }

		public static string PurgedServerName { get; set; }

		public static string LastJoiningServerData { get; set; } = "";

		public static string LastJoiningServerName { get; set; } = "";

		private static string StorageDirectory => Path.Combine(Paths.ConfigPath, "AutoServerPassword");

		private static string StorageFilePath => Path.Combine(StorageDirectory, "passwords.json");

		public static bool HasActiveAutoAttempt
		{
			get
			{
				lock (_lock)
				{
					return _activeAttempt != null && _activeAttempt.IsAuto;
				}
			}
		}

		public static void Initialize()
		{
			LoadFromDisk();
		}

		public static void LoadFromDisk()
		{
			lock (_lock)
			{
				try
				{
					if (!Directory.Exists(StorageDirectory))
					{
						Directory.CreateDirectory(StorageDirectory);
					}
					if (File.Exists(StorageFilePath))
					{
						Dictionary<string, SavedServerEntry> dictionary = JsonConvert.DeserializeObject<Dictionary<string, SavedServerEntry>>(File.ReadAllText(StorageFilePath, Encoding.UTF8));
						if (dictionary != null)
						{
							_servers = new Dictionary<string, SavedServerEntry>(dictionary, StringComparer.OrdinalIgnoreCase);
							Plugin.Log.LogInfo((object)$"[AutoServerPassword] Loaded {_servers.Count} saved server password(s) from disk.");
						}
					}
					else
					{
						_servers = new Dictionary<string, SavedServerEntry>(StringComparer.OrdinalIgnoreCase);
					}
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"[AutoServerPassword] Failed to load passwords from {StorageFilePath}: {arg}");
					_servers = new Dictionary<string, SavedServerEntry>(StringComparer.OrdinalIgnoreCase);
				}
			}
		}

		public static void SaveToDisk()
		{
			lock (_lock)
			{
				try
				{
					if (!Directory.Exists(StorageDirectory))
					{
						Directory.CreateDirectory(StorageDirectory);
					}
					string contents = JsonConvert.SerializeObject((object)_servers, (Formatting)1);
					string text = StorageFilePath + ".tmp";
					File.WriteAllText(text, contents, Encoding.UTF8);
					if (File.Exists(StorageFilePath))
					{
						File.Delete(StorageFilePath);
					}
					File.Move(text, StorageFilePath);
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"[AutoServerPassword] Failed to save passwords to {StorageFilePath}: {arg}");
				}
			}
		}

		public static ServerIdentifiers CollectCurrentIdentifiers(ZNet net, ZRpc rpc)
		{
			ServerIdentifiers serverIdentifiers = new ServerIdentifiers();
			try
			{
				serverIdentifiers.PrimaryServerKey = ZNet.GetServerString(true)?.Trim() ?? "";
				serverIdentifiers.ServerStringNoBackend = ZNet.GetServerString(false)?.Trim() ?? "";
			}
			catch
			{
			}
			try
			{
				ISocket val = ((rpc != null) ? rpc.GetSocket() : null);
				if (val != null)
				{
					serverIdentifiers.SocketEndpoint = val.GetEndPointString()?.Trim() ?? "";
					serverIdentifiers.SocketHost = val.GetHostName()?.Trim() ?? "";
				}
			}
			catch
			{
			}
			try
			{
				if (!string.IsNullOrEmpty(ZNet.m_serverHost))
				{
					serverIdentifiers.ServerHost = ((ZNet.m_serverHostPort > 0) ? $"{ZNet.m_serverHost}:{ZNet.m_serverHostPort}".Trim() : ZNet.m_serverHost.Trim());
				}
			}
			catch
			{
			}
			serverIdentifiers.JoinData = LastJoiningServerData?.Trim() ?? "";
			serverIdentifiers.ServerName = LastJoiningServerName?.Trim() ?? "";
			if (string.IsNullOrEmpty(serverIdentifiers.PrimaryServerKey))
			{
				serverIdentifiers.PrimaryServerKey = ((!string.IsNullOrEmpty(serverIdentifiers.SocketEndpoint)) ? serverIdentifiers.SocketEndpoint : ((!string.IsNullOrEmpty(serverIdentifiers.JoinData)) ? serverIdentifiers.JoinData : serverIdentifiers.ServerHost));
			}
			return serverIdentifiers;
		}

		public static bool TryFindSavedPassword(ServerIdentifiers identifiers, out SavedServerEntry matchedEntry, out string matchedKey)
		{
			lock (_lock)
			{
				matchedEntry = null;
				matchedKey = null;
				if (identifiers == null)
				{
					return false;
				}
				List<string> list = identifiers.GetAllKeys().ToList();
				foreach (string item in list)
				{
					if (_servers.TryGetValue(item, out var value))
					{
						matchedEntry = value;
						matchedKey = item;
						return true;
					}
				}
				foreach (KeyValuePair<string, SavedServerEntry> server in _servers)
				{
					SavedServerEntry value2 = server.Value;
					if (value2.Aliases == null)
					{
						continue;
					}
					foreach (string key in list)
					{
						if (value2.Aliases.Any((string a) => string.Equals(a, key, StringComparison.OrdinalIgnoreCase)))
						{
							matchedEntry = value2;
							matchedKey = key;
							return true;
						}
					}
				}
				if (!string.IsNullOrWhiteSpace(identifiers.ServerName))
				{
					List<SavedServerEntry> list2 = _servers.Values.Where((SavedServerEntry e) => !string.IsNullOrWhiteSpace(e.ServerName) && string.Equals(e.ServerName, identifiers.ServerName, StringComparison.OrdinalIgnoreCase)).ToList();
					if (list2.Count == 1)
					{
						matchedEntry = list2[0];
						matchedKey = identifiers.ServerName;
						return true;
					}
				}
				return false;
			}
		}

		public unsafe static bool HasSavedPassword(ServerJoinData joinData)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			string joinData2 = ((object)(*(ServerJoinData*)(&joinData))/*cast due to .constrained prefix*/).ToString();
			string serverName = MultiBackendMatchmaking.GetServerName(joinData);
			SavedServerEntry matchedEntry;
			string matchedKey;
			return TryFindSavedPassword(new ServerIdentifiers
			{
				JoinData = joinData2,
				ServerName = serverName
			}, out matchedEntry, out matchedKey);
		}

		public static bool IsFailedThisSession(string serverKey)
		{
			lock (_lock)
			{
				return _failedThisSession.Contains(serverKey);
			}
		}

		public static void RecordActiveAttempt(string serverKey, string password, bool isAuto, ServerIdentifiers ids)
		{
			lock (_lock)
			{
				_activeAttempt = new InFlightAttempt
				{
					ServerKey = serverKey,
					Password = password,
					IsAuto = isAuto,
					Identifiers = ids
				};
			}
		}

		public static void ClearActiveAttempt()
		{
			lock (_lock)
			{
				_activeAttempt = null;
			}
		}

		public static void SavePassword(string primaryKey, string password, ServerIdentifiers ids)
		{
			lock (_lock)
			{
				if (string.IsNullOrWhiteSpace(primaryKey) || string.IsNullOrEmpty(password))
				{
					return;
				}
				if (!_servers.TryGetValue(primaryKey, out var value))
				{
					value = new SavedServerEntry
					{
						ServerKey = primaryKey,
						Password = password,
						Aliases = new List<string>(),
						LastSaved = DateTime.UtcNow,
						LastUsed = DateTime.UtcNow
					};
					_servers[primaryKey] = value;
				}
				else
				{
					value.Password = password;
					value.LastSaved = DateTime.UtcNow;
					value.LastUsed = DateTime.UtcNow;
				}
				if (ids != null)
				{
					if (!string.IsNullOrWhiteSpace(ids.ServerName))
					{
						value.ServerName = ids.ServerName;
					}
					foreach (string allKey in ids.GetAllKeys())
					{
						if (!string.Equals(allKey, primaryKey, StringComparison.OrdinalIgnoreCase) && !value.Aliases.Contains<string>(allKey, StringComparer.OrdinalIgnoreCase))
						{
							value.Aliases.Add(allKey);
						}
					}
				}
				SaveToDisk();
			}
		}

		public static void UpdateLastUsedAndAliases(string primaryKey, ServerIdentifiers ids)
		{
			lock (_lock)
			{
				if (!_servers.TryGetValue(primaryKey, out var value))
				{
					return;
				}
				value.LastUsed = DateTime.UtcNow;
				if (ids != null)
				{
					if (!string.IsNullOrWhiteSpace(ids.ServerName) && string.IsNullOrWhiteSpace(value.ServerName))
					{
						value.ServerName = ids.ServerName;
					}
					foreach (string allKey in ids.GetAllKeys())
					{
						if (!string.Equals(allKey, primaryKey, StringComparison.OrdinalIgnoreCase) && !value.Aliases.Contains<string>(allKey, StringComparer.OrdinalIgnoreCase))
						{
							value.Aliases.Add(allKey);
						}
					}
				}
				SaveToDisk();
			}
		}

		public static bool RemoveSavedPassword(string keyOrName)
		{
			lock (_lock)
			{
				if (string.IsNullOrWhiteSpace(keyOrName))
				{
					return false;
				}
				if (_servers.Remove(keyOrName))
				{
					SaveToDisk();
					return true;
				}
				string text = null;
				foreach (KeyValuePair<string, SavedServerEntry> server in _servers)
				{
					if (string.Equals(server.Value.ServerName, keyOrName, StringComparison.OrdinalIgnoreCase) || server.Value.Aliases.Any((string a) => string.Equals(a, keyOrName, StringComparison.OrdinalIgnoreCase)))
					{
						text = server.Key;
						break;
					}
				}
				if (text != null && _servers.Remove(text))
				{
					SaveToDisk();
					return true;
				}
				return false;
			}
		}

		public static void ClearAllPasswords()
		{
			lock (_lock)
			{
				_servers.Clear();
				SaveToDisk();
			}
		}

		public static IReadOnlyList<SavedServerEntry> GetAllSavedServers()
		{
			lock (_lock)
			{
				return _servers.Values.ToList();
			}
		}

		public static void OnConnectionSuccess(ZNet net, ZRpc rpc)
		{
			InFlightAttempt activeAttempt;
			lock (_lock)
			{
				activeAttempt = _activeAttempt;
				_activeAttempt = null;
			}
			if (activeAttempt == null)
			{
				return;
			}
			ServerIdentifiers serverIdentifiers = CollectCurrentIdentifiers(net, rpc);
			string text = ((!string.IsNullOrEmpty(activeAttempt.ServerKey)) ? activeAttempt.ServerKey : serverIdentifiers.PrimaryServerKey);
			string text2 = ((!string.IsNullOrEmpty(serverIdentifiers.ServerName)) ? serverIdentifiers.ServerName : text);
			lock (_lock)
			{
				_failedThisSession.Remove(text);
			}
			if (!activeAttempt.IsAuto)
			{
				if (PluginConfig.AutoSave.Value)
				{
					SavePassword(text, activeAttempt.Password, serverIdentifiers);
					Plugin.Log.LogInfo((object)("[AutoServerPassword] Successfully connected to '" + text2 + "'! Password saved."));
					QueueNotification("AutoServerPassword: Saved password for " + text2);
				}
			}
			else
			{
				UpdateLastUsedAndAliases(text, serverIdentifiers);
				Plugin.Log.LogInfo((object)("[AutoServerPassword] Successfully auto-connected to '" + text2 + "'."));
				QueueNotification("AutoServerPassword: Auto-entered password for " + text2);
			}
		}

		public static void OnPasswordError(ZNet net, ZRpc rpc)
		{
			InFlightAttempt activeAttempt;
			lock (_lock)
			{
				activeAttempt = _activeAttempt;
				_activeAttempt = null;
			}
			if (activeAttempt == null)
			{
				return;
			}
			ServerIdentifiers serverIdentifiers = CollectCurrentIdentifiers(net, rpc);
			string text = ((!string.IsNullOrEmpty(activeAttempt.ServerKey)) ? activeAttempt.ServerKey : serverIdentifiers.PrimaryServerKey);
			string text2 = ((!string.IsNullOrEmpty(serverIdentifiers.ServerName)) ? serverIdentifiers.ServerName : text);
			if (activeAttempt.IsAuto)
			{
				if (PluginConfig.PurgeOnWrongPassword.Value)
				{
					Plugin.Log.LogWarning((object)("[AutoServerPassword] Saved password rejected by server '" + text2 + "' (" + text + "). Purging saved password."));
					RemoveSavedPassword(text);
					lock (_lock)
					{
						_failedThisSession.Add(text);
						WasAutoPasswordPurged = true;
						PurgedServerName = text2;
					}
				}
			}
			else
			{
				Plugin.Log.LogWarning((object)("[AutoServerPassword] Manually entered password rejected by server '" + text2 + "'. Password will not be saved."));
			}
		}

		public static void QueueNotification(string message)
		{
			if (PluginConfig.ShowNotifications.Value)
			{
				_queuedNotification = message;
				TryDisplayQueuedNotification();
			}
		}

		public static void TryDisplayQueuedNotification()
		{
			if (!string.IsNullOrEmpty(_queuedNotification) && (Object)(object)MessageHud.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				MessageHud.instance.ShowMessage((MessageType)1, _queuedNotification, 0, (Sprite)null, false, true);
				_queuedNotification = null;
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}