fix: 修复ipv6作为证书域名申请证书校验失败的bug

This commit is contained in:
xiaojunnuo
2025-12-15 23:34:47 +08:00
parent e4c21c4d5c
commit e4e16bc6a6
8 changed files with 59 additions and 24 deletions

View File

@@ -8,7 +8,7 @@ import {log as defaultLog} from './logger.js'
import axios from './axios.js'
import * as util from './util.js'
import {isAlpnCertificateAuthorizationValid} from './crypto/index.js'
import {utils} from '@certd/basic'
const dns = dnsSdk.promises
@@ -60,11 +60,15 @@ async function verifyHttpChallenge(authz, challenge, keyAuthorization, suffix =
}
const httpPort = axios.defaults.acmeSettings.httpChallengePort || 80;
const challengeUrl = `http://${authz.identifier.value}:${httpPort}${suffix}`;
let host = authz.identifier.value;
if(utils.domain.isIpv6(host)){
host = `[${host}]`;
}
const challengeUrl = `http://${host}:${httpPort}${suffix}`;
if (!await doQuery(challengeUrl)) {
const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443;
const httpsChallengeUrl = `https://${authz.identifier.value}:${httpsPort}${suffix}`;
const httpsChallengeUrl = `https://${host}:${httpsPort}${suffix}`;
const res = await doQuery(httpsChallengeUrl)
if (!res) {
throw new Error(`[error] 验证失败请检查以上测试url是否可以正常访问`);

View File

@@ -26,3 +26,4 @@ dist-ssr
test/user.secret.*
test/**/*.js
src/**/*.spec.ts
test.mjs

View File

@@ -58,7 +58,7 @@ function isIpv6(d: string) {
if (!d) {
return false;
}
const isIPv6Regex = /^([\da-f]{1,4}:){2,7}[\da-f]{1,4}$/i;
const isIPv6Regex = /^([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})$/gm;
return isIPv6Regex.test(d);
}

View File

@@ -1,14 +1,18 @@
import { random } from "lodash-es";
import { locker } from "./dist/utils/util.lock.js";
// import { random } from "lodash-es";
// import { locker } from "./dist/utils/util.lock.js";
async function testLocker() {
for (let i = 0; i < 10; i++) {
await locker.execute("test", async () => {
console.log("test", i);
await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));
throw new Error("test error");
});
}
}
// async function testLocker() {
// for (let i = 0; i < 10; i++) {
// await locker.execute("test", async () => {
// console.log("test", i);
// await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));
// throw new Error("test error");
// });
// }
// }
await testLocker();
// await testLocker();
import { domainUtils } from "./dist/utils/util.domain.js";
console.log(domainUtils.isIpv6("::0:0:0:FFFF:129.144.52.38"));

View File

@@ -134,12 +134,9 @@ export class SysEmailConf extends BaseSettings {
templates:{
registerCode?: EmailTemplate,
forgotPasswordCode?: EmailTemplate,
certSuccessNotify?: EmailTemplate,
certSend?: EmailTemplate,
pipelineNotify?: EmailTemplate,
test?: EmailTemplate,
siteMonitorNotify?: EmailTemplate,
forgotPassword?: EmailTemplate,
pipelineResult?: EmailTemplate,
common?: EmailTemplate,
}
}

View File

@@ -21,6 +21,11 @@ export class DomainParser implements IDomainParser {
}
async parse(fullDomain: string) {
//如果是ip
if (utils.domain.isIp(fullDomain)) {
return fullDomain;
}
this.logger.info(`查找主域名:${fullDomain}`);
const cacheKey = `domain_parse:${fullDomain}`;
const value = utils.cache.get(cacheKey);

View File

@@ -220,7 +220,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
if(form.challengeType === 'cname' ){
return '请按照上面的提示给要申请证书的域名添加CNAME记录添加后点击验证验证成功后不要删除记录申请和续期证书会一直用它'
}else if (form.challengeType === 'http'){
return '请按照上面的提示,给每个域名设置文件上传配置,证书申请过程中会上传校验文件到网站根目录下'
return '请按照上面的提示,给每个域名设置文件上传配置,证书申请过程中会上传校验文件到网站根目录的.well-known/acme-challenge/目录下'
}else if (form.challengeType === 'http'){
return '给每个域名单独配置dns提供商'
}

View File

@@ -1,4 +1,26 @@
import Validator from "async-validator";
function isIpv6(d: string) {
if (!d) {
return false;
}
const isIPv6Regex = /^([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{1,4}$|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})$/gm;
return isIPv6Regex.test(d);
}
function isIpv4(d: string) {
if (!d) {
return false;
}
const isIPv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
return isIPv4Regex.test(d);
}
function isIp(d: string) {
if (!d) {
return false;
}
return isIpv4(d) || isIpv6(d);
}
// 自定义验证器函数
export function isDomain(rule: any, value: any) {
if (value == null || value == "") {
@@ -14,7 +36,9 @@ export function isDomain(rule: any, value: any) {
const compiled = new RegExp(exp);
for (const domain of domains) {
//域名可以是泛域名,中文域名,数字域名,英文域名,域名中可以包含-和. ,可以_开头
if (isIp(domain)) {
continue;
}
if (!compiled.test(domain)) {
throw new Error(`域名有误:${domain},请输入正确的域名`);
}