mirror of https://github.com/certd/certd
perf: 支持51dns
parent
42dfe936b7
commit
96a0900edc
|
@ -1,13 +1,13 @@
|
||||||
import axios, { AxiosHeaders, AxiosRequestConfig } from 'axios';
|
import axios, { AxiosHeaders, AxiosRequestConfig } from "axios";
|
||||||
import { ILogger, logger } from './util.log.js';
|
import { ILogger, logger } from "./util.log.js";
|
||||||
import { Logger } from 'log4js';
|
import { Logger } from "log4js";
|
||||||
import { HttpProxyAgent } from 'http-proxy-agent';
|
import { HttpProxyAgent } from "http-proxy-agent";
|
||||||
import { HttpsProxyAgent } from 'https-proxy-agent';
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
||||||
import nodeHttp from 'http';
|
import nodeHttp from "http";
|
||||||
import * as https from 'node:https';
|
import * as https from "node:https";
|
||||||
import { merge } from 'lodash-es';
|
import { merge } from "lodash-es";
|
||||||
import { safePromise } from './util.promise.js';
|
import { safePromise } from "./util.promise.js";
|
||||||
import fs from 'fs';
|
import fs from "fs";
|
||||||
export class HttpError extends Error {
|
export class HttpError extends Error {
|
||||||
status?: number;
|
status?: number;
|
||||||
statusText?: string;
|
statusText?: string;
|
||||||
|
@ -22,10 +22,10 @@ export class HttpError extends Error {
|
||||||
super(error.message || error.response?.statusText);
|
super(error.message || error.response?.statusText);
|
||||||
|
|
||||||
const message = error?.message;
|
const message = error?.message;
|
||||||
if (message && typeof message === 'string') {
|
if (message && typeof message === "string") {
|
||||||
if (message.indexOf && message.indexOf('ssl3_get_record:wrong version number') >= 0) {
|
if (message.indexOf && message.indexOf("ssl3_get_record:wrong version number") >= 0) {
|
||||||
this.message = `${message}(http协议错误,服务端要求http协议,请检查是否使用了https请求)`;
|
this.message = `${message}(http协议错误,服务端要求http协议,请检查是否使用了https请求)`;
|
||||||
} else if (message.indexOf('getaddrinfo EAI_AGAIN') >= 0) {
|
} else if (message.indexOf("getaddrinfo EAI_AGAIN") >= 0) {
|
||||||
this.message = `${message}(无法解析域名,请检查网络连接或dns配置,更换docker-compose.yaml中dns配置)`;
|
this.message = `${message}(无法解析域名,请检查网络连接或dns配置,更换docker-compose.yaml中dns配置)`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ export class HttpError extends Error {
|
||||||
};
|
};
|
||||||
let url = error.config?.url;
|
let url = error.config?.url;
|
||||||
if (error.config?.baseURL) {
|
if (error.config?.baseURL) {
|
||||||
url = (error.config?.baseURL || '') + url;
|
url = (error.config?.baseURL || "") + url;
|
||||||
}
|
}
|
||||||
if (url) {
|
if (url) {
|
||||||
this.message = `${this.message} 【${url}】`;
|
this.message = `${this.message} 【${url}】`;
|
||||||
|
@ -73,7 +73,7 @@ export const HttpCommonError = HttpError;
|
||||||
let defaultAgents = createAgent();
|
let defaultAgents = createAgent();
|
||||||
|
|
||||||
export function setGlobalProxy(opts: { httpProxy?: string; httpsProxy?: string }) {
|
export function setGlobalProxy(opts: { httpProxy?: string; httpsProxy?: string }) {
|
||||||
logger.info('setGlobalProxy:', opts);
|
logger.info("setGlobalProxy:", opts);
|
||||||
defaultAgents = createAgent(opts);
|
defaultAgents = createAgent(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,12 +102,12 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||||
if (config.skipSslVerify || config.httpProxy) {
|
if (config.skipSslVerify || config.httpProxy) {
|
||||||
let rejectUnauthorized = true;
|
let rejectUnauthorized = true;
|
||||||
if (config.skipSslVerify) {
|
if (config.skipSslVerify) {
|
||||||
logger.info('跳过SSL验证');
|
logger.info("跳过SSL验证");
|
||||||
rejectUnauthorized = false;
|
rejectUnauthorized = false;
|
||||||
}
|
}
|
||||||
const proxy: any = {};
|
const proxy: any = {};
|
||||||
if (config.httpProxy) {
|
if (config.httpProxy) {
|
||||||
logger.info('使用自定义http代理:', config.httpProxy);
|
logger.info("使用自定义http代理:", config.httpProxy);
|
||||||
proxy.httpProxy = config.httpProxy;
|
proxy.httpProxy = config.httpProxy;
|
||||||
proxy.httpsProxy = config.httpProxy;
|
proxy.httpsProxy = config.httpProxy;
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||||
},
|
},
|
||||||
(error: Error) => {
|
(error: Error) => {
|
||||||
// 发送失败
|
// 发送失败
|
||||||
logger.error('接口请求失败:', error);
|
logger.error("接口请求失败:", error);
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -143,7 +143,7 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||||
|
|
||||||
logger.info(`http response : status=${response?.status},data=${resData}`);
|
logger.info(`http response : status=${response?.status},data=${resData}`);
|
||||||
} else {
|
} else {
|
||||||
logger.info('http response status:', response?.status);
|
logger.info("http response status:", response?.status);
|
||||||
}
|
}
|
||||||
if (response?.config?.returnResponse) {
|
if (response?.config?.returnResponse) {
|
||||||
return response;
|
return response;
|
||||||
|
@ -154,53 +154,51 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||||
const status = error.response?.status;
|
const status = error.response?.status;
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 400:
|
case 400:
|
||||||
error.message = '请求错误';
|
error.message = "请求错误";
|
||||||
break;
|
break;
|
||||||
case 401:
|
case 401:
|
||||||
error.message = '认证/登录失败';
|
error.message = "认证/登录失败";
|
||||||
break;
|
break;
|
||||||
case 403:
|
case 403:
|
||||||
error.message = '拒绝访问';
|
error.message = "拒绝访问";
|
||||||
break;
|
break;
|
||||||
case 404:
|
case 404:
|
||||||
error.message = `请求地址出错`;
|
error.message = `请求地址出错`;
|
||||||
break;
|
break;
|
||||||
case 408:
|
case 408:
|
||||||
error.message = '请求超时';
|
error.message = "请求超时";
|
||||||
break;
|
break;
|
||||||
case 500:
|
case 500:
|
||||||
error.message = '服务器内部错误';
|
error.message = "服务器内部错误";
|
||||||
break;
|
break;
|
||||||
case 501:
|
case 501:
|
||||||
error.message = '服务未实现';
|
error.message = "服务未实现";
|
||||||
break;
|
break;
|
||||||
case 502:
|
case 502:
|
||||||
error.message = '网关错误';
|
error.message = "网关错误";
|
||||||
break;
|
break;
|
||||||
case 503:
|
case 503:
|
||||||
error.message = '服务不可用';
|
error.message = "服务不可用";
|
||||||
break;
|
break;
|
||||||
case 504:
|
case 504:
|
||||||
error.message = '网关超时';
|
error.message = "网关超时";
|
||||||
break;
|
break;
|
||||||
case 505:
|
case 505:
|
||||||
error.message = 'HTTP版本不受支持';
|
error.message = "HTTP版本不受支持";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
logger.error(
|
logger.error(`请求出错:status:${error.response?.status},statusText:${error.response?.statusText},url:${error.config?.url},method:${error.config?.method}。`);
|
||||||
`请求出错:status:${error.response?.status},statusText:${error.response?.statusText},url:${error.config?.url},method:${error.config?.method}。`
|
logger.error("返回数据:", JSON.stringify(error.response?.data));
|
||||||
);
|
|
||||||
logger.error('返回数据:', JSON.stringify(error.response?.data));
|
|
||||||
if (error.response?.data) {
|
if (error.response?.data) {
|
||||||
const message = error.response.data.message || error.response.data.msg || error.response.data.error;
|
const message = error.response.data.message || error.response.data.msg || error.response.data.error;
|
||||||
if (typeof message === 'string') {
|
if (typeof message === "string") {
|
||||||
error.message = message;
|
error.message = message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (error instanceof AggregateError) {
|
if (error instanceof AggregateError) {
|
||||||
logger.error('AggregateError', error);
|
logger.error("AggregateError", error);
|
||||||
}
|
}
|
||||||
const err = new HttpError(error);
|
const err = new HttpError(error);
|
||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
|
@ -244,24 +242,24 @@ export function createAgent(opts: CreateAgentOptions = {}) {
|
||||||
if (httpProxy) {
|
if (httpProxy) {
|
||||||
process.env.HTTP_PROXY = httpProxy;
|
process.env.HTTP_PROXY = httpProxy;
|
||||||
process.env.http_proxy = httpProxy;
|
process.env.http_proxy = httpProxy;
|
||||||
logger.info('use httpProxy:', httpProxy);
|
logger.info("use httpProxy:", httpProxy);
|
||||||
httpAgent = new HttpProxyAgent(httpProxy, opts as any);
|
httpAgent = new HttpProxyAgent(httpProxy, opts as any);
|
||||||
merge(httpAgent.options, opts);
|
merge(httpAgent.options, opts);
|
||||||
} else {
|
} else {
|
||||||
process.env.HTTP_PROXY = '';
|
process.env.HTTP_PROXY = "";
|
||||||
process.env.http_proxy = '';
|
process.env.http_proxy = "";
|
||||||
httpAgent = new nodeHttp.Agent(opts);
|
httpAgent = new nodeHttp.Agent(opts);
|
||||||
}
|
}
|
||||||
const httpsProxy = opts.httpsProxy;
|
const httpsProxy = opts.httpsProxy;
|
||||||
if (httpsProxy) {
|
if (httpsProxy) {
|
||||||
process.env.HTTPS_PROXY = httpsProxy;
|
process.env.HTTPS_PROXY = httpsProxy;
|
||||||
process.env.https_proxy = httpsProxy;
|
process.env.https_proxy = httpsProxy;
|
||||||
logger.info('use httpsProxy:', httpsProxy);
|
logger.info("use httpsProxy:", httpsProxy);
|
||||||
httpsAgent = new HttpsProxyAgent(httpsProxy, opts as any);
|
httpsAgent = new HttpsProxyAgent(httpsProxy, opts as any);
|
||||||
merge(httpsAgent.options, opts);
|
merge(httpsAgent.options, opts);
|
||||||
} else {
|
} else {
|
||||||
process.env.HTTPS_PROXY = '';
|
process.env.HTTPS_PROXY = "";
|
||||||
process.env.https_proxy = '';
|
process.env.https_proxy = "";
|
||||||
httpsAgent = new https.Agent(opts);
|
httpsAgent = new https.Agent(opts);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -276,27 +274,27 @@ export async function download(req: { http: HttpClient; config: HttpRequestConfi
|
||||||
http
|
http
|
||||||
.request({
|
.request({
|
||||||
logRes: false,
|
logRes: false,
|
||||||
responseType: 'stream',
|
responseType: "stream",
|
||||||
...config,
|
...config,
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const writer = fs.createWriteStream(savePath);
|
const writer = fs.createWriteStream(savePath);
|
||||||
res.pipe(writer);
|
res.pipe(writer);
|
||||||
writer.on('close', () => {
|
writer.on("close", () => {
|
||||||
logger.info('文件下载成功');
|
logger.info("文件下载成功");
|
||||||
resolve(true);
|
resolve(true);
|
||||||
});
|
});
|
||||||
//error
|
//error
|
||||||
writer.on('error', err => {
|
writer.on("error", err => {
|
||||||
logger.error('下载失败', err);
|
logger.error("下载失败", err);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
//进度条打印
|
//进度条打印
|
||||||
const totalLength = res.headers['content-length'];
|
const totalLength = res.headers["content-length"];
|
||||||
let currentLength = 0;
|
let currentLength = 0;
|
||||||
// 每5%打印一次
|
// 每5%打印一次
|
||||||
const step = (totalLength / 100) * 5;
|
const step = (totalLength / 100) * 5;
|
||||||
res.on('data', (chunk: any) => {
|
res.on("data", (chunk: any) => {
|
||||||
currentLength += chunk.length;
|
currentLength += chunk.length;
|
||||||
if (currentLength % step < chunk.length) {
|
if (currentLength % step < chunk.length) {
|
||||||
const percent = ((currentLength / totalLength) * 100).toFixed(2);
|
const percent = ((currentLength / totalLength) * 100).toFixed(2);
|
||||||
|
@ -305,19 +303,19 @@ export async function download(req: { http: HttpClient; config: HttpRequestConfi
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
logger.info('下载失败', err);
|
logger.info("下载失败", err);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCookie(response: any, name: string) {
|
export function getCookie(response: any, name: string) {
|
||||||
const cookies = response.headers['set-cookie'];
|
const cookies = response.headers["set-cookie"];
|
||||||
//根据name 返回对应的cookie
|
//根据name 返回对应的cookie
|
||||||
const found = cookies.find((cookie: any) => cookie.includes(name));
|
const found = cookies.find((cookie: any) => cookie.includes(name));
|
||||||
if (!found) {
|
if (!found) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const cookie = found.split(';')[0];
|
const cookie = found.split(";")[0];
|
||||||
return cookie.substring(cookie.indexOf('=') + 1);
|
return cookie.substring(cookie.indexOf("=") + 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
"cos-nodejs-sdk-v5": "^2.14.6",
|
"cos-nodejs-sdk-v5": "^2.14.6",
|
||||||
"cron-parser": "^4.9.0",
|
"cron-parser": "^4.9.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"glob": "^11.0.0",
|
"glob": "^11.0.0",
|
||||||
|
|
|
@ -18,3 +18,4 @@ export * from './plugin-dnsla/index.js';
|
||||||
export * from './plugin-upyun/index.js';
|
export * from './plugin-upyun/index.js';
|
||||||
export * from './plugin-volcengine/index.js'
|
export * from './plugin-volcengine/index.js'
|
||||||
export * from './plugin-jdcloud/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';
|
|
@ -1566,6 +1566,9 @@ importers:
|
||||||
cross-env:
|
cross-env:
|
||||||
specifier: ^7.0.3
|
specifier: ^7.0.3
|
||||||
version: 7.0.3
|
version: 7.0.3
|
||||||
|
crypto-js:
|
||||||
|
specifier: ^4.2.0
|
||||||
|
version: 4.2.0
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.7
|
specifier: ^1.11.7
|
||||||
version: 1.11.13
|
version: 1.11.13
|
||||||
|
@ -20673,13 +20676,13 @@ snapshots:
|
||||||
resolve: 1.22.10
|
resolve: 1.22.10
|
||||||
semver: 6.3.1
|
semver: 6.3.1
|
||||||
|
|
||||||
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8):
|
eslint-plugin-prettier@3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 7.32.0
|
eslint: 7.32.0
|
||||||
prettier: 2.8.8
|
prettier: 2.8.8
|
||||||
prettier-linter-helpers: 1.0.0
|
prettier-linter-helpers: 1.0.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
eslint-config-prettier: 8.10.0(eslint@8.57.0)
|
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
||||||
|
|
||||||
eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8):
|
eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -23393,7 +23396,7 @@ snapshots:
|
||||||
eslint: 7.32.0
|
eslint: 7.32.0
|
||||||
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
eslint-config-prettier: 8.10.0(eslint@7.32.0)
|
||||||
eslint-plugin-node: 11.1.0(eslint@7.32.0)
|
eslint-plugin-node: 11.1.0(eslint@7.32.0)
|
||||||
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@7.32.0)(prettier@2.8.8)
|
eslint-plugin-prettier: 3.4.1(eslint-config-prettier@8.10.0(eslint@7.32.0))(eslint@7.32.0)(prettier@2.8.8)
|
||||||
execa: 5.1.1
|
execa: 5.1.1
|
||||||
inquirer: 7.3.3
|
inquirer: 7.3.3
|
||||||
json5: 2.2.3
|
json5: 2.2.3
|
||||||
|
|
Loading…
Reference in New Issue