diff --git a/src/Core/Settings/AmazonSettings.cs b/src/Core/Settings/AmazonSettings.cs new file mode 100644 index 000000000000..8ea867436e5d --- /dev/null +++ b/src/Core/Settings/AmazonSettings.cs @@ -0,0 +1,8 @@ +namespace Bit.Core.Settings; + +public class AmazonSettings +{ + public string AccessKeyId { get; set; } + public string AccessKeySecret { get; set; } + public string Region { get; set; } +} diff --git a/src/Core/Settings/AppleIapSettings.cs b/src/Core/Settings/AppleIapSettings.cs new file mode 100644 index 000000000000..c81b41322abe --- /dev/null +++ b/src/Core/Settings/AppleIapSettings.cs @@ -0,0 +1,7 @@ +namespace Bit.Core.Settings; + +public class AppleIapSettings +{ + public string Password { get; set; } + public bool AppInReview { get; set; } +} diff --git a/src/Core/Settings/BaseServiceUriSettings.cs b/src/Core/Settings/BaseServiceUriSettings.cs new file mode 100644 index 000000000000..96bcdf971b42 --- /dev/null +++ b/src/Core/Settings/BaseServiceUriSettings.cs @@ -0,0 +1,105 @@ +namespace Bit.Core.Settings; + +public class BaseServiceUriSettings : IBaseServiceUriSettings +{ + private readonly GlobalSettings _globalSettings; + + private string _api; + private string _identity; + private string _admin; + private string _notifications; + private string _sso; + private string _scim; + private string _internalApi; + private string _internalIdentity; + private string _internalAdmin; + private string _internalNotifications; + private string _internalSso; + private string _internalVault; + private string _internalScim; + private string _internalBilling; + + public BaseServiceUriSettings(GlobalSettings globalSettings) + { + _globalSettings = globalSettings; + } + + public string CloudRegion { get; set; } + public string Vault { get; set; } + public string VaultWithHash => $"{Vault}/#"; + + public string VaultWithHashAndSecretManagerProduct => $"{Vault}/#/sm"; + + public string Api + { + get => _globalSettings.InfrastructureResourceProvider.BuildExternalUri(_api, "api"); + set => _api = value; + } + public string Identity + { + get => _globalSettings.InfrastructureResourceProvider.BuildExternalUri(_identity, "identity"); + set => _identity = value; + } + public string Admin + { + get => _globalSettings.InfrastructureResourceProvider.BuildExternalUri(_admin, "admin"); + set => _admin = value; + } + public string Notifications + { + get => _globalSettings.InfrastructureResourceProvider.BuildExternalUri(_notifications, "notifications"); + set => _notifications = value; + } + public string Sso + { + get => _globalSettings.InfrastructureResourceProvider.BuildExternalUri(_sso, "sso"); + set => _sso = value; + } + public string Scim + { + get => _globalSettings.InfrastructureResourceProvider.BuildExternalUri(_scim, "scim"); + set => _scim = value; + } + + public string InternalNotifications + { + get => _globalSettings.InfrastructureResourceProvider.BuildInternalUri(_internalNotifications, "notifications"); + set => _internalNotifications = value; + } + public string InternalAdmin + { + get => _globalSettings.InfrastructureResourceProvider.BuildInternalUri(_internalAdmin, "admin"); + set => _internalAdmin = value; + } + public string InternalIdentity + { + get => _globalSettings.InfrastructureResourceProvider.BuildInternalUri(_internalIdentity, "identity"); + set => _internalIdentity = value; + } + public string InternalApi + { + get => _globalSettings.InfrastructureResourceProvider.BuildInternalUri(_internalApi, "api"); + set => _internalApi = value; + } + public string InternalVault + { + get => _globalSettings.InfrastructureResourceProvider.BuildInternalUri(_internalVault, "web"); + set => _internalVault = value; + } + public string InternalSso + { + get => _globalSettings.InfrastructureResourceProvider.BuildInternalUri(_internalSso, "sso"); + set => _internalSso = value; + } + public string InternalScim + { + get => _globalSettings.InfrastructureResourceProvider.BuildInternalUri(_scim, "scim"); + set => _internalScim = value; + } + + public string InternalBilling + { + get => _globalSettings.InfrastructureResourceProvider.BuildInternalUri(_internalBilling, "billing"); + set => _internalBilling = value; + } +} diff --git a/src/Core/Settings/BitPaySettings.cs b/src/Core/Settings/BitPaySettings.cs new file mode 100644 index 000000000000..80049c6ee541 --- /dev/null +++ b/src/Core/Settings/BitPaySettings.cs @@ -0,0 +1,8 @@ +namespace Bit.Core.Settings; + +public class BitPaySettings +{ + public bool Production { get; set; } + public string Token { get; set; } + public string NotificationUrl { get; set; } +} diff --git a/src/Core/Settings/BraintreeSettings.cs b/src/Core/Settings/BraintreeSettings.cs new file mode 100644 index 000000000000..3f5eac6996cf --- /dev/null +++ b/src/Core/Settings/BraintreeSettings.cs @@ -0,0 +1,9 @@ +namespace Bit.Core.Settings; + +public class BraintreeSettings +{ + public bool Production { get; set; } + public string MerchantId { get; set; } + public string PublicKey { get; set; } + public string PrivateKey { get; set; } +} diff --git a/src/Core/Settings/CaptchaSettings.cs b/src/Core/Settings/CaptchaSettings.cs new file mode 100644 index 000000000000..32a4ab1102c2 --- /dev/null +++ b/src/Core/Settings/CaptchaSettings.cs @@ -0,0 +1,11 @@ +namespace Bit.Core.Settings; + +public class CaptchaSettings +{ + public bool ForceCaptchaRequired { get; set; } = false; + public string HCaptchaSecretKey { get; set; } + public string HCaptchaSiteKey { get; set; } + public int MaximumFailedLoginAttempts { get; set; } + public double MaybeBotScoreThreshold { get; set; } = double.MaxValue; + public double IsBotScoreThreshold { get; set; } = double.MaxValue; +} diff --git a/src/Core/Settings/ConnectionStringSettings.cs b/src/Core/Settings/ConnectionStringSettings.cs new file mode 100644 index 000000000000..8407549bdc49 --- /dev/null +++ b/src/Core/Settings/ConnectionStringSettings.cs @@ -0,0 +1,12 @@ +namespace Bit.Core.Settings; + +public class ConnectionStringSettings : IConnectionStringSettings +{ + private string _connectionString; + + public string ConnectionString + { + get => _connectionString; + set => _connectionString = value.Trim('"'); + } +} diff --git a/src/Core/Settings/DataProtectionSettings.cs b/src/Core/Settings/DataProtectionSettings.cs new file mode 100644 index 000000000000..ddf03cb41cc9 --- /dev/null +++ b/src/Core/Settings/DataProtectionSettings.cs @@ -0,0 +1,21 @@ +namespace Bit.Core.Settings; + +public class DataProtectionSettings +{ + private readonly GlobalSettings _globalSettings; + + private string _directory; + + public DataProtectionSettings(GlobalSettings globalSettings) + { + _globalSettings = globalSettings; + } + + public string CertificateThumbprint { get; set; } + public string CertificatePassword { get; set; } + public string Directory + { + get => _globalSettings.InfrastructureResourceProvider.BuildDirectory(_directory, "/core/aspnet-dataprotection"); + set => _directory = value; + } +} diff --git a/src/Core/Settings/DistributedCacheSettings.cs b/src/Core/Settings/DistributedCacheSettings.cs new file mode 100644 index 000000000000..9193d66bcac8 --- /dev/null +++ b/src/Core/Settings/DistributedCacheSettings.cs @@ -0,0 +1,8 @@ +namespace Bit.Core.Settings; + +public class DistributedCacheSettings +{ + public virtual IConnectionStringSettings Redis { get; set; } = new ConnectionStringSettings(); + public virtual IConnectionStringSettings Cosmos { get; set; } = new ConnectionStringSettings(); +} + diff --git a/src/Core/Settings/DistributedIpRateLimitingSettings.cs b/src/Core/Settings/DistributedIpRateLimitingSettings.cs new file mode 100644 index 000000000000..8b4010a8d7a5 --- /dev/null +++ b/src/Core/Settings/DistributedIpRateLimitingSettings.cs @@ -0,0 +1,20 @@ +namespace Bit.Core.Settings; + +public class DistributedIpRateLimitingSettings +{ + public string RedisConnectionString { get; set; } + public bool Enabled { get; set; } = true; + + /// + /// Maximum number of Redis timeouts that can be experienced within the sliding timeout + /// window before IP rate limiting is temporarily disabled. + /// TODO: Determine/discuss a suitable maximum + /// + public int MaxRedisTimeoutsThreshold { get; set; } = 10; + + /// + /// Length of the sliding window in seconds to track Redis timeout exceptions. + /// TODO: Determine/discuss a suitable sliding window + /// + public int SlidingWindowSeconds { get; set; } = 120; +} diff --git a/src/Core/Settings/DomainVerificationSettings.cs b/src/Core/Settings/DomainVerificationSettings.cs new file mode 100644 index 000000000000..5091753cbb81 --- /dev/null +++ b/src/Core/Settings/DomainVerificationSettings.cs @@ -0,0 +1,8 @@ +namespace Bit.Core.Settings; + +public class DomainVerificationSettings : IDomainVerificationSettings +{ + public int VerificationInterval { get; set; } = 12; + public int ExpirationPeriod { get; set; } = 7; +} + diff --git a/src/Core/Settings/DuoSettings.cs b/src/Core/Settings/DuoSettings.cs new file mode 100644 index 000000000000..163b25c68ed9 --- /dev/null +++ b/src/Core/Settings/DuoSettings.cs @@ -0,0 +1,7 @@ +namespace Bit.Core.Settings; + +public class DuoSettings +{ + public string AKey { get; set; } +} + diff --git a/src/Core/Settings/EventLoggingSettings.cs b/src/Core/Settings/EventLoggingSettings.cs new file mode 100644 index 000000000000..8571c2146f2a --- /dev/null +++ b/src/Core/Settings/EventLoggingSettings.cs @@ -0,0 +1,62 @@ +namespace Bit.Core.Settings; + +public class EventLoggingSettings +{ + public AzureServiceBusSettings AzureServiceBus { get; set; } = new AzureServiceBusSettings(); + public virtual string WebhookUrl { get; set; } + public RabbitMqSettings RabbitMq { get; set; } = new RabbitMqSettings(); + + public class AzureServiceBusSettings + { + private string _connectionString; + private string _topicName; + + public virtual string EventRepositorySubscriptionName { get; set; } = "events-write-subscription"; + public virtual string WebhookSubscriptionName { get; set; } = "events-webhook-subscription"; + + public string ConnectionString + { + get => _connectionString; + set => _connectionString = value.Trim('"'); + } + + public string TopicName + { + get => _topicName; + set => _topicName = value.Trim('"'); + } + } + + public class RabbitMqSettings + { + private string _hostName; + private string _username; + private string _password; + private string _exchangeName; + + public virtual string EventRepositoryQueueName { get; set; } = "events-write-queue"; + public virtual string WebhookQueueName { get; set; } = "events-webhook-queue"; + + public string HostName + { + get => _hostName; + set => _hostName = value.Trim('"'); + } + public string Username + { + get => _username; + set => _username = value.Trim('"'); + } + public string Password + { + get => _password; + set => _password = value.Trim('"'); + } + public string ExchangeName + { + get => _exchangeName; + set => _exchangeName = value.Trim('"'); + } + } +} + diff --git a/src/Core/Settings/FileStorageSettings.cs b/src/Core/Settings/FileStorageSettings.cs new file mode 100644 index 000000000000..2366053eaa02 --- /dev/null +++ b/src/Core/Settings/FileStorageSettings.cs @@ -0,0 +1,36 @@ +namespace Bit.Core.Settings; + +public class FileStorageSettings : IFileStorageSettings +{ + private readonly GlobalSettings _globalSettings; + private readonly string _urlName; + private readonly string _directoryName; + private string _connectionString; + private string _baseDirectory; + private string _baseUrl; + + public FileStorageSettings(GlobalSettings globalSettings, string urlName, string directoryName) + { + _globalSettings = globalSettings; + _urlName = urlName; + _directoryName = directoryName; + } + + public string ConnectionString + { + get => _connectionString; + set => _connectionString = value.Trim('"'); + } + + public string BaseDirectory + { + get => _globalSettings.InfrastructureResourceProvider.BuildDirectory(_baseDirectory, string.Concat("/core/", _directoryName)); + set => _baseDirectory = value; + } + + public string BaseUrl + { + get => _globalSettings.InfrastructureResourceProvider.BuildExternalUri(_baseUrl, _urlName); + set => _baseUrl = value; + } +} diff --git a/src/Core/Settings/GlobalSettings.cs b/src/Core/Settings/GlobalSettings.cs index 6bb76eb50a5e..d3a7943ee9e1 100644 --- a/src/Core/Settings/GlobalSettings.cs +++ b/src/Core/Settings/GlobalSettings.cs @@ -3,7 +3,7 @@ namespace Bit.Core.Settings; -public class GlobalSettings : IGlobalSettings +public partial class GlobalSettings : IGlobalSettings { private string _logDirectory; private string _licenseDirectory; @@ -14,6 +14,7 @@ public GlobalSettings() Attachment = new FileStorageSettings(this, "attachments", "attachments"); Send = new FileStorageSettings(this, "attachments/send", "attachments/send"); DataProtection = new DataProtectionSettings(this); + InfrastructureResourceProvider = new InfrastructureResourceProvider(this); } public bool SelfHosted { get; set; } @@ -23,7 +24,7 @@ public GlobalSettings() public virtual string ProjectName { get; set; } public virtual string LogDirectory { - get => BuildDirectory(_logDirectory, "/logs"); + get => InfrastructureResourceProvider.BuildDirectory(_logDirectory, "/logs"); set => _logDirectory = value; } public virtual bool LogDirectoryByProject { get; set; } = true; @@ -31,7 +32,7 @@ public virtual string LogDirectory public virtual bool EnableDevLogging { get; set; } = false; public virtual string LicenseDirectory { - get => BuildDirectory(_licenseDirectory, "/core/licenses"); + get => InfrastructureResourceProvider.BuildDirectory(_licenseDirectory, "/core/licenses"); set => _licenseDirectory = value; } public string LicenseCertificatePassword { get; set; } @@ -88,600 +89,5 @@ public virtual string LicenseDirectory public virtual bool EnableEmailVerification { get; set; } public virtual string KdfDefaultHashKey { get; set; } public virtual string PricingUri { get; set; } - - public string BuildExternalUri(string explicitValue, string name) - { - if (!string.IsNullOrWhiteSpace(explicitValue)) - { - return explicitValue; - } - if (!SelfHosted) - { - return null; - } - return string.Format("{0}/{1}", BaseServiceUri.Vault, name); - } - - public string BuildInternalUri(string explicitValue, string name) - { - if (!string.IsNullOrWhiteSpace(explicitValue)) - { - return explicitValue; - } - if (!SelfHosted) - { - return null; - } - return string.Format("http://{0}:5000", name); - } - - public string BuildDirectory(string explicitValue, string appendedPath) - { - if (!string.IsNullOrWhiteSpace(explicitValue)) - { - return explicitValue; - } - if (!SelfHosted) - { - return null; - } - return string.Concat("/etc/bitwarden", appendedPath); - } - - public class BaseServiceUriSettings : IBaseServiceUriSettings - { - private readonly GlobalSettings _globalSettings; - - private string _api; - private string _identity; - private string _admin; - private string _notifications; - private string _sso; - private string _scim; - private string _internalApi; - private string _internalIdentity; - private string _internalAdmin; - private string _internalNotifications; - private string _internalSso; - private string _internalVault; - private string _internalScim; - private string _internalBilling; - - public BaseServiceUriSettings(GlobalSettings globalSettings) - { - _globalSettings = globalSettings; - } - - public string CloudRegion { get; set; } - public string Vault { get; set; } - public string VaultWithHash => $"{Vault}/#"; - - public string VaultWithHashAndSecretManagerProduct => $"{Vault}/#/sm"; - - public string Api - { - get => _globalSettings.BuildExternalUri(_api, "api"); - set => _api = value; - } - public string Identity - { - get => _globalSettings.BuildExternalUri(_identity, "identity"); - set => _identity = value; - } - public string Admin - { - get => _globalSettings.BuildExternalUri(_admin, "admin"); - set => _admin = value; - } - public string Notifications - { - get => _globalSettings.BuildExternalUri(_notifications, "notifications"); - set => _notifications = value; - } - public string Sso - { - get => _globalSettings.BuildExternalUri(_sso, "sso"); - set => _sso = value; - } - public string Scim - { - get => _globalSettings.BuildExternalUri(_scim, "scim"); - set => _scim = value; - } - - public string InternalNotifications - { - get => _globalSettings.BuildInternalUri(_internalNotifications, "notifications"); - set => _internalNotifications = value; - } - public string InternalAdmin - { - get => _globalSettings.BuildInternalUri(_internalAdmin, "admin"); - set => _internalAdmin = value; - } - public string InternalIdentity - { - get => _globalSettings.BuildInternalUri(_internalIdentity, "identity"); - set => _internalIdentity = value; - } - public string InternalApi - { - get => _globalSettings.BuildInternalUri(_internalApi, "api"); - set => _internalApi = value; - } - public string InternalVault - { - get => _globalSettings.BuildInternalUri(_internalVault, "web"); - set => _internalVault = value; - } - public string InternalSso - { - get => _globalSettings.BuildInternalUri(_internalSso, "sso"); - set => _internalSso = value; - } - public string InternalScim - { - get => _globalSettings.BuildInternalUri(_scim, "scim"); - set => _internalScim = value; - } - - public string InternalBilling - { - get => _globalSettings.BuildInternalUri(_internalBilling, "billing"); - set => _internalBilling = value; - } - } - - public class SqlSettings - { - private string _connectionString; - private string _readOnlyConnectionString; - private string _jobSchedulerConnectionString; - public bool SkipDatabasePreparation { get; set; } - public bool DisableDatabaseMaintenanceJobs { get; set; } - - public string ConnectionString - { - get => _connectionString; - set - { - // On development environment, the self-hosted overrides would not override the read-only connection string, since it is already set from the non-self-hosted connection string. - // This causes a bug, where the read-only connection string is pointing to self-hosted database. - if (!string.IsNullOrWhiteSpace(_readOnlyConnectionString) && - _readOnlyConnectionString == _connectionString) - { - _readOnlyConnectionString = null; - } - - _connectionString = value.Trim('"'); - } - } - - public string ReadOnlyConnectionString - { - get => string.IsNullOrWhiteSpace(_readOnlyConnectionString) ? - _connectionString : _readOnlyConnectionString; - set => _readOnlyConnectionString = value.Trim('"'); - } - - public string JobSchedulerConnectionString - { - get => _jobSchedulerConnectionString; - set => _jobSchedulerConnectionString = value.Trim('"'); - } - } - - public class EventLoggingSettings - { - public AzureServiceBusSettings AzureServiceBus { get; set; } = new AzureServiceBusSettings(); - public virtual string WebhookUrl { get; set; } - public RabbitMqSettings RabbitMq { get; set; } = new RabbitMqSettings(); - - public class AzureServiceBusSettings - { - private string _connectionString; - private string _topicName; - - public virtual string EventRepositorySubscriptionName { get; set; } = "events-write-subscription"; - public virtual string WebhookSubscriptionName { get; set; } = "events-webhook-subscription"; - - public string ConnectionString - { - get => _connectionString; - set => _connectionString = value.Trim('"'); - } - - public string TopicName - { - get => _topicName; - set => _topicName = value.Trim('"'); - } - } - - public class RabbitMqSettings - { - private string _hostName; - private string _username; - private string _password; - private string _exchangeName; - - public virtual string EventRepositoryQueueName { get; set; } = "events-write-queue"; - public virtual string WebhookQueueName { get; set; } = "events-webhook-queue"; - - public string HostName - { - get => _hostName; - set => _hostName = value.Trim('"'); - } - public string Username - { - get => _username; - set => _username = value.Trim('"'); - } - public string Password - { - get => _password; - set => _password = value.Trim('"'); - } - public string ExchangeName - { - get => _exchangeName; - set => _exchangeName = value.Trim('"'); - } - } - } - - public class ConnectionStringSettings : IConnectionStringSettings - { - private string _connectionString; - - public string ConnectionString - { - get => _connectionString; - set => _connectionString = value.Trim('"'); - } - } - - public class FileStorageSettings : IFileStorageSettings - { - private readonly GlobalSettings _globalSettings; - private readonly string _urlName; - private readonly string _directoryName; - private string _connectionString; - private string _baseDirectory; - private string _baseUrl; - - public FileStorageSettings(GlobalSettings globalSettings, string urlName, string directoryName) - { - _globalSettings = globalSettings; - _urlName = urlName; - _directoryName = directoryName; - } - - public string ConnectionString - { - get => _connectionString; - set => _connectionString = value.Trim('"'); - } - - public string BaseDirectory - { - get => _globalSettings.BuildDirectory(_baseDirectory, string.Concat("/core/", _directoryName)); - set => _baseDirectory = value; - } - - public string BaseUrl - { - get => _globalSettings.BuildExternalUri(_baseUrl, _urlName); - set => _baseUrl = value; - } - } - - public class MailSettings - { - private ConnectionStringSettings _connectionStringSettings; - public string ConnectionString - { - get => _connectionStringSettings?.ConnectionString; - set - { - if (_connectionStringSettings == null) - { - _connectionStringSettings = new ConnectionStringSettings(); - } - _connectionStringSettings.ConnectionString = value; - } - } - public string ReplyToEmail { get; set; } - public string AmazonConfigSetName { get; set; } - public SmtpSettings Smtp { get; set; } = new SmtpSettings(); - public string SendGridApiKey { get; set; } - public int? SendGridPercentage { get; set; } - - public class SmtpSettings - { - public string Host { get; set; } - public int Port { get; set; } = 25; - public bool StartTls { get; set; } = false; - public bool Ssl { get; set; } = false; - public bool SslOverride { get; set; } = false; - public string Username { get; set; } - public string Password { get; set; } - public bool TrustServer { get; set; } = false; - } - } - - public class IdentityServerSettings - { - public string CertificateThumbprint { get; set; } - public string CertificatePassword { get; set; } - public string RedisConnectionString { get; set; } - public string CosmosConnectionString { get; set; } - public string LicenseKey { get; set; } = "eyJhbGciOiJQUzI1NiIsImtpZCI6IklkZW50aXR5U2VydmVyTGljZW5zZWtleS83Y2VhZGJiNzgxMzA0NjllODgwNjg5MTAyNTQxNGYxNiIsInR5cCI6ImxpY2Vuc2Urand0In0.eyJpc3MiOiJodHRwczovL2R1ZW5kZXNvZnR3YXJlLmNvbSIsImF1ZCI6IklkZW50aXR5U2VydmVyIiwiaWF0IjoxNzM0NTY2NDAwLCJleHAiOjE3NjQ5NzkyMDAsImNvbXBhbnlfbmFtZSI6IkJpdHdhcmRlbiBJbmMuIiwiY29udGFjdF9pbmZvIjoiY29udGFjdEBkdWVuZGVzb2Z0d2FyZS5jb20iLCJlZGl0aW9uIjoiU3RhcnRlciIsImlkIjoiNjg3OCIsImZlYXR1cmUiOlsiaXN2IiwidW5saW1pdGVkX2NsaWVudHMiXSwicHJvZHVjdCI6IkJpdHdhcmRlbiJ9.TYc88W_t2t0F2AJV3rdyKwGyQKrKFriSAzm1tWFNHNR9QizfC-8bliGdT4Wgeie-ynCXs9wWaF-sKC5emg--qS7oe2iIt67Qd88WS53AwgTvAddQRA4NhGB1R7VM8GAikLieSos-DzzwLYRgjZdmcsprItYGSJuY73r-7-F97ta915majBytVxGF966tT9zF1aYk0bA8FS6DcDYkr5f7Nsy8daS_uIUAgNa_agKXtmQPqKujqtUb6rgWEpSp4OcQcG-8Dpd5jHqoIjouGvY-5LTgk5WmLxi_m-1QISjxUJrUm-UGao3_VwV5KFGqYrz8csdTl-HS40ihWcsWnrV0ug"; - } - - public class DataProtectionSettings - { - private readonly GlobalSettings _globalSettings; - - private string _directory; - - public DataProtectionSettings(GlobalSettings globalSettings) - { - _globalSettings = globalSettings; - } - - public string CertificateThumbprint { get; set; } - public string CertificatePassword { get; set; } - public string Directory - { - get => _globalSettings.BuildDirectory(_directory, "/core/aspnet-dataprotection"); - set => _directory = value; - } - } - - public class SentrySettings - { - public string Dsn { get; set; } - } - - public class NotificationsSettings : ConnectionStringSettings - { - public string RedisConnectionString { get; set; } - } - - public class SyslogSettings - { - /// - /// The connection string used to connect to a remote syslog server over TCP or UDP, or to connect locally. - /// - /// - /// The connection string will be parsed using to extract the protocol, host name and port number. - /// - /// - /// Supported protocols are: - /// - /// UDP (use udp://) - /// TCP (use tcp://) - /// TLS over TCP (use tls://) - /// - /// - /// - /// - /// A remote server (logging.dev.example.com) is listening on UDP (port 514): - /// - /// udp://logging.dev.example.com:514. - /// - public string Destination { get; set; } - /// - /// The absolute path to a Certificate (DER or Base64 encoded with private key). - /// - /// - /// The certificate path and are passed into the . - /// The file format of the certificate may be binary encoded (DER) or base64. If the private key is encrypted, provide the password in , - /// - public string CertificatePath { get; set; } - /// - /// The password for the encrypted private key in the certificate supplied in . - /// - /// - public string CertificatePassword { get; set; } - /// - /// The thumbprint of the certificate in the X.509 certificate store for personal certificates for the user account running Bitwarden. - /// - /// - public string CertificateThumbprint { get; set; } - } - - public class NotificationHubSettings - { - private string _connectionString; - - public string ConnectionString - { - get => _connectionString; - set => _connectionString = value?.Trim('"'); - } - public string HubName { get; set; } - /// - /// Enables TestSend on the Azure Notification Hub, which allows tracing of the request through the hub and to the platform-specific push notification service (PNS). - /// Enabling this will result in delayed responses because the Hub must wait on delivery to the PNS. This should ONLY be enabled in a non-production environment, as results are throttled. - /// - public bool EnableSendTracing { get; set; } = false; - /// - /// The date and time at which registration will be enabled. - /// - /// **This value should not be updated once set, as it is used to determine installation location of devices.** - /// - /// If null, registration is disabled. - /// - /// - public DateTime? RegistrationStartDate { get; set; } - /// - /// The date and time at which registration will be disabled. - /// - /// **This value should not be updated once set, as it is used to determine installation location of devices.** - /// - /// If null, hub registration has no yet known expiry. - /// - public DateTime? RegistrationEndDate { get; set; } - } - - public class NotificationHubPoolSettings - { - /// - /// List of Notification Hub settings to use for sending push notifications. - /// - /// Note that hubs on the same namespace share active device limits, so multiple namespaces should be used to increase capacity. - /// - public List NotificationHubs { get; set; } = new(); - } - - public class YubicoSettings - { - public string ClientId { get; set; } - public string Key { get; set; } - public string[] ValidationUrls { get; set; } - } - - public class DuoSettings - { - public string AKey { get; set; } - } - - public class BraintreeSettings - { - public bool Production { get; set; } - public string MerchantId { get; set; } - public string PublicKey { get; set; } - public string PrivateKey { get; set; } - } - - public class ImportCiphersLimitationSettings - { - public int CiphersLimit { get; set; } - public int CollectionRelationshipsLimit { get; set; } - public int CollectionsLimit { get; set; } - } - - public class BitPaySettings - { - public bool Production { get; set; } - public string Token { get; set; } - public string NotificationUrl { get; set; } - } - - public class InstallationSettings : IInstallationSettings - { - private string _identityUri; - private string _apiUri; - - public Guid Id { get; set; } - public string Key { get; set; } - public string IdentityUri - { - get => string.IsNullOrWhiteSpace(_identityUri) ? "https://identity.bitwarden.com" : _identityUri; - set => _identityUri = value; - } - public string ApiUri - { - get => string.IsNullOrWhiteSpace(_apiUri) ? "https://api.bitwarden.com" : _apiUri; - set => _apiUri = value; - } - - } - - public class AmazonSettings - { - public string AccessKeyId { get; set; } - public string AccessKeySecret { get; set; } - public string Region { get; set; } - } - - public class ServiceBusSettings : ConnectionStringSettings - { - public string ApplicationCacheTopicName { get; set; } - public string ApplicationCacheSubscriptionName { get; set; } - public string WebSiteInstanceId { get; set; } - } - - public class AppleIapSettings - { - public string Password { get; set; } - public bool AppInReview { get; set; } - } - - public class SsoSettings : ISsoSettings - { - public int CacheLifetimeInSeconds { get; set; } = 60; - public double SsoTokenLifetimeInSeconds { get; set; } = 5; - public bool EnforceSsoPolicyForAllUsers { get; set; } - } - - public class CaptchaSettings - { - public bool ForceCaptchaRequired { get; set; } = false; - public string HCaptchaSecretKey { get; set; } - public string HCaptchaSiteKey { get; set; } - public int MaximumFailedLoginAttempts { get; set; } - public double MaybeBotScoreThreshold { get; set; } = double.MaxValue; - public double IsBotScoreThreshold { get; set; } = double.MaxValue; - } - - public class StripeSettings - { - public string ApiKey { get; set; } - public int MaxNetworkRetries { get; set; } = 2; - } - - public class DistributedIpRateLimitingSettings - { - public string RedisConnectionString { get; set; } - public bool Enabled { get; set; } = true; - - /// - /// Maximum number of Redis timeouts that can be experienced within the sliding timeout - /// window before IP rate limiting is temporarily disabled. - /// TODO: Determine/discuss a suitable maximum - /// - public int MaxRedisTimeoutsThreshold { get; set; } = 10; - - /// - /// Length of the sliding window in seconds to track Redis timeout exceptions. - /// TODO: Determine/discuss a suitable sliding window - /// - public int SlidingWindowSeconds { get; set; } = 120; - } - - public class PasswordlessAuthSettings : IPasswordlessAuthSettings - { - public bool KnownDevicesOnly { get; set; } = true; - public TimeSpan UserRequestExpiration { get; set; } = TimeSpan.FromMinutes(15); - public TimeSpan AdminRequestExpiration { get; set; } = TimeSpan.FromDays(7); - public TimeSpan AfterAdminApprovalExpiration { get; set; } = TimeSpan.FromHours(12); - } - - public class DomainVerificationSettings : IDomainVerificationSettings - { - public int VerificationInterval { get; set; } = 12; - public int ExpirationPeriod { get; set; } = 7; - } - - public class LaunchDarklySettings : ILaunchDarklySettings - { - public string SdkKey { get; set; } - public string FlagDataFilePath { get; set; } = "flags.json"; - public Dictionary FlagValues { get; set; } = new Dictionary(); - } - - public class DistributedCacheSettings - { - public virtual IConnectionStringSettings Redis { get; set; } = new ConnectionStringSettings(); - public virtual IConnectionStringSettings Cosmos { get; set; } = new ConnectionStringSettings(); - } - - public class WebPushSettings : IWebPushSettings - { - public string VapidPublicKey { get; set; } - } + public virtual IInfrastructureResourceProvider InfrastructureResourceProvider { get; set; } } diff --git a/src/Core/Settings/IGlobalSettings.cs b/src/Core/Settings/IGlobalSettings.cs index 411014ea3291..0b99b86d794d 100644 --- a/src/Core/Settings/IGlobalSettings.cs +++ b/src/Core/Settings/IGlobalSettings.cs @@ -25,8 +25,9 @@ public interface IGlobalSettings IDomainVerificationSettings DomainVerification { get; set; } ILaunchDarklySettings LaunchDarkly { get; set; } string DatabaseProvider { get; set; } - GlobalSettings.SqlSettings SqlServer { get; set; } + SqlSettings SqlServer { get; set; } string DevelopmentDirectory { get; set; } IWebPushSettings WebPush { get; set; } - GlobalSettings.EventLoggingSettings EventLogging { get; set; } + EventLoggingSettings EventLogging { get; set; } + IInfrastructureResourceProvider InfrastructureResourceProvider { get; set; } } diff --git a/src/Core/Settings/IInfrastructureResourceProvider.cs b/src/Core/Settings/IInfrastructureResourceProvider.cs new file mode 100644 index 000000000000..ba5e69dae7dc --- /dev/null +++ b/src/Core/Settings/IInfrastructureResourceProvider.cs @@ -0,0 +1,8 @@ +namespace Bit.Core.Settings; + +public interface IInfrastructureResourceProvider +{ + string BuildExternalUri(string explicitValue, string name); + string BuildInternalUri(string explicitValue, string name); + string BuildDirectory(string explicitValue, string appendedPath); +} diff --git a/src/Core/Settings/IdentityServerSettings.cs b/src/Core/Settings/IdentityServerSettings.cs new file mode 100644 index 000000000000..a8e321ab94aa --- /dev/null +++ b/src/Core/Settings/IdentityServerSettings.cs @@ -0,0 +1,10 @@ +namespace Bit.Core.Settings; + +public class IdentityServerSettings +{ + public string CertificateThumbprint { get; set; } + public string CertificatePassword { get; set; } + public string RedisConnectionString { get; set; } + public string CosmosConnectionString { get; set; } + public string LicenseKey { get; set; } = "eyJhbGciOiJQUzI1NiIsImtpZCI6IklkZW50aXR5U2VydmVyTGljZW5zZWtleS83Y2VhZGJiNzgxMzA0NjllODgwNjg5MTAyNTQxNGYxNiIsInR5cCI6ImxpY2Vuc2Urand0In0.eyJpc3MiOiJodHRwczovL2R1ZW5kZXNvZnR3YXJlLmNvbSIsImF1ZCI6IklkZW50aXR5U2VydmVyIiwiaWF0IjoxNzM0NTY2NDAwLCJleHAiOjE3NjQ5NzkyMDAsImNvbXBhbnlfbmFtZSI6IkJpdHdhcmRlbiBJbmMuIiwiY29udGFjdF9pbmZvIjoiY29udGFjdEBkdWVuZGVzb2Z0d2FyZS5jb20iLCJlZGl0aW9uIjoiU3RhcnRlciIsImlkIjoiNjg3OCIsImZlYXR1cmUiOlsiaXN2IiwidW5saW1pdGVkX2NsaWVudHMiXSwicHJvZHVjdCI6IkJpdHdhcmRlbiJ9.TYc88W_t2t0F2AJV3rdyKwGyQKrKFriSAzm1tWFNHNR9QizfC-8bliGdT4Wgeie-ynCXs9wWaF-sKC5emg--qS7oe2iIt67Qd88WS53AwgTvAddQRA4NhGB1R7VM8GAikLieSos-DzzwLYRgjZdmcsprItYGSJuY73r-7-F97ta915majBytVxGF966tT9zF1aYk0bA8FS6DcDYkr5f7Nsy8daS_uIUAgNa_agKXtmQPqKujqtUb6rgWEpSp4OcQcG-8Dpd5jHqoIjouGvY-5LTgk5WmLxi_m-1QISjxUJrUm-UGao3_VwV5KFGqYrz8csdTl-HS40ihWcsWnrV0ug"; +} diff --git a/src/Core/Settings/ImportCiphersLimitationSettings.cs b/src/Core/Settings/ImportCiphersLimitationSettings.cs new file mode 100644 index 000000000000..044a64f714b1 --- /dev/null +++ b/src/Core/Settings/ImportCiphersLimitationSettings.cs @@ -0,0 +1,8 @@ +namespace Bit.Core.Settings; + +public class ImportCiphersLimitationSettings +{ + public int CiphersLimit { get; set; } + public int CollectionRelationshipsLimit { get; set; } + public int CollectionsLimit { get; set; } +} diff --git a/src/Core/Settings/InfrastructureResourceProvider.cs b/src/Core/Settings/InfrastructureResourceProvider.cs new file mode 100644 index 000000000000..e89ee11e1d41 --- /dev/null +++ b/src/Core/Settings/InfrastructureResourceProvider.cs @@ -0,0 +1,50 @@ +namespace Bit.Core.Settings; + +public class InfrastructureResourceProvider : IInfrastructureResourceProvider +{ + private readonly GlobalSettings _globalSettings; + + public InfrastructureResourceProvider(GlobalSettings globalSettings) + { + _globalSettings = globalSettings; + } + + public string BuildExternalUri(string explicitValue, string name) + { + if (!string.IsNullOrWhiteSpace(explicitValue)) + { + return explicitValue; + } + if (!_globalSettings.SelfHosted) + { + return null; + } + return string.Format("{0}/{1}", _globalSettings.BaseServiceUri.Vault, name); + } + + public string BuildInternalUri(string explicitValue, string name) + { + if (!string.IsNullOrWhiteSpace(explicitValue)) + { + return explicitValue; + } + if (!_globalSettings.SelfHosted) + { + return null; + } + return string.Format("http://{0}:5000", name); + } + + public string BuildDirectory(string explicitValue, string appendedPath) + { + if (!string.IsNullOrWhiteSpace(explicitValue)) + { + return explicitValue; + } + if (!_globalSettings.SelfHosted) + { + return null; + } + return string.Concat("/etc/bitwarden", appendedPath); + } +} diff --git a/src/Core/Settings/InstallationSettings.cs b/src/Core/Settings/InstallationSettings.cs new file mode 100644 index 000000000000..c10ececb4ab3 --- /dev/null +++ b/src/Core/Settings/InstallationSettings.cs @@ -0,0 +1,21 @@ +namespace Bit.Core.Settings; + +public class InstallationSettings : IInstallationSettings +{ + private string _identityUri; + private string _apiUri; + + public Guid Id { get; set; } + public string Key { get; set; } + public string IdentityUri + { + get => string.IsNullOrWhiteSpace(_identityUri) ? "https://identity.bitwarden.com" : _identityUri; + set => _identityUri = value; + } + public string ApiUri + { + get => string.IsNullOrWhiteSpace(_apiUri) ? "https://api.bitwarden.com" : _apiUri; + set => _apiUri = value; + } + +} diff --git a/src/Core/Settings/LaunchDarklySettings.cs b/src/Core/Settings/LaunchDarklySettings.cs new file mode 100644 index 000000000000..12130c161c62 --- /dev/null +++ b/src/Core/Settings/LaunchDarklySettings.cs @@ -0,0 +1,8 @@ +namespace Bit.Core.Settings; + +public class LaunchDarklySettings : ILaunchDarklySettings +{ + public string SdkKey { get; set; } + public string FlagDataFilePath { get; set; } = "flags.json"; + public Dictionary FlagValues { get; set; } = new Dictionary(); +} diff --git a/src/Core/Settings/MailSettings.cs b/src/Core/Settings/MailSettings.cs new file mode 100644 index 000000000000..8c66ea809089 --- /dev/null +++ b/src/Core/Settings/MailSettings.cs @@ -0,0 +1,36 @@ +namespace Bit.Core.Settings; + +public class MailSettings +{ + private ConnectionStringSettings _connectionStringSettings; + public string ConnectionString + { + get => _connectionStringSettings?.ConnectionString; + set + { + if (_connectionStringSettings == null) + { + _connectionStringSettings = new ConnectionStringSettings(); + } + _connectionStringSettings.ConnectionString = value; + } + } + public string ReplyToEmail { get; set; } + public string AmazonConfigSetName { get; set; } + public SmtpSettings Smtp { get; set; } = new SmtpSettings(); + public string SendGridApiKey { get; set; } + public int? SendGridPercentage { get; set; } + + public class SmtpSettings + { + public string Host { get; set; } + public int Port { get; set; } = 25; + public bool StartTls { get; set; } = false; + public bool Ssl { get; set; } = false; + public bool SslOverride { get; set; } = false; + public string Username { get; set; } + public string Password { get; set; } + public bool TrustServer { get; set; } = false; + } +} + diff --git a/src/Core/Settings/NotificationHubPoolSettings.cs b/src/Core/Settings/NotificationHubPoolSettings.cs new file mode 100644 index 000000000000..43075eea1906 --- /dev/null +++ b/src/Core/Settings/NotificationHubPoolSettings.cs @@ -0,0 +1,11 @@ +namespace Bit.Core.Settings; + +public class NotificationHubPoolSettings +{ + /// + /// List of Notification Hub settings to use for sending push notifications. + /// + /// Note that hubs on the same namespace share active device limits, so multiple namespaces should be used to increase capacity. + /// + public List NotificationHubs { get; set; } = new(); +} diff --git a/src/Core/Settings/NotificationHubSettings.cs b/src/Core/Settings/NotificationHubSettings.cs new file mode 100644 index 000000000000..17c747affa79 --- /dev/null +++ b/src/Core/Settings/NotificationHubSettings.cs @@ -0,0 +1,36 @@ +namespace Bit.Core.Settings; + +public class NotificationHubSettings +{ + private string _connectionString; + + public string ConnectionString + { + get => _connectionString; + set => _connectionString = value?.Trim('"'); + } + public string HubName { get; set; } + /// + /// Enables TestSend on the Azure Notification Hub, which allows tracing of the request through the hub and to the platform-specific push notification service (PNS). + /// Enabling this will result in delayed responses because the Hub must wait on delivery to the PNS. This should ONLY be enabled in a non-production environment, as results are throttled. + /// + public bool EnableSendTracing { get; set; } = false; + /// + /// The date and time at which registration will be enabled. + /// + /// **This value should not be updated once set, as it is used to determine installation location of devices.** + /// + /// If null, registration is disabled. + /// + /// + public DateTime? RegistrationStartDate { get; set; } + /// + /// The date and time at which registration will be disabled. + /// + /// **This value should not be updated once set, as it is used to determine installation location of devices.** + /// + /// If null, hub registration has no yet known expiry. + /// + public DateTime? RegistrationEndDate { get; set; } +} + diff --git a/src/Core/Settings/NotificationsSettings.cs b/src/Core/Settings/NotificationsSettings.cs new file mode 100644 index 000000000000..9f85a0b4a993 --- /dev/null +++ b/src/Core/Settings/NotificationsSettings.cs @@ -0,0 +1,6 @@ +namespace Bit.Core.Settings; + +public class NotificationsSettings : ConnectionStringSettings +{ + public string RedisConnectionString { get; set; } +} diff --git a/src/Core/Settings/PasswordlessAuthSettings.cs b/src/Core/Settings/PasswordlessAuthSettings.cs new file mode 100644 index 000000000000..9d38a24fc858 --- /dev/null +++ b/src/Core/Settings/PasswordlessAuthSettings.cs @@ -0,0 +1,12 @@ +using Bit.Core.Auth.Settings; + +namespace Bit.Core.Settings; + +public class PasswordlessAuthSettings : IPasswordlessAuthSettings +{ + public bool KnownDevicesOnly { get; set; } = true; + public TimeSpan UserRequestExpiration { get; set; } = TimeSpan.FromMinutes(15); + public TimeSpan AdminRequestExpiration { get; set; } = TimeSpan.FromDays(7); + public TimeSpan AfterAdminApprovalExpiration { get; set; } = TimeSpan.FromHours(12); +} + diff --git a/src/Core/Settings/SentrySettings.cs b/src/Core/Settings/SentrySettings.cs new file mode 100644 index 000000000000..9345486750c0 --- /dev/null +++ b/src/Core/Settings/SentrySettings.cs @@ -0,0 +1,7 @@ +namespace Bit.Core.Settings; + +public class SentrySettings +{ + public string Dsn { get; set; } +} + diff --git a/src/Core/Settings/ServiceBusSettings.cs b/src/Core/Settings/ServiceBusSettings.cs new file mode 100644 index 000000000000..0d9a2001b313 --- /dev/null +++ b/src/Core/Settings/ServiceBusSettings.cs @@ -0,0 +1,8 @@ +namespace Bit.Core.Settings; +public class ServiceBusSettings : ConnectionStringSettings +{ + public string ApplicationCacheTopicName { get; set; } + public string ApplicationCacheSubscriptionName { get; set; } + public string WebSiteInstanceId { get; set; } +} + diff --git a/src/Core/Settings/SqlSettings.cs b/src/Core/Settings/SqlSettings.cs new file mode 100644 index 000000000000..58f4a40d8b90 --- /dev/null +++ b/src/Core/Settings/SqlSettings.cs @@ -0,0 +1,41 @@ +namespace Bit.Core.Settings; + +public class SqlSettings +{ + private string _connectionString; + private string _readOnlyConnectionString; + private string _jobSchedulerConnectionString; + public bool SkipDatabasePreparation { get; set; } + public bool DisableDatabaseMaintenanceJobs { get; set; } + + public string ConnectionString + { + get => _connectionString; + set + { + // On development environment, the self-hosted overrides would not override the read-only connection string, since it is already set from the non-self-hosted connection string. + // This causes a bug, where the read-only connection string is pointing to self-hosted database. + if (!string.IsNullOrWhiteSpace(_readOnlyConnectionString) && + _readOnlyConnectionString == _connectionString) + { + _readOnlyConnectionString = null; + } + + _connectionString = value.Trim('"'); + } + } + + public string ReadOnlyConnectionString + { + get => string.IsNullOrWhiteSpace(_readOnlyConnectionString) ? + _connectionString : _readOnlyConnectionString; + set => _readOnlyConnectionString = value.Trim('"'); + } + + public string JobSchedulerConnectionString + { + get => _jobSchedulerConnectionString; + set => _jobSchedulerConnectionString = value.Trim('"'); + } +} + diff --git a/src/Core/Settings/SsoSettings.cs b/src/Core/Settings/SsoSettings.cs new file mode 100644 index 000000000000..0b213e60dd2a --- /dev/null +++ b/src/Core/Settings/SsoSettings.cs @@ -0,0 +1,8 @@ +namespace Bit.Core.Settings; +public class SsoSettings : ISsoSettings +{ + public int CacheLifetimeInSeconds { get; set; } = 60; + public double SsoTokenLifetimeInSeconds { get; set; } = 5; + public bool EnforceSsoPolicyForAllUsers { get; set; } +} + diff --git a/src/Core/Settings/StripeSettings.cs b/src/Core/Settings/StripeSettings.cs new file mode 100644 index 000000000000..3a9ae66facd4 --- /dev/null +++ b/src/Core/Settings/StripeSettings.cs @@ -0,0 +1,6 @@ +namespace Bit.Core.Settings; +public class StripeSettings +{ + public string ApiKey { get; set; } + public int MaxNetworkRetries { get; set; } = 2; +} diff --git a/src/Core/Settings/SyslogSettings.cs b/src/Core/Settings/SyslogSettings.cs new file mode 100644 index 000000000000..dfd1f75d57a6 --- /dev/null +++ b/src/Core/Settings/SyslogSettings.cs @@ -0,0 +1,44 @@ +namespace Bit.Core.Settings; +public class SyslogSettings +{ + /// + /// The connection string used to connect to a remote syslog server over TCP or UDP, or to connect locally. + /// + /// + /// The connection string will be parsed using to extract the protocol, host name and port number. + /// + /// + /// Supported protocols are: + /// + /// UDP (use udp://) + /// TCP (use tcp://) + /// TLS over TCP (use tls://) + /// + /// + /// + /// + /// A remote server (logging.dev.example.com) is listening on UDP (port 514): + /// + /// udp://logging.dev.example.com:514. + /// + public string Destination { get; set; } + /// + /// The absolute path to a Certificate (DER or Base64 encoded with private key). + /// + /// + /// The certificate path and are passed into the . + /// The file format of the certificate may be binary encoded (DER) or base64. If the private key is encrypted, provide the password in , + /// + public string CertificatePath { get; set; } + /// + /// The password for the encrypted private key in the certificate supplied in . + /// + /// + public string CertificatePassword { get; set; } + /// + /// The thumbprint of the certificate in the X.509 certificate store for personal certificates for the user account running Bitwarden. + /// + /// + public string CertificateThumbprint { get; set; } +} + diff --git a/src/Core/Settings/WebPushSettings.cs b/src/Core/Settings/WebPushSettings.cs new file mode 100644 index 000000000000..ee6ea59e1164 --- /dev/null +++ b/src/Core/Settings/WebPushSettings.cs @@ -0,0 +1,7 @@ +namespace Bit.Core.Settings; + +public class WebPushSettings : IWebPushSettings +{ + public string VapidPublicKey { get; set; } +} + diff --git a/src/Core/Settings/YubicoSettings.cs b/src/Core/Settings/YubicoSettings.cs new file mode 100644 index 000000000000..f97aad7003c5 --- /dev/null +++ b/src/Core/Settings/YubicoSettings.cs @@ -0,0 +1,9 @@ +namespace Bit.Core.Settings; + +public class YubicoSettings +{ + public string ClientId { get; set; } + public string Key { get; set; } + public string[] ValidationUrls { get; set; } +} +