mirror of
https://github.com/certd/certd.git
synced 2026-04-24 04:17:25 +08:00
fix: 修复ipv6作为证书域名申请证书校验失败的bug
This commit is contained in:
@@ -8,7 +8,7 @@ import {log as defaultLog} from './logger.js'
|
|||||||
import axios from './axios.js'
|
import axios from './axios.js'
|
||||||
import * as util from './util.js'
|
import * as util from './util.js'
|
||||||
import {isAlpnCertificateAuthorizationValid} from './crypto/index.js'
|
import {isAlpnCertificateAuthorizationValid} from './crypto/index.js'
|
||||||
|
import {utils} from '@certd/basic'
|
||||||
|
|
||||||
const dns = dnsSdk.promises
|
const dns = dnsSdk.promises
|
||||||
|
|
||||||
@@ -60,11 +60,15 @@ async function verifyHttpChallenge(authz, challenge, keyAuthorization, suffix =
|
|||||||
}
|
}
|
||||||
|
|
||||||
const httpPort = axios.defaults.acmeSettings.httpChallengePort || 80;
|
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)) {
|
if (!await doQuery(challengeUrl)) {
|
||||||
const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443;
|
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)
|
const res = await doQuery(httpsChallengeUrl)
|
||||||
if (!res) {
|
if (!res) {
|
||||||
throw new Error(`[error] 验证失败,请检查以上测试url是否可以正常访问`);
|
throw new Error(`[error] 验证失败,请检查以上测试url是否可以正常访问`);
|
||||||
|
|||||||
@@ -26,3 +26,4 @@ dist-ssr
|
|||||||
test/user.secret.*
|
test/user.secret.*
|
||||||
test/**/*.js
|
test/**/*.js
|
||||||
src/**/*.spec.ts
|
src/**/*.spec.ts
|
||||||
|
test.mjs
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ function isIpv6(d: string) {
|
|||||||
if (!d) {
|
if (!d) {
|
||||||
return false;
|
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);
|
return isIPv6Regex.test(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
import { random } from "lodash-es";
|
// import { random } from "lodash-es";
|
||||||
import { locker } from "./dist/utils/util.lock.js";
|
// import { locker } from "./dist/utils/util.lock.js";
|
||||||
|
|
||||||
async function testLocker() {
|
// async function testLocker() {
|
||||||
for (let i = 0; i < 10; i++) {
|
// for (let i = 0; i < 10; i++) {
|
||||||
await locker.execute("test", async () => {
|
// await locker.execute("test", async () => {
|
||||||
console.log("test", i);
|
// console.log("test", i);
|
||||||
await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));
|
// await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));
|
||||||
throw new Error("test error");
|
// 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"));
|
||||||
|
|||||||
@@ -134,12 +134,9 @@ export class SysEmailConf extends BaseSettings {
|
|||||||
|
|
||||||
templates:{
|
templates:{
|
||||||
registerCode?: EmailTemplate,
|
registerCode?: EmailTemplate,
|
||||||
forgotPasswordCode?: EmailTemplate,
|
forgotPassword?: EmailTemplate,
|
||||||
certSuccessNotify?: EmailTemplate,
|
pipelineResult?: EmailTemplate,
|
||||||
certSend?: EmailTemplate,
|
common?: EmailTemplate,
|
||||||
pipelineNotify?: EmailTemplate,
|
|
||||||
test?: EmailTemplate,
|
|
||||||
siteMonitorNotify?: EmailTemplate,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ export class DomainParser implements IDomainParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async parse(fullDomain: string) {
|
async parse(fullDomain: string) {
|
||||||
|
//如果是ip
|
||||||
|
if (utils.domain.isIp(fullDomain)) {
|
||||||
|
return fullDomain;
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.info(`查找主域名:${fullDomain}`);
|
this.logger.info(`查找主域名:${fullDomain}`);
|
||||||
const cacheKey = `domain_parse:${fullDomain}`;
|
const cacheKey = `domain_parse:${fullDomain}`;
|
||||||
const value = utils.cache.get(cacheKey);
|
const value = utils.cache.get(cacheKey);
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||||||
if(form.challengeType === 'cname' ){
|
if(form.challengeType === 'cname' ){
|
||||||
return '请按照上面的提示,给要申请证书的域名添加CNAME记录,添加后,点击验证,验证成功后不要删除记录,申请和续期证书会一直用它'
|
return '请按照上面的提示,给要申请证书的域名添加CNAME记录,添加后,点击验证,验证成功后不要删除记录,申请和续期证书会一直用它'
|
||||||
}else if (form.challengeType === 'http'){
|
}else if (form.challengeType === 'http'){
|
||||||
return '请按照上面的提示,给每个域名设置文件上传配置,证书申请过程中会上传校验文件到网站根目录下'
|
return '请按照上面的提示,给每个域名设置文件上传配置,证书申请过程中会上传校验文件到网站根目录的.well-known/acme-challenge/目录下'
|
||||||
}else if (form.challengeType === 'http'){
|
}else if (form.challengeType === 'http'){
|
||||||
return '给每个域名单独配置dns提供商'
|
return '给每个域名单独配置dns提供商'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,26 @@
|
|||||||
import Validator from "async-validator";
|
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) {
|
export function isDomain(rule: any, value: any) {
|
||||||
if (value == null || value == "") {
|
if (value == null || value == "") {
|
||||||
@@ -14,7 +36,9 @@ export function isDomain(rule: any, value: any) {
|
|||||||
const compiled = new RegExp(exp);
|
const compiled = new RegExp(exp);
|
||||||
for (const domain of domains) {
|
for (const domain of domains) {
|
||||||
//域名可以是泛域名,中文域名,数字域名,英文域名,域名中可以包含-和. ,可以_开头
|
//域名可以是泛域名,中文域名,数字域名,英文域名,域名中可以包含-和. ,可以_开头
|
||||||
|
if (isIp(domain)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!compiled.test(domain)) {
|
if (!compiled.test(domain)) {
|
||||||
throw new Error(`域名有误:${domain},请输入正确的域名`);
|
throw new Error(`域名有误:${domain},请输入正确的域名`);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user