chore: auto

v2-dev-auto
xiaojunnuo 2025-07-12 23:00:04 +08:00
parent 4b335db31c
commit 785bee2b39
7 changed files with 230 additions and 16 deletions

View File

@ -1,6 +1,6 @@
import {Inject, Provide, Scope, ScopeEnum} from '@midwayjs/core'; import {Inject, Provide, Scope, ScopeEnum} from '@midwayjs/core';
import {InjectEntityModel} from '@midwayjs/typeorm'; import {InjectEntityModel} from '@midwayjs/typeorm';
import {Repository} from 'typeorm'; import { In, Repository } from "typeorm";
import {AccessGetter, BaseService, PageReq, PermissionException, ValidateException} from '../../../index.js'; import {AccessGetter, BaseService, PageReq, PermissionException, ValidateException} from '../../../index.js';
import {AccessEntity} from '../entity/access.js'; import {AccessEntity} from '../entity/access.js';
import {AccessDefine, accessRegistry, newAccess} from '@certd/pipeline'; import {AccessDefine, accessRegistry, newAccess} from '@certd/pipeline';
@ -175,4 +175,27 @@ export class AccessService extends BaseService<AccessEntity> {
getDefineByType(type: string) { getDefineByType(type: string) {
return accessRegistry.getDefine(type); return accessRegistry.getDefine(type);
} }
async getSimpleByIds(ids: number[], userId: any) {
if (ids.length === 0) {
return [];
}
if (!userId) {
return [];
}
return await this.repository.find({
where: {
id: In(ids),
userId,
},
select: {
id: true,
name: true,
type: true,
userId:true
},
});
}
} }

View File

@ -59,3 +59,32 @@ export interface ISubDomainsGetter {
export interface IDomainParser { export interface IDomainParser {
parse(fullDomain: string): Promise<string>; parse(fullDomain: string): Promise<string>;
} }
export type DnsVerifier = {
// dns直接校验
dnsProviderType: string;
dnsProviderAccessId: number;
};
export type CnameVerifier = {
cnameRecord: string;
};
export type HttpVerifier = {
// http校验
httpUploaderType: string;
httpUploaderAccess: string;
httpUploadRootDir: string;
};
export type DomainVerifier = {
domain: string;
mainDomain: string;
challengeType: string;
dns?: DnsVerifier;
cname?: CnameVerifier;
http?: HttpVerifier;
};
export interface IDomainVerifierGetter {
getVerifiers(domains: string[]): Promise<DomainVerifier[]>;
}

View File

@ -4,7 +4,7 @@ import { utils } from "@certd/basic";
import type { CertInfo, CnameVerifyPlan, DomainsVerifyPlan, HttpVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js"; import type { CertInfo, CnameVerifyPlan, DomainsVerifyPlan, HttpVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js";
import { AcmeService } from "./acme.js"; import { AcmeService } from "./acme.js";
import * as _ from "lodash-es"; import * as _ from "lodash-es";
import { createDnsProvider, DnsProviderContext, IDnsProvider, ISubDomainsGetter } from "../../dns-provider/index.js"; import { createDnsProvider, DnsProviderContext, DomainVerifier, IDnsProvider, IDomainVerifierGetter, ISubDomainsGetter } from "../../dns-provider/index.js";
import { CertReader } from "./cert-reader.js"; import { CertReader } from "./cert-reader.js";
import { CertApplyBasePlugin } from "./base.js"; import { CertApplyBasePlugin } from "./base.js";
import { GoogleClient } from "../../libs/google.js"; import { GoogleClient } from "../../libs/google.js";
@ -66,6 +66,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
{ value: "cname", label: "CNAME代理验证" }, { value: "cname", label: "CNAME代理验证" },
{ value: "http", label: "HTTP文件验证" }, { value: "http", label: "HTTP文件验证" },
{ value: "dnses", label: "多DNS提供商" }, { value: "dnses", label: "多DNS提供商" },
{ value: "auto", label: "自动选择" },
], ],
}, },
required: true, required: true,
@ -73,6 +74,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
2. <b>CNAME</b>CNAMEDNS/使DNS 2. <b>CNAME</b>CNAMEDNS/使DNS
3. <b>HTTP</b> 3. <b>HTTP</b>
4. <b>DNS</b>DNS 4. <b>DNS</b>DNS
5. <b></b>[](#/certd/cert/domain)
`, `,
}) })
challengeType!: string; challengeType!: string;
@ -408,7 +410,11 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
let dnsProvider: IDnsProvider = null; let dnsProvider: IDnsProvider = null;
let domainsVerifyPlan: DomainsVerifyPlan = null; let domainsVerifyPlan: DomainsVerifyPlan = null;
if (this.challengeType === "cname" || this.challengeType === "http" || this.challengeType === "dnses") { if (this.challengeType === "cname" || this.challengeType === "http" || this.challengeType === "dnses") {
domainsVerifyPlan = await this.createDomainsVerifyPlan(); domainsVerifyPlan = await this.createDomainsVerifyPlan(this.domainsVerifyPlan);
}
if (this.challengeType === "auto") {
const planInput = await this.buildVerifyPlanInputByAuto();
domainsVerifyPlan = await this.createDomainsVerifyPlan(planInput);
} else { } else {
const dnsProviderType = this.dnsProviderType; const dnsProviderType = this.dnsProviderType;
const access = await this.getAccess(this.dnsProviderAccess); const access = await this.getAccess(this.dnsProviderAccess);
@ -451,10 +457,10 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
}); });
} }
async createDomainsVerifyPlan(): Promise<DomainsVerifyPlan> { async createDomainsVerifyPlan(verifyPlanSetting: DomainsVerifyPlanInput): Promise<DomainsVerifyPlan> {
const plan: DomainsVerifyPlan = {}; const plan: DomainsVerifyPlan = {};
for (const domain in this.domainsVerifyPlan) { for (const domain in verifyPlanSetting) {
const domainVerifyPlan = this.domainsVerifyPlan[domain]; const domainVerifyPlan = verifyPlanSetting[domain];
let dnsProvider = null; let dnsProvider = null;
const cnameVerifyPlan: Record<string, CnameVerifyPlan> = {}; const cnameVerifyPlan: Record<string, CnameVerifyPlan> = {};
const httpVerifyPlan: Record<string, HttpVerifyPlan> = {}; const httpVerifyPlan: Record<string, HttpVerifyPlan> = {};
@ -511,6 +517,66 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
} }
return plan; return plan;
} }
private async buildVerifyPlanInputByAuto() {
//从数据库里面自动选择校验方式
// domain list
const domainList = new Set<string>();
//整理域名
for (let domain in this.domains) {
domain = domain.replaceAll("*.", "");
domainList.add(domain);
}
const domainVerifierGetter: IDomainVerifierGetter = await this.ctx.serviceGetter.get("DomainVerifierGetter");
const verifiers = await domainVerifierGetter.getVerifiers([...domainList]);
const verifyPlanInput: DomainsVerifyPlanInput = {};
for (const verifier of verifiers) {
const domain = verifier.domain;
const mainDomain = verifier.mainDomain;
let plan = verifyPlanInput[mainDomain];
if (!plan) {
plan = {
domain: mainDomain,
type: "cname",
};
verifyPlanInput[mainDomain] = plan;
}
if (verifier.challengeType === "cname") {
verifyPlanInput[domain] = {
type: "cname",
domain: domain,
cnameVerifyPlan: {
[domain]: {
id: 0,
status: "validate",
},
},
};
} else if (verifier.challengeType === "http") {
//http
const http = verifier.http;
verifyPlanInput[domain] = {
type: "http",
domain: domain,
httpVerifyPlan: {
[domain]: {
domain: domain,
httpUploaderType: http.httpUploaderType,
httpUploaderAccess: http.httpUploaderAccess,
httpUploadRootDir: http.httpUploadRootDir,
},
},
};
} else {
//dns
}
}
return verifyPlanInput;
}
} }
new CertApplyPlugin(); new CertApplyPlugin();

View File

@ -9,9 +9,9 @@ export const Dicts = {
}), }),
challengeTypeDict: dict({ challengeTypeDict: dict({
data: [ data: [
{ value: "dns", label: "DNS校验" }, { value: "dns", label: "DNS校验", color: "green" },
{ value: "cname", label: "CNAME代理校验" }, { value: "cname", label: "CNAME代理校验", color: "blue" },
{ value: "http", label: "HTTP校验" }, { value: "http", label: "HTTP校验", color: "yellow" },
], ],
}), }),
dnsProviderTypeDict: dict({ dnsProviderTypeDict: dict({

View File

@ -55,6 +55,14 @@ export function createAccessApi(from = "user") {
}); });
}, },
async GetDictByIds(ids: number[]) {
return await request({
url: apiPrefix + "/getDictByIds",
method: "post",
data: { ids },
});
},
async GetSecretPlain(id: number, key: string) { async GetSecretPlain(id: number, key: string) {
return await request({ return await request({
url: apiPrefix + "/getSecretPlain", url: apiPrefix + "/getSecretPlain",

View File

@ -5,8 +5,9 @@ import { useRouter } from "vue-router";
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { useUserStore } from "/@/store/user"; import { useUserStore } from "/@/store/user";
import { useSettingStore } from "/@/store/settings"; import { useSettingStore } from "/@/store/settings";
import { message } from "ant-design-vue";
import { Dicts } from "/@/components/plugins/lib/dicts"; import { Dicts } from "/@/components/plugins/lib/dicts";
import { createAccessApi } from "/@/views/certd/access/api";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter(); const router = useRouter();
const { t } = useI18n(); const { t } = useI18n();
@ -32,6 +33,21 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
const selectedRowKeys: Ref<any[]> = ref([]); const selectedRowKeys: Ref<any[]> = ref([]);
context.selectedRowKeys = selectedRowKeys; context.selectedRowKeys = selectedRowKeys;
const accessApi = createAccessApi();
const accessDict = dict({
value: "id",
label: "name",
url: "accessDict",
async getNodesByValues(ids: number[]) {
return await accessApi.GetDictByIds(ids);
},
});
const httpUploaderTypeDict = Dicts.uploaderTypeDict;
const dnsProviderTypeDict = dict({
url: "pi/dnsProvider/dnsProviderTypeDict",
});
return { return {
crudOptions: { crudOptions: {
settings: { settings: {
@ -90,6 +106,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
disabled: false, disabled: false,
}, },
}, },
column: {
sorter: true,
},
}, },
challengeType: { challengeType: {
title: t("certd.domain.challengeType"), title: t("certd.domain.challengeType"),
@ -98,6 +117,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
form: { form: {
required: true, required: true,
}, },
column: {
sorter: true,
},
}, },
/** /**
* challengeType varchar(50), * challengeType varchar(50),
@ -109,7 +131,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
*/ */
dnsProviderType: { dnsProviderType: {
title: t("certd.domain.dnsProviderType"), title: t("certd.domain.dnsProviderType"),
type: "text", type: "dict-select",
dict: dnsProviderTypeDict,
form: { form: {
component: { component: {
name: "DnsProviderSelector", name: "DnsProviderSelector",
@ -119,10 +142,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}), }),
required: true, required: true,
}, },
column: {
show: false,
component: {
color: "auto",
},
},
}, },
dnsProviderAccess: { dnsProviderAccess: {
title: t("certd.domain.dnsProviderAccess"), title: t("certd.domain.dnsProviderAccess"),
type: "text", type: "dict-select",
dict: accessDict,
form: { form: {
component: { component: {
name: "AccessSelector", name: "AccessSelector",
@ -136,10 +166,16 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}), }),
required: true, required: true,
}, },
column: {
show: false,
component: {
color: "auto",
},
},
}, },
httpUploaderType: { httpUploaderType: {
title: t("certd.domain.httpUploaderType"), title: t("certd.domain.httpUploaderType"),
type: "dict-text", type: "dict-select",
dict: Dicts.uploaderTypeDict, dict: Dicts.uploaderTypeDict,
form: { form: {
show: compute(({ form }) => { show: compute(({ form }) => {
@ -147,6 +183,12 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}), }),
required: true, required: true,
}, },
column: {
show: false,
component: {
color: "auto",
},
},
}, },
httpUploaderAccess: { httpUploaderAccess: {
title: t("certd.domain.httpUploaderAccess"), title: t("certd.domain.httpUploaderAccess"),
@ -160,6 +202,12 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}), }),
required: true, required: true,
}, },
column: {
show: false,
component: {
color: "auto",
},
},
}, },
httpUploadRootDir: { httpUploadRootDir: {
title: t("certd.domain.httpUploadRootDir"), title: t("certd.domain.httpUploadRootDir"),
@ -170,14 +218,47 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}), }),
required: true, required: true,
}, },
column: {
show: false,
component: {
color: "auto",
},
},
},
challengeSetting: {
title: "校验配置",
type: "text",
form: { show: false },
column: {
width: 400,
conditionalRender: false,
cellRender({ row }) {
if (row.challengeType === "dns") {
return (
<div class={"flex"}>
<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>
);
} else if (row.challengeType === "http") {
return (
<div class={"flex"}>
<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>
</div>
);
}
},
},
}, },
disabled: { disabled: {
title: t("certd.domain.disabled"), title: t("certd.domain.disabled"),
type: "dict-switch", type: "dict-switch",
dict: dict({ dict: dict({
data: [ data: [
{ label: "启用", value: false }, { label: "启用", value: false, color: "green" },
{ label: "禁用", value: true }, { label: "禁用", value: true, color: "red" },
], ],
}), }),
form: { form: {
@ -185,7 +266,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
required: true, required: true,
}, },
column: { column: {
width: 80, width: 100,
sorter: true,
}, },
}, },
createTime: { createTime: {

View File

@ -101,4 +101,10 @@ export class AccessController extends CrudController<AccessService> {
const res = await this.service.getSimpleInfo(id); const res = await this.service.getSimpleInfo(id);
return this.ok(res); return this.ok(res);
} }
@Post('/getDictByIds', { summary: Constants.per.authOnly })
async getDictByIds(@Body('ids') ids: number[]) {
const res = await this.service.getSimpleByIds(ids, this.getUserId());
return this.ok(res);
}
} }