mirror of
https://github.com/certd/certd.git
synced 2026-05-16 21:27:34 +08:00
97 lines
2.4 KiB
TypeScript
97 lines
2.4 KiB
TypeScript
import { logger, safePromise, utils } from "@certd/basic";
|
||
import { merge } from "lodash-es";
|
||
import https from "https";
|
||
import { PeerCertificate } from "tls";
|
||
|
||
export type SiteTestReq = {
|
||
host: string; // 只用域名部分
|
||
port?: number;
|
||
method?: string;
|
||
retryTimes?: number;
|
||
ipAddress?: string;
|
||
};
|
||
|
||
export type SiteTestRes = {
|
||
certificate?: PeerCertificate;
|
||
};
|
||
|
||
export class SiteTester {
|
||
async test(req: SiteTestReq): Promise<SiteTestRes> {
|
||
logger.info("测试站点:", JSON.stringify(req));
|
||
const maxRetryTimes = req.retryTimes==null ? 3 : req.retryTimes;
|
||
let tryCount = 0;
|
||
let result: SiteTestRes = {};
|
||
while (true) {
|
||
try {
|
||
result = await this.doTestOnce(req);
|
||
return result;
|
||
} catch (e) {
|
||
tryCount++;
|
||
if (tryCount > maxRetryTimes) {
|
||
logger.error(`测试站点出错,已超过最大重试次数(${maxRetryTimes})`, e.message);
|
||
throw e;
|
||
}
|
||
//指数退避
|
||
const time = 2 ** tryCount;
|
||
logger.error(`测试站点出错,${time}s后重试(${tryCount}/${maxRetryTimes})`, e);
|
||
await utils.sleep(time * 1000);
|
||
}
|
||
}
|
||
}
|
||
|
||
async doTestOnce(req: SiteTestReq): Promise<SiteTestRes> {
|
||
const options: any = merge(
|
||
{
|
||
port: 443,
|
||
method: "GET",
|
||
rejectUnauthorized: false
|
||
},
|
||
req
|
||
);
|
||
|
||
if (req.ipAddress) {
|
||
//使用固定的ip
|
||
const ipAddress = req.ipAddress;
|
||
options.headers={
|
||
host: options.host,
|
||
//sni
|
||
servername: options.host
|
||
}
|
||
options.host = ipAddress;
|
||
}
|
||
|
||
options.agent = new https.Agent({ keepAlive: false });
|
||
|
||
// 创建 HTTPS 请求
|
||
const requestPromise = safePromise((resolve, reject) => {
|
||
const req = https.request(options, res => {
|
||
// 获取证书
|
||
// @ts-ignore
|
||
const certificate = res.socket.getPeerCertificate();
|
||
// logger.info('证书信息', certificate);
|
||
if (certificate.subject == null) {
|
||
logger.warn("证书信息为空");
|
||
resolve({
|
||
certificate: null
|
||
});
|
||
}
|
||
resolve({
|
||
certificate
|
||
});
|
||
res.socket.end();
|
||
// 关闭响应
|
||
res.destroy();
|
||
});
|
||
|
||
req.on("error", e => {
|
||
reject(e);
|
||
});
|
||
req.end();
|
||
});
|
||
|
||
return await requestPromise;
|
||
}
|
||
}
|
||
|
||
export const siteTester = new SiteTester();
|