From 1228a06a905e485dcb7ec8cc42f36f5284df311d Mon Sep 17 00:00:00 2001 From: Nicolas Dorier Date: Wed, 18 Jan 2023 14:15:27 +0900 Subject: [PATCH] Improve detection of plugin bricking an install on startup (#4533) --- BTCPayServer/Plugins/PluginManager.cs | 32 ++++++++++++++++++++++----- BTCPayServer/Program.cs | 6 ++--- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/BTCPayServer/Plugins/PluginManager.cs b/BTCPayServer/Plugins/PluginManager.cs index 364d341ab..804e950a3 100644 --- a/BTCPayServer/Plugins/PluginManager.cs +++ b/BTCPayServer/Plugins/PluginManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; @@ -24,9 +25,29 @@ namespace BTCPayServer.Plugins public const string BTCPayPluginSuffix = ".btcpay"; private static readonly List _pluginAssemblies = new List(); - public static bool IsExceptionByPlugin(Exception exception) + public static bool IsExceptionByPlugin(Exception exception, [MaybeNullWhen(false)] out string pluginName) { - return _pluginAssemblies.Any(assembly => assembly?.FullName?.Contains(exception.Source!, StringComparison.OrdinalIgnoreCase) is true); + foreach (var assembly in _pluginAssemblies) + { + var assemblyName = assembly.GetName().Name; + if (assemblyName is null) + continue; + // Comparison is case sensitive as it is theorically possible to have a different plugin + // with same name but different casing. + if (exception.Source is not null && + assemblyName.Equals(exception.Source, StringComparison.Ordinal)) + { + pluginName = assemblyName; + return true; + } + if (exception.Message.Contains(assemblyName, StringComparison.Ordinal)) + { + pluginName = assemblyName; + return true; + } + } + pluginName = null; + return false; } public static IMvcBuilder AddPlugins(this IMvcBuilder mvcBuilder, IServiceCollection serviceCollection, IConfiguration config, ILoggerFactory loggerFactory) @@ -51,14 +72,14 @@ namespace BTCPayServer.Plugins // as the assembly. Except for the system assembly (btcpayserver assembly) which are fake plugins foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { - var pluginIdentifier = assembly.GetName().Name; + var assemblyName = assembly.GetName().Name; bool isSystemPlugin = assembly == systemAssembly; - if (!isSystemPlugin && disabledPlugins.Contains(pluginIdentifier)) + if (!isSystemPlugin && disabledPlugins.Contains(assemblyName)) continue; foreach (var plugin in GetPluginInstancesFromAssembly(assembly)) { - if (!isSystemPlugin && plugin.Identifier != pluginIdentifier) + if (!isSystemPlugin && plugin.Identifier != assemblyName) continue; if (!loadedPluginIdentifiers.Add(plugin.Identifier)) continue; @@ -150,7 +171,6 @@ namespace BTCPayServer.Plugins $"Error when loading plugin {plugin.Identifier} - {plugin.Version}{Environment.NewLine}{e.Message}"); } } - return mvcBuilder; } diff --git a/BTCPayServer/Program.cs b/BTCPayServer/Program.cs index 0aff901ed..05d8b8a67 100644 --- a/BTCPayServer/Program.cs +++ b/BTCPayServer/Program.cs @@ -85,11 +85,11 @@ namespace BTCPayServer if (!string.IsNullOrEmpty(ex.Message)) logs.Configuration.LogError(ex.Message); } - catch (Exception e) when (PluginManager.IsExceptionByPlugin(e)) + catch (Exception e) when (PluginManager.IsExceptionByPlugin(e, out var pluginName)) { - logs.Configuration.LogError(e, $"Disabling plugin {e.Source} as it crashed on startup"); + logs.Configuration.LogError(e, $"Disabling plugin {pluginName} as it crashed on startup"); var pluginDir = new DataDirectories().Configure(conf).PluginDir; - PluginManager.DisablePlugin(pluginDir, e.Source); + PluginManager.DisablePlugin(pluginDir, pluginName); } finally {