mirror of https://github.com/certd/certd
chore:
parent
ec342708b2
commit
03b751fa13
|
@ -9,16 +9,24 @@ import { IDnsProvider, parseDomain } from "../../dns-provider/index.js";
|
|||
import { HttpChallengeUploader } from "./uploads/api.js";
|
||||
|
||||
export type CnameVerifyPlan = {
|
||||
type?: string;
|
||||
domain: string;
|
||||
fullRecord: string;
|
||||
dnsProvider: IDnsProvider;
|
||||
};
|
||||
|
||||
export type HttpVerifyPlan = {
|
||||
type: string;
|
||||
domain: string;
|
||||
httpUploader: HttpChallengeUploader;
|
||||
};
|
||||
|
||||
export type DomainVerifyPlan = {
|
||||
domain: string;
|
||||
type: "cname" | "dns" | "http";
|
||||
dnsProvider?: IDnsProvider;
|
||||
cnameVerifyPlan?: Record<string, CnameVerifyPlan>;
|
||||
httpVerifyPlan?: Record<string, HttpVerifyPlan>;
|
||||
};
|
||||
export type DomainsVerifyPlan = {
|
||||
[key: string]: DomainVerifyPlan;
|
||||
|
@ -171,7 +179,23 @@ export class AcmeService {
|
|||
const filePath = `.well-known/acme-challenge/${challenge.token}`;
|
||||
const fileContents = keyAuthorization;
|
||||
this.logger.info(`校验 ${fullDomain} ,准备上传文件:${filePath}`);
|
||||
await providers.httpUploader.upload(filePath, fileContents);
|
||||
|
||||
let httpUploaderPlan: HttpVerifyPlan = null;
|
||||
if (providers.domainsVerifyPlan) {
|
||||
//查找文件上传配置
|
||||
for (const mainDomain in providers.domainsVerifyPlan) {
|
||||
const domainVerifyPlan = providers.domainsVerifyPlan[mainDomain];
|
||||
if (domainVerifyPlan && domainVerifyPlan.type === "http" && domainVerifyPlan.httpVerifyPlan[fullDomain]) {
|
||||
httpUploaderPlan = domainVerifyPlan.httpVerifyPlan[fullDomain];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (httpUploaderPlan == null) {
|
||||
throw new Error(`未找到域名【${fullDomain}】的http校验计划`);
|
||||
}
|
||||
|
||||
await httpUploaderPlan.httpUploader.upload(filePath, fileContents);
|
||||
this.logger.info(`上传文件【${filePath}】成功`);
|
||||
} else if (challenge.type === "dns-01") {
|
||||
/* dns-01 */
|
||||
|
@ -204,8 +228,11 @@ export class AcmeService {
|
|||
} else {
|
||||
this.logger.error("未找到域名Cname校验计划,使用默认的dnsProvider");
|
||||
}
|
||||
} else if (domainVerifyPlan.type === "http") {
|
||||
throw new Error("切换为http校验");
|
||||
} else {
|
||||
this.logger.error("不支持的校验类型", domainVerifyPlan.type);
|
||||
// this.logger.error("不支持的校验类型", domainVerifyPlan.type);
|
||||
throw new Error("不支持的校验类型", domainVerifyPlan.type);
|
||||
}
|
||||
} else {
|
||||
this.logger.info("未找到域名校验计划,使用默认的dnsProvider");
|
||||
|
@ -346,7 +373,7 @@ export class AcmeService {
|
|||
email: email,
|
||||
termsOfServiceAgreed: true,
|
||||
skipChallengeVerification: this.skipLocalVerify,
|
||||
challengePriority: ["dns-01"],
|
||||
challengePriority: ["dns-01", "http-01"],
|
||||
challengeCreateFn: async (
|
||||
authz: acme.Authorization,
|
||||
challenge: Challenge,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { CancelError, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { utils } from "@certd/basic";
|
||||
|
||||
import type { CertInfo, CnameVerifyPlan, DomainsVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js";
|
||||
import type { CertInfo, CnameVerifyPlan, DomainsVerifyPlan, HttpVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js";
|
||||
import { AcmeService } from "./acme.js";
|
||||
import * as _ from "lodash-es";
|
||||
import { createDnsProvider, DnsProviderContext, IDnsProvider } from "../../dns-provider/index.js";
|
||||
|
@ -9,7 +9,6 @@ import { CertReader } from "./cert-reader.js";
|
|||
import { CertApplyBasePlugin } from "./base.js";
|
||||
import { GoogleClient } from "../../libs/google.js";
|
||||
import { EabAccess } from "../../access";
|
||||
import { HttpChallengeUploader } from "./uploads/api";
|
||||
import { httpChallengeUploaderFactory } from "./uploads/factory.js";
|
||||
|
||||
export type { CertInfo };
|
||||
|
@ -67,8 +66,9 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||
],
|
||||
},
|
||||
required: true,
|
||||
helper:
|
||||
"DNS直接验证:域名是在阿里云、腾讯云、华为云、Cloudflare、NameSilo、西数注册的,选它。\nCNAME代理验证:支持任何注册商注册的域名,但第一次需要手动添加CNAME记录",
|
||||
helper: `DNS直接验证:域名是在阿里云、腾讯云、华为云、Cloudflare、NameSilo、西数注册的,选它;
|
||||
CNAME代理验证:支持任何注册商注册的域名,但第一次需要手动添加CNAME记录;
|
||||
HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
})
|
||||
challengeType!: string;
|
||||
|
||||
|
@ -127,75 +127,13 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||
})
|
||||
dnsProviderAccess!: number;
|
||||
|
||||
@TaskInput({
|
||||
title: "文件上传方式",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{ value: "ftp", label: "FTP" },
|
||||
{ value: "sftp", label: "SFTP" },
|
||||
{ value: "alioss", label: "阿里云OSS" },
|
||||
{ value: "tencentcos", label: "腾讯云COS" },
|
||||
{ value: "qiniuoss", label: "七牛OSS" },
|
||||
],
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.challengeType === 'http'
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
helper: "您的域名注册商,或者域名的dns服务器属于哪个平台\n如果这里没有,请选择CNAME代理验证校验方式",
|
||||
})
|
||||
httpUploadType!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "文件上传授权",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
},
|
||||
required: true,
|
||||
helper: "请选择文件上传授权",
|
||||
mergeScript: `return {
|
||||
component:{
|
||||
type: ctx.compute(({form})=>{
|
||||
return form.httpUploadType
|
||||
})
|
||||
},
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.challengeType === 'http'
|
||||
})
|
||||
}
|
||||
`,
|
||||
})
|
||||
httpUploadAccess!: number;
|
||||
@TaskInput({
|
||||
title: "网站根路径",
|
||||
component: {
|
||||
name: "a-input",
|
||||
},
|
||||
required: true,
|
||||
helper: "请选择网站根路径,校验文件将上传到此目录下",
|
||||
mergeScript: `return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.challengeType === 'http'
|
||||
})
|
||||
}
|
||||
`,
|
||||
})
|
||||
httpUploadRootDir!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: "域名验证配置",
|
||||
component: {
|
||||
name: "domains-verify-plan-editor",
|
||||
},
|
||||
rules: [{ type: "checkCnameVerifyPlan" }],
|
||||
rules: [{ type: "checkDomainVerifyPlan" }],
|
||||
required: true,
|
||||
helper: "如果选择CNAME方式,请按照上面的显示,给要申请证书的域名添加CNAME记录,添加后,点击验证,验证成功后不要删除记录,申请和续期证书会一直用它",
|
||||
col: {
|
||||
span: 24,
|
||||
},
|
||||
|
@ -203,10 +141,20 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||
component:{
|
||||
domains: ctx.compute(({form})=>{
|
||||
return form.domains
|
||||
}),
|
||||
defaultType: ctx.compute(({form})=>{
|
||||
return form.challengeType || 'cname'
|
||||
})
|
||||
},
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.challengeType === 'cname'
|
||||
return form.challengeType === 'cname' || form.challengeType === 'http'
|
||||
}),
|
||||
helper: ctx.compute(({form})=>{
|
||||
if(form.challengeType === 'cname' ){
|
||||
return '请按照上面的提示,给要申请证书的域名添加CNAME记录,添加后,点击验证,验证成功后不要删除记录,申请和续期证书会一直用它'
|
||||
}else if (form.challengeType === 'http'){
|
||||
return '请按照上面的提示,给每个域名设置文件上传配置,证书申请过程中会上传校验文件到网站根目录下'
|
||||
}
|
||||
})
|
||||
}
|
||||
`,
|
||||
|
@ -393,15 +341,8 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||
|
||||
let dnsProvider: IDnsProvider = null;
|
||||
let domainsVerifyPlan: DomainsVerifyPlan = null;
|
||||
let httpUploader: HttpChallengeUploader = null;
|
||||
if (this.challengeType === "cname") {
|
||||
if (this.challengeType === "cname" || this.challengeType === "http") {
|
||||
domainsVerifyPlan = await this.createDomainsVerifyPlan();
|
||||
} else if (this.challengeType === "http") {
|
||||
const access = await this.ctx.accessService.getById(this.httpUploadAccess);
|
||||
httpUploader = await httpChallengeUploaderFactory.createUploaderByType(this.httpUploadType, {
|
||||
rootDir: this.httpUploadRootDir,
|
||||
access,
|
||||
});
|
||||
} else {
|
||||
const dnsProviderType = this.dnsProviderType;
|
||||
const access = await this.ctx.accessService.getById(this.dnsProviderAccess);
|
||||
|
@ -414,7 +355,6 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||
domains,
|
||||
dnsProvider,
|
||||
domainsVerifyPlan,
|
||||
httpUploader,
|
||||
csrInfo,
|
||||
isTest: false,
|
||||
privateKeyType: this.privateKeyType,
|
||||
|
@ -449,10 +389,11 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||
const domainVerifyPlan = this.domainsVerifyPlan[domain];
|
||||
let dnsProvider = null;
|
||||
const cnameVerifyPlan: Record<string, CnameVerifyPlan> = {};
|
||||
const httpVerifyPlan: Record<string, HttpVerifyPlan> = {};
|
||||
if (domainVerifyPlan.type === "dns") {
|
||||
const access = await this.ctx.accessService.getById(domainVerifyPlan.dnsProviderAccessId);
|
||||
dnsProvider = await this.createDnsProvider(domainVerifyPlan.dnsProviderType, access);
|
||||
} else {
|
||||
} else if (domainVerifyPlan.type === "cname") {
|
||||
for (const key in domainVerifyPlan.cnameVerifyPlan) {
|
||||
const cnameRecord = await this.ctx.cnameProxyService.getByDomain(key);
|
||||
let dnsProvider = cnameRecord.commonDnsProvider;
|
||||
|
@ -460,17 +401,39 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||
dnsProvider = await this.createDnsProvider(cnameRecord.cnameProvider.dnsProviderType, cnameRecord.cnameProvider.access);
|
||||
}
|
||||
cnameVerifyPlan[key] = {
|
||||
type: "cname",
|
||||
domain: cnameRecord.cnameProvider.domain,
|
||||
fullRecord: cnameRecord.recordValue,
|
||||
dnsProvider,
|
||||
};
|
||||
}
|
||||
} else if (domainVerifyPlan.type === "http") {
|
||||
const httpUploaderContext = {
|
||||
accessService: this.ctx.accessService,
|
||||
logger: this.logger,
|
||||
utils,
|
||||
};
|
||||
for (const key in domainVerifyPlan.httpVerifyPlan) {
|
||||
const httpRecord = domainVerifyPlan.httpVerifyPlan[key];
|
||||
const access = await this.ctx.accessService.getById(httpRecord.httpUploaderAccess);
|
||||
const httpUploader = await httpChallengeUploaderFactory.createUploaderByType(httpRecord.httpUploaderType, {
|
||||
access,
|
||||
rootDir: httpRecord.httpUploadRootDir,
|
||||
ctx: httpUploaderContext,
|
||||
});
|
||||
httpVerifyPlan[key] = {
|
||||
type: "http",
|
||||
domain: key,
|
||||
httpUploader,
|
||||
};
|
||||
}
|
||||
}
|
||||
plan[domain] = {
|
||||
domain,
|
||||
type: domainVerifyPlan.type,
|
||||
dnsProvider,
|
||||
cnameVerifyPlan,
|
||||
httpVerifyPlan,
|
||||
};
|
||||
}
|
||||
return plan;
|
||||
|
|
|
@ -1,24 +1,33 @@
|
|||
import { HttpChallengeUploadContext } from "./api";
|
||||
|
||||
export class HttpChallengeUploaderFactory {
|
||||
async getClassByType(type: string) {
|
||||
if (type === "alioss") {
|
||||
return (await import("./impls/alioss.js")).AliossHttpChallengeUploader;
|
||||
const module = await import("./impls/alioss.js");
|
||||
return module.AliossHttpChallengeUploader;
|
||||
} else if (type === "ssh") {
|
||||
return (await import("./impls/ssh.js")).SshHttpChallengeUploader;
|
||||
const module = await import("./impls/ssh.js");
|
||||
return module.SshHttpChallengeUploader;
|
||||
} else if (type === "ftp") {
|
||||
return (await import("./impls/ftp.js")).FtpHttpChallengeUploader;
|
||||
const module = await import("./impls/ftp.js");
|
||||
return module.FtpHttpChallengeUploader;
|
||||
} else if (type === "tencentcos") {
|
||||
return (await import("./impls/tencentcos.js")).TencentCosHttpChallengeUploader;
|
||||
const module = await import("./impls/tencentcos.js");
|
||||
return module.TencentCosHttpChallengeUploader;
|
||||
} else if (type === "qiniuoss") {
|
||||
return (await import("./impls/qiniuoss.js")).QiniuOssHttpChallengeUploader;
|
||||
const module = await import("./impls/qiniuoss.js");
|
||||
return module.QiniuOssHttpChallengeUploader;
|
||||
} else {
|
||||
throw new Error(`暂不支持此文件上传方式: ${type}`);
|
||||
}
|
||||
}
|
||||
createUploaderByType(type: string, opts: { rootDir: string; access: any }) {
|
||||
const cls = this.getClassByType(type);
|
||||
async createUploaderByType(type: string, opts: { rootDir: string; access: any; ctx: HttpChallengeUploadContext }) {
|
||||
const cls = await this.getClassByType(type);
|
||||
if (cls) {
|
||||
// @ts-ignore
|
||||
return new cls(opts);
|
||||
const instance = new cls(opts);
|
||||
await instance.setCtx(opts.ctx);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BaseHttpChallengeUploader } from "../api";
|
||||
import { BaseHttpChallengeUploader } from "../api.js";
|
||||
import { AliossAccess, AliyunAccess } from "@certd/plugin-lib";
|
||||
import { AliossClient } from "@certd/plugin-lib/dist/aliyun/lib/oss-client";
|
||||
import { AliossClient } from "@certd/plugin-lib";
|
||||
|
||||
export class AliossHttpChallengeUploader extends BaseHttpChallengeUploader<AliossAccess> {
|
||||
async upload(filePath: string, fileContent: string) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { BaseHttpChallengeUploader } from "../api";
|
||||
import { FtpAccess } from "@certd/plugin-lib";
|
||||
import { FtpClient } from "@certd/plugin-lib/dist/ftp/client";
|
||||
import { BaseHttpChallengeUploader } from "../api.js";
|
||||
import { FtpAccess, FtpClient } from "@certd/plugin-lib";
|
||||
|
||||
export class FtpHttpChallengeUploader extends BaseHttpChallengeUploader<FtpAccess> {
|
||||
async upload(fileName: string, fileContent: string) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BaseHttpChallengeUploader } from "../api";
|
||||
import { FtpAccess } from "@certd/plugin-lib";
|
||||
import { BaseHttpChallengeUploader } from "../api.js";
|
||||
import { QiniuOssAccess } from "@certd/plugin-lib/dist/qiniu/access-oss";
|
||||
|
||||
export class QiniuOssHttpChallengeUploader extends BaseHttpChallengeUploader<FtpAccess> {
|
||||
export class QiniuOssHttpChallengeUploader extends BaseHttpChallengeUploader<QiniuOssAccess> {
|
||||
async upload(fileName: string, fileContent: string) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { BaseHttpChallengeUploader } from "../api";
|
||||
import { BaseHttpChallengeUploader } from "../api.js";
|
||||
import { SshAccess, SshClient } from "@certd/plugin-lib";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { BaseHttpChallengeUploader } from "../api";
|
||||
import { FtpAccess } from "@certd/plugin-lib";
|
||||
import { BaseHttpChallengeUploader } from "../api.js";
|
||||
import { TencentCosAccess } from "@certd/plugin-lib/dist/tencent/access-cos";
|
||||
|
||||
export class TencentCosHttpChallengeUploader extends BaseHttpChallengeUploader<FtpAccess> {
|
||||
export class TencentCosHttpChallengeUploader extends BaseHttpChallengeUploader<TencentCosAccess> {
|
||||
async upload(fileName: string, fileContent: string) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export * from "./base-client.js";
|
||||
export * from "./ssl-client.js";
|
||||
export * from "./oss-client.js";
|
||||
|
|
|
@ -24,10 +24,7 @@ defineOptions({
|
|||
name: "CnameVerifyPlan"
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
"update:modelValue": any;
|
||||
change: Record<string, any>;
|
||||
}>();
|
||||
const emit = defineEmits(["update:modelValue", "change"]);
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: Record<string, any>;
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
<template>
|
||||
<table class="http-verify-plan">
|
||||
<thead>
|
||||
<tr>
|
||||
<td style="width: 160px">网站域名</td>
|
||||
<td style="width: 100px; text-align: center">上传方式</td>
|
||||
<td style="width: 150px">上传授权</td>
|
||||
<td style="width: 200px">网站根目录路径</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-if="records" class="http-record-body">
|
||||
<template v-for="(item, key) of records" :key="key">
|
||||
<tr>
|
||||
<td class="domain">
|
||||
{{ item.domain }}
|
||||
</td>
|
||||
<td>
|
||||
<fs-dict-select v-model:value="item.httpUploaderType" :dict="uploaderTypeDict" @change="onRecordChange"></fs-dict-select>
|
||||
</td>
|
||||
<td>
|
||||
<access-selector v-model="item.httpUploaderAccess" :type="item.httpUploaderType" @change="onRecordChange"></access-selector>
|
||||
</td>
|
||||
<td>
|
||||
<a-input v-model:value="item.httpUploadRootDir" placeholder="网站根目录,如:/www/wwwroot" @change="onRecordChange"></a-input>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Ref, ref, watch } from "vue";
|
||||
import { HttpRecord } from "/@/components/plugins/cert/domains-verify-plan-editor/type";
|
||||
import { dict } from "@fast-crud/fast-crud";
|
||||
|
||||
defineOptions({
|
||||
name: "HttpVerifyPlan"
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue", "change"]);
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: Record<string, any>;
|
||||
}>();
|
||||
|
||||
const records: Ref<Record<string, HttpRecord>> = ref({});
|
||||
|
||||
watch(
|
||||
() => {
|
||||
return props.modelValue;
|
||||
},
|
||||
(value: any) => {
|
||||
if (value) {
|
||||
records.value = {
|
||||
...value
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
|
||||
function onRecordChange() {
|
||||
emit("update:modelValue", records.value);
|
||||
emit("change", records.value);
|
||||
}
|
||||
|
||||
const uploaderTypeDict = dict({
|
||||
data: [
|
||||
{ label: "SFTP/SSH", value: "ssh" },
|
||||
{ label: "FTP", value: "ftp" },
|
||||
{ label: "阿里云OSS", value: "alioss" },
|
||||
{ label: "腾讯云COS", value: "tencentcos" },
|
||||
{ label: "七牛OSS", value: "qiniuoss" }
|
||||
]
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.http-verify-plan {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
tbody tr td {
|
||||
border-top: 1px solid #e8e8e8 !important;
|
||||
}
|
||||
tr {
|
||||
td {
|
||||
border: 0 !important;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
&.center {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
//&:last-child {
|
||||
// td {
|
||||
// border-bottom: 0 !important;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -13,7 +13,7 @@
|
|||
<table class="plan-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>域名</th>
|
||||
<th style="min-width: 100px">主域名</th>
|
||||
<th>验证方式</th>
|
||||
<th>验证计划</th>
|
||||
</tr>
|
||||
|
@ -59,7 +59,7 @@
|
|||
<cname-verify-plan v-model="item.cnameVerifyPlan" @change="onPlanChanged" />
|
||||
</div>
|
||||
<div v-if="item.type === 'http'" class="plan-http">
|
||||
<cname-verify-plan v-model="item.cnameVerifyPlan" @change="onPlanChanged" />
|
||||
<http-verify-plan v-model="item.httpVerifyPlan" @change="onPlanChanged" />
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -79,6 +79,7 @@ import { ref, watch } from "vue";
|
|||
import { dict, FsDictSelect } from "@fast-crud/fast-crud";
|
||||
import AccessSelector from "/@/views/certd/access/access-selector/index.vue";
|
||||
import CnameVerifyPlan from "./cname-verify-plan.vue";
|
||||
import HttpVerifyPlan from "./http-verify-plan.vue";
|
||||
import psl from "psl";
|
||||
import { Form } from "ant-design-vue";
|
||||
import { DomainsVerifyPlanInput } from "./type";
|
||||
|
@ -95,12 +96,17 @@ const challengeTypeOptions = ref<any[]>([
|
|||
{
|
||||
label: "CNAME验证",
|
||||
value: "cname"
|
||||
},
|
||||
{
|
||||
label: "HTTP验证",
|
||||
value: "http"
|
||||
}
|
||||
]);
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: DomainsVerifyPlanInput;
|
||||
domains?: string[];
|
||||
defaultType?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
@ -132,6 +138,16 @@ function showError(error: string) {
|
|||
|
||||
type DomainGroup = Record<string, Record<string, CnameRecord>>;
|
||||
|
||||
watch(
|
||||
() => {
|
||||
return props.defaultType;
|
||||
},
|
||||
(value: string) => {
|
||||
planRef.value = {};
|
||||
onDomainsChanged(props.domains);
|
||||
}
|
||||
);
|
||||
|
||||
function onDomainsChanged(domains: string[]) {
|
||||
console.log("域名变化", domains);
|
||||
if (domains == null) {
|
||||
|
@ -155,9 +171,7 @@ function onDomainsChanged(domains: string[]) {
|
|||
group = {};
|
||||
domainGroups[mainDomain] = group;
|
||||
}
|
||||
group[domain] = {
|
||||
id: 0
|
||||
};
|
||||
group[domain] = {};
|
||||
}
|
||||
|
||||
for (const domain in domainGroups) {
|
||||
|
@ -166,27 +180,43 @@ function onDomainsChanged(domains: string[]) {
|
|||
if (!planItem) {
|
||||
planItem = {
|
||||
domain,
|
||||
type: "cname",
|
||||
//@ts-ignore
|
||||
type: props.defaultType || "cname",
|
||||
//@ts-ignore
|
||||
cnameVerifyPlan: {
|
||||
...subDomains
|
||||
},
|
||||
//@ts-ignore
|
||||
httpVerifyPlan: {
|
||||
...subDomains
|
||||
}
|
||||
};
|
||||
planRef.value[domain] = planItem;
|
||||
} else {
|
||||
const cnamePlan = planItem.cnameVerifyPlan;
|
||||
for (const subDomain in subDomains) {
|
||||
if (!cnamePlan[subDomain]) {
|
||||
//@ts-ignore
|
||||
cnamePlan[subDomain] = {
|
||||
id: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
const cnamePlan = planItem.cnameVerifyPlan;
|
||||
for (const subDomain in subDomains) {
|
||||
//@ts-ignore
|
||||
cnamePlan[subDomain] = {
|
||||
id: 0
|
||||
};
|
||||
}
|
||||
for (const subDomain of Object.keys(cnamePlan)) {
|
||||
if (!subDomains[subDomain]) {
|
||||
delete cnamePlan[subDomain];
|
||||
}
|
||||
for (const subDomain of Object.keys(cnamePlan)) {
|
||||
if (!subDomains[subDomain]) {
|
||||
delete cnamePlan[subDomain];
|
||||
}
|
||||
}
|
||||
|
||||
// httpVerifyPlan
|
||||
const httpPlan = planItem.httpVerifyPlan;
|
||||
for (const subDomain in subDomains) {
|
||||
//@ts-ignore
|
||||
httpPlan[subDomain] = {
|
||||
domain: subDomain
|
||||
};
|
||||
}
|
||||
for (const subDomain of Object.keys(httpPlan)) {
|
||||
if (!subDomains[subDomain]) {
|
||||
delete httpPlan[subDomain];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import Validator from "async-validator";
|
||||
import { DomainsVerifyPlanInput } from "./type";
|
||||
|
||||
function checkCnameVerifyPlan(rule, value: DomainsVerifyPlanInput) {
|
||||
function checkDomainVerifyPlan(rule: any, value: DomainsVerifyPlanInput) {
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
for (const domain in value) {
|
||||
if (value[domain].type === "cname") {
|
||||
const type = value[domain].type;
|
||||
if (type === "cname") {
|
||||
const subDomains = Object.keys(value[domain].cnameVerifyPlan);
|
||||
if (subDomains.length > 0) {
|
||||
for (const subDomain of subDomains) {
|
||||
|
@ -16,7 +17,21 @@ function checkCnameVerifyPlan(rule, value: DomainsVerifyPlanInput) {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if (type === "http") {
|
||||
const subDomains = Object.keys(value[domain].httpVerifyPlan);
|
||||
if (subDomains.length > 0) {
|
||||
for (const subDomain of subDomains) {
|
||||
const plan = value[domain].httpVerifyPlan[subDomain];
|
||||
if (plan.httpUploaderType == null) {
|
||||
throw new Error(`域名${subDomain}的上传方式必须填写`);
|
||||
} else if (plan.httpUploaderAccess == null) {
|
||||
throw new Error(`域名${subDomain}的上传授权信息必须填写`);
|
||||
} else if (plan.httpUploadRootDir == null) {
|
||||
throw new Error(`域名${subDomain}的网站根路径必须填写`);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (type === "dns") {
|
||||
if (value[domain].dnsProviderType == null || value[domain].dnsProviderAccessId == null) {
|
||||
throw new Error(`DNS模式下,域名${domain}的DNS类型和授权信息必须填写`);
|
||||
}
|
||||
|
@ -25,4 +40,4 @@ function checkCnameVerifyPlan(rule, value: DomainsVerifyPlanInput) {
|
|||
return true;
|
||||
}
|
||||
// 注册自定义验证器
|
||||
Validator.register("checkCnameVerifyPlan", checkCnameVerifyPlan);
|
||||
Validator.register("checkDomainVerifyPlan", checkDomainVerifyPlan);
|
||||
|
|
Loading…
Reference in New Issue