possible fix for remotely loaded plugins
This commit is contained in:
parent
cae77357ca
commit
35c4bbd2d5
@ -13,10 +13,10 @@ namespace IW4MAdmin.Application.Misc
|
||||
{
|
||||
public class RemoteAssemblyHandler : IRemoteAssemblyHandler
|
||||
{
|
||||
private const int keyLength = 32;
|
||||
private const int tagLength = 16;
|
||||
private const int nonceLength = 12;
|
||||
private const int iterationCount = 10000;
|
||||
private const int KeyLength = 32;
|
||||
private const int TagLength = 16;
|
||||
private const int NonceLength = 12;
|
||||
private const int IterationCount = 10000;
|
||||
|
||||
private readonly ApplicationConfiguration _appconfig;
|
||||
private readonly ILogger _logger;
|
||||
@ -30,7 +30,7 @@ namespace IW4MAdmin.Application.Misc
|
||||
public IEnumerable<Assembly> DecryptAssemblies(string[] encryptedAssemblies)
|
||||
{
|
||||
return DecryptContent(encryptedAssemblies)
|
||||
.Select(decryptedAssembly => Assembly.Load(decryptedAssembly));
|
||||
.Select(Assembly.Load);
|
||||
}
|
||||
|
||||
public IEnumerable<string> DecryptScripts(string[] encryptedScripts)
|
||||
@ -38,24 +38,24 @@ namespace IW4MAdmin.Application.Misc
|
||||
return DecryptContent(encryptedScripts).Select(decryptedScript => Encoding.UTF8.GetString(decryptedScript));
|
||||
}
|
||||
|
||||
private byte[][] DecryptContent(string[] content)
|
||||
private IEnumerable<byte[]> DecryptContent(string[] content)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_appconfig.Id) || string.IsNullOrWhiteSpace(_appconfig.SubscriptionId))
|
||||
{
|
||||
_logger.LogWarning($"{nameof(_appconfig.Id)} and {nameof(_appconfig.SubscriptionId)} must be provided to attempt loading remote assemblies/scripts");
|
||||
return new byte[0][];
|
||||
return Array.Empty<byte[]>();
|
||||
}
|
||||
|
||||
var assemblies = content.Select(piece =>
|
||||
{
|
||||
byte[] byteContent = Convert.FromBase64String(piece);
|
||||
byte[] encryptedContent = byteContent.Take(byteContent.Length - (tagLength + nonceLength)).ToArray();
|
||||
byte[] tag = byteContent.Skip(byteContent.Length - (tagLength + nonceLength)).Take(tagLength).ToArray();
|
||||
byte[] nonce = byteContent.Skip(byteContent.Length - nonceLength).Take(nonceLength).ToArray();
|
||||
byte[] decryptedContent = new byte[encryptedContent.Length];
|
||||
var byteContent = Convert.FromBase64String(piece);
|
||||
var encryptedContent = byteContent.Take(byteContent.Length - (TagLength + NonceLength)).ToArray();
|
||||
var tag = byteContent.Skip(byteContent.Length - (TagLength + NonceLength)).Take(TagLength).ToArray();
|
||||
var nonce = byteContent.Skip(byteContent.Length - NonceLength).Take(NonceLength).ToArray();
|
||||
var decryptedContent = new byte[encryptedContent.Length];
|
||||
|
||||
var keyGen = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(_appconfig.SubscriptionId), Encoding.UTF8.GetBytes(_appconfig.Id.ToString()), iterationCount, HashAlgorithmName.SHA512);
|
||||
var encryption = new AesGcm(keyGen.GetBytes(keyLength));
|
||||
var keyGen = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(_appconfig.SubscriptionId), Encoding.UTF8.GetBytes(_appconfig.Id), IterationCount, HashAlgorithmName.SHA512);
|
||||
var encryption = new AesGcm(keyGen.GetBytes(KeyLength));
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -20,13 +20,21 @@ namespace IW4MAdmin.Application.Plugin
|
||||
public class PluginImporter : IPluginImporter
|
||||
{
|
||||
private IEnumerable<PluginSubscriptionContent> _pluginSubscription;
|
||||
private static readonly string PluginDir = "Plugins";
|
||||
private const string PluginDir = "Plugins";
|
||||
private const string PluginV2Match = "^ *((?:var|const|let) +init)|function init";
|
||||
private readonly ILogger _logger;
|
||||
private readonly IRemoteAssemblyHandler _remoteAssemblyHandler;
|
||||
private readonly IMasterApi _masterApi;
|
||||
private readonly ApplicationConfiguration _appConfig;
|
||||
|
||||
private static readonly Type[] FilterTypes =
|
||||
{
|
||||
typeof(IPlugin),
|
||||
typeof(IPluginV2),
|
||||
typeof(Command),
|
||||
typeof(IBaseConfiguration)
|
||||
};
|
||||
|
||||
public PluginImporter(ILogger<PluginImporter> logger, ApplicationConfiguration appConfig, IMasterApi masterApi,
|
||||
IRemoteAssemblyHandler remoteAssemblyHandler)
|
||||
{
|
||||
@ -77,74 +85,80 @@ namespace IW4MAdmin.Application.Plugin
|
||||
public (IEnumerable<Type>, IEnumerable<Type>, IEnumerable<Type>) DiscoverAssemblyPluginImplementations()
|
||||
{
|
||||
var pluginDir = $"{Utilities.OperatingDirectory}{PluginDir}{Path.DirectorySeparatorChar}";
|
||||
var pluginTypes = Enumerable.Empty<Type>();
|
||||
var commandTypes = Enumerable.Empty<Type>();
|
||||
var configurationTypes = Enumerable.Empty<Type>();
|
||||
var pluginTypes = new List<Type>();
|
||||
var commandTypes = new List<Type>();
|
||||
var configurationTypes = new List<Type>();
|
||||
|
||||
if (Directory.Exists(pluginDir))
|
||||
if (!Directory.Exists(pluginDir))
|
||||
{
|
||||
var dllFileNames = Directory.GetFiles(pluginDir, "*.dll");
|
||||
_logger.LogDebug("Discovered {Count} potential plugin assemblies", dllFileNames.Length);
|
||||
return (pluginTypes, commandTypes, configurationTypes);
|
||||
}
|
||||
|
||||
if (dllFileNames.Length > 0)
|
||||
var dllFileNames = Directory.GetFiles(pluginDir, "*.dll");
|
||||
_logger.LogDebug("Discovered {Count} potential plugin assemblies", dllFileNames.Length);
|
||||
|
||||
if (!dllFileNames.Any())
|
||||
{
|
||||
return (pluginTypes, commandTypes, configurationTypes);
|
||||
}
|
||||
|
||||
// we only want to load the most recent assembly in case of duplicates
|
||||
var assemblies = dllFileNames.Select(Assembly.LoadFrom)
|
||||
.Union(GetRemoteAssemblies())
|
||||
.GroupBy(assembly => assembly.FullName).Select(assembly =>
|
||||
assembly.OrderByDescending(asm => asm.GetName().Version).First());
|
||||
|
||||
var eligibleAssemblyTypes = assemblies
|
||||
.SelectMany(asm =>
|
||||
{
|
||||
// we only want to load the most recent assembly in case of duplicates
|
||||
var assemblies = dllFileNames.Select(name => Assembly.LoadFrom(name))
|
||||
.Union(GetRemoteAssemblies())
|
||||
.GroupBy(assembly => assembly.FullName).Select(assembly => assembly.OrderByDescending(asm => asm.GetName().Version).First());
|
||||
try
|
||||
{
|
||||
return asm.GetTypes();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<Type>();
|
||||
}
|
||||
}).Where(type =>
|
||||
FilterTypes.Any(filterType => type.GetInterface(filterType.Name, false) != null) ||
|
||||
(type.IsClass && FilterTypes.Contains(type.BaseType)));
|
||||
|
||||
pluginTypes = assemblies
|
||||
.SelectMany(asm =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return asm.GetTypes();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<Type>();
|
||||
}
|
||||
})
|
||||
.Where(assemblyType => (assemblyType.GetInterface(nameof(IPlugin), false) ?? assemblyType.GetInterface(nameof(IPluginV2), false)) != null)
|
||||
.Where(assemblyType => !assemblyType.Namespace?.StartsWith(nameof(SharedLibraryCore)) ?? false);
|
||||
foreach (var assemblyType in eligibleAssemblyTypes)
|
||||
{
|
||||
var isPlugin =
|
||||
(assemblyType.GetInterface(nameof(IPlugin), false) ??
|
||||
assemblyType.GetInterface(nameof(IPluginV2), false)) != null &&
|
||||
(!assemblyType.Namespace?.StartsWith(nameof(SharedLibraryCore)) ?? false);
|
||||
|
||||
_logger.LogDebug("Discovered {count} plugin implementations", pluginTypes.Count());
|
||||
if (isPlugin)
|
||||
{
|
||||
pluginTypes.Add(assemblyType);
|
||||
continue;
|
||||
}
|
||||
|
||||
commandTypes = assemblies
|
||||
.SelectMany(asm =>{
|
||||
try
|
||||
{
|
||||
return asm.GetTypes();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<Type>();
|
||||
}
|
||||
})
|
||||
.Where(assemblyType => assemblyType.IsClass && assemblyType.BaseType == typeof(Command))
|
||||
.Where(assemblyType => !assemblyType.Namespace?.StartsWith(nameof(SharedLibraryCore)) ?? false);
|
||||
var isCommand = assemblyType.IsClass && assemblyType.BaseType == typeof(Command) &&
|
||||
(!assemblyType.Namespace?.StartsWith(nameof(SharedLibraryCore)) ?? false);
|
||||
|
||||
_logger.LogDebug("Discovered {Count} plugin commands", commandTypes.Count());
|
||||
if (isCommand)
|
||||
{
|
||||
commandTypes.Add(assemblyType);
|
||||
continue;
|
||||
}
|
||||
|
||||
configurationTypes = assemblies
|
||||
.SelectMany(asm => {
|
||||
try
|
||||
{
|
||||
return asm.GetTypes();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<Type>();
|
||||
}
|
||||
})
|
||||
.Where(asmType =>
|
||||
asmType.IsClass && asmType.GetInterface(nameof(IBaseConfiguration), false) != null)
|
||||
.Where(assemblyType => !assemblyType.Namespace?.StartsWith(nameof(SharedLibraryCore)) ?? false);
|
||||
var isConfiguration = assemblyType.IsClass &&
|
||||
assemblyType.GetInterface(nameof(IBaseConfiguration), false) != null &&
|
||||
(!assemblyType.Namespace?.StartsWith(nameof(SharedLibraryCore)) ?? false);
|
||||
|
||||
_logger.LogDebug("Discovered {Count} configuration implementations", configurationTypes.Count());
|
||||
if (isConfiguration)
|
||||
{
|
||||
configurationTypes.Add(assemblyType);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogDebug("Discovered {Count} plugin implementations", pluginTypes.Count);
|
||||
_logger.LogDebug("Discovered {Count} plugin commands", pluginTypes.Count);
|
||||
_logger.LogDebug("Discovered {Count} configuration implementations", pluginTypes.Count);
|
||||
|
||||
return (pluginTypes, commandTypes, configurationTypes);
|
||||
}
|
||||
|
||||
@ -152,10 +166,11 @@ namespace IW4MAdmin.Application.Plugin
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_pluginSubscription == null)
|
||||
_pluginSubscription = _masterApi.GetPluginSubscription(Guid.Parse(_appConfig.Id), _appConfig.SubscriptionId).Result;
|
||||
_pluginSubscription ??= _masterApi
|
||||
.GetPluginSubscription(Guid.Parse(_appConfig.Id), _appConfig.SubscriptionId).Result;
|
||||
|
||||
return _remoteAssemblyHandler.DecryptAssemblies(_pluginSubscription.Where(sub => sub.Type == PluginType.Binary).Select(sub => sub.Content).ToArray());
|
||||
return _remoteAssemblyHandler.DecryptAssemblies(_pluginSubscription
|
||||
.Where(sub => sub.Type == PluginType.Binary).Select(sub => sub.Content).ToArray());
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
@ -169,9 +184,11 @@ namespace IW4MAdmin.Application.Plugin
|
||||
{
|
||||
try
|
||||
{
|
||||
_pluginSubscription ??= _masterApi.GetPluginSubscription(Guid.Parse(_appConfig.Id), _appConfig.SubscriptionId).Result;
|
||||
_pluginSubscription ??= _masterApi
|
||||
.GetPluginSubscription(Guid.Parse(_appConfig.Id), _appConfig.SubscriptionId).Result;
|
||||
|
||||
return _remoteAssemblyHandler.DecryptScripts(_pluginSubscription.Where(sub => sub.Type == PluginType.Script).Select(sub => sub.Content).ToArray());
|
||||
return _remoteAssemblyHandler.DecryptScripts(_pluginSubscription
|
||||
.Where(sub => sub.Type == PluginType.Script).Select(sub => sub.Content).ToArray());
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
|
Loading…
Reference in New Issue
Block a user