chore: auto

v2-dev-auto
xiaojunnuo 2025-07-13 23:08:00 +08:00
parent af5e1b805f
commit 896cd950e9
10 changed files with 96 additions and 29 deletions

View File

@ -62,12 +62,14 @@ export interface IDomainParser {
export type DnsVerifier = {
// dns直接校验
dnsProviderType: string;
dnsProviderAccessId: number;
dnsProviderType?: string;
dnsProviderAccessId?: number;
};
export type CnameVerifier = {
cnameRecord: string;
hostRecord: string;
domain: string;
recordValue: string;
};
export type HttpVerifier = {

View File

@ -269,11 +269,11 @@ export class AcmeService {
throw new Error("不支持的校验类型", domainVerifyPlan.type);
}
} else {
this.logger.info("未找到域名校验计划使用默认的dnsProvider");
this.logger.warn(`未找到域名${fullDomain}的校验计划使用默认的dnsProvider`);
}
}
if (!dnsProvider) {
this.logger.error("dnsProvider不存在无法申请证书");
throw new Error(`域名${fullDomain}没有匹配到任何校验方式,证书申请失败`);
}
const dnsChallenge = getChallenge("dns-01");

View File

@ -66,15 +66,15 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
{ value: "cname", label: "CNAME代理验证" },
{ value: "http", label: "HTTP文件验证" },
{ value: "dnses", label: "多DNS提供商" },
{ value: "auto", label: "自动选择" },
{ value: "auto", label: "自动匹配" },
],
},
required: true,
helper: `1. <b>DNS直接验证</b>域名dns解析是在阿里云/腾讯云/华为云/CF/NameSilo/西数/火山/dns.la/京东云/51dns的选它
2. <b>CNAME</b>CNAMEDNS/使DNS
2. <b>CNAME</b>[CNAME](#/certd/cname/record)DNS/使DNS
3. <b>HTTP</b>
4. <b>DNS</b>DNS
5. <b></b>[](#/certd/cert/domain)
5. <b></b>[](#/certd/cert/domain)
`,
})
challengeType!: string;
@ -469,13 +469,13 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
for (const fullDomain of domains) {
const domain = fullDomain.replaceAll("*.", "");
const mainDomain = await domainParser.parse(domain);
const planSetting = verifyPlanSetting[mainDomain];
const planSetting: DomainVerifyPlanInput = verifyPlanSetting[mainDomain];
if (planSetting.type === "dns") {
await this.createDnsDomainVerifyPlan(planSetting[mainDomain], domain, mainDomain);
plan[domain] = await this.createDnsDomainVerifyPlan(planSetting, domain, mainDomain);
} else if (planSetting.type === "cname") {
await this.createCnameDomainVerifyPlan(domain, mainDomain);
plan[domain] = await this.createCnameDomainVerifyPlan(domain, mainDomain);
} else if (planSetting.type === "http") {
await this.createHttpDomainVerifyPlan(planSetting.httpVerifyPlan[domain], domain, mainDomain);
plan[domain] = await this.createHttpDomainVerifyPlan(planSetting.httpVerifyPlan[domain], domain, mainDomain);
}
}
return plan;
@ -486,7 +486,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
// domain list
const domainList = new Set<string>();
//整理域名
for (let domain in this.domains) {
for (let domain of domains) {
domain = domain.replaceAll("*.", "");
domainList.add(domain);
}
@ -563,7 +563,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
domain,
mainDomain,
cnameVerifyPlan: {
domain,
domain: cnameRecord.cnameProvider.domain,
fullRecord: cnameRecord.recordValue,
dnsProvider,
},

View File

@ -714,6 +714,7 @@ export default {
},
domain: {
domainManager: "Domain Manager",
domainDescription: "used to auto apply for certificate", //管理域名的校验方式,用于申请证书时自动选择验证方式
domain: "Domain",
challengeType: "Challenge Type",
dnsProviderType: "DNS Provider Type",
@ -722,5 +723,7 @@ export default {
httpUploaderAccess: "HTTP Uploader Access",
httpUploadRootDir: "HTTP Upload Root Dir",
disabled: "Disabled",
challengeSetting: "Challenge Setting",
gotoCnameTip: "Please go to CNAME Record Page",
},
};

View File

@ -14,6 +14,8 @@ export default {
search: "Search",
enabled: "Enabled",
disabled: "Disabled",
enable: "Enable",
disable: "Disable",
edit: "Edit",
delete: "Delete",
create: "Create",

View File

@ -717,6 +717,7 @@ export default {
},
domain: {
domainManager: "域名管理",
domainDescription: "管理域名的校验方式,用于申请证书时自动选择验证方式",
domain: "域名",
challengeType: "校验类型",
dnsProviderType: "DNS提供商类型",
@ -725,5 +726,7 @@ export default {
httpUploaderAccess: "上传授权信息",
httpUploadRootDir: "网站根路径",
disabled: "禁用/启用",
challengeSetting: "校验配置",
gotoCnameTip: "CNAME域名配置请前往CNAME记录页面添加",
},
};

View File

@ -14,6 +14,8 @@ export default {
search: "搜索",
enabled: "已启用",
disabled: "已禁用",
enable: "启用",
disable: "禁用",
edit: "修改",
delete: "删除",
create: "新增",

View File

@ -7,6 +7,7 @@ import { useUserStore } from "/@/store/user";
import { useSettingStore } from "/@/store/settings";
import { Dicts } from "/@/components/plugins/lib/dicts";
import { createAccessApi } from "/@/views/certd/access/api";
import { Modal } from "ant-design-vue";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter();
@ -73,13 +74,20 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
delRequest,
},
tabs: {
name: "status",
name: "challengeType",
show: true,
},
rowHandle: {
minWidth: 200,
fixed: "right",
},
form: {
beforeSubmit({ form }) {
if (form.challengeType === "cname") {
throw new Error("CNAME方式请前往CNAME记录页面进行管理");
}
},
},
columns: {
id: {
title: "ID",
@ -114,11 +122,28 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
title: t("certd.domain.challengeType"),
type: "dict-select",
dict: Dicts.challengeTypeDict,
search: {
show: true,
},
form: {
required: true,
valueChange({ value }) {
if (value === "cname") {
Modal.confirm({
title: t("certd.domain.gotoCnameTip"),
async onOk() {
router.push({
path: "/certd/cname/record",
});
crudExpose.getFormWrapperRef().close();
},
});
}
},
},
column: {
sorter: true,
show: false,
},
},
/**
@ -196,6 +221,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
form: {
component: {
name: "AccessSelector",
vModel: "modelValue",
type: compute(({ form }) => {
return form.httpUploaderType;
}),
},
show: compute(({ form }) => {
return form.challengeType === "http";
@ -226,16 +255,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
},
challengeSetting: {
title: "校验配置",
title: t("certd.domain.challengeSetting"),
type: "text",
form: { show: false },
column: {
width: 400,
width: 600,
conditionalRender: false,
cellRender({ row }) {
if (row.challengeType === "dns") {
return (
<div class={"flex"}>
<fs-values-format modelValue={row.challengeType} dict={Dicts.challengeTypeDict} color={"auto"}></fs-values-format>
<fs-values-format modelValue={row.dnsProviderType} dict={dnsProviderTypeDict} color={"auto"}></fs-values-format>
<fs-values-format class={"ml-5"} modelValue={row.dnsProviderAccess} dict={accessDict} color={"auto"}></fs-values-format>
</div>
@ -243,9 +273,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
} else if (row.challengeType === "http") {
return (
<div class={"flex"}>
<fs-values-format modelValue={row.challengeType} dict={Dicts.challengeTypeDict} color={"auto"}></fs-values-format>
<fs-values-format modelValue={row.httpUploaderType} dict={httpUploaderTypeDict} color={"auto"}></fs-values-format>
<fs-values-format class={"ml-5"} modelValue={row.httpUploaderAccess} dict={accessDict} color={"auto"}></fs-values-format>
<a-tag class={"ml-5"}>{row.httpUploadRootDir}</a-tag>
<a-tag class={"ml-5 flex items-center"}>{row.httpUploadRootDir}</a-tag>
</div>
);
}
@ -255,10 +286,11 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
disabled: {
title: t("certd.domain.disabled"),
type: "dict-switch",
search: { show: true },
dict: dict({
data: [
{ label: "启用", value: false, color: "green" },
{ label: "禁用", value: true, color: "red" },
{ label: t("common.enabled"), value: false, color: "green" },
{ label: t("common.disabled"), value: true, color: "red" },
],
}),
form: {

View File

@ -3,7 +3,9 @@
<template #header>
<div class="title">
{{ t("certd.domain.domainManager") }}
<span class="sub"> </span>
<span class="sub">
{{ t("certd.domain.domainDescription") }}
</span>
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding">

View File

@ -7,6 +7,8 @@ import {SubDomainService} from "../../pipeline/service/sub-domain-service.js";
import {DomainParser} from "@certd/plugin-cert/dist/dns-provider/domain-parser.js";
import {DomainVerifiers} from "@certd/plugin-cert";
import { SubDomainsGetter } from '../../pipeline/service/getter/sub-domain-getter.js';
import { CnameRecordService } from '../../cname/service/cname-record-service.js';
import { CnameRecordEntity } from "../../cname/entity/cname-record.js";
/**
@ -23,6 +25,9 @@ export class DomainService extends BaseService<DomainEntity> {
@Inject()
subDomainService: SubDomainService;
@Inject()
cnameRecordService: CnameRecordService;
//@ts-ignore
getRepository() {
return this.repository;
@ -96,10 +101,12 @@ export class DomainService extends BaseService<DomainEntity> {
//去重
allDomains = [...new Set(allDomains)]
//从 domain 表中获取配置
const domainRecords = await this.find({
where: {
domain: In(allDomains),
userId
userId,
disabled:false,
}
})
@ -107,16 +114,28 @@ export class DomainService extends BaseService<DomainEntity> {
pre[item.domain] = item
return pre
}, {})
const cnameMap = domainRecords.filter(item=>item.challengeType === 'cname').reduce((pre, item) => {
pre[item.domain] = item
return pre
}, {})
const httpMap = domainRecords.filter(item=>item.challengeType === 'http').reduce((pre, item) => {
pre[item.domain] = item
return pre
}, {})
//从cname record表中获取配置
const cnameRecords = await this.cnameRecordService.find({
where: {
domain: In(allDomains),
userId,
status: "valid",
}
})
const cnameMap = cnameRecords.reduce((pre, item) => {
pre[item.domain] = item
return pre
}, {})
//构建域名验证计划
const domainVerifiers:DomainVerifiers = {}
for (const domain of domains) {
@ -130,19 +149,21 @@ export class DomainService extends BaseService<DomainEntity> {
type: 'dns',
dns: {
dnsProviderType: dnsRecord.dnsProviderType,
dnsProviderAccessId: dnsRecord.dnsProviderAccessId
dnsProviderAccessId: dnsRecord.dnsProviderAccess
}
}
continue
}
const cnameRecord = cnameMap[mainDomain]
const cnameRecord:CnameRecordEntity = cnameMap[mainDomain]
if (cnameRecord) {
domainVerifiers[domain] = {
domain,
mainDomain,
type: 'cname',
cname: {
cnameRecord: cnameRecord.cnameRecord
domain: cnameRecord.domain,
hostRecord: cnameRecord.hostRecord,
recordValue: cnameRecord.recordValue
}
}
continue