diff --git a/packages/core/pipeline/src/service/cname.ts b/packages/core/pipeline/src/service/cname.ts index 3fa63e75..419bae90 100644 --- a/packages/core/pipeline/src/service/cname.ts +++ b/packages/core/pipeline/src/service/cname.ts @@ -18,6 +18,7 @@ export type CnameRecord = { status: string; commonDnsProvider?: any; }; + export type ICnameProxyService = { getByDomain: (domain: string) => Promise; }; diff --git a/packages/plugins/plugin-cert/package.json b/packages/plugins/plugin-cert/package.json index 5345de63..cade91c4 100644 --- a/packages/plugins/plugin-cert/package.json +++ b/packages/plugins/plugin-cert/package.json @@ -18,6 +18,7 @@ "@certd/acme-client": "^1.29.2", "@certd/basic": "^1.29.2", "@certd/pipeline": "^1.29.2", + "@certd/plugin-lib": "^1.29.2", "@google-cloud/publicca": "^1.3.0", "dayjs": "^1.11.7", "jszip": "^3.10.1", diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts index 085466a5..0054e4b2 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/acme.ts @@ -6,6 +6,7 @@ import { Challenge } from "@certd/acme-client/types/rfc8555"; import { IContext } from "@certd/pipeline"; import { ILogger, utils } from "@certd/basic"; import { IDnsProvider, parseDomain } from "../../dns-provider/index.js"; +import { HttpChallengeUploader } from "./uploads/api.js"; export type CnameVerifyPlan = { domain: string; @@ -15,7 +16,7 @@ export type CnameVerifyPlan = { export type DomainVerifyPlan = { domain: string; - type: "cname" | "dns"; + type: "cname" | "dns" | "http"; dnsProvider?: IDnsProvider; cnameVerifyPlan?: Record; }; @@ -23,6 +24,12 @@ export type DomainsVerifyPlan = { [key: string]: DomainVerifyPlan; }; +export type Providers = { + dnsProvider?: IDnsProvider; + domainsVerifyPlan?: DomainsVerifyPlan; + httpUploader?: HttpChallengeUploader; +}; + export type CertInfo = { crt: string; //fullchain证书 key: string; //私钥 @@ -155,20 +162,17 @@ export class AcmeService { return key.toString(); } - async challengeCreateFn(authz: any, challenge: any, keyAuthorization: string, dnsProvider: IDnsProvider, domainsVerifyPlan: DomainsVerifyPlan) { + async challengeCreateFn(authz: any, challenge: any, keyAuthorization: string, providers: Providers) { this.logger.info("Triggered challengeCreateFn()"); /* http-01 */ const fullDomain = authz.identifier.value; if (challenge.type === "http-01") { - const filePath = `/var/www/html/.well-known/acme-challenge/${challenge.token}`; + const filePath = `.well-known/acme-challenge/${challenge.token}`; const fileContents = keyAuthorization; - - this.logger.info(`Creating challenge response for ${fullDomain} at path: ${filePath}`); - - /* Replace this */ - this.logger.info(`Would write "${fileContents}" to path "${filePath}"`); - // await fs.writeFileAsync(filePath, fileContents); + this.logger.info(`校验 ${fullDomain} ,准备上传文件:${filePath}`); + await providers.httpUploader.upload(filePath, fileContents); + this.logger.info(`上传文件【${filePath}】成功`); } else if (challenge.type === "dns-01") { /* dns-01 */ let fullRecord = `_acme-challenge.${fullDomain}`; @@ -181,9 +185,10 @@ export class AcmeService { let domain = parseDomain(fullDomain); this.logger.info("解析到域名domain=" + domain); - if (domainsVerifyPlan) { + let dnsProvider = providers.dnsProvider; + if (providers.domainsVerifyPlan) { //按照计划执行 - const domainVerifyPlan = domainsVerifyPlan[domain]; + const domainVerifyPlan = providers.domainsVerifyPlan[domain]; if (domainVerifyPlan) { if (domainVerifyPlan.type === "dns") { dnsProvider = domainVerifyPlan.dnsProvider; @@ -239,22 +244,28 @@ export class AcmeService { * @param recordReq * @param recordRes * @param dnsProvider dnsProvider + * @param httpUploader * @returns {Promise} */ - async challengeRemoveFn(authz: any, challenge: any, keyAuthorization: string, recordReq: any, recordRes: any, dnsProvider: IDnsProvider) { - this.logger.info("Triggered challengeRemoveFn()"); + async challengeRemoveFn( + authz: any, + challenge: any, + keyAuthorization: string, + recordReq: any, + recordRes: any, + dnsProvider?: IDnsProvider, + httpUploader?: HttpChallengeUploader + ) { + this.logger.info("执行清理"); /* http-01 */ const fullDomain = authz.identifier.value; if (challenge.type === "http-01") { - const filePath = `/var/www/html/.well-known/acme-challenge/${challenge.token}`; - - this.logger.info(`Removing challenge response for ${fullDomain} at path: ${filePath}`); - - /* Replace this */ - this.logger.info(`Would remove file on path "${filePath}"`); - // await fs.unlinkAsync(filePath); + const filePath = `.well-known/acme-challenge/${challenge.token}`; + this.logger.info(`Removing challenge response for ${fullDomain} at file: ${filePath}`); + await httpUploader.remove(filePath); + this.logger.info(`删除文件【${filePath}】成功`); } else if (challenge.type === "dns-01") { this.logger.info(`删除 TXT 解析记录:${JSON.stringify(recordReq)} ,recordRes = ${JSON.stringify(recordRes)}`); try { @@ -275,11 +286,12 @@ export class AcmeService { domains: string | string[]; dnsProvider?: any; domainsVerifyPlan?: DomainsVerifyPlan; + httpUploader?: any; csrInfo: any; isTest?: boolean; privateKeyType?: string; }): Promise { - const { email, isTest, domains, csrInfo, dnsProvider, domainsVerifyPlan } = options; + const { email, isTest, domains, csrInfo, dnsProvider, domainsVerifyPlan, httpUploader } = options; const client: acme.Client = await this.getAcmeClient(email, isTest); /* Create CSR */ @@ -319,9 +331,15 @@ export class AcmeService { privateKey ); - if (dnsProvider == null && domainsVerifyPlan == null) { - throw new Error("dnsProvider 、 domainsVerifyPlan 不能都为空"); + if (dnsProvider == null && domainsVerifyPlan == null && httpUploader == null) { + throw new Error("dnsProvider 、 domainsVerifyPlan 、 httpUploader不能都为空"); } + + const providers: Providers = { + dnsProvider, + domainsVerifyPlan, + httpUploader, + }; /* 自动申请证书 */ const crt = await client.auto({ csr, @@ -334,7 +352,7 @@ export class AcmeService { challenge: Challenge, keyAuthorization: string ): Promise<{ recordReq: any; recordRes: any; dnsProvider: any }> => { - return await this.challengeCreateFn(authz, challenge, keyAuthorization, dnsProvider, domainsVerifyPlan); + return await this.challengeCreateFn(authz, challenge, keyAuthorization, providers); }, challengeRemoveFn: async ( authz: acme.Authorization, @@ -344,7 +362,7 @@ export class AcmeService { recordRes: any, dnsProvider: IDnsProvider ): Promise => { - return await this.challengeRemoveFn(authz, challenge, keyAuthorization, recordReq, recordRes, dnsProvider); + return await this.challengeRemoveFn(authz, challenge, keyAuthorization, recordReq, recordRes, dnsProvider, httpUploader); }, signal: this.options.signal, }); diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts index 6807028c..d82a6dc6 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts @@ -147,10 +147,11 @@ export class CertReader { tmpOnePath, }); } catch (err) { + logger.error("处理失败", err); throw err; } finally { //删除临时文件 - logger.info("删除临时文件"); + logger.info("清理临时文件"); function removeFile(filepath?: string) { if (filepath) { fs.unlinkSync(filepath); diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts index 503be4dc..50b28efb 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/index.ts @@ -1,4 +1,4 @@ -import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { CancelError, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; import { utils } from "@certd/basic"; import type { CertInfo, CnameVerifyPlan, DomainsVerifyPlan, PrivateKeyType, SSLProvider } from "./acme.js"; @@ -9,7 +9,8 @@ import { CertReader } from "./cert-reader.js"; import { CertApplyBasePlugin } from "./base.js"; import { GoogleClient } from "../../libs/google.js"; import { EabAccess } from "../../access"; -import { CancelError } from "@certd/pipeline"; +import { HttpChallengeUploader } from "./uploads/api"; +import { httpChallengeUploaderFactory } from "./uploads/factory.js"; export type { CertInfo }; export * from "./cert-reader.js"; @@ -17,12 +18,20 @@ export type CnameRecordInput = { id: number; status: string; }; + +export type HttpRecordInput = { + domain: string; + httpUploaderType: string; + httpUploaderAccess: number; + httpUploadRootDir: string; +}; export type DomainVerifyPlanInput = { domain: string; - type: "cname" | "dns"; + type: "cname" | "dns" | "http"; dnsProviderType?: string; dnsProviderAccessId?: number; cnameVerifyPlan?: Record; + httpVerifyPlan?: Record; }; export type DomainsVerifyPlanInput = { [key: string]: DomainVerifyPlanInput; @@ -54,6 +63,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { options: [ { value: "dns", label: "DNS直接验证" }, { value: "cname", label: "CNAME代理验证" }, + { value: "http", label: "HTTP文件验证" }, ], }, required: true, @@ -117,6 +127,67 @@ 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: { @@ -320,10 +391,17 @@ export class CertApplyPlugin extends CertApplyBasePlugin { ); this.logger.info("开始申请证书,", email, domains); - let dnsProvider: any = null; + let dnsProvider: IDnsProvider = null; let domainsVerifyPlan: DomainsVerifyPlan = null; + let httpUploader: HttpChallengeUploader = null; if (this.challengeType === "cname") { 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); @@ -336,6 +414,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin { domains, dnsProvider, domainsVerifyPlan, + httpUploader, csrInfo, isTest: false, privateKeyType: this.privateKeyType, diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/api.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/api.ts new file mode 100644 index 00000000..d9148cfd --- /dev/null +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/api.ts @@ -0,0 +1,35 @@ +import { IAccessService } from "@certd/pipeline"; +import { ILogger, utils } from "@certd/basic"; + +export type HttpChallengeUploader = { + upload: (fileName: string, fileContent: string) => Promise; + remove: (fileName: string) => Promise; +}; + +export type HttpChallengeUploadContext = { + accessService: IAccessService; + logger: ILogger; + utils: typeof utils; +}; + +export abstract class BaseHttpChallengeUploader implements HttpChallengeUploader { + rootDir: string; + access: A = null; + logger: ILogger; + utils: typeof utils; + ctx: HttpChallengeUploadContext; + protected constructor(opts: { rootDir: string; access: A }) { + this.rootDir = opts.rootDir; + this.access = opts.access; + } + + async setCtx(ctx: any) { + // set context + this.ctx = ctx; + this.logger = ctx.logger; + this.utils = ctx.utils; + } + + abstract remove(fileName: string): Promise; + abstract upload(fileName: string, fileContent: string): Promise; +} diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/factory.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/factory.ts new file mode 100644 index 00000000..70f14dd4 --- /dev/null +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/factory.ts @@ -0,0 +1,26 @@ +export class HttpChallengeUploaderFactory { + async getClassByType(type: string) { + if (type === "alioss") { + return (await import("./impls/alioss.js")).AliossHttpChallengeUploader; + } else if (type === "ssh") { + return (await import("./impls/ssh.js")).SshHttpChallengeUploader; + } else if (type === "ftp") { + return (await import("./impls/ftp.js")).FtpHttpChallengeUploader; + } else if (type === "tencentcos") { + return (await import("./impls/tencentcos.js")).TencentCosHttpChallengeUploader; + } else if (type === "qiniuoss") { + return (await import("./impls/qiniuoss.js")).QiniuOssHttpChallengeUploader; + } else { + throw new Error(`暂不支持此文件上传方式: ${type}`); + } + } + createUploaderByType(type: string, opts: { rootDir: string; access: any }) { + const cls = this.getClassByType(type); + if (cls) { + // @ts-ignore + return new cls(opts); + } + } +} + +export const httpChallengeUploaderFactory = new HttpChallengeUploaderFactory(); diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/alioss.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/alioss.ts new file mode 100644 index 00000000..9f2a5fe6 --- /dev/null +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/alioss.ts @@ -0,0 +1,36 @@ +import { BaseHttpChallengeUploader } from "../api"; +import { AliossAccess, AliyunAccess } from "@certd/plugin-lib"; +import { AliossClient } from "@certd/plugin-lib/dist/aliyun/lib/oss-client"; + +export class AliossHttpChallengeUploader extends BaseHttpChallengeUploader { + async upload(filePath: string, fileContent: string) { + const aliyunAccess = await this.ctx.accessService.getById(this.access.accessId); + const client = new AliossClient({ + access: aliyunAccess, + bucket: this.access.bucket, + region: this.access.region, + }); + + await client.uploadFile(filePath, Buffer.from(fileContent)); + + this.logger.info(`校验文件上传成功: ${filePath}`); + } + + async remove(filePath: string) { + // remove file from alioss + const client = await this.getAliossClient(); + await client.removeFile(filePath); + this.logger.info(`文件删除成功: ${filePath}`); + } + + private async getAliossClient() { + const aliyunAccess = await this.ctx.accessService.getById(this.access.accessId); + const client = new AliossClient({ + access: aliyunAccess, + bucket: this.access.bucket, + region: this.access.region, + }); + await client.init(); + return client; + } +} diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/ftp.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/ftp.ts new file mode 100644 index 00000000..8300a712 --- /dev/null +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/ftp.ts @@ -0,0 +1,25 @@ +import { BaseHttpChallengeUploader } from "../api"; +import { FtpAccess } from "@certd/plugin-lib"; +import { FtpClient } from "@certd/plugin-lib/dist/ftp/client"; + +export class FtpHttpChallengeUploader extends BaseHttpChallengeUploader { + async upload(fileName: string, fileContent: string) { + const client = new FtpClient({ + access: this.access, + logger: this.logger, + }); + await client.connect(async (client) => { + await client.upload(fileName, fileContent); + }); + } + + async remove(fileName: string) { + const client = new FtpClient({ + access: this.access, + logger: this.logger, + }); + await client.connect(async (client) => { + await client.client.remove(fileName); + }); + } +} diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/qiniuoss.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/qiniuoss.ts new file mode 100644 index 00000000..ef1065eb --- /dev/null +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/qiniuoss.ts @@ -0,0 +1,10 @@ +import { BaseHttpChallengeUploader } from "../api"; +import { FtpAccess } from "@certd/plugin-lib"; + +export class QiniuOssHttpChallengeUploader extends BaseHttpChallengeUploader { + async upload(fileName: string, fileContent: string) { + return null; + } + + async remove(fileName: string) {} +} diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/ssh.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/ssh.ts new file mode 100644 index 00000000..f8a9d370 --- /dev/null +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/ssh.ts @@ -0,0 +1,38 @@ +import { BaseHttpChallengeUploader } from "../api"; +import { SshAccess, SshClient } from "@certd/plugin-lib"; +import path from "path"; +import os from "os"; +import fs from "fs"; + +export class SshHttpChallengeUploader extends BaseHttpChallengeUploader { + async upload(fileName: string, fileContent: string) { + const tmpFilePath = path.join(os.tmpdir(), "cert", "http", fileName); + + // Write file to temp path + fs.writeFileSync(tmpFilePath, fileContent); + try { + const client = new SshClient(this.logger); + await client.uploadFiles({ + connectConf: this.access, + mkdirs: true, + transports: [ + { + localPath: fileName, + remotePath: fileName, + }, + ], + }); + } finally { + // Remove temp file + fs.unlinkSync(tmpFilePath); + } + } + + async remove(filePath: string) { + const client = new SshClient(this.logger); + await client.removeFiles({ + connectConf: this.access, + files: [filePath], + }); + } +} diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/tencentcos.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/tencentcos.ts new file mode 100644 index 00000000..a63cc33a --- /dev/null +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/uploads/impls/tencentcos.ts @@ -0,0 +1,10 @@ +import { BaseHttpChallengeUploader } from "../api"; +import { FtpAccess } from "@certd/plugin-lib"; + +export class TencentCosHttpChallengeUploader extends BaseHttpChallengeUploader { + async upload(fileName: string, fileContent: string) { + return null; + } + + async remove(fileName: string) {} +} diff --git a/packages/plugins/plugin-lib/package.json b/packages/plugins/plugin-lib/package.json index 7fbe76e5..779f36e9 100644 --- a/packages/plugins/plugin-lib/package.json +++ b/packages/plugins/plugin-lib/package.json @@ -18,8 +18,8 @@ "@alicloud/pop-core": "^1.7.10", "@certd/basic": "^1.29.2", "@certd/pipeline": "^1.29.2", - "@certd/plugin-cert": "^1.29.2", "@kubernetes/client-node": "0.21.0", + "basic-ftp": "^5.0.5", "dayjs": "^1.11.7", "iconv-lite": "^0.6.3", "lodash-es": "^4.17.21", diff --git a/packages/plugins/plugin-lib/src/aliyun/access/alioss-access.ts b/packages/plugins/plugin-lib/src/aliyun/access/alioss-access.ts new file mode 100644 index 00000000..eb5bc9e7 --- /dev/null +++ b/packages/plugins/plugin-lib/src/aliyun/access/alioss-access.ts @@ -0,0 +1,71 @@ +import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline"; + +@IsAccess({ + name: "alioss", + title: "阿里云OSS授权", + desc: "包含地域和Bucket", + icon: "ant-design:aliyun-outlined", +}) +export class AliossAccess extends BaseAccess { + @AccessInput({ + title: "阿里云授权", + component: { + name: "access-selector", + vModel: "modelValue", + type: "aliyun", + }, + helper: "请选择阿里云授权", + required: true, + }) + accessId = ""; + + @AccessInput({ + title: "大区", + component: { + name: "a-auto-complete", + vModel: "value", + options: [ + { value: "oss-cn-hangzhou", label: "华东1(杭州)" }, + { value: "oss-cn-shanghai", label: "华东2(上海)" }, + { value: "oss-cn-nanjing", label: "华东5(南京-本地地域)" }, + { value: "oss-cn-fuzhou", label: "华东6(福州-本地地域)" }, + { value: "oss-cn-wuhan-lr", label: "华中1(武汉-本地地域)" }, + { value: "oss-cn-qingdao", label: "华北1(青岛)" }, + { value: "oss-cn-beijing", label: "华北2(北京)" }, + { value: "oss-cn-zhangjiakou", label: "华北 3(张家口)" }, + { value: "oss-cn-huhehaote", label: "华北5(呼和浩特)" }, + { value: "oss-cn-wulanchabu", label: "华北6(乌兰察布)" }, + { value: "oss-cn-shenzhen", label: "华南1(深圳)" }, + { value: "oss-cn-heyuan", label: "华南2(河源)" }, + { value: "oss-cn-guangzhou", label: "华南3(广州)" }, + { value: "oss-cn-chengdu", label: "西南1(成都)" }, + { value: "oss-cn-hongkong", label: "中国香港" }, + { value: "oss-us-west-1", label: "美国(硅谷)①" }, + { value: "oss-us-east-1", label: "美国(弗吉尼亚)①" }, + { value: "oss-ap-northeast-1", label: "日本(东京)①" }, + { value: "oss-ap-northeast-2", label: "韩国(首尔)" }, + { value: "oss-ap-southeast-1", label: "新加坡①" }, + { value: "oss-ap-southeast-2", label: "澳大利亚(悉尼)①" }, + { value: "oss-ap-southeast-3", label: "马来西亚(吉隆坡)①" }, + { value: "oss-ap-southeast-5", label: "印度尼西亚(雅加达)①" }, + { value: "oss-ap-southeast-6", label: "菲律宾(马尼拉)" }, + { value: "oss-ap-southeast-7", label: "泰国(曼谷)" }, + { value: "oss-eu-central-1", label: "德国(法兰克福)①" }, + { value: "oss-eu-west-1", label: "英国(伦敦)" }, + { value: "oss-me-east-1", label: "阿联酋(迪拜)①" }, + { value: "oss-rg-china-mainland", label: "无地域属性(中国内地)" }, + ], + }, + required: true, + }) + region!: string; + + @AccessInput({ + title: "Bucket", + helper: "存储桶名称", + required: true, + }) + bucket!: string; +} + +new AliossAccess(); diff --git a/packages/plugins/plugin-lib/src/aliyun/access/index.ts b/packages/plugins/plugin-lib/src/aliyun/access/index.ts index 2d686298..80693fa3 100644 --- a/packages/plugins/plugin-lib/src/aliyun/access/index.ts +++ b/packages/plugins/plugin-lib/src/aliyun/access/index.ts @@ -1 +1,2 @@ -export * from './aliyun-access.js'; +export * from "./aliyun-access.js"; +export * from "./alioss-access.js"; diff --git a/packages/plugins/plugin-lib/src/aliyun/lib/oss-client.ts b/packages/plugins/plugin-lib/src/aliyun/lib/oss-client.ts new file mode 100644 index 00000000..ee812ad4 --- /dev/null +++ b/packages/plugins/plugin-lib/src/aliyun/lib/oss-client.ts @@ -0,0 +1,56 @@ +import { AliyunAccess } from "../access"; + +export class AliossClient { + access: AliyunAccess; + + region: string; + bucket: string; + client: any; + constructor(opts: { access: AliyunAccess; bucket: string; region: string }) { + this.access = opts.access; + this.bucket = opts.bucket; + this.region = opts.region; + } + + async init() { + // @ts-ignore + const OSS = await import("ali-oss"); + this.client = new OSS.default({ + accessKeyId: this.access.accessKeyId, + accessKeySecret: this.access.accessKeySecret, + // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。 + region: this.region, + //@ts-ignore + authorizationV4: true, + // yourBucketName填写Bucket名称。 + bucket: this.bucket, + }); + } + + async doRequest(client: any, bucket: string, xml: string, params: any) { + params = client._bucketRequestParams("POST", bucket, { + ...params, + }); + params.content = xml; + params.mime = "xml"; + params.successStatuses = [200]; + const res = await client.request(params); + this.checkRet(res); + return res; + } + + checkRet(ret: any) { + if (ret.code != null) { + throw new Error("执行失败:" + ret.Message); + } + } + + async uploadFile(filePath: string, content: Buffer) { + const memFile = new File([content], filePath); + return await this.client.put(filePath, memFile); + } + + async removeFile(filePath: string) { + return await this.client.delete(filePath); + } +} diff --git a/packages/plugins/plugin-lib/src/aliyun/lib/ssl-client.ts b/packages/plugins/plugin-lib/src/aliyun/lib/ssl-client.ts index cb6c9abb..65d13240 100644 --- a/packages/plugins/plugin-lib/src/aliyun/lib/ssl-client.ts +++ b/packages/plugins/plugin-lib/src/aliyun/lib/ssl-client.ts @@ -1,8 +1,11 @@ import { ILogger } from "@certd/basic"; import { AliyunAccess } from "../access/index.js"; import { AliyunClient } from "./index.js"; -import { CertInfo } from "@certd/plugin-cert"; +export type AliyunCertInfo = { + crt: string; //fullchain证书 + key: string; //私钥 +}; export type AliyunSslClientOpts = { access: AliyunAccess; logger: ILogger; @@ -23,7 +26,7 @@ export type AliyunSslCreateDeploymentJobReq = { export type AliyunSslUploadCertReq = { name: string; - cert: CertInfo; + cert: AliyunCertInfo; }; export class AliyunSslClient { diff --git a/packages/plugins/plugin-lib/src/ftp/access.ts b/packages/plugins/plugin-lib/src/ftp/access.ts new file mode 100644 index 00000000..bfe4450f --- /dev/null +++ b/packages/plugins/plugin-lib/src/ftp/access.ts @@ -0,0 +1,77 @@ +import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline"; + +/** + * 这个注解将注册一个授权配置 + * 在certd的后台管理系统中,用户可以选择添加此类型的授权 + */ +@IsAccess({ + name: "ftp", + title: "FTP授权", + desc: "", + icon: "mdi:folder-upload-outline", +}) +export class FtpAccess extends BaseAccess { + @AccessInput({ + title: "host", + component: { + placeholder: "ip / 域名", + name: "a-input", + vModel: "value", + }, + helper: "FTP地址", + required: true, + }) + host!: string; + + @AccessInput({ + title: "host", + value: 21, + component: { + placeholder: "21", + name: "a-input-number", + vModel: "value", + }, + helper: "FTP端口", + required: true, + }) + port!: string; + + @AccessInput({ + title: "user", + component: { + placeholder: "用户名", + }, + helper: "FTP用户名", + required: true, + }) + user!: string; + + @AccessInput({ + title: "password", + component: { + placeholder: "密码", + component: { + name: "a-input-password", + vModel: "value", + }, + }, + encrypt: true, + helper: "FTP密码", + required: true, + }) + password!: string; + + @AccessInput({ + title: "secure", + value: false, + component: { + name: "a-switch", + vModel: "checked", + }, + helper: "是否使用SSL", + required: true, + }) + secure?: boolean = false; +} + +new FtpAccess(); diff --git a/packages/plugins/plugin-lib/src/ftp/client.ts b/packages/plugins/plugin-lib/src/ftp/client.ts new file mode 100644 index 00000000..04d2eee9 --- /dev/null +++ b/packages/plugins/plugin-lib/src/ftp/client.ts @@ -0,0 +1,47 @@ +import { FtpAccess } from "./access"; +import { ILogger } from "@certd/basic"; +import path from "node:path"; + +export class FtpClient { + access: FtpAccess = null; + logger: ILogger = null; + client: any; + constructor(opts: { access: FtpAccess; logger: ILogger }) { + this.access = opts.access; + this.logger = opts.logger; + } + + async connect(callback: (client: FtpClient) => Promise) { + const ftp = await import("basic-ftp"); + const Client = ftp.Client; + const client = new Client(); + client.ftp.verbose = true; + this.logger.info("开始连接FTP"); + await client.access(this.access as any); + this.logger.info("FTP连接成功"); + this.client = client; + try { + await callback(this); + } finally { + if (client) { + client.close(); + } + } + } + + async upload(filePath: string, remotePath: string): Promise { + if (!remotePath) { + return; + } + const dirname = path.dirname(remotePath); + this.logger.info(`确保目录存在:${dirname}`); + await this.client.ensureDir(dirname); + this.logger.info(`开始上传文件${filePath} -> ${remotePath}`); + await this.client.uploadFrom(filePath, remotePath); + } + + async remove(filePath: string): Promise { + this.logger.info(`开始删除文件${filePath}`); + await this.client.remove(filePath, true); + } +} diff --git a/packages/plugins/plugin-lib/src/ftp/index.ts b/packages/plugins/plugin-lib/src/ftp/index.ts new file mode 100644 index 00000000..6e754af1 --- /dev/null +++ b/packages/plugins/plugin-lib/src/ftp/index.ts @@ -0,0 +1,2 @@ +export * from "./access.js"; +export * from "./client.js"; diff --git a/packages/plugins/plugin-lib/src/index.ts b/packages/plugins/plugin-lib/src/index.ts index 61ee752c..e441e043 100644 --- a/packages/plugins/plugin-lib/src/index.ts +++ b/packages/plugins/plugin-lib/src/index.ts @@ -1,3 +1,6 @@ export * from "./ssh/index.js"; export * from "./aliyun/index.js"; export * from "./common/index.js"; +export * from "./ftp/index.js"; +export * from "./tencent/index.js"; +export * from "./qiniu/index.js"; diff --git a/packages/plugins/plugin-lib/src/qiniu/access-oss.ts b/packages/plugins/plugin-lib/src/qiniu/access-oss.ts new file mode 100644 index 00000000..211e14a4 --- /dev/null +++ b/packages/plugins/plugin-lib/src/qiniu/access-oss.ts @@ -0,0 +1,31 @@ +import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline"; + +@IsAccess({ + name: "qiniuoss", + title: "七牛OSS授权", + desc: "", + icon: "svg:icon-qiniuyun", + input: {}, +}) +export class QiniuOssAccess extends BaseAccess { + @AccessInput({ + title: "七牛云授权", + component: { + name: "access-selector", + vModel: "modelValue", + type: "qiniu", + }, + helper: "请选择七牛云授权", + required: true, + }) + accessId = ""; + + @AccessInput({ + title: "Bucket", + helper: "存储桶名称", + required: true, + }) + bucket = ""; +} + +new QiniuOssAccess(); diff --git a/packages/plugins/plugin-lib/src/qiniu/access.ts b/packages/plugins/plugin-lib/src/qiniu/access.ts new file mode 100644 index 00000000..d760abbf --- /dev/null +++ b/packages/plugins/plugin-lib/src/qiniu/access.ts @@ -0,0 +1,25 @@ +import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline"; + +@IsAccess({ + name: "qiniu", + title: "七牛云授权", + desc: "", + icon: "svg:icon-qiniuyun", + input: {}, +}) +export class QiniuAccess extends BaseAccess { + @AccessInput({ + title: "AccessKey", + rules: [{ required: true, message: "此项必填" }], + helper: "AK,前往[密钥管理](https://portal.qiniu.com/developer/user/key)获取", + }) + accessKey!: string; + @AccessInput({ + title: "SecretKey", + encrypt: true, + helper: "SK", + }) + secretKey!: string; +} + +new QiniuAccess(); diff --git a/packages/plugins/plugin-lib/src/qiniu/index.ts b/packages/plugins/plugin-lib/src/qiniu/index.ts new file mode 100644 index 00000000..655094d0 --- /dev/null +++ b/packages/plugins/plugin-lib/src/qiniu/index.ts @@ -0,0 +1 @@ +export * from "./access.js"; diff --git a/packages/plugins/plugin-lib/src/ssh/ssh.ts b/packages/plugins/plugin-lib/src/ssh/ssh.ts index 4a1ac081..4e239eca 100644 --- a/packages/plugins/plugin-lib/src/ssh/ssh.ts +++ b/packages/plugins/plugin-lib/src/ssh/ssh.ts @@ -7,6 +7,7 @@ import { SshAccess } from "./ssh-access.js"; import stripAnsi from "strip-ansi"; import { SocksClient } from "socks"; import { SocksProxy, SocksProxyType } from "socks/typings/common/constants.js"; +export type TransportItem = { localPath: string; remotePath: string }; export class AsyncSsh2Client { conn: ssh2.Client; @@ -95,6 +96,21 @@ export class AsyncSsh2Client { }); } + async unlink(options: { sftp: any; remotePath: string }) { + const { sftp, remotePath } = options; + return new Promise((resolve, reject) => { + this.logger.info(`开始删除远程文件:${remotePath}`); + sftp.unlink(remotePath, (err: Error) => { + if (err) { + reject(err); + return; + } + this.logger.info(`删除文件成功:${remotePath}`); + resolve({}); + }); + }); + } + async exec( script: string, opts: { @@ -239,7 +255,7 @@ export class SshClient { } * @param options */ - async uploadFiles(options: { connectConf: SshAccess; transports: any; mkdirs: boolean }) { + async uploadFiles(options: { connectConf: SshAccess; transports: TransportItem[]; mkdirs: boolean }) { const { connectConf, transports, mkdirs } = options; await this._call({ connectConf, @@ -272,6 +288,24 @@ export class SshClient { }); } + async removeFiles(opts: { connectConf: SshAccess; files: string[] }) { + const { connectConf, files } = opts; + await this._call({ + connectConf, + callable: async (conn: AsyncSsh2Client) => { + const sftp = await conn.getSftp(); + this.logger.info("开始删除"); + for (const file of files) { + await conn.unlink({ + sftp, + remotePath: file, + }); + } + this.logger.info("文件全部删除成功"); + }, + }); + } + async isCmd(conn: AsyncSsh2Client) { const spec = await conn.exec("echo %COMSPEC% "); if (spec.toString().trim() === "%COMSPEC%") { diff --git a/packages/plugins/plugin-lib/src/tencent/access-cos.ts b/packages/plugins/plugin-lib/src/tencent/access-cos.ts new file mode 100644 index 00000000..c29b8adc --- /dev/null +++ b/packages/plugins/plugin-lib/src/tencent/access-cos.ts @@ -0,0 +1,63 @@ +import { AccessInput, BaseAccess, IsAccess } from "@certd/pipeline"; + +@IsAccess({ + name: "tencentcos", + title: "腾讯云COS授权", + icon: "svg:icon-tencentcloud", + desc: "腾讯云对象存储授权,包含地域和存储桶", +}) +export class TencentCosAccess extends BaseAccess { + @AccessInput({ + title: "腾讯云授权", + component: { + name: "access-selector", + vModel: "modelValue", + type: "tencent", + }, + helper: "请选择腾讯云授权", + required: true, + }) + accessId = ""; + + @AccessInput({ + title: "所在地域", + helper: "存储桶所在地域", + component: { + name: "a-auto-complete", + vModel: "value", + options: [ + { value: "", label: "--------中国大陆地区-------", disabled: true }, + { value: "ap-beijing-1", label: "北京1区" }, + { value: "ap-beijing", label: "北京" }, + { value: "ap-nanjing", label: "南京" }, + { value: "ap-shanghai", label: "上海" }, + { value: "ap-guangzhou", label: "广州" }, + { value: "ap-chengdu", label: "成都" }, + { value: "ap-chongqing", label: "重庆" }, + { value: "ap-shenzhen-fsi", label: "深圳金融" }, + { value: "ap-shanghai-fsi", label: "上海金融" }, + { value: "ap-beijing-fsi", label: "北京金融" }, + { value: "", label: "--------中国香港及境外-------", disabled: true }, + { value: "ap-hongkong", label: "中国香港" }, + { value: "ap-singapore", label: "新加坡" }, + { value: "ap-mumbai", label: "孟买" }, + { value: "ap-jakarta", label: "雅加达" }, + { value: "ap-seoul", label: "首尔" }, + { value: "ap-bangkok", label: "曼谷" }, + { value: "ap-tokyo", label: "东京" }, + { value: "na-siliconvalley", label: "硅谷" }, + { value: "na-ashburn", label: "弗吉尼亚" }, + { value: "sa-saopaulo", label: "圣保罗" }, + { value: "eu-frankfurt", label: "法兰克福" }, + ], + }, + }) + region!: string; + + @AccessInput({ + title: "Bucket", + helper: "存储桶名称", + required: true, + }) + bucket = ""; +} diff --git a/packages/plugins/plugin-lib/src/tencent/access.ts b/packages/plugins/plugin-lib/src/tencent/access.ts new file mode 100644 index 00000000..2387a659 --- /dev/null +++ b/packages/plugins/plugin-lib/src/tencent/access.ts @@ -0,0 +1,28 @@ +import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline"; + +@IsAccess({ + name: "tencent", + title: "腾讯云", + icon: "svg:icon-tencentcloud", +}) +export class TencentAccess extends BaseAccess { + @AccessInput({ + title: "secretId", + helper: + "使用对应的插件需要有对应的权限,比如上传证书,需要证书管理权限;部署到clb需要clb相关权限\n前往[密钥管理](https://console.cloud.tencent.com/cam/capi)进行创建", + component: { + placeholder: "secretId", + }, + rules: [{ required: true, message: "该项必填" }], + }) + secretId = ""; + @AccessInput({ + title: "secretKey", + component: { + placeholder: "secretKey", + }, + encrypt: true, + rules: [{ required: true, message: "该项必填" }], + }) + secretKey = ""; +} diff --git a/packages/plugins/plugin-lib/src/tencent/index.ts b/packages/plugins/plugin-lib/src/tencent/index.ts new file mode 100644 index 00000000..655094d0 --- /dev/null +++ b/packages/plugins/plugin-lib/src/tencent/index.ts @@ -0,0 +1 @@ +export * from "./access.js"; diff --git a/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/index.vue b/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/index.vue index acdb82a7..1a43dddc 100644 --- a/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/index.vue +++ b/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/index.vue @@ -58,6 +58,9 @@
+
+ +
@@ -127,12 +130,7 @@ function showError(error: string) { errorMessageRef.value = error; } -type DomainGroup = Record< - string, - { - [key: string]: CnameRecord; - } ->[]; +type DomainGroup = Record>; function onDomainsChanged(domains: string[]) { console.log("域名变化", domains); @@ -169,6 +167,7 @@ function onDomainsChanged(domains: string[]) { planItem = { domain, type: "cname", + //@ts-ignore cnameVerifyPlan: { ...subDomains } @@ -178,6 +177,7 @@ function onDomainsChanged(domains: string[]) { const cnamePlan = planItem.cnameVerifyPlan; for (const subDomain in subDomains) { if (!cnamePlan[subDomain]) { + //@ts-ignore cnamePlan[subDomain] = { id: 0 }; diff --git a/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/type.ts b/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/type.ts index 30deeca5..cfaed15e 100644 --- a/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/type.ts +++ b/packages/ui/certd-client/src/components/plugins/cert/domains-verify-plan-editor/type.ts @@ -1,11 +1,19 @@ import { CnameRecord } from "@certd/pipeline"; +export type HttpRecord = { + domain: string; + httpUploaderType: string; + httpUploaderAccess: number; + httpUploadRootDir: string; +}; + export type DomainVerifyPlanInput = { domain: string; - type: "cname" | "dns"; + type: "cname" | "dns" | "http"; dnsProviderType?: string; dnsProviderAccessId?: number; cnameVerifyPlan?: Record; + httpVerifyPlan?: Record; }; export type DomainsVerifyPlanInput = { [key: string]: DomainVerifyPlanInput; diff --git a/packages/ui/certd-client/src/router/source/modules/sys.ts b/packages/ui/certd-client/src/router/source/modules/sys.ts index b633464f..1479dc9b 100644 --- a/packages/ui/certd-client/src/router/source/modules/sys.ts +++ b/packages/ui/certd-client/src/router/source/modules/sys.ts @@ -109,7 +109,7 @@ export const sysResources = [ meta: { show: () => { const settingStore = useSettingStore(); - return settingStore.isComm; + return settingStore.isPlus; }, icon: "ion:extension-puzzle-outline", permission: "sys:settings:view" diff --git a/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts b/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts index 03ce4ae6..6a4c3fc7 100644 --- a/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-host/plugin/upload-to-host/index.ts @@ -1,6 +1,5 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline'; import { CertInfo, CertReader, CertReaderHandleContext } from '@certd/plugin-cert'; -import * as fs from 'fs'; import dayjs from 'dayjs'; import { SshAccess, SshClient } from '@certd/plugin-lib'; @@ -243,27 +242,32 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin { }) hostJksPath!: string; + @TaskOutput({ + title: '一体证书保存路径', + }) + hostOnePath!: string; + async onInstance() {} - copyFile(srcFile: string, destFile: string) { - if (!srcFile || !destFile) { - this.logger.warn(`srcFile:${srcFile} 或 destFile:${destFile} 为空,不复制`); - return; - } - const dir = destFile.substring(0, destFile.lastIndexOf('/')); - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - fs.copyFileSync(srcFile, destFile); - this.logger.info(`复制文件:${srcFile} => ${destFile}`); - } + // copyFile(srcFile: string, destFile: string) { + // if (!srcFile || !destFile) { + // this.logger.warn(`srcFile:${srcFile} 或 destFile:${destFile} 为空,不复制`); + // return; + // } + // const dir = destFile.substring(0, destFile.lastIndexOf('/')); + // if (!fs.existsSync(dir)) { + // fs.mkdirSync(dir, { recursive: true }); + // } + // fs.copyFileSync(srcFile, destFile); + // this.logger.info(`复制文件:${srcFile} => ${destFile}`); + // } async execute(): Promise { const { cert, accessId } = this; - let { crtPath, keyPath, icPath, pfxPath, derPath, jksPath } = this; + let { crtPath, keyPath, icPath, pfxPath, derPath, jksPath, onePath } = this; const certReader = new CertReader(cert); const handle = async (opts: CertReaderHandleContext) => { - const { tmpCrtPath, tmpKeyPath, tmpDerPath, tmpJksPath, tmpPfxPath, tmpIcPath } = opts; + const { tmpCrtPath, tmpKeyPath, tmpDerPath, tmpJksPath, tmpPfxPath, tmpIcPath, tmpOnePath } = opts; // if (this.copyToThisHost) { // this.logger.info('复制到目标路径'); // this.copyFile(tmpCrtPath, crtPath); @@ -336,6 +340,16 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin { }); this.logger.info(`上传jks证书到主机:${jksPath}`); } + + if (this.onePath) { + this.logger.info(`上传一体证书到主机:${this.onePath}`); + onePath = this.onePath.trim(); + transports.push({ + localPath: tmpOnePath, + remotePath: this.onePath, + }); + } + this.logger.info('开始上传文件到服务器'); await sshClient.uploadFiles({ connectConf, @@ -350,6 +364,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin { this.hostPfxPath = pfxPath; this.hostDerPath = derPath; this.hostJksPath = jksPath; + this.hostOnePath = onePath; }; await certReader.readCertFile({ @@ -376,6 +391,8 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin { env['HOST_IC_PATH'] = this.hostIcPath || ''; env['HOST_PFX_PATH'] = this.hostPfxPath || ''; env['HOST_DER_PATH'] = this.hostDerPath || ''; + env['HOST_JKS_PATH'] = this.hostJksPath || ''; + env['HOST_ONE_PATH'] = this.hostOnePath || ''; } const scripts = this.script.split('\n'); diff --git a/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/deploy-to-cdn/index.ts b/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/deploy-to-cdn/index.ts index 0a4082e8..d07e0cf6 100644 --- a/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/deploy-to-cdn/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/deploy-to-cdn/index.ts @@ -1,8 +1,8 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; -import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; +import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine, QiniuAccess } from '@certd/plugin-lib'; import { CertInfo } from '@certd/plugin-cert'; import { optionsUtils } from '@certd/basic/dist/utils/util.options.js'; -import { QiniuAccess, QiniuClient } from '@certd/plugin-plus'; +import { QiniuClient } from '@certd/plugin-plus'; @IsTaskPlugin({ name: 'QiniuDeployCertToCDN', diff --git a/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/upload-cert/index.ts b/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/upload-cert/index.ts index 2a9ef001..f639d217 100644 --- a/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/upload-cert/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-qiniu/plugin/upload-cert/index.ts @@ -1,6 +1,7 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline'; -import { QiniuAccess, QiniuClient } from '@certd/plugin-plus'; +import { QiniuClient } from '@certd/plugin-plus'; import { CertInfo } from '@certd/plugin-cert'; +import { QiniuAccess } from '@certd/plugin-lib'; @IsTaskPlugin({ name: 'QiniuCertUpload', @@ -51,7 +52,7 @@ export class QiniuCertUpload extends AbstractTaskPlugin { async onInstance() {} async execute(): Promise { this.logger.info('开始上传证书到七牛云'); - const access = (await this.accessService.getById(this.accessId)) as QiniuAccess; + const access = await this.accessService.getById(this.accessId); const qiniuClient = new QiniuClient({ http: this.ctx.http, access, diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/dns-provider/tencent-dns-provider.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/dns-provider/tencent-dns-provider.ts index da15cf03..95a25785 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/dns-provider/tencent-dns-provider.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/dns-provider/tencent-dns-provider.ts @@ -1,7 +1,7 @@ import { Autowire } from '@certd/pipeline'; import { AbstractDnsProvider, CreateRecordOptions, IsDnsProvider, RemoveRecordOptions } from '@certd/plugin-cert'; -import { TencentAccess } from '@certd/plugin-plus'; +import { TencentAccess } from '@certd/plugin-lib'; @IsDnsProvider({ name: 'tencent', diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/lib/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/lib/index.ts index 2bc8395a..8a92d294 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/lib/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/lib/index.ts @@ -1,4 +1,4 @@ -import { TencentAccess } from '@certd/plugin-plus'; +import { TencentAccess } from '@certd/plugin-lib'; import { CertInfo } from '@certd/plugin-cert'; import { ILogger } from '@certd/basic'; export class TencentSslClient { diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/delete-expiring-cert/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/delete-expiring-cert/index.ts index 06b8b43d..34ab3965 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/delete-expiring-cert/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/delete-expiring-cert/index.ts @@ -1,8 +1,9 @@ import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; -import { AbstractPlusTaskPlugin, TencentAccess } from '@certd/plugin-plus'; +import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; import { TencentSslClient } from '../../lib/index.js'; import dayjs from 'dayjs'; import { remove } from 'lodash-es'; +import { TencentAccess } from '@certd/plugin-lib'; @IsTaskPlugin({ name: 'TencentDeleteExpiringCert', diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-cdn-v2/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-cdn-v2/index.ts index 521287ff..e90f2e99 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-cdn-v2/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-cdn-v2/index.ts @@ -1,9 +1,8 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; -import { TencentAccess } from '@certd/plugin-plus'; import { CertInfo } from '@certd/plugin-cert'; import { TencentSslClient } from '../../lib/index.js'; import { createRemoteSelectInputDefine } from '@certd/plugin-lib'; - +import { TencentAccess } from '@certd/plugin-lib'; @IsTaskPlugin({ name: 'TencentDeployCertToCDNv2', title: '腾讯云-部署到CDN-v2', diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-cdn/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-cdn/index.ts index 46400f25..c1b720f6 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-cdn/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-cdn/index.ts @@ -1,7 +1,6 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; -import { TencentAccess } from '@certd/plugin-plus'; import { CertInfo } from '@certd/plugin-cert'; - +import { TencentAccess } from '@certd/plugin-lib'; @IsTaskPlugin({ name: 'DeployCertToTencentCDN', title: '腾讯云-部署到CDN(废弃)', diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-clb/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-clb/index.ts index 0534dd30..62eba96d 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-clb/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-clb/index.ts @@ -1,7 +1,6 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; -import { TencentAccess } from '@certd/plugin-plus'; import dayjs from 'dayjs'; - +import { TencentAccess } from '@certd/plugin-lib'; @IsTaskPlugin({ name: 'DeployCertToTencentCLB', title: '腾讯云-部署到CLB', diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-eo/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-eo/index.ts index e56b9d92..ad155f8b 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-eo/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-eo/index.ts @@ -1,6 +1,5 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; -import { TencentAccess } from '@certd/plugin-plus'; - +import { TencentAccess } from '@certd/plugin-lib'; @IsTaskPlugin({ name: 'DeployCertToTencentEO', title: '腾讯云-部署到腾讯云EO', diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/start-instances/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/start-instances/index.ts index 762266c7..3bbfc923 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/start-instances/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/start-instances/index.ts @@ -1,6 +1,6 @@ import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin } from '@certd/pipeline'; -import { TencentAccess } from '@certd/plugin-plus'; +import { TencentAccess } from '@certd/plugin-lib'; import { createRemoteSelectInputDefine } from '@certd/plugin-lib'; @IsTaskPlugin({