mirror of
https://github.com/certd/certd.git
synced 2026-04-14 20:40:53 +08:00
chore:
This commit is contained in:
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user