Files
tiku-backend.net/Tiku.Api/Configuration/ExternalServiceOptionsExtensions.cs
xiong c497a3ca8d
Some checks failed
ci / release-gate (push) Has been cancelled
清理代码
2026-08-03 12:31:39 +08:00

115 lines
5.7 KiB
C#

using Microsoft.Extensions.Options;
using Tiku.Application.Auth;
using Tiku.Application.Storage;
using Tiku.Infrastructure.Assets;
using Tiku.Infrastructure.Commerce;
using Tiku.Infrastructure.Storage;
namespace Tiku.Api.Configuration;
internal static class ExternalServiceOptionsExtensions
{
internal static IServiceCollection AddExternalServiceOptions(
this IServiceCollection services,
IConfiguration configuration,
IHostEnvironment environment)
{
services.Configure<ObjectStorageOptions>(
configuration.GetSection(ObjectStorageOptions.SectionName));
services.Configure<AliyunOssOptions>(
configuration.GetSection(AliyunOssOptions.SectionName));
services.PostConfigure<ObjectStorageOptions>(options =>
{
options.DefaultProvider = configuration["STORAGE_DEFAULT_PROVIDER"] ?? options.DefaultProvider;
options.DefaultBucket = configuration["STORAGE_DEFAULT_BUCKET"] ?? options.DefaultBucket;
options.PublicBaseUrl = configuration["STORAGE_PUBLIC_BASE_URL"] ?? options.PublicBaseUrl;
options.AllowedMimePrefixes = SplitLegacyList(
configuration["STORAGE_ALLOWED_MIME_PREFIXES"],
options.AllowedMimePrefixes);
options.AllowedMimeTypes = SplitLegacyList(
configuration["STORAGE_ALLOWED_MIME_TYPES"],
options.AllowedMimeTypes);
options.RequireTenantPrefix = bool.TryParse(
configuration["STORAGE_REQUIRE_TENANT_PREFIX"],
out var requireTenantPrefix)
? requireTenantPrefix
: options.RequireTenantPrefix;
options.MaxUploadBytes = long.TryParse(
configuration["STORAGE_MAX_UPLOAD_BYTES"],
out var maxUploadBytes)
? maxUploadBytes
: options.MaxUploadBytes;
});
services.PostConfigure<AliyunOssOptions>(options =>
{
options.Region = configuration["ALIYUN_OSS_REGION"] ?? options.Region;
options.Endpoint = configuration["ALIYUN_OSS_ENDPOINT"] ?? options.Endpoint;
options.AccessKeyId = configuration["ALIYUN_OSS_ACCESS_KEY_ID"] ?? options.AccessKeyId;
options.AccessKeySecret = configuration["ALIYUN_OSS_ACCESS_KEY_SECRET"] ?? options.AccessKeySecret;
options.SecurityToken = configuration["ALIYUN_OSS_STS_TOKEN"] ?? options.SecurityToken;
options.UseInternalEndpoint = bool.TryParse(
configuration["ALIYUN_OSS_INTERNAL"],
out var useInternalEndpoint)
? useInternalEndpoint
: options.UseInternalEndpoint;
});
services.AddOptions<ObjectStorageOptions>()
.Validate(
options => !environment.IsProduction() ||
options.DefaultProvider == ObjectStorageProviders.AliyunOss,
"Production managed storage must use the configured Aliyun OSS provider.")
.ValidateOnStart();
services.AddOptions<AliyunOssOptions>()
.Validate<IOptions<ObjectStorageOptions>>(
(aliyun, storage) =>
!environment.IsProduction() ||
storage.Value.DefaultProvider != ObjectStorageProviders.AliyunOss ||
aliyun.IsConfigured,
"Aliyun OSS credentials and region or endpoint are required when it is the default provider.")
.ValidateOnStart();
services.AddOptions<ClamAvOptions>()
.Bind(configuration.GetSection(ClamAvOptions.SectionName))
.Validate(ClamAvOptions.BeValid, "ClamAV settings are invalid.")
.Validate<IOptions<ObjectStorageOptions>>(
(clamAv, storage) => clamAv.StreamMaxLength >= storage.Value.MaxUploadBytes,
"ClamAV StreamMaxLength must be greater than or equal to the storage max upload size.")
.ValidateOnStart();
services.AddOptions<TenantSecretEncryptionOptions>()
.Bind(configuration.GetSection(TenantSecretEncryptionOptions.SectionName))
.PostConfigure(options =>
{
options.KeyId = configuration["TIKU_TENANT_SECRET_KEY_ID"] ?? options.KeyId;
options.MasterKey = configuration["TIKU_TENANT_SECRET_MASTER_KEY"] ?? options.MasterKey;
})
.Validate(
TenantSecretEncryptionOptions.BeValid,
"Tenant secret encryption requires a key ID and a base64-encoded 32-byte master key.")
.Validate(
options => !environment.IsProduction() ||
!TenantSecretEncryptionOptions.IsDevelopmentDefault(options),
"Production tenant secret encryption cannot use the development master key.")
.ValidateOnStart();
services.AddOptions<SmsSecurityOptions>()
.Bind(configuration.GetSection(SmsSecurityOptions.SectionName))
.PostConfigure(options =>
{
options.CodePepper = configuration["TIKU_SMS_CODE_PEPPER"] ?? options.CodePepper;
})
.Validate(
SmsSecurityOptions.BeValid,
"SMS security requires a pepper of at least 32 characters, exactly five verification attempts, " +
"and positive tenant, phone, IP, and device rate limits.")
.ValidateOnStart();
return services;
}
private static string[] SplitLegacyList(string? value, string[] fallback)
{
return string.IsNullOrWhiteSpace(value)
? fallback
: value.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
}
}