diff --git a/Iceshrimp.Backend/Core/Configuration/Config.cs b/Iceshrimp.Backend/Core/Configuration/Config.cs index e72602c0..bec80eae 100644 --- a/Iceshrimp.Backend/Core/Configuration/Config.cs +++ b/Iceshrimp.Backend/Core/Configuration/Config.cs @@ -88,13 +88,14 @@ public sealed class Config public sealed class DatabaseSection { - [Required] public string Host { get; init; } = "localhost"; - [Range(1, 65535)] public int Port { get; init; } = 5432; - [Required] public string Database { get; init; } = null!; - [Required] public string Username { get; init; } = null!; - public string? Password { get; init; } - [Range(1, 1000)] public int MaxConnections { get; init; } = 100; - public bool Multiplexing { get; init; } = false; + [Required] public string Host { get; init; } = "localhost"; + [Range(1, 65535)] public int Port { get; init; } = 5432; + [Required] public string Database { get; init; } = null!; + [Required] public string Username { get; init; } = null!; + public string? Password { get; init; } + [Range(1, 1000)] public int MaxConnections { get; init; } = 100; + public bool Multiplexing { get; init; } = false; + public bool ParameterLogging { get; init; } = false; } public sealed class StorageSection diff --git a/Iceshrimp.Backend/Core/Database/DatabaseContext.cs b/Iceshrimp.Backend/Core/Database/DatabaseContext.cs index 088aef79..d83fa16d 100644 --- a/Iceshrimp.Backend/Core/Database/DatabaseContext.cs +++ b/Iceshrimp.Backend/Core/Database/DatabaseContext.cs @@ -91,25 +91,28 @@ public class DatabaseContext(DbContextOptions options) public virtual DbSet Filters { get; init; } = null!; public virtual DbSet DataProtectionKeys { get; init; } = null!; - public static NpgsqlDataSource GetDataSource(Config.DatabaseSection? config) + public static NpgsqlDataSource GetDataSource(Config.DatabaseSection config) { - var dataSourceBuilder = new NpgsqlDataSourceBuilder(); + var dataSourceBuilder = new NpgsqlDataSourceBuilder + { + ConnectionStringBuilder = + { + Host = config.Host, + Port = config.Port, + Username = config.Username, + Password = config.Password, + Database = config.Database, + MaxPoolSize = config.MaxConnections, + Multiplexing = config.Multiplexing + } + }; - if (config == null) - throw new Exception("Failed to initialize database: Failed to load configuration"); - - dataSourceBuilder.ConnectionStringBuilder.Host = config.Host; - dataSourceBuilder.ConnectionStringBuilder.Port = config.Port; - dataSourceBuilder.ConnectionStringBuilder.Username = config.Username; - dataSourceBuilder.ConnectionStringBuilder.Password = config.Password; - dataSourceBuilder.ConnectionStringBuilder.Database = config.Database; - dataSourceBuilder.ConnectionStringBuilder.MaxPoolSize = config.MaxConnections; - dataSourceBuilder.ConnectionStringBuilder.Multiplexing = config.Multiplexing; - - return ConfigureDataSource(dataSourceBuilder); + return ConfigureDataSource(dataSourceBuilder, config); } - public static NpgsqlDataSource ConfigureDataSource(NpgsqlDataSourceBuilder dataSourceBuilder) + private static NpgsqlDataSource ConfigureDataSource( + NpgsqlDataSourceBuilder dataSourceBuilder, Config.DatabaseSection config + ) { dataSourceBuilder.MapEnum(); dataSourceBuilder.MapEnum(); @@ -125,14 +128,22 @@ public class DatabaseContext(DbContextOptions options) dataSourceBuilder.EnableDynamicJson(); + if (config.ParameterLogging) + dataSourceBuilder.EnableParameterLogging(); + return dataSourceBuilder.Build(); } - public static void Configure(DbContextOptionsBuilder optionsBuilder, NpgsqlDataSource dataSource) + public static void Configure( + DbContextOptionsBuilder optionsBuilder, NpgsqlDataSource dataSource, Config.DatabaseSection config + ) { optionsBuilder.UseNpgsql(dataSource); optionsBuilder.UseProjectables(options => { options.CompatibilityMode(CompatibilityMode.Full); }); optionsBuilder.UseExceptionProcessor(); + + if (config.ParameterLogging) + optionsBuilder.EnableSensitiveDataLogging(); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -1292,10 +1303,12 @@ public class DesignTimeDatabaseContextFactory : IDesignTimeDbContextFactory(); + var config = configuration.GetSection("Database").Get() ?? + throw new Exception("Failed to initialize database: Failed to load configuration"); + var dataSource = DatabaseContext.GetDataSource(config); var builder = new DbContextOptionsBuilder(); - DatabaseContext.Configure(builder, dataSource); + DatabaseContext.Configure(builder, dataSource, config); return new DatabaseContext(builder.Options); } } \ No newline at end of file diff --git a/Iceshrimp.Backend/Core/Extensions/ServiceExtensions.cs b/Iceshrimp.Backend/Core/Extensions/ServiceExtensions.cs index 230671be..aec3dc56 100644 --- a/Iceshrimp.Backend/Core/Extensions/ServiceExtensions.cs +++ b/Iceshrimp.Backend/Core/Extensions/ServiceExtensions.cs @@ -159,9 +159,11 @@ public static class ServiceExtensions public static void AddDatabaseContext(this IServiceCollection services, IConfiguration configuration) { - var config = configuration.GetSection("Database").Get(); + var config = configuration.GetSection("Database").Get() ?? + throw new Exception("Failed to initialize database: Failed to load configuration"); + var dataSource = DatabaseContext.GetDataSource(config); - services.AddDbContext(options => { DatabaseContext.Configure(options, dataSource); }); + services.AddDbContext(options => { DatabaseContext.Configure(options, dataSource, config); }); services.AddKeyedDatabaseContext("cache"); services.AddDataProtection() .PersistKeysToDbContextAsync() diff --git a/Iceshrimp.Backend/configuration.ini b/Iceshrimp.Backend/configuration.ini index aaf9e893..a1aafe65 100644 --- a/Iceshrimp.Backend/configuration.ini +++ b/Iceshrimp.Backend/configuration.ini @@ -102,6 +102,10 @@ MaxConnections = 100 ;; Whether to enable connection multiplexing, which allows for more efficient use of the connection pool. Multiplexing = false +;; Whether to log parameter information on errors. +;; Caution: this may contain sensitive information, it's recommended to keep this disabled except for debugging purposes +ParameterLogging = false + [Storage] ;; Where to store media attachments ;; Options: [Local, ObjectStorage]