perf: 支持51dns

This commit is contained in:
xiaojunnuo
2025-04-22 07:26:11 +08:00
parent 42dfe936b7
commit 96a0900edc
8 changed files with 398 additions and 55 deletions
@@ -18,3 +18,4 @@ export * from './plugin-dnsla/index.js';
export * from './plugin-upyun/index.js';
export * from './plugin-volcengine/index.js'
export * from './plugin-jdcloud/index.js'
export * from './plugin-51dns/index.js'
@@ -0,0 +1,40 @@
import { IsAccess, AccessInput, BaseAccess } from '@certd/pipeline';
/**
* 这个注解将注册一个授权配置
* 在certd的后台管理系统中,用户可以选择添加此类型的授权
*/
@IsAccess({
name: '51dns',
title: '51dns授权',
icon: 'arcticons:dns-changer-3',
desc: '',
})
export class Dns51Access extends BaseAccess {
/**
* 授权属性配置
*/
@AccessInput({
title: '用户名',
component: {
placeholder: '用户名或手机号',
},
required: true,
encrypt: false,
})
username = '';
@AccessInput({
title: '登录密码',
component: {
name:"a-input-password",
vModel:"value",
placeholder: '密码',
},
required: true,
encrypt: true,
})
password = '';
}
new Dns51Access();
@@ -0,0 +1,200 @@
import { createAxiosService, HttpClient, ILogger } from "@certd/basic";
import { Dns51Access } from "./access.js";
export class Dns51Client {
logger: ILogger;
access: Dns51Access;
http: HttpClient;
cryptoJs: any;
isLogined = false;
_token = "";
constructor(options: {
logger: ILogger;
access: Dns51Access;
}) {
this.logger = options.logger;
this.access = options.access;
this.http = createAxiosService({
logger: this.logger
});
}
aes(val: string) {
if (!this.cryptoJs) {
throw new Error("crypto-js not init");
}
const CryptoJS = this.cryptoJs;
var k = CryptoJS.enc.Utf8.parse("1234567890abcDEF");
var iv = CryptoJS.enc.Utf8.parse("1234567890abcDEF");
return CryptoJS.AES.encrypt(val, k, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
}).toString();
}
async init() {
if (this.cryptoJs) {
return;
}
const CryptoJSModule = await import("crypto-js");
this.cryptoJs = CryptoJSModule.default;
}
async login() {
if (this.isLogined) {
return;
}
await this.init();
const res = await this.http.request({
url: "https://www.51dns.com/login.html",
method: "get",
withCredentials: true,
logRes:false,
returnResponse:true
});
//提取 var csrfToken = "ieOfM21eDd9nWJv3OZtMJF6ogDsnPKQHJ17dlMck";
const _token = res.data.match(/var csrfToken = "(.*?)"/)[1];
this.logger.info("_token:", _token);
this._token = _token;
var obj = {
"email_or_phone": this.aes("18603046467"),
"password": this.aes("JiDian1Zu"),
"type": this.aes("account"),
"redirectTo": "https://www.51dns.com/domain",
"_token": _token
};
const res2 = await this.http.request({
url: "https://www.51dns.com/login",
method: "post",
data: {
...obj
},
withCredentials: true,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
logRes:false,
returnResponse:true,
});
// 提取 <span class="user_email">182****43522</span><br>
// console.log(res2.headers)
// console.log(res2.data)
const username = res2.data.match(/<span class="user_email">(.*?)<\/span>/)[1];
this.logger.info("登录成功:username:", username);
this.isLogined = true;
}
async getDomainId(domain: string) {
await this.login();
const res = await this.http.request({
url: `https://www.51dns.com/domain?domain=${domain}&status=`,
method: "get",
withCredentials: true,
logRes:false,
returnResponse:true
});
// 提取 <a target="_blank" href="https://www.51dns.com/domain/record/193341603"
// class="color47">certd.top</a>
const regex = new RegExp(`<a target="_blank" href="https://www.51dns.com/domain/record/(.*?)".*${domain}<\/a>`, "g");
const matched = res.data.match(regex);
if (!matched || matched.length === 0) {
throw new Error(`域名${domain}不存在`);
}
return matched[1];
}
async createRecord(param: { domain: string, data: any; domainId: void; host: string; ttl: number; type: string }) {
const { domain, data, host, type } = param;
const domainId = await this.getDomainId(domain);
const url = "https://www.51dns.com/domain/storenNewRecord";
const req = {
_token: this._token,
domain_id: parseInt(domainId),
record: host,
type: type,
value: data,
ttl: 300,
view_id: 0
};
const res = await this.http.request({
url,
method: "post",
data: req,
withCredentials: true,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
});
/*
{
"status": 200,
"msg": "\u6b63\u786e",
"data": {
"record": "1111",
"type": "TXT",
"value": "2222",
"mx": "-",
"ttl": "300",
"view_id": "0",
"id": 601019779,
"domain_id": "193341603",
"trecord": "1111",
"view_name": "\u9ed8\u8ba4"
}
}
*/
if(res.status !== 200){
throw new Error(`创建域名解析失败:${res.msg}`);
}
const id = res.data.id;
return {
id,
domainId
};
}
async deleteRecord(param: { domainId: number; id: number }) {
const url ="https://www.51dns.com/domain/operateRecord"
/*
type: delete
ids[0]: 601019779
domain_id: 193341603
_token: ieOfM21eDd9nWJv3OZtMJF6ogDsnPKQHJ17dlMck
*/
const body = {
type: "delete",
ids: [param.id],
domain_id: param.domainId,
_token: this._token
}
const res = await this.http.request({
url,
method: "post",
data: body,
withCredentials: true,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
});
if(res.status !== 200){
throw new Error(`删除域名解析失败:${res.msg}`);
}
}
}
@@ -0,0 +1,97 @@
import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from "@certd/plugin-cert";
import { Dns51Access } from "./access.js";
import { Dns51Client } from "./client.js";
export type Dns51Record = {
id: number;
domainId: number,
client: Dns51Client,
};
// 这里通过IsDnsProvider注册一个dnsProvider
@IsDnsProvider({
name: '51dns',
title: '51dns',
desc: '51DNS',
icon: 'arcticons:dns-changer-3',
// 这里是对应的 cloudflare的access类型名称
accessType: '51dns',
})
export class Dns51DnsProvider extends AbstractDnsProvider<Dns51Record> {
// 通过Autowire传递context
access!: Dns51Access;
async onInstance() {
//一些初始化的操作
// 也可以通过ctx成员变量传递context 与Autowire效果一样
this.access = this.ctx.access as Dns51Access;
}
/**
* 创建dns解析记录,用于验证域名所有权
*/
async createRecord(options: CreateRecordOptions): Promise<Dns51Record> {
/**
* fullRecord: '_acme-challenge.test.example.com',
* value: 一串uuid
* type: 'TXT',
* domain: 'example.com'
*/
const { fullRecord,hostRecord, value, type, domain } = options;
this.logger.info('添加域名解析:', fullRecord, value, type, domain);
const dns51Client = new Dns51Client({
logger: this.logger,
access: this.access,
});
const domainId = await dns51Client.getDomainId(domain);
this.logger.info('获取domainId成功:', domainId);
const res = await dns51Client.createRecord({
domain: domain,
domainId: domainId,
type: 'TXT',
host: hostRecord,
data: value,
ttl: 300,
})
return {
id: res.id,
domainId: domainId,
client: dns51Client,
};
}
/**
* 删除dns解析记录,清理申请痕迹
* @param options
*/
async removeRecord(options: RemoveRecordOptions<Dns51Record>): Promise<void> {
const { fullRecord, value } = options.recordReq;
const record = options.recordRes;
this.logger.info('删除域名解析:', fullRecord, value);
if (!record) {
this.logger.info('record为空,不执行删除');
return;
}
//这里调用删除txt dns解析记录接口
/**
* 请求示例
* DELETE /api/record?id=85371689655342080 HTTP/1.1
* Authorization: Basic {token}
* 请求参数
*/
const { client,id,domainId} = record
await client.deleteRecord({
id,
domainId
})
this.logger.info(`删除域名解析成功:fullRecord=${fullRecord},id=${id}`);
}
}
//实例化这个provider,将其自动注册到系统中
new Dns51DnsProvider();
@@ -0,0 +1,3 @@
export * from './dns-provider.js';
export * from './access.js';
export * from './client.js';