From 54e56d2fc1d0d388b3764bfbeab0655a46f14b30 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Fri, 3 Sep 2021 23:35:44 -0700 Subject: [PATCH] fix: Fixes assembly loading. (#759) * `AssemblyHandler.Assemblies` will now only contain assemblies listed in `assemblies.json` * `assemblies.json` has been updated to only contain asssemblies directly loaded by the server. Namely, only `UOContent.dll`. * Specifically assemblies loaded by assemblies.json are subject to check for `Configure` and `Initialize` methods. * `modernuo.json` now has a new property called `assemblyDirectories`. This will be automatically set to `Distribution/Assemblies` (absolute path on your machine). * You can add more directories to this list. * All assemblies in assemblies.json _AND_ dependents of any assembly will be searched for in the directories specified by `assemblyDirectories`. --- Distribution/Data/assemblies.json | 6 -- Projects/Server/AssemblyHandler.cs | 62 ++++++++++++++++++- .../Configuration/ServerConfiguration.cs | 2 + .../Server/Configuration/ServerSettings.cs | 3 + Projects/Server/Main.cs | 3 +- 5 files changed, 67 insertions(+), 9 deletions(-) diff --git a/Distribution/Data/assemblies.json b/Distribution/Data/assemblies.json index fe275996b..fc24c4266 100644 --- a/Distribution/Data/assemblies.json +++ b/Distribution/Data/assemblies.json @@ -1,9 +1,3 @@ [ - "Argon2.Bindings.dll", - "BouncyCastle.Crypto.dll", - "MailKit.dll", - "MimeKit.dll", - "Microsoft.Extensions.FileSystemGlobbing.dll", - "Zlib.Bindings.dll", "UOContent.dll" ] diff --git a/Projects/Server/AssemblyHandler.cs b/Projects/Server/AssemblyHandler.cs index c8e91ac1b..2cccc222a 100644 --- a/Projects/Server/AssemblyHandler.cs +++ b/Projects/Server/AssemblyHandler.cs @@ -29,13 +29,71 @@ namespace Server private static TypeCache m_NullCache; public static Assembly[] Assemblies { get; set; } - public static void LoadScripts(string[] files) + internal static Assembly AssemblyResolver(object sender, ResolveEventArgs args) => + LoadAssemblyByAssemblyName(args.Name); + + private static void EnsureAssemblyDirectories() + { + if (ServerConfiguration.AssemblyDirectories.Count == 0) + { + ServerConfiguration.AssemblyDirectories.Add(Path.Combine(Core.BaseDirectory, "Assemblies")); + ServerConfiguration.Save(); + } + } + + public static Assembly LoadAssemblyByAssemblyName(string fullAssemblyName) + { + var assemblyName = new AssemblyName(fullAssemblyName); + var assemblyFile = $"{assemblyName.Name}.dll"; + + EnsureAssemblyDirectories(); + var assemblyDirectories = ServerConfiguration.AssemblyDirectories; + + foreach (var assemblyDir in assemblyDirectories) + { + var assemblyPath = Path.Combine(assemblyDir, assemblyFile); + if (File.Exists(assemblyPath)) + { + var assemblyNameCheck = AssemblyName.GetAssemblyName(assemblyPath); + if (assemblyNameCheck.FullName == assemblyName.FullName) + { + return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); + } + } + } + + return null; + } + + public static Assembly LoadAssemblyByFileName(string assemblyFile) + { + EnsureAssemblyDirectories(); + var assemblyDirectories = ServerConfiguration.AssemblyDirectories; + + foreach (var assemblyDir in assemblyDirectories) + { + var assemblyPath = Path.Combine(assemblyDir, assemblyFile); + if (File.Exists(assemblyPath)) + { + return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); + } + } + + return null; + } + + public static void LoadAssemblies(string[] files) { var assemblies = new Assembly[files.Length]; for (var i = 0; i < files.Length; i++) { - assemblies[i] = AssemblyLoadContext.Default.LoadFromAssemblyPath(files[i]); + var assembly = LoadAssemblyByFileName(files[i]); + if (assembly == null) + { + throw new FileNotFoundException($"Could not load {files[i]}"); + } + assemblies[i] = LoadAssemblyByFileName(files[i]); } Assemblies = assemblies; diff --git a/Projects/Server/Configuration/ServerConfiguration.cs b/Projects/Server/Configuration/ServerConfiguration.cs index 820d72bd7..f2e785b1f 100644 --- a/Projects/Server/Configuration/ServerConfiguration.cs +++ b/Projects/Server/Configuration/ServerConfiguration.cs @@ -32,6 +32,8 @@ namespace Server private static ServerSettings m_Settings; private static bool m_Mocked; + public static List AssemblyDirectories => m_Settings.AssemblyDirectories; + public static List DataDirectories => m_Settings.DataDirectories; public static List Listeners => m_Settings.Listeners; diff --git a/Projects/Server/Configuration/ServerSettings.cs b/Projects/Server/Configuration/ServerSettings.cs index a9c9178be..87f69a595 100644 --- a/Projects/Server/Configuration/ServerSettings.cs +++ b/Projects/Server/Configuration/ServerSettings.cs @@ -21,6 +21,9 @@ namespace Server { public class ServerSettings { + [JsonPropertyName("assemblyDirectories")] + public List AssemblyDirectories { get; set; } = new(); + [JsonPropertyName("dataDirectories")] public List DataDirectories { get; set; } = new(); diff --git a/Projects/Server/Main.cs b/Projects/Server/Main.cs index 4263c01b4..18804b003 100644 --- a/Projects/Server/Main.cs +++ b/Projects/Server/Main.cs @@ -365,6 +365,7 @@ namespace Server { AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; + AppDomain.CurrentDomain.AssemblyResolve += AssemblyHandler.AssemblyResolver; LoopContext = new EventLoopContext(); @@ -463,7 +464,7 @@ namespace Server assemblyFiles[i] = Path.Join(BaseDirectory, "Assemblies", assemblyFiles[i]); } - AssemblyHandler.LoadScripts(assemblyFiles); + AssemblyHandler.LoadAssemblies(assemblyFiles); VerifySerialization();