perf: 支持使用letencrypt测试环境申请ip证书

This commit is contained in:
xiaojunnuo
2025-11-12 23:56:02 +08:00
parent e1eef013a8
commit 86ce00adf9
4 changed files with 68 additions and 28 deletions
+2 -1
View File
@@ -4,5 +4,6 @@
"typescript.tsc.autoDetect": "watch", "typescript.tsc.autoDetect": "watch",
"git.scanRepositories": [ "git.scanRepositories": [
"./packages/pro" "./packages/pro"
] ],
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
} }
+18 -3
View File
@@ -4,6 +4,9 @@
import { readCsrDomains } from "./crypto/index.js"; import { readCsrDomains } from "./crypto/index.js";
import { wait } from "./wait.js"; import { wait } from "./wait.js";
import { CancelError } from "./error.js"; import { CancelError } from "./error.js";
import { domainUtils } from '@certd/basic';
const defaultOpts = { const defaultOpts = {
@@ -65,7 +68,7 @@ export default async (client, userOpts) => {
* Parse domains from CSR * Parse domains from CSR
*/ */
log("[auto] Parsing domains from Certificate Signing Request "); log("[auto] Parsing domains from Certificate Signing Request");
const { commonName, altNames } = readCsrDomains(opts.csr); const { commonName, altNames } = readCsrDomains(opts.csr);
const uniqueDomains = Array.from(new Set([commonName].concat(altNames).filter((d) => d))); const uniqueDomains = Array.from(new Set([commonName].concat(altNames).filter((d) => d)));
@@ -76,9 +79,21 @@ export default async (client, userOpts) => {
*/ */
log("[auto] Placing new certificate order with ACME provider"); log("[auto] Placing new certificate order with ACME provider");
const orderPayload = { identifiers: uniqueDomains.map((d) => ({ type: "dns", value: d })) };
if (opts.profile && client.sslProvider === 'letsencrypt' ){ let hasIp = false
const orderPayload = { identifiers: uniqueDomains.map((d) =>{
// 判断是否为IP(v4或v6),否则按域名处理
const type = domainUtils.isIp(d) ? 'ip' : 'dns';
if(type === 'ip'){
hasIp = true
}
return { type, value: d }
}) };
if (opts.profile && client.sslProvider.startsWith("letsencrypt") ){
orderPayload.profile = opts.profile; orderPayload.profile = opts.profile;
if(hasIp){
orderPayload.profile = "shortlived"
}
} }
const order = await client.createOrder(orderPayload); const order = await client.createOrder(orderPayload);
const authorizations = await client.getAuthorizations(order); const authorizations = await client.getAuthorizations(order);
+33 -7
View File
@@ -7,29 +7,29 @@ function match(targetDomains: string | string[], inDomains: string[]) {
return false; return false;
} }
if (typeof targetDomains === 'string') { if (typeof targetDomains === "string") {
targetDomains = [targetDomains]; targetDomains = [targetDomains];
} }
for (let targetDomain of targetDomains) { for (let targetDomain of targetDomains) {
let matched = false; let matched = false;
if (targetDomain.startsWith('.')) { if (targetDomain.startsWith(".")) {
targetDomain = '*' + targetDomain; targetDomain = "*" + targetDomain;
} }
for (let inDomain of inDomains) { for (let inDomain of inDomains) {
if (inDomain.startsWith('.')) { if (inDomain.startsWith(".")) {
inDomain = '*' + inDomain; inDomain = "*" + inDomain;
} }
if (targetDomain === inDomain) { if (targetDomain === inDomain) {
matched = true; matched = true;
break; break;
} }
if (!inDomain.startsWith('*.')) { if (!inDomain.startsWith("*.")) {
//不可能匹配 //不可能匹配
continue; continue;
} }
//子域名匹配通配符即可 //子域名匹配通配符即可
const firstDotIndex = targetDomain.indexOf('.'); const firstDotIndex = targetDomain.indexOf(".");
const targetDomainSuffix = targetDomain.substring(firstDotIndex + 1); const targetDomainSuffix = targetDomain.substring(firstDotIndex + 1);
if (targetDomainSuffix === inDomain.substring(2)) { if (targetDomainSuffix === inDomain.substring(2)) {
matched = true; matched = true;
@@ -46,6 +46,32 @@ function match(targetDomains: string | string[], inDomains: string[]) {
return true; return true;
} }
function isIpv4(d: string) {
if (!d) {
return false;
}
const isIPv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
return isIPv4Regex.test(d);
}
function isIpv6(d: string) {
if (!d) {
return false;
}
const isIPv6Regex = /^([\da-f]{1,4}:){2,7}[\da-f]{1,4}$/i;
return isIPv6Regex.test(d);
}
function isIp(d: string) {
if (!d) {
return false;
}
return isIpv4(d) || isIpv6(d);
}
export const domainUtils = { export const domainUtils = {
match, match,
isIpv4,
isIpv6,
isIp,
}; };
@@ -364,15 +364,13 @@ export class AcmeService {
//兼容老版本 //兼容老版本
createCsr = acme.forge.createCsr; createCsr = acme.forge.createCsr;
} }
const [key, csr] = await createCsr( const csrData: any = {
{ // commonName,
commonName, ...csrInfo,
...csrInfo, altNames,
altNames, // emailAddress: email,
// emailAddress: email, };
}, const [key, csr] = await createCsr(csrData, privateKey);
privateKey
);
if (dnsProvider == null && domainsVerifyPlan == null) { if (dnsProvider == null && domainsVerifyPlan == null) {
throw new Error("dnsProvider 、 domainsVerifyPlan不能都为空"); throw new Error("dnsProvider 、 domainsVerifyPlan不能都为空");
@@ -417,7 +415,7 @@ export class AcmeService {
} }
buildCommonNameByDomains(domains: string | string[]): { buildCommonNameByDomains(domains: string | string[]): {
commonName: string; commonName?: string;
altNames: string[] | undefined; altNames: string[] | undefined;
} { } {
if (typeof domains === "string") { if (typeof domains === "string") {
@@ -426,14 +424,14 @@ export class AcmeService {
if (domains.length === 0) { if (domains.length === 0) {
throw new Error("domain can not be empty"); throw new Error("domain can not be empty");
} }
const commonName = domains[0]; // const commonName = domains[0];
let altNames: undefined | string[] = undefined; // let altNames: undefined | string[] = undefined;
if (domains.length > 1) { // if (domains.length > 1) {
altNames = _.slice(domains, 1); // altNames = _.slice(domains, 1);
} // }
return { return {
commonName, // commonName,
altNames, altNames: domains,
}; };
} }