diff --git a/Kyoo.Authentication/AuthenticationModule.cs b/Kyoo.Authentication/AuthenticationModule.cs index 085fc2dd..fe7e07e3 100644 --- a/Kyoo.Authentication/AuthenticationModule.cs +++ b/Kyoo.Authentication/AuthenticationModule.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using Autofac; using IdentityServer4.Extensions; using IdentityServer4.Models; using IdentityServer4.Services; @@ -40,7 +41,9 @@ namespace Kyoo.Authentication /// public Dictionary Configuration => new() { - { AuthenticationOption.Path, typeof(AuthenticationOption) } + { AuthenticationOption.Path, typeof(AuthenticationOption) }, + { PermissionOption.Path, typeof(PermissionOption) }, + { CertificateOption.Path, typeof(CertificateOption) } }; @@ -75,6 +78,18 @@ namespace Kyoo.Authentication _environment = environment; } + /// + public void Configure(ContainerBuilder builder) + { + builder.RegisterType().As().SingleInstance(); + + DefaultCorsPolicyService cors = new(_loggerFactory.CreateLogger()) + { + AllowedOrigins = { new Uri(_configuration.GetPublicUrl()).GetLeftPart(UriPartial.Authority) } + }; + builder.RegisterInstance(cors).As().SingleInstance(); + } + /// public void Configure(IServiceCollection services) { @@ -115,13 +130,6 @@ namespace Kyoo.Authentication options.Audience = "kyoo"; options.RequireHttpsMetadata = false; }); - services.AddSingleton(); - - DefaultCorsPolicyService cors = new(_loggerFactory.CreateLogger()) - { - AllowedOrigins = {new Uri(publicUrl).GetLeftPart(UriPartial.Authority)} - }; - services.AddSingleton(cors); } /// diff --git a/Kyoo.Authentication/Controllers/Certificates.cs b/Kyoo.Authentication/Controllers/Certificates.cs index 3aaab9b8..906890c4 100644 --- a/Kyoo.Authentication/Controllers/Certificates.cs +++ b/Kyoo.Authentication/Controllers/Certificates.cs @@ -34,7 +34,7 @@ namespace Kyoo.Authentication X509Certificate2 certificate = GetCertificate(options); builder.AddSigningCredential(certificate); - if (certificate.NotAfter.AddDays(7) <= DateTime.UtcNow) + if (certificate.NotAfter.AddDays(-7) <= DateTime.UtcNow) { Console.WriteLine("Signin certificate will expire soon, renewing it."); if (File.Exists(options.OldFile)) @@ -67,7 +67,7 @@ namespace Kyoo.Authentication /// The loaded certificate private static X509Certificate2 GetExistingCredential(string file, string password) { - return new(file, password, + return new X509Certificate2(file, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable diff --git a/Kyoo.Common/Controllers/IConfigurationManager.cs b/Kyoo.Common/Controllers/IConfigurationManager.cs index 02430b10..6f01f627 100644 --- a/Kyoo.Common/Controllers/IConfigurationManager.cs +++ b/Kyoo.Common/Controllers/IConfigurationManager.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using JetBrains.Annotations; using Kyoo.Models; using Kyoo.Models.Exceptions; @@ -26,6 +27,15 @@ namespace Kyoo.Controllers /// /// The root path of the editable configuration. It should not be a nested type. void AddUntyped(string path); + + /// + /// An helper method of and . + /// This register a typed value if is not null and registers an untyped type + /// if is null. + /// + /// The root path of the editable configuration. It should not be a nested type. + /// The type of the configuration or null. + void Register(string path, [CanBeNull] Type type); /// /// Get the value of a setting using it's path. diff --git a/Kyoo.Common/Controllers/IPlugin.cs b/Kyoo.Common/Controllers/IPlugin.cs index 817435f1..4d86f06c 100644 --- a/Kyoo.Common/Controllers/IPlugin.cs +++ b/Kyoo.Common/Controllers/IPlugin.cs @@ -44,8 +44,12 @@ namespace Kyoo.Controllers /// /// A list of types that will be available via the IOptions interfaces and will be listed inside - /// an IConfiguration. If a field should be loosely typed, or null + /// an IConfiguration. + /// + /// If a field should be loosely typed, or null /// can be specified. + /// WARNING: null means an unmanaged type that won't be editable. This can be used + /// for external libraries or variable arguments. /// /// /// All use of the configuration must be specified here and not registered elsewhere, if a type is registered diff --git a/Kyoo/Controllers/ConfigurationManager.cs b/Kyoo/Controllers/ConfigurationManager.cs index 32b2e7f7..286c6a2a 100644 --- a/Kyoo/Controllers/ConfigurationManager.cs +++ b/Kyoo/Controllers/ConfigurationManager.cs @@ -50,6 +50,21 @@ namespace Kyoo.Controllers ConfigurationReference config = ConfigurationReference.CreateUntyped(path); _references.Add(config.Path, config.Type); } + + /// + public void Register(string path, Type type) + { + if (type == null) + { + ConfigurationReference config = ConfigurationReference.CreateUntyped(path); + _references.Add(config.Path, config.Type); + } + else + { + foreach (ConfigurationReference confRef in ConfigurationReference.CreateReference(path, type)) + _references.Add(confRef.Path, confRef.Type); + } + } /// /// Get the type of the resource at the given path diff --git a/Kyoo/PluginsStartup.cs b/Kyoo/PluginsStartup.cs index 33305f6e..189ebb92 100644 --- a/Kyoo/PluginsStartup.cs +++ b/Kyoo/PluginsStartup.cs @@ -32,14 +32,23 @@ namespace Kyoo /// A plugin manager used to load plugins and allow them to configure services / asp net. /// private readonly IPluginManager _plugins; - + + /// + /// The configuration used to register and so on for plugin's specified types. + /// + private readonly IConfiguration _configuration; + /// /// Created from the DI container, those services are needed to load information and instantiate plugins.s /// /// The plugin manager to use to load new plugins and configure the host. - public PluginsStartup(IPluginManager plugins) + /// + /// The configuration used to register and so on for plugin's specified types. + /// + public PluginsStartup(IPluginManager plugins, IConfiguration configuration) { _plugins = plugins; + _configuration = configuration; _plugins.LoadPlugins( typeof(CoreModule), typeof(AuthenticationModule), @@ -58,9 +67,9 @@ namespace Kyoo { services.AddMvc().AddControllersAsServices(); - services.AddSpaStaticFiles(configuration => + services.AddSpaStaticFiles(x => { - configuration.RootPath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "wwwroot"); + x.RootPath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "wwwroot"); }); services.AddResponseCompression(x => { @@ -70,6 +79,18 @@ namespace Kyoo services.AddHttpClient(); _plugins.ConfigureServices(services); + IEnumerable> configTypes = _plugins.GetAllPlugins() + .SelectMany(x => x.Configuration) + .Where(x => x.Value != null); + foreach ((string path, Type type) in configTypes) + { + Utility.RunGenericMethod( + typeof(OptionsConfigurationServiceCollectionExtensions), + nameof(OptionsConfigurationServiceCollectionExtensions.Configure), + type, + services, _configuration.GetSection(path) + ); + } } /// @@ -89,7 +110,7 @@ namespace Kyoo /// /// The asp net host to configure /// The host environment (is the app in development mode?) - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider provider) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IConfigurationManager config, ILifetimeScope container) { if (!env.IsDevelopment()) app.UseSpaStaticFiles(); @@ -111,9 +132,23 @@ namespace Kyoo IEnumerable steps = _plugins.GetAllPlugins() .SelectMany(x => x.ConfigureSteps) .OrderByDescending(x => x.Priority); + + using ILifetimeScope scope = container.BeginLifetimeScope(x => + x.RegisterInstance(app).SingleInstance().ExternallyOwned()); + IServiceProvider provider = scope.Resolve(); foreach (IStartupAction step in steps) step.Run(provider); + IEnumerable> pluginConfig = _plugins.GetAllPlugins() + .SelectMany(x => x.Configuration) + .GroupBy(x => x.Key.Split(':').First()) + .Select(x => x + .OrderBy(y => y.Key.Length) + .First() + ); + foreach ((string path, Type type) in pluginConfig) + config.Register(path, type); + app.UseSpa(spa => { spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp"); @@ -148,7 +183,7 @@ namespace Kyoo Options.Create(host.Configuration.GetSection(BasicOptions.Path).Get()), logger.CreateLogger() ); - return new PluginsStartup(plugins); + return new PluginsStartup(plugins, host.Configuration); } ///