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 {InjectEntityModel} from '@midwayjs/typeorm';
import {Repository} from 'typeorm';
import { In, Repository } from "typeorm";
import {AccessGetter, BaseService, PageReq, PermissionException, ValidateException} from '../../../index.js';
import {AccessEntity} from '../entity/access.js';
import {AccessDefine, accessRegistry, newAccess} from '@certd/pipeline';
@ -175,4 +175,27 @@ export class AccessService extends BaseService<AccessEntity> {
getDefineByType(type: string) {
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 {
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 { AcmeService } from "./acme.js";
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 { CertApplyBasePlugin } from "./base.js";
import { GoogleClient } from "../../libs/google.js";
@ -66,6 +66,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
{ value: "cname", label: "CNAME代理验证" },
{ value: "http", label: "HTTP文件验证" },
{ value: "dnses", label: "多DNS提供商" },
{ value: "auto", label: "自动选择" },
],
},
required: true,
@ -73,6 +74,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
2. <b>CNAME</b>CNAMEDNS/使DNS
3. <b>HTTP</b>
4. <b>DNS</b>DNS
5. <b></b>[](#/certd/cert/domain)
`,
})
challengeType!: string;
@ -408,7 +410,11 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
let dnsProvider: IDnsProvider = null;
let domainsVerifyPlan: DomainsVerifyPlan = null;
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 {
const dnsProviderType = this.dnsProviderType;
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 = {};
for (const domain in this.domainsVerifyPlan) {
const domainVerifyPlan = this.domainsVerifyPlan[domain];
for (const domain in verifyPlanSetting) {
const domainVerifyPlan = verifyPlanSetting[domain];
let dnsProvider = null;
const cnameVerifyPlan: Record<string, CnameVerifyPlan> = {};
const httpVerifyPlan: Record<string, HttpVerifyPlan> = {};
@ -511,6 +517,66 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
}
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();

View File

@ -9,9 +9,9 @@ export const Dicts = {
}),
challengeTypeDict: dict({
data: [
{ value: "dns", label: "DNS校验" },
{ value: "cname", label: "CNAME代理校验" },
{ value: "http", label: "HTTP校验" },
{ value: "dns", label: "DNS校验", color: "green" },
{ value: "cname", label: "CNAME代理校验", color: "blue" },
{ value: "http", label: "HTTP校验", color: "yellow" },
],
}),
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) {
return await request({
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 { useUserStore } from "/@/store/user";
import { useSettingStore } from "/@/store/settings";
import { message } from "ant-design-vue";
import { Dicts } from "/@/components/plugins/lib/dicts";
import { createAccessApi } from "/@/views/certd/access/api";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter();
const { t } = useI18n();
@ -32,6 +33,21 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
const selectedRowKeys: Ref<any[]> = ref([]);
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 {
crudOptions: {
settings: {
@ -90,6 +106,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
disabled: false,
},
},
column: {
sorter: true,
},
},
challengeType: {
title: t("certd.domain.challengeType"),
@ -98,6 +117,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
form: {
required: true,
},
column: {
sorter: true,
},
},
/**
* challengeType varchar(50),
@ -109,7 +131,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
*/
dnsProviderType: {
title: t("certd.domain.dnsProviderType"),
type: "text",
type: "dict-select",
dict: dnsProviderTypeDict,
form: {
component: {
name: "DnsProviderSelector",
@ -119,10 +142,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}),
required: true,
},
column: {
show: false,
component: {
color: "auto",
},
},
},
dnsProviderAccess: {
title: t("certd.domain.dnsProviderAccess"),
type: "text",
type: "dict-select",
dict: accessDict,
form: {
component: {
name: "AccessSelector",
@ -136,10 +166,16 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}),
required: true,
},
column: {
show: false,
component: {
color: "auto",
},
},
},
httpUploaderType: {
title: t("certd.domain.httpUploaderType"),
type: "dict-text",
type: "dict-select",
dict: Dicts.uploaderTypeDict,
form: {
show: compute(({ form }) => {
@ -147,6 +183,12 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}),
required: true,
},
column: {
show: false,
component: {
color: "auto",
},
},
},
httpUploaderAccess: {
title: t("certd.domain.httpUploaderAccess"),
@ -160,6 +202,12 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}),
required: true,
},
column: {
show: false,
component: {
color: "auto",
},
},
},
httpUploadRootDir: {
title: t("certd.domain.httpUploadRootDir"),
@ -170,14 +218,47 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}),
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: {
title: t("certd.domain.disabled"),
type: "dict-switch",
dict: dict({
data: [
{ label: "启用", value: false },
{ label: "禁用", value: true },
{ label: "启用", value: false, color: "green" },
{ label: "禁用", value: true, color: "red" },
],
}),
form: {
@ -185,7 +266,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
required: true,
},
column: {
width: 80,
width: 100,
sorter: true,
},
},
createTime: {

View File

@ -101,4 +101,10 @@ export class AccessController extends CrudController<AccessService> {
const res = await this.service.getSimpleInfo(id);
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);
}
}