diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts
index 5991f22b0..3cac97e5c 100644
--- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts
+++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts
@@ -117,11 +117,11 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
],
},
required: true,
- helper: `1. DNS直接验证:域名dns解析是在阿里云/腾讯云/华为云/CF/NameSilo/西数/火山/dns.la/京东云/51dns的,选它
-2. CNAME代理验证:支持任何注册商的域名,第一次需要手动添加[CNAME记录](#/certd/cname/record)(建议将DNS服务器修改为阿里云/腾讯云的,然后使用DNS直接验证)
+ helper: `1. DNS直接验证:当域名dns解析已被本系统支持时(即下方DNS解析服务商选项中可选),推荐选择此方式
+2. CNAME代理验证:支持任何注册商的域名,第一次需要手动添加[CNAME记录](#/certd/cname/record)(如果经常申请失败,建议将DNS服务器修改为阿里云/腾讯云的,然后使用DNS直接验证)
3. HTTP文件验证:不支持泛域名,需要配置网站文件上传
4. 多DNS提供商:每个域名可以选择独立的DNS提供商
-5. 自动匹配:需要在[域名管理](#/certd/cert/domain)中事先配置好校验方式
+5. 自动匹配:此处无需选择校验方式,需要在[域名管理](#/certd/cert/domain)中提前配置好校验方式
`,
})
challengeType!: string;
diff --git a/packages/ui/certd-server/src/plugins/plugin-xinnet/access-agent.ts b/packages/ui/certd-server/src/plugins/plugin-xinnet/access-agent.ts
index 9fa65629d..93234566c 100644
--- a/packages/ui/certd-server/src/plugins/plugin-xinnet/access-agent.ts
+++ b/packages/ui/certd-server/src/plugins/plugin-xinnet/access-agent.ts
@@ -1,79 +1,157 @@
-// import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
-// import { XinnetClient } from "@certd/plugin-plus";
+import { IsAccess, AccessInput, BaseAccess, Pager, PageSearch } from "@certd/pipeline";
+import crypto from "crypto";
+/**
+ * 这个注解将注册一个授权配置
+ * 在certd的后台管理系统中,用户可以选择添加此类型的授权
+ */
+@IsAccess({
+ name: "xinnetagent",
+ title: "新网授权(代理方式)",
+ icon: "lsicon:badge-new-filled",
+ desc: ""
+})
+export class XinnetAgentAccess extends BaseAccess {
-// /**
-// * 这个注解将注册一个授权配置
-// * 在certd的后台管理系统中,用户可以选择添加此类型的授权
-// */
-// @IsAccess({
-// name: "xinnetagent",
-// title: "新网授权(代理方式)",
-// icon: "lsicon:badge-new-filled",
-// desc: ""
-// })
-// export class XinnetAccess extends BaseAccess {
+ /**
+ * 授权属性配置
+ */
+ @AccessInput({
+ title: "代理账号",
+ component: {
+ placeholder: "代理账号,如:agent0001"
+ },
+ required: true,
+ encrypt: false
+ })
+ agentCode = "";
-// /**
-// * 授权属性配置
-// */
-// @AccessInput({
-// title: "代理账号",
-// component: {
-// placeholder: "代理账号,如:agent0001"
-// },
-// required: true,
-// encrypt: false
-// })
-// username = "";
+ @AccessInput({
+ title: "API密钥",
+ component: {
+ name: "a-input-password",
+ vModel: "value",
+ placeholder: "API密钥"
+ },
+ required: true,
+ encrypt: true
+ })
+ appSecret = "";
-// @AccessInput({
-// title: "API密钥",
-// component: {
-// name: "a-input-password",
-// vModel: "value",
-// placeholder: "API密钥"
-// },
-// required: true,
-// encrypt: true
-// })
-// apikey = "";
+ @AccessInput({
+ title: "测试",
+ component: {
+ name: "api-test",
+ action: "TestRequest"
+ },
+ helper: "点击测试接口是否正常"
+ })
+ testRequest = true;
-// @AccessInput({
-// title: "测试",
-// component: {
-// name: "api-test",
-// action: "TestRequest"
-// },
-// helper: "点击测试接口是否正常"
-// })
-// testRequest = true;
+ async onTestRequest() {
-// async onTestRequest() {
+ // const client = new XinnetClient({
+ // access: this,
+ // logger: this.ctx.logger,
+ // http: this.ctx.http
+ // });
+ await this.getDomainList({ pageNo: 1, pageSize: 1 });
-// // const client = new XinnetClient({
-// // access: this,
-// // logger: this.ctx.logger,
-// // http: this.ctx.http
-// // });
-
-// await client.getDomainList({ pageNo: 1, pageSize: 1 });
-
-// return "ok";
-// }
+ return "ok";
+ }
-// getCacheKey () {
-// let hashStr = ""
-// for (const key in this) {
-// if (Object.prototype.hasOwnProperty.call(this, key)) {
-// const element = this[key];
-// hashStr += element;
-// }
-// }
-// const hashCode = this.ctx.utils.hash.sha256(hashStr);
-// return `xinnet-${hashCode}`;
-// }
-// }
+ async getDomainList(req:PageSearch) {
+ const pager = new Pager(req);
+ const conf = {
+ url: "/api/domain/list",
+ data: {
+ pageNo: String(pager.pageNo),
+ pageSize: String(pager.pageSize)
+ }
+ }
+ return await this.doRequest(conf);
+ }
-// new XinnetAccess();
+
+ /**
+ * 生成 UTC 0 时区的时间戳
+ */
+ generateTimestamp() {
+ const timestamp = new Date().toISOString().replace(/\.\d{3}Z$/, "Z").replaceAll(":", "").replaceAll("-", "");
+ return timestamp;
+ }
+
+ /**
+ * 字节转16进制字符串
+ */
+ bytesToHex(bytes:any) {
+ return bytes.toString('hex');
+ }
+
+ /**
+ * 生成签名
+ */
+ generateSignature(timestamp, urlPath, requestBody) {
+ const algorithm = 'HMAC-SHA256';
+ const requestMethod = 'POST';
+
+ // 构建待签名字符串
+ const stringToSign = `${algorithm}\n${timestamp}\n${requestMethod}\n${urlPath}\n${requestBody}`;
+
+ // 使用 HMAC-SHA256 计算签名
+ const hmac = crypto.createHmac('sha256', this.appSecret);
+ hmac.update(stringToSign);
+ const signatureBytes = hmac.digest();
+
+ // 转换为16进制字符串
+ return this.bytesToHex(signatureBytes);
+ }
+
+ /**
+ * 生成 authorization header
+ */
+ generateAuthorization(timestamp, urlPath, requestBody) {
+ const signature = this.generateSignature(timestamp, urlPath, requestBody);
+ return `HMAC-SHA256 Access=${this.agentCode}, Signature=${signature}`;
+ }
+
+ /**
+ * 查询域名分页列表
+ */
+ async doRequest(req:any) {
+
+ const baseURL = 'https://apiv2.xinnet.com';
+ const urlPath = req.url;
+ const requestURL = baseURL + urlPath; // 实际请求URL去掉最后的斜杠
+
+ // 请求体
+ const requestBody = JSON.stringify(req.data);
+
+ // 生成时间戳和授权头
+ const timestamp = this.generateTimestamp();
+ const authorization = this.generateAuthorization(timestamp, urlPath+"/", requestBody);
+
+ // 请求配置
+ const config = {
+ method: 'POST',
+ url: requestURL,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'timestamp': timestamp,
+ 'authorization': authorization
+ },
+ data: requestBody,
+ };
+
+ const res = await this.ctx.http.request(config);
+
+ if (res.code !="0"){
+ throw new Error(`API Error: ${res.code} ${res.requestId} - ${JSON.stringify(res.msg)}`);
+ }
+ return res.data;
+ }
+
+}
+
+new XinnetAgentAccess();
diff --git a/packages/ui/certd-server/src/plugins/plugin-xinnet/dns-provider-agent.ts b/packages/ui/certd-server/src/plugins/plugin-xinnet/dns-provider-agent.ts
new file mode 100644
index 000000000..c32b8da20
--- /dev/null
+++ b/packages/ui/certd-server/src/plugins/plugin-xinnet/dns-provider-agent.ts
@@ -0,0 +1,90 @@
+import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
+import { XinnetAgentAccess } from "./access-agent.js";
+
+export type XinnetAgentRecord = {
+ recordId: number;
+ domainName: string;
+};
+
+// 这里通过IsDnsProvider注册一个dnsProvider
+@IsDnsProvider({
+ name: "xinnetagent",
+ title: "新网(代理方式)",
+ desc: "新网域名解析(代理方式)",
+ icon: "lsicon:badge-new-filled",
+ // 这里是对应的 cloudflare的access类型名称
+ accessType: "xinnetagent",
+ order: 7
+})
+export class XinnetAgentProvider extends AbstractDnsProvider {
+ access!: XinnetAgentAccess;
+
+ async onInstance() {
+ //一些初始化的操作
+ // 也可以通过ctx成员变量传递context
+ this.access = this.ctx.access as XinnetAgentAccess;
+ }
+
+ /**
+ * 创建dns解析记录,用于验证域名所有权
+ */
+ async createRecord(options: CreateRecordOptions): Promise {
+ /**
+ * fullRecord: '_acme-challenge.test.example.com',
+ * value: 一串uuid
+ * type: 'TXT',
+ * domain: 'example.com'
+ */
+ const { fullRecord, value, type, domain } = options;
+ this.logger.info("添加域名解析:", fullRecord, value, type, domain);
+
+
+ /**
+ * /api/dns/create
+ * domainName 是 string 域名名称 test-xinnet-0516-ceshi.cn
+recordName 是 string 记录名 test1.test-xinnet-0516-ceshi.cn,如果是@和空字符只需要传域名即可
+type 是 string 解析记录的类型 可选择类型如下: NS A CNAME MX TXT URL SRV AAAA A
+value 是 string 解析内容 192.168.1.50
+line 是 string 线路 只能传"默认"
+ */
+
+ const res = await this.access.doRequest({
+ url:"/api/dns/create",
+ data:{
+ domainName: domain,
+ recordName: fullRecord,
+ type: type,
+ value: value,
+ line: "默认"
+ }
+ });
+
+
+ return {
+ recordId:res,
+ domainName: domain
+ };
+ }
+
+
+ /**
+ * 删除dns解析记录,清理申请痕迹
+ * @param options
+ */
+ async removeRecord(options: RemoveRecordOptions): Promise {
+
+ const {domainName,recordId} = options.recordRes;
+ await this.access.doRequest({
+ url:"/api/dns/delete",
+ data:{
+ recordId: recordId,
+ domainName: domainName
+ }
+ });
+
+
+ }
+}
+
+//实例化这个provider,将其自动注册到系统中
+new XinnetAgentProvider();
diff --git a/packages/ui/certd-server/src/plugins/plugin-xinnet/index.ts b/packages/ui/certd-server/src/plugins/plugin-xinnet/index.ts
index db899c717..871ad2050 100644
--- a/packages/ui/certd-server/src/plugins/plugin-xinnet/index.ts
+++ b/packages/ui/certd-server/src/plugins/plugin-xinnet/index.ts
@@ -1,2 +1,5 @@
export * from './dns-provider.js';
export * from './access.js';
+
+export * from './access-agent.js';
+export * from './dns-provider-agent.js';