protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (value != null) { var cert = (CertificateOptions)value; if (!string.IsNullOrEmpty(cert.Pfx) && !X509.TryValidate(cert.Pfx, cert.Password, out var certResult)) { return(new ValidationResult($"Invalid HTTPs certificate: {certResult}")); } } return(ValidationResult.Success); }
/// <summary> /// Entrypoint. /// </summary> /// <param name="args">Command line arguments.</param> public static void Main(string[] args) { // populate the properties above so that we can override the default config file if needed, and to // check if the application is being run in command mode (run task and quit). EnvironmentVariables.Populate(prefix: EnvironmentVariablePrefix); Arguments.Populate(clearExistingValues: false); if (ShowVersion) { Console.WriteLine(Version); return; } if (ShowHelp || ShowEnvironmentVariables) { if (!NoLogo) { PrintLogo(Version); } if (ShowHelp) { PrintCommandLineArguments(typeof(Options)); } if (ShowEnvironmentVariables) { PrintEnvironmentVariables(typeof(Options), EnvironmentVariablePrefix); } return; } if (GenerateCertificate) { GenerateX509Certificate(password: Guid.NewGuid().ToString(), filename: $"{AppName}.pfx"); return; } // the application isn't bein run in command mode. load all configuration values and proceed // with bootstrapping. try { Configuration = new ConfigurationBuilder() .AddConfigurationProviders(EnvironmentVariablePrefix, ConfigurationFile) .Build(); Configuration.GetSection(AppName) .Bind(Options, (o) => { o.BindNonPublicProperties = true; }); if (!Options.TryValidate(out var result)) { Console.WriteLine(result.GetResultView("Invalid configuration:")); return; } var cert = Options.Web.Https.Certificate; if (!string.IsNullOrEmpty(cert.Pfx) && !X509.TryValidate(cert.Pfx, cert.Password, out var certResult)) { Console.WriteLine($"Invalid HTTPs certificate: {certResult}"); return; } } catch (Exception ex) { Console.WriteLine($"Invalid configuration: {(!Options.Debug ? ex : ex.Message)}"); return; } if (!Options.NoLogo) { PrintLogo(Version); } if (Options.Debug) { Console.WriteLine("Configuration:"); Console.WriteLine(Configuration.GetDebugView()); Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .MinimumLevel.Override("slskd.API.Authentication.PassthroughAuthenticationHandler", LogEventLevel.Information) .Enrich.WithProperty("Version", Version) .Enrich.WithProperty("InstanceName", Options.InstanceName) .Enrich.WithProperty("InvocationId", InvocationId) .Enrich.WithProperty("ProcessId", ProcessId) .Enrich.FromLogContext() .WriteTo.Console( outputTemplate: "[{SourceContext}] [{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}") .WriteTo.Async(config => config.File( Path.Combine(AppContext.BaseDirectory, "logs", $"{AppName}-.log"), outputTemplate: "[{SourceContext}] [{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}", rollingInterval: RollingInterval.Day)) .WriteTo.Conditional( e => !string.IsNullOrEmpty(Options.Logger.Loki), config => config.GrafanaLoki( Options.Logger.Loki ?? string.Empty, outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")) .CreateLogger(); } else { Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .MinimumLevel.Override("slskd.API.Authentication.PassthroughAuthenticationHandler", LogEventLevel.Information) .Enrich.WithProperty("Version", Version) .Enrich.WithProperty("InstanceName", Options.InstanceName) .Enrich.WithProperty("InvocationId", InvocationId) .Enrich.WithProperty("ProcessId", ProcessId) .Enrich.FromLogContext() .WriteTo.Console( outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}") .WriteTo.Async(config => config.File( Path.Combine(AppContext.BaseDirectory, "logs", $"{AppName}-.log"), outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}", rollingInterval: RollingInterval.Day)) .WriteTo.Conditional( e => !string.IsNullOrEmpty(Options.Logger.Loki), config => config.GrafanaLoki( Options.Logger.Loki ?? string.Empty, outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")) .CreateLogger(); } var logger = Log.ForContext(typeof(Program)); if (ConfigurationFile != DefaultConfigurationFile && !File.Exists(ConfigurationFile)) { logger.Warning($"Specified configuration file '{ConfigurationFile}' could not be found and was not loaded."); } logger.Information("Version: {Version}", Version); logger.Information("Instance Name: {InstanceName}", Options.InstanceName); logger.Information("Invocation ID: {InvocationId}", InvocationId); logger.Information("Process ID: {ProcessId}", ProcessId); if (!string.IsNullOrEmpty(Options.Logger.Loki)) { logger.Information("Forwarding logs to Grafana Loki instance at {LoggerLokiUrl}", Options.Logger.Loki); } try { if (Options.Feature.Prometheus) { using var runtimeMetrics = DotNetRuntimeStatsBuilder.Default().StartCollecting(); } WebHost.CreateDefaultBuilder(args) .SuppressStatusMessages(true) .ConfigureAppConfiguration((hostingContext, builder) => { builder.Sources.Clear(); builder.AddConfigurationProviders(EnvironmentVariablePrefix, ConfigurationFile); }) .UseSerilog() .UseUrls() .UseKestrel(options => { logger.Information($"Listening for HTTP requests at http://{IPAddress.Any}:{Options.Web.Port}/"); options.Listen(IPAddress.Any, Options.Web.Port); logger.Information($"Listening for HTTPS requests at https://{IPAddress.Any}:{Options.Web.Https.Port}/"); options.Listen(IPAddress.Any, Options.Web.Https.Port, listenOptions => { var cert = Options.Web.Https.Certificate; if (!string.IsNullOrEmpty(cert.Pfx)) { logger.Information($"Using certificate from {cert.Pfx}"); listenOptions.UseHttps(cert.Pfx, cert.Password); } else { logger.Information($"Using randomly generated self-signed certificate"); listenOptions.UseHttps(X509.Generate(subject: AppName)); } }); }) .UseStartup <Startup>() .Build() .Run(); } catch (Exception ex) { logger.Fatal(ex, "Application terminated unexpectedly"); } finally { Log.CloseAndFlush(); } }