perf: 新增站点证书监控从DNS解析记录批量导入功能

本次提交新增了从DNS解析记录批量导入站点监控的完整功能:
1. 扩展Registrable类型新增icon字段支持
2. 新增DNS解析记录获取接口和基础实现
3. 为阿里云、腾讯云、Cloudflare等DNS提供商添加解析记录分页获取支持
4. 新增站点监控导入任务管理功能,支持保存、启动、删除导入任务
5. 新增中文/英文多语言支持
6. 优化暗黑模式表格样式
7. 修复ACME账户访问修复逻辑中项目ID可选的问题
8. 优化HiPM DNS提供商的域名获取逻辑
This commit is contained in:
xiaojunnuo
2026-06-10 23:32:39 +08:00
parent 8d9870e9c6
commit f9541fab70
21 changed files with 749 additions and 55 deletions
@@ -1,4 +1,4 @@
import { AbstractDnsProvider, CreateRecordOptions, DomainRecord, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
import { AbstractDnsProvider, CreateRecordOptions, DomainRecord, DnsResolveRecord, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
import { AliyunAccess } from "../../plugin-lib/aliyun/access/aliyun-access.js";
import { AliyunClient } from "../../plugin-lib/aliyun/index.js";
import { Pager, PageRes, PageSearch } from "@certd/pipeline";
@@ -177,6 +177,35 @@ export class AliyunDnsProvider extends AbstractDnsProvider {
total: ret.TotalCount,
};
}
async getRecordListPage(domain: string, req: PageSearch): Promise<PageRes<DnsResolveRecord>> {
const pager = new Pager(req);
const params = {
RegionId: "cn-hangzhou",
DomainName: domain,
PageSize: pager.pageSize,
PageNumber: pager.pageNo,
};
const requestOption = {
method: "POST",
};
const ret = await this.client.request("DescribeDomainRecords", params, requestOption);
const rawList = ret.DomainRecords?.Record || [];
const list = rawList.map(item => ({
id: item.RecordId,
hostRecord: item.RR,
fullRecord: item.RR === "@" ? domain : `${item.RR}.${domain}`,
type: item.Type,
value: item.Value,
}));
return {
list,
total: ret.TotalCount,
};
}
}
new AliyunDnsProvider();
@@ -1,4 +1,4 @@
import { AbstractDnsProvider, CreateRecordOptions, DomainRecord, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
import { AbstractDnsProvider, CreateRecordOptions, DomainRecord, DnsResolveRecord, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
import { CloudflareAccess } from "./access.js";
import { Pager, PageRes, PageSearch } from "@certd/pipeline";
@@ -137,6 +137,34 @@ export class CloudflareDnsProvider extends AbstractDnsProvider<CloudflareRecord>
list,
};
}
async getRecordListPage(domain: string, req: PageSearch): Promise<PageRes<DnsResolveRecord>> {
const pager = new Pager(req);
const zoneId = await this.getZoneId(domain);
let url = `https://api.cloudflare.com/client/v4/zones/${zoneId}/dns_records?page=${pager.pageNo}&per_page=${pager.pageSize}`;
if (req.searchKey) {
url += `&name=${req.searchKey}`;
}
const ret = await this.access.doRequestApi(url, null, "get");
let list = ret.result || [];
list = list.map((item: any) => {
const hostRecord = item.name === domain ? "@" : item.name.slice(0, item.name.length - domain.length - 1);
return {
id: item.id,
hostRecord,
fullRecord: item.name,
type: item.type,
value: item.content,
};
});
const total = ret.result_info.total_count || list.length;
return {
total,
list,
};
}
}
//实例化这个provider,将其自动注册到系统中
@@ -30,16 +30,6 @@ export class HipmDnsmgrDnsProvider extends AbstractDnsProvider<{ domainId: strin
// 1. 获取域名 ID(双层查询策略)
const domainId = await this.access.getDomainId(domain);
this.logger.debug('[HiPM DNSMgr] 找到域名:', domain, 'ID:', domainId);
// 1. 获取域名列表,找到对应的域名 ID
const domainList = await this.access.getDomainList();
const domainInfo = domainList.find((item: any) => item.domain === domain);
if (!domainInfo) {
throw new Error(`[HiPM DNSMgr] 未找到域名:${domain}`);
}
const domainId = String(domainInfo.id);
this.logger.debug("[HiPM DNSMgr] 找到域名:", domain, "ID:", domainId);
// 2. 创建 DNS 记录
const name = hostRecord; // 使用子域名,如 _acme-challenge
@@ -1,4 +1,4 @@
import { AbstractDnsProvider, CreateRecordOptions, DomainRecord, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
import { AbstractDnsProvider, CreateRecordOptions, DnsResolveRecord, DomainRecord, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
import { TencentAccess } from "../../plugin-lib/tencent/index.js";
import { Pager, PageRes, PageSearch } from "@certd/pipeline";
@@ -114,5 +114,29 @@ export class TencentDnsProvider extends AbstractDnsProvider {
const total = ret.DomainCountInfo?.AllTotal || list.length;
return { total, list };
}
async getRecordListPage(domain: string, req: PageSearch): Promise<PageRes<DnsResolveRecord>> {
const pager = new Pager(req);
const params: any = {
Domain: domain,
Offset: pager.getOffset(),
Limit: pager.pageSize,
};
if (req.searchKey) {
params.Subdomain = req.searchKey;
}
const ret = await this.client.DescribeRecordList(params);
let list = ret.RecordList || [];
list = list.map((item: any) => ({
id: String(item.RecordId),
hostRecord: item.Name,
fullRecord: item.Name === "@" ? domain : `${item.Name}.${domain}`,
type: item.Type,
value: item.Value,
}));
const total = ret.TotalCount || list.length;
return { total, list };
}
}
new TencentDnsProvider();