添加自动下载ssl证书
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -41,7 +41,7 @@ namespace Hua.DDNS.Test.Start
|
||||
services.AddSingleton<Url>();
|
||||
services.AddSingleton<SqlHelper>();
|
||||
services.AddTransient<IHttpHelper, HttpHelper>();
|
||||
services.AddTransient<AppJob>();
|
||||
services.AddTransient<NewJob>();
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
}
|
||||
|
||||
10
Hua.DDNS/Common/Config/Options/AliCloudOption.cs
Normal file
10
Hua.DDNS/Common/Config/Options/AliCloudOption.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Hua.DDNS.Common.Config.Options
|
||||
{
|
||||
public class AliCloudOption
|
||||
{
|
||||
public string AccessKeyId { get; set; }
|
||||
public string AccessKeySecret { get; set; }
|
||||
public string RegionId { get; set; }
|
||||
public string Endpoint { get; set; }
|
||||
}
|
||||
}
|
||||
24
Hua.DDNS/Common/Config/Options/SslDownloadOption.cs
Normal file
24
Hua.DDNS/Common/Config/Options/SslDownloadOption.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Hua.DDNS.Common.Config.Options
|
||||
{
|
||||
public enum SslPlatformEnum
|
||||
{
|
||||
Ali = 1,
|
||||
Tencent = 2
|
||||
}
|
||||
|
||||
public class SslDownloadOption
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public string Corn { get; set; }
|
||||
public SslPlatformEnum Platform { get; set; }
|
||||
public string SavePath { get; set; }
|
||||
public int ExpireDays { get; set; }
|
||||
public List<SslDownloadItem> DownloadItems { get; set; }
|
||||
}
|
||||
|
||||
public class SslDownloadItem
|
||||
{
|
||||
public string Domain { get; set; }
|
||||
public string FileName { get; set; }
|
||||
}
|
||||
}
|
||||
12
Hua.DDNS/Common/Config/Options/TencentCloudOption.cs
Normal file
12
Hua.DDNS/Common/Config/Options/TencentCloudOption.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Hua.DDNS.DDNSProviders.Dnspod;
|
||||
|
||||
namespace Hua.DDNS.Common.Config.Options
|
||||
{
|
||||
public class TencentCloudOption
|
||||
{
|
||||
public string SecretId { get; set; }
|
||||
public string SecretKey { get; set; }
|
||||
public string Region { get; set; }
|
||||
public DnspodOption Dnspod { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,12 @@ namespace Hua.DDNS.Common.Http
|
||||
{
|
||||
private static ILogger<HttpHelper> _logger;
|
||||
private static HttpClientHandler _handler;
|
||||
private IConfiguration _configuration;
|
||||
|
||||
public HttpHelper(ILogger<HttpHelper> logger)
|
||||
public HttpHelper(ILogger<HttpHelper> logger, IConfiguration configuration)
|
||||
{
|
||||
_logger = logger;
|
||||
_configuration = configuration;
|
||||
_handler = new HttpClientHandler();
|
||||
}
|
||||
|
||||
@@ -85,31 +87,45 @@ namespace Hua.DDNS.Common.Http
|
||||
#region 下载文件
|
||||
|
||||
/// <summary>
|
||||
/// http下载文件 (仅支持小文件)
|
||||
/// http下载文件
|
||||
/// </summary>
|
||||
/// <param name="url">下载文件地址</param>
|
||||
/// <param name="localPath">文件存放地址,包含文件名</param>
|
||||
/// <returns></returns>
|
||||
public bool DownloadFile(string url, string localPath)
|
||||
{
|
||||
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
|
||||
|
||||
var request = WebRequest.Create(url) as HttpWebRequest;
|
||||
Stream stream = new FileStream(localPath, FileMode.CreateNew);
|
||||
try
|
||||
{
|
||||
// 设置参数
|
||||
//发送请求并获取相应回应数据
|
||||
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
|
||||
|
||||
var request = WebRequest.Create(url) as HttpWebRequest;
|
||||
var response = request?.GetResponse() as HttpWebResponse;
|
||||
//直到request.GetResponse()程序才开始向目标网页发送Post请求
|
||||
var responseStream = response?.GetResponseStream();
|
||||
//创建本地文件写入流
|
||||
stream.Close();
|
||||
responseStream?.Close();
|
||||
|
||||
if (responseStream == null)
|
||||
{
|
||||
_logger.LogError($"下载文件失败: {url}, 无法获取响应流");
|
||||
return false;
|
||||
}
|
||||
|
||||
var directory = Path.GetDirectoryName(localPath);
|
||||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
using var fileStream = new FileStream(localPath, FileMode.Create);
|
||||
responseStream.CopyTo(fileStream);
|
||||
fileStream.Close();
|
||||
responseStream.Close();
|
||||
response?.Close();
|
||||
|
||||
_logger.LogInformation($"文件下载成功: {url} -> {localPath}");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"下载文件失败: {url}, 错误: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -123,7 +139,7 @@ namespace Hua.DDNS.Common.Http
|
||||
public async Task<string> GetCurrentPublicIpv4()
|
||||
{
|
||||
using var client = new HttpClient();
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, "http://175.24.175.136:8008/WebUtil/GetIp");
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, _configuration["App:GetIpv4Url"]);
|
||||
using var response = await client.SendAsync(request);
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
|
||||
@@ -1,25 +1,9 @@
|
||||
namespace Hua.DDNS.DDNSProviders.Ali
|
||||
namespace Hua.DDNS.DDNSProviders.Ali
|
||||
{
|
||||
/// <summary>
|
||||
/// domain configuration Ali
|
||||
/// </summary>
|
||||
public class AliDdnsOption
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Id, the id and key from DnsPod
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Key
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Endpoint
|
||||
/// </summary>
|
||||
public string Endpoint { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -21,24 +21,22 @@ namespace Hua.DDNS.DDNSProviders.Ali
|
||||
public class AliDdnsProvider : IDdnsProvider
|
||||
{
|
||||
private readonly Client _client;
|
||||
private readonly AliDdnsOption _aliDDNSOption;
|
||||
private readonly AliCloudOption _aliCloudOption;
|
||||
private readonly DdnsOption _ddnsOption;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public AliDdnsProvider(IOptions<AliDdnsOption> aliDDNSOption, IMapper mapper,IOptions<DdnsOption> ddnsOption)
|
||||
public AliDdnsProvider(IOptions<AliCloudOption> aliCloudOption, IMapper mapper,IOptions<DdnsOption> ddnsOption)
|
||||
{
|
||||
_aliDDNSOption = aliDDNSOption.Value;
|
||||
_aliCloudOption = aliCloudOption.Value;
|
||||
_ddnsOption = ddnsOption.Value;
|
||||
_mapper = mapper;
|
||||
|
||||
|
||||
_client = new Client(new Config()
|
||||
{
|
||||
// 您的 AccessKey ID
|
||||
AccessKeyId = _aliDDNSOption.Id,
|
||||
// 您的 AccessKey Secret
|
||||
AccessKeySecret = _aliDDNSOption.Key,
|
||||
Endpoint = _aliDDNSOption.Endpoint,//alidns.cn-beijing.aliyuncs.com
|
||||
AccessKeyId = _aliCloudOption.AccessKeyId,
|
||||
AccessKeySecret = _aliCloudOption.AccessKeySecret,
|
||||
Endpoint = _aliCloudOption.Endpoint,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Hua.DDNS.DDNSProviders.Ali;
|
||||
using Hua.DDNS.Common.Config.Options;
|
||||
using Hua.DDNS.Models;
|
||||
using Microsoft.Extensions.Options;
|
||||
using TencentCloud.Common.Profile;
|
||||
@@ -25,26 +25,22 @@ namespace Hua.DDNS.DDNSProviders.Dnspod
|
||||
{
|
||||
|
||||
private readonly DnspodClient _client;
|
||||
private readonly DnspodOption _dnspodOption;
|
||||
private readonly TencentCloudOption _tencentCloudOption;
|
||||
private readonly DdnsOption _ddnsOption;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public DnspodDdnsProvider(IMapper mapper, IOptions<DnspodOption> dnspodOption, IOptions<DdnsOption> ddnsOption)
|
||||
public DnspodDdnsProvider(IMapper mapper, IOptions<TencentCloudOption> tencentCloudOption, IOptions<DdnsOption> ddnsOption)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_dnspodOption = dnspodOption.Value;
|
||||
_tencentCloudOption = tencentCloudOption.Value;
|
||||
_ddnsOption = ddnsOption.Value;
|
||||
|
||||
_client = new DnspodClient(
|
||||
// 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密
|
||||
// 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
|
||||
new Credential { SecretId = _dnspodOption.Id, SecretKey = _dnspodOption.Key },
|
||||
new Credential { SecretId = _tencentCloudOption.SecretId, SecretKey = _tencentCloudOption.SecretKey },
|
||||
"",
|
||||
// 实例化一个client选项,可选的,没有特殊需求可以跳过
|
||||
new ClientProfile()
|
||||
{
|
||||
// 实例化一个http选项,可选的,没有特殊需求可以跳过
|
||||
HttpProfile = new HttpProfile { Endpoint = (_dnspodOption.Endpoint) }//"dnspod.tencentcloudapi.com"
|
||||
HttpProfile = new HttpProfile { Endpoint = _tencentCloudOption.Dnspod.Endpoint }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,13 @@
|
||||
namespace Hua.DDNS.DDNSProviders.Dnspod
|
||||
namespace Hua.DDNS.DDNSProviders.Dnspod
|
||||
{
|
||||
/// <summary>
|
||||
/// domain configuration Dnspod
|
||||
/// </summary>
|
||||
public class DnspodOption
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Id, the id and key from AliCould or DnsPod
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Key
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Endpoint dnspod.tencentcloudapi.com
|
||||
/// </summary>
|
||||
public string Endpoint { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS base
|
||||
USER app
|
||||
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
#Depending on the operating system of the host machines(s) that will build or run the containers, the image specified in the FROM statement may need to be changed.
|
||||
#For more information, please see https://aka.ms/containercompat
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
|
||||
WORKDIR /app
|
||||
#EXPOSE 8080
|
||||
#EXPOSE 8081
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
COPY ["Hua.DDNS/Hua.DDNS.csproj", "Hua.DDNS/"]
|
||||
RUN dotnet restore "./Hua.DDNS/Hua.DDNS.csproj"
|
||||
COPY ["/Hua.DDNS.csproj", "Hua.DDNS/"]
|
||||
RUN dotnet restore "Hua.DDNS/Hua.DDNS.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/Hua.DDNS"
|
||||
RUN dotnet build "./Hua.DDNS.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||
WORKDIR "/Hua.DDNS"
|
||||
RUN dotnet build "Hua.DDNS.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
RUN dotnet publish "./Hua.DDNS.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=true
|
||||
RUN dotnet publish "Hua.DDNS.csproj" -c Release -o /app/publish
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AlibabaCloud.SDK.Alidns20150109" Version="3.5.0" />
|
||||
<PackageReference Include="AlibabaCloud.SDK.Cas20200407" Version="3.0.4" />
|
||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
|
||||
<PackageReference Include="Hua.DotNet.Code" Version="0.0.15" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
||||
@@ -28,6 +29,7 @@
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="TencentCloudSDK.Dnspod" Version="3.0.1024" />
|
||||
<PackageReference Include="TencentCloudSDK.Ssl" Version="3.0.1371" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
133
Hua.DDNS/Jobs/SslDownloadJob.cs
Normal file
133
Hua.DDNS/Jobs/SslDownloadJob.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using Hua.DDNS.Common.Config.Options;
|
||||
using Hua.DDNS.SslProviders;
|
||||
using Hua.DDNS.SslProviders.Ali;
|
||||
using Hua.DDNS.SslProviders.Tencent;
|
||||
using Quartz;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Hua.DDNS.Jobs
|
||||
{
|
||||
[DisallowConcurrentExecution]
|
||||
public class SslDownloadJob : IJob, IDisposable
|
||||
{
|
||||
private readonly ILogger<SslDownloadJob> _logger;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly SslDownloadOption _sslDownloadOption;
|
||||
|
||||
public SslDownloadJob(
|
||||
ILogger<SslDownloadJob> logger,
|
||||
IServiceProvider serviceProvider,
|
||||
IOptions<SslDownloadOption> sslDownloadOption)
|
||||
{
|
||||
_logger = logger;
|
||||
_serviceProvider = serviceProvider;
|
||||
_sslDownloadOption = sslDownloadOption.Value;
|
||||
}
|
||||
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
if (!_sslDownloadOption.Enabled)
|
||||
{
|
||||
_logger.LogInformation("SSL下载任务已禁用,跳过执行");
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("开始SSL文件下载任务");
|
||||
|
||||
try
|
||||
{
|
||||
ISslDownloadProvider? sslProvider = _sslDownloadOption.Platform switch
|
||||
{
|
||||
SslPlatformEnum.Ali => _serviceProvider.GetService(typeof(AliSslProvider)) as ISslDownloadProvider,
|
||||
SslPlatformEnum.Tencent => _serviceProvider.GetService(typeof(TencentSslProvider)) as ISslDownloadProvider,
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (sslProvider == null)
|
||||
{
|
||||
_logger.LogError($"未找到 SSL 下载提供者: {_sslDownloadOption.Platform}");
|
||||
return;
|
||||
}
|
||||
;
|
||||
if (!Directory.Exists(_sslDownloadOption.SavePath))
|
||||
{
|
||||
Directory.CreateDirectory(_sslDownloadOption.SavePath);
|
||||
_logger.LogInformation($"创建目录: {_sslDownloadOption.SavePath}");
|
||||
}
|
||||
|
||||
var certificates = await sslProvider.GetCertificatesAsync();
|
||||
var downloadTasks = new List<Task>();
|
||||
|
||||
foreach (var item in _sslDownloadOption.DownloadItems)
|
||||
{
|
||||
var matchingCertificates = certificates.Where(c => c.Domain == item.Domain).ToList();
|
||||
|
||||
if (matchingCertificates.Count == 0)
|
||||
{
|
||||
_logger.LogWarning($"未找到域名 {item.Domain} 的证书,跳过下载");
|
||||
continue;
|
||||
}
|
||||
|
||||
var certificate = matchingCertificates.OrderByDescending(c => c.CertEndTime).First();
|
||||
|
||||
var daysUntilExpiry = (certificate.CertEndTime - DateTime.Now).Days;
|
||||
|
||||
if (daysUntilExpiry <= _sslDownloadOption.ExpireDays)
|
||||
{
|
||||
_logger.LogInformation($"证书 {certificate.CertificateId} ({certificate.Domain}) 将在 {daysUntilExpiry} 天后过期,开始下载");
|
||||
downloadTasks.Add(DownloadFileAsync(sslProvider, item, certificate.CertificateId, certificate.Domain));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation($"证书 {certificate.CertificateId} ({certificate.Domain}) 还有 {daysUntilExpiry} 天过期,跳过下载");
|
||||
}
|
||||
}
|
||||
|
||||
await Task.WhenAll(downloadTasks);
|
||||
|
||||
_logger.LogInformation($"SSL文件下载任务完成,共下载 {downloadTasks.Count} 个文件");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "SSL文件下载任务执行失败");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DownloadFileAsync(ISslDownloadProvider provider, SslDownloadItem item, string certificateId, string domain)
|
||||
{
|
||||
try
|
||||
{
|
||||
var domainPath = Path.Combine(_sslDownloadOption.SavePath, domain);
|
||||
|
||||
if (!Directory.Exists(domainPath))
|
||||
{
|
||||
Directory.CreateDirectory(domainPath);
|
||||
_logger.LogInformation($"创建域名目录: {domainPath}");
|
||||
}
|
||||
|
||||
var localPath = Path.Combine(domainPath, item.FileName);
|
||||
_logger.LogInformation($"开始下载证书: {certificateId} -> {localPath}");
|
||||
|
||||
var success = await provider.DownloadCertificateAsync(certificateId, domainPath, item.FileName);
|
||||
|
||||
if (success)
|
||||
{
|
||||
_logger.LogInformation($"证书下载成功: {domain}/{item.FileName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError($"证书下载失败: {domain}/{item.FileName}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"下载证书时发生错误: {item.FileName}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_logger.LogInformation("SslDownloadJob已销毁");
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Hua.DDNS/SslProviders/Ali/AliSslOption.cs
Normal file
9
Hua.DDNS/SslProviders/Ali/AliSslOption.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Hua.DDNS.SslProviders.Ali
|
||||
{
|
||||
public class AliSslOption
|
||||
{
|
||||
public string AccessKeyId { get; set; }
|
||||
public string AccessKeySecret { get; set; }
|
||||
public string Endpoint { get; set; }
|
||||
}
|
||||
}
|
||||
62
Hua.DDNS/SslProviders/Ali/AliSslProvider.cs
Normal file
62
Hua.DDNS/SslProviders/Ali/AliSslProvider.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using AlibabaCloud.SDK.Cas20200407;
|
||||
using AlibabaCloud.SDK.Cas20200407.Models;
|
||||
using AlibabaCloud.OpenApiClient.Models;
|
||||
using Hua.DDNS.Common.Config.Options;
|
||||
using Hua.DDNS.SslProviders;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Hua.DDNS.SslProviders.Ali
|
||||
{
|
||||
public class AliSslProvider : ISslDownloadProvider
|
||||
{
|
||||
private readonly Client _client;
|
||||
private readonly AliCloudOption _aliCloudOption;
|
||||
private readonly ILogger<AliSslProvider> _logger;
|
||||
|
||||
public AliSslProvider(
|
||||
ILogger<AliSslProvider> logger,
|
||||
IOptions<AliCloudOption> aliCloudOption)
|
||||
{
|
||||
_logger = logger;
|
||||
_aliCloudOption = aliCloudOption.Value;
|
||||
|
||||
var config = new Config
|
||||
{
|
||||
AccessKeyId = _aliCloudOption.AccessKeyId,
|
||||
AccessKeySecret = _aliCloudOption.AccessKeySecret,
|
||||
Endpoint = _aliCloudOption.Endpoint
|
||||
};
|
||||
|
||||
_client = new Client(config);
|
||||
}
|
||||
|
||||
public async Task<List<SslCertificate>> GetCertificatesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogWarning("阿里云 SSL 证书列表功能待实现");
|
||||
return new List<SslCertificate>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "获取阿里云 SSL 证书列表失败");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DownloadCertificateAsync(string certificateId, string savePath, string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogWarning($"阿里云 SSL 证书下载功能待实现: {certificateId}");
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"下载证书失败: {certificateId}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Hua.DDNS/SslProviders/ISslDownloadProvider.cs
Normal file
19
Hua.DDNS/SslProviders/ISslDownloadProvider.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace Hua.DDNS.SslProviders
|
||||
{
|
||||
public interface ISslDownloadProvider
|
||||
{
|
||||
Task<List<SslCertificate>> GetCertificatesAsync();
|
||||
Task<bool> DownloadCertificateAsync(string certificateId, string savePath, string fileName);
|
||||
}
|
||||
|
||||
public class SslCertificate
|
||||
{
|
||||
public string CertificateId { get; set; }
|
||||
public string Domain { get; set; }
|
||||
public string Alias { get; set; }
|
||||
public DateTime CertBeginTime { get; set; }
|
||||
public DateTime CertEndTime { get; set; }
|
||||
public int Status { get; set; }
|
||||
public string StatusMsg { get; set; }
|
||||
}
|
||||
}
|
||||
11
Hua.DDNS/SslProviders/Tencent/TencentSslOption.cs
Normal file
11
Hua.DDNS/SslProviders/Tencent/TencentSslOption.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Hua.DDNS.Common.Config.Options;
|
||||
|
||||
namespace Hua.DDNS.SslProviders.Tencent
|
||||
{
|
||||
public class TencentSslOption
|
||||
{
|
||||
public string SecretId { get; set; }
|
||||
public string SecretKey { get; set; }
|
||||
public string Region { get; set; }
|
||||
}
|
||||
}
|
||||
176
Hua.DDNS/SslProviders/Tencent/TencentSslProvider.cs
Normal file
176
Hua.DDNS/SslProviders/Tencent/TencentSslProvider.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using Hua.DDNS.Common.Config.Options;
|
||||
using Hua.DDNS.SslProviders;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using TencentCloud.Common;
|
||||
using TencentCloud.Common.Profile;
|
||||
using TencentCloud.Ssl.V20191205;
|
||||
using TencentCloud.Ssl.V20191205.Models;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace Hua.DDNS.SslProviders.Tencent
|
||||
{
|
||||
public class TencentSslProvider : ISslDownloadProvider
|
||||
{
|
||||
private readonly SslClient _client;
|
||||
private readonly TencentCloudOption _tencentCloudOption;
|
||||
private readonly ILogger<TencentSslProvider> _logger;
|
||||
|
||||
public TencentSslProvider(
|
||||
ILogger<TencentSslProvider> logger,
|
||||
IOptions<TencentCloudOption> tencentCloudOption)
|
||||
{
|
||||
_logger = logger;
|
||||
_tencentCloudOption = tencentCloudOption.Value;
|
||||
|
||||
_client = new SslClient(
|
||||
new Credential { SecretId = _tencentCloudOption.SecretId, SecretKey = _tencentCloudOption.SecretKey },
|
||||
_tencentCloudOption.Region,
|
||||
new ClientProfile()
|
||||
{
|
||||
HttpProfile = new HttpProfile { Endpoint = "ssl.tencentcloudapi.com" }
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<List<SslCertificate>> GetCertificatesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = new DescribeCertificatesRequest
|
||||
{
|
||||
Limit = 100,
|
||||
Offset = 0
|
||||
};
|
||||
|
||||
var response = await _client.DescribeCertificates(request);
|
||||
var certificates = new List<SslCertificate>();
|
||||
|
||||
if (response.Certificates != null)
|
||||
{
|
||||
foreach (var cert in response.Certificates)
|
||||
{
|
||||
certificates.Add(new SslCertificate
|
||||
{
|
||||
CertificateId = cert.CertificateId,
|
||||
Domain = cert.Domain,
|
||||
Alias = cert.Alias,
|
||||
CertBeginTime = DateTime.Parse(cert.CertBeginTime),
|
||||
CertEndTime = DateTime.Parse(cert.CertEndTime),
|
||||
Status = (int)(cert.Status ?? 0),
|
||||
StatusMsg = cert.StatusMsg
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation($"获取到 {certificates.Count} 个腾讯云 SSL 证书");
|
||||
return certificates;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "获取腾讯云 SSL 证书列表失败");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DownloadCertificateAsync(string certificateId, string savePath, string fileName)
|
||||
{
|
||||
string tempZipPath = null;
|
||||
string tempExtractPath = null;
|
||||
|
||||
try
|
||||
{
|
||||
var request = new DownloadCertificateRequest
|
||||
{
|
||||
CertificateId = certificateId
|
||||
};
|
||||
|
||||
var response = await _client.DownloadCertificate(request);
|
||||
|
||||
if (response == null || string.IsNullOrEmpty(response.Content))
|
||||
{
|
||||
_logger.LogError($"证书内容为空: {certificateId}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var zipBytes = Convert.FromBase64String(response.Content);
|
||||
|
||||
if (!Directory.Exists(savePath))
|
||||
{
|
||||
Directory.CreateDirectory(savePath);
|
||||
}
|
||||
|
||||
tempZipPath = Path.Combine(Path.GetTempPath(), $"ssl_{Guid.NewGuid()}.zip");
|
||||
await File.WriteAllBytesAsync(tempZipPath, zipBytes);
|
||||
_logger.LogInformation($"证书ZIP文件临时保存成功: {tempZipPath}");
|
||||
|
||||
tempExtractPath = Path.Combine(Path.GetTempPath(), $"ssl_extract_{Guid.NewGuid()}");
|
||||
ZipFile.ExtractToDirectory(tempZipPath, tempExtractPath);
|
||||
_logger.LogInformation($"证书ZIP文件解压成功: {tempExtractPath}");
|
||||
|
||||
var nginxPath = Path.Combine(tempExtractPath, "Nginx");
|
||||
if (!Directory.Exists(nginxPath))
|
||||
{
|
||||
_logger.LogError($"ZIP文件中未找到Nginx目录");
|
||||
return false;
|
||||
}
|
||||
|
||||
var certFiles = Directory.GetFiles(nginxPath, "*.crt");
|
||||
var keyFiles = Directory.GetFiles(nginxPath, "*.key");
|
||||
|
||||
if (certFiles.Length == 0 || keyFiles.Length == 0)
|
||||
{
|
||||
_logger.LogError($"Nginx目录中未找到证书文件或私钥文件");
|
||||
return false;
|
||||
}
|
||||
|
||||
var certFile = certFiles[0];
|
||||
var keyFile = keyFiles[0];
|
||||
|
||||
var certFileName = Path.GetFileNameWithoutExtension(fileName);
|
||||
var certSavePath = Path.Combine(savePath, $"{certFileName}_bundle.crt");
|
||||
var keySavePath = Path.Combine(savePath, $"{certFileName}.key");
|
||||
|
||||
File.Copy(certFile, certSavePath, true);
|
||||
File.Copy(keyFile, keySavePath, true);
|
||||
|
||||
_logger.LogInformation($"证书文件保存成功: {certSavePath}");
|
||||
_logger.LogInformation($"私钥文件保存成功: {keySavePath}");
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"下载证书失败: {certificateId}");
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (tempExtractPath != null && Directory.Exists(tempExtractPath))
|
||||
{
|
||||
Directory.Delete(tempExtractPath, true);
|
||||
_logger.LogInformation($"清理临时解压目录: {tempExtractPath}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, $"清理临时解压目录失败: {tempExtractPath}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (tempZipPath != null && File.Exists(tempZipPath))
|
||||
{
|
||||
File.Delete(tempZipPath);
|
||||
_logger.LogInformation($"清理临时ZIP文件: {tempZipPath}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, $"清理临时ZIP文件失败: {tempZipPath}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,16 @@ using System.Configuration;
|
||||
using System.Reflection;
|
||||
using Hua.DDNS.Common;
|
||||
using Hua.DDNS.Common.Config;
|
||||
using Hua.DDNS.Common.Config.Options;
|
||||
using Hua.DDNS.Common.Http;
|
||||
using Hua.DDNS.DDNSProviders;
|
||||
using Hua.DDNS.DDNSProviders.Ali;
|
||||
using Hua.DDNS.DDNSProviders.Dnspod;
|
||||
using Hua.DDNS.DDNSProviders.Namesilo;
|
||||
using Hua.DDNS.Jobs;
|
||||
using Hua.DDNS.SslProviders;
|
||||
using Hua.DDNS.SslProviders.Ali;
|
||||
using Hua.DDNS.SslProviders.Tencent;
|
||||
using Quartz;
|
||||
using Serilog;
|
||||
using Serilog.Extensions.Logging;
|
||||
@@ -47,8 +51,9 @@ namespace Hua.DDNS.Start
|
||||
services.AddAutoMapper(Assembly.GetExecutingAssembly());
|
||||
services.Configure<DdnsOption>(hostContext.Configuration.GetSection("DDNS"));
|
||||
services.Configure<NamesiloOption>(hostContext.Configuration.GetSection("Namesilo"));
|
||||
services.Configure<DnspodOption>(hostContext.Configuration.GetSection("Dnspod"));
|
||||
services.Configure<AliDdnsOption>(hostContext.Configuration.GetSection("Ali"));
|
||||
services.Configure<TencentCloudOption>(hostContext.Configuration.GetSection("TencentCloud"));
|
||||
services.Configure<AliCloudOption>(hostContext.Configuration.GetSection("AliCloud"));
|
||||
services.Configure<SslDownloadOption>(hostContext.Configuration.GetSection("SslDownload"));
|
||||
ConfigDi(hostContext, services);
|
||||
ConfigQuartz(hostContext, services);
|
||||
});
|
||||
@@ -62,6 +67,8 @@ namespace Hua.DDNS.Start
|
||||
services.AddTransient<NamesiloDdnsProvider>();
|
||||
services.AddTransient<AliDdnsProvider>();
|
||||
services.AddTransient<DnspodDdnsProvider>();
|
||||
services.AddTransient<AliSslProvider>();
|
||||
services.AddTransient<TencentSslProvider>();
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
@@ -102,6 +109,27 @@ namespace Hua.DDNS.Start
|
||||
.WithDescription("NewJob trigger")
|
||||
.StartNow()
|
||||
);
|
||||
|
||||
var sslDownloadJobKey = new JobKey("SslDownloadJob", "SslDownloadJobGroup");
|
||||
q.AddJob<SslDownloadJob>(j => j
|
||||
.StoreDurably()
|
||||
.WithIdentity(sslDownloadJobKey)
|
||||
.WithDescription("SslDownloadJob")
|
||||
);
|
||||
|
||||
var sslCorn = hostContext.Configuration.GetSection("SslDownload:Corn").Value;
|
||||
var sslEnabled = hostContext.Configuration.GetSection("SslDownload:Enabled").Get<bool>();
|
||||
|
||||
if (sslEnabled && !string.IsNullOrEmpty(sslCorn))
|
||||
{
|
||||
q.AddTrigger(t => t
|
||||
.WithIdentity("SslDownloadJob Trigger")
|
||||
.ForJob(sslDownloadJobKey)
|
||||
.WithCronSchedule(sslCorn)
|
||||
.WithDescription("SslDownloadJob trigger")
|
||||
.StartNow()
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Quartz.Extensions.Hosting hosting
|
||||
|
||||
@@ -8,15 +8,16 @@
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"App": {
|
||||
"AppJob": {
|
||||
"Corn": "* * * * * ?" //https://cron.qqe2.com/
|
||||
}
|
||||
},
|
||||
"App": {
|
||||
"GetIpv4Url": "http://47.108.74.59:8001/api/NetWork/GetIp",
|
||||
"AppJob": {
|
||||
"Corn": "0/5 * * * * ?" //https://cron.qqe2.com/
|
||||
}
|
||||
},
|
||||
"DDNS": {
|
||||
"Platform": 3, //1 Ali 2 Tencent 3 Namesilo
|
||||
"Platform": 2, //1 Ali 2 Tencent 3 Namesilo
|
||||
// 主域名
|
||||
"Domain": "we965.com",
|
||||
"Domain": "we965.cn",
|
||||
// 子域名前缀
|
||||
"SubDomainArray": [ "git", "webutil", "dev" ],
|
||||
// 记录类型
|
||||
@@ -24,17 +25,42 @@
|
||||
//间隔时间 秒
|
||||
"time": "30"
|
||||
},
|
||||
"SslDownload": {
|
||||
"Enabled": true,
|
||||
"Corn": "0/5 * * * * ?",
|
||||
"Platform": 2,
|
||||
"SavePath": "D:\\Paths\\ssl",
|
||||
"ExpireDays": 10000,
|
||||
"DownloadItems": [
|
||||
{
|
||||
"Domain": "git.we965.cn",
|
||||
"FileName": "git.we965.cn.pem"
|
||||
},
|
||||
{
|
||||
"Domain": "webutil.we965.cn",
|
||||
"FileName": "webutil.we965.cn.pem"
|
||||
},
|
||||
{
|
||||
"Domain": "dev.we965.cn",
|
||||
"FileName": "dev.we965.cn.pem"
|
||||
}
|
||||
]
|
||||
},
|
||||
"TencentCloud": {
|
||||
"SecretId": "1111",
|
||||
"SecretKey": "11111",
|
||||
"Region": "ap-guangzhou",
|
||||
"Dnspod": {
|
||||
"Endpoint": "dnspod.tencentcloudapi.com"
|
||||
}
|
||||
},
|
||||
"AliCloud": {
|
||||
"AccessKeyId": "1111",
|
||||
"AccessKeySecret": "1111",
|
||||
"RegionId": "cn-hangzhou",
|
||||
"Endpoint": "1111"
|
||||
},
|
||||
"Namesilo": {
|
||||
"ApiKey": "1111"
|
||||
},
|
||||
"Dnspod": {
|
||||
"Id": "1111",
|
||||
"Key": "1111",
|
||||
"Endpoint": "1111"
|
||||
},
|
||||
"Ali": {
|
||||
"Id": "1111",
|
||||
"Key": "1111",
|
||||
"Endpoint": "1111"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user