chore: 支持手动上传证书并部署

pull/361/head
xiaojunnuo 2025-03-18 00:52:50 +08:00
parent 29a6a992f0
commit de40be430b
74 changed files with 1040 additions and 597 deletions

View File

@ -0,0 +1,7 @@
{
"printWidth": 220,
"bracketSpacing": true,
"singleQuote": false,
"trailingComma": "es5",
"arrowParens": "avoid"
}

View File

@ -16,7 +16,7 @@
"@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
// "no-unused-expressions": "off", "@typescript-eslint/no-empty-function": "off",
"max-len": [0, 160, 2, { "ignoreUrls": true }] "@typescript-eslint/no-unused-vars": "off"
} }
} }

View File

@ -0,0 +1,7 @@
{
"printWidth": 220,
"bracketSpacing": true,
"singleQuote": false,
"trailingComma": "es5",
"arrowParens": "avoid"
}

View File

@ -7,8 +7,8 @@ function sha256(data: string, digest: BinaryToTextEncoding = 'hex') {
return crypto.createHash('sha256').update(data).digest(digest); return crypto.createHash('sha256').update(data).digest(digest);
} }
function HmacSha256(data: string, key: string, digest: BinaryToTextEncoding = 'base64') { function hmacSha256(data: string, digest: BinaryToTextEncoding = 'base64') {
return crypto.createHmac('sha256', Buffer.from(key, 'base64')).update(data).digest(digest); return crypto.createHmac('sha256', data).update(Buffer.alloc(0)).digest(digest);
} }
function base64(data: string) { function base64(data: string) {
@ -18,5 +18,5 @@ export const hashUtils = {
md5, md5,
sha256, sha256,
base64, base64,
HmacSha256, hmacSha256,
}; };

View File

@ -16,7 +16,7 @@
"@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
// "no-unused-expressions": "off", "@typescript-eslint/no-empty-function": "off",
"max-len": [0, 160, 2, { "ignoreUrls": true }] "@typescript-eslint/no-unused-vars": "off"
} }
} }

View File

@ -1,3 +1,7 @@
{ {
"printWidth": 160 "printWidth": 220,
"bracketSpacing": true,
"singleQuote": false,
"trailingComma": "es5",
"arrowParens": "avoid"
} }

View File

@ -7,7 +7,7 @@ import { createAxiosService, hashUtils, HttpRequestConfig, ILogger, logger, util
import { IAccessService } from "../access/index.js"; import { IAccessService } from "../access/index.js";
import { RegistryItem } from "../registry/index.js"; import { RegistryItem } from "../registry/index.js";
import { Decorator } from "../decorator/index.js"; import { Decorator } from "../decorator/index.js";
import { ICnameProxyService, IEmailService, IPluginConfigService, IUrlService } from "../service/index.js"; import { ICnameProxyService, IEmailService, IPluginConfigService, IServiceGetter, IUrlService } from "../service/index.js";
import { FileStore } from "./file-store.js"; import { FileStore } from "./file-store.js";
import { cloneDeep, forEach, merge } from "lodash-es"; import { cloneDeep, forEach, merge } from "lodash-es";
import { INotificationService } from "../notification/index.js"; import { INotificationService } from "../notification/index.js";
@ -33,7 +33,7 @@ export type ExecutorOptions = {
user: UserInfo; user: UserInfo;
baseURL?: string; baseURL?: string;
sysInfo?: SysInfo; sysInfo?: SysInfo;
serviceGetter: (name: string) => any; serviceGetter: IServiceGetter;
}; };
export class Executor { export class Executor {
@ -366,6 +366,7 @@ export class Executor {
step, step,
pipeline: this.pipeline, pipeline: this.pipeline,
}), }),
serviceGetter: this.options.serviceGetter,
}; };
instance.setCtx(taskCtx); instance.setCtx(taskCtx);

View File

@ -2,7 +2,7 @@ import { Registrable } from "../registry/index.js";
import { FileItem, FormItemProps, Pipeline, Runnable, Step } from "../dt/index.js"; import { FileItem, FormItemProps, Pipeline, Runnable, Step } from "../dt/index.js";
import { FileStore } from "../core/file-store.js"; import { FileStore } from "../core/file-store.js";
import { IAccessService } from "../access/index.js"; import { IAccessService } from "../access/index.js";
import { ICnameProxyService, IEmailService, IUrlService } from "../service/index.js"; import { ICnameProxyService, IEmailService, IServiceGetter, IUrlService } from "../service/index.js";
import { CancelError, IContext, RunHistory, RunnableCollection } from "../core/index.js"; import { CancelError, IContext, RunHistory, RunnableCollection } from "../core/index.js";
import { HttpRequestConfig, ILogger, logger, utils } from "@certd/basic"; import { HttpRequestConfig, ILogger, logger, utils } from "@certd/basic";
import { HttpClient } from "@certd/basic"; import { HttpClient } from "@certd/basic";
@ -116,7 +116,7 @@ export type TaskInstanceContext = {
emitter: TaskEmitter; emitter: TaskEmitter;
//service 容器 //service 容器
serviceContainer?: Record<string, any>; serviceGetter?: IServiceGetter;
}; };
export abstract class AbstractTaskPlugin implements ITaskPlugin { export abstract class AbstractTaskPlugin implements ITaskPlugin {
@ -224,7 +224,7 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin {
getStepFromPipeline(stepId: string) { getStepFromPipeline(stepId: string) {
let found: any = null; let found: any = null;
RunnableCollection.each(this.ctx.pipeline.stages, (step) => { RunnableCollection.each(this.ctx.pipeline.stages, step => {
if (step.id === stepId) { if (step.id === stepId) {
found = step; found = step;
return; return;

View File

@ -3,3 +3,6 @@ export * from "./cname.js";
export * from "./config.js"; export * from "./config.js";
export * from "./url.js"; export * from "./url.js";
export * from "./emit.js"; export * from "./emit.js";
export type IServiceGetter = {
get: (name: string) => Promise<any>;
};

View File

@ -17,7 +17,6 @@
"@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-empty-function": "off",
// "no-unused-expressions": "off", "@typescript-eslint/no-unused-vars": "off"
"max-len": [0, 160, 2, { "ignoreUrls": true }]
} }
} }

View File

@ -1,3 +1,7 @@
{ {
"printWidth": 160 "printWidth": 220,
"bracketSpacing": true,
"singleQuote": false,
"trailingComma": "es5",
"arrowParens": "avoid"
} }

View File

@ -17,7 +17,6 @@
"@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-empty-function": "off",
// "no-unused-expressions": "off", "@typescript-eslint/no-unused-vars": "off"
"max-len": [0, 160, 2, { "ignoreUrls": true }]
} }
} }

View File

@ -1,7 +1,7 @@
{ {
"printWidth": 160, "printWidth": 220,
"bracketSpacing": true, "bracketSpacing": true,
"singleQuote": true, "singleQuote": false,
"trailingComma": "es5", "trailingComma": "es5",
"arrowParens": "avoid" "arrowParens": "avoid"
} }

View File

@ -1,7 +1,7 @@
{ {
"printWidth": 160, "printWidth": 220,
"bracketSpacing": true, "bracketSpacing": true,
"singleQuote": true, "singleQuote": false,
"trailingComma": "es5", "trailingComma": "es5",
"arrowParens": "avoid" "arrowParens": "avoid"
} }

View File

@ -1,7 +1,7 @@
{ {
"printWidth": 160, "printWidth": 220,
"bracketSpacing": true, "bracketSpacing": true,
"singleQuote": true, "singleQuote": false,
"trailingComma": "es5", "trailingComma": "es5",
"arrowParens": "avoid" "arrowParens": "avoid"
} }

View File

@ -1,7 +1,7 @@
{ {
"printWidth": 160, "printWidth": 220,
"bracketSpacing": true, "bracketSpacing": true,
"singleQuote": true, "singleQuote": false,
"trailingComma": "es5", "trailingComma": "es5",
"arrowParens": "avoid" "arrowParens": "avoid"
} }

View File

@ -17,7 +17,6 @@
"@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-empty-function": "off",
// "no-unused-expressions": "off", "@typescript-eslint/no-unused-vars": "off"
"max-len": [0, 160, 2, { "ignoreUrls": true }]
} }
} }

View File

@ -1,3 +1,7 @@
{ {
"printWidth": 160 "printWidth": 220,
"bracketSpacing": true,
"singleQuote": false,
"trailingComma": "es5",
"arrowParens": "avoid"
} }

View File

@ -0,0 +1,177 @@
import { AbstractTaskPlugin, IContext, Step, TaskInput, TaskOutput } from "@certd/pipeline";
import dayjs from "dayjs";
import type { CertInfo } from "./acme.js";
import { CertReader } from "./cert-reader.js";
import JSZip from "jszip";
import { CertConverter } from "./convert.js";
export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin {
@TaskInput({
title: "域名",
component: {
name: "a-select",
vModel: "value",
mode: "tags",
open: false,
placeholder: "foo.com / *.foo.com / *.bar.com",
tokenSeparators: [",", " ", "", "、", "|"],
},
rules: [{ type: "domains" }],
required: true,
col: {
span: 24,
},
order: -999,
helper:
"1、支持多个域名打到一个证书上例如 foo.com*.foo.com*.bar.com\n" +
"2、子域名被通配符包含的不要填写例如www.foo.com已经被*.foo.com包含不要填写www.foo.com\n" +
"3、泛域名只能通配*号那一级(*.foo.com的证书不能用于xxx.yyy.foo.com、不能用于foo.com\n" +
"4、输入一个空格之后再输入下一个",
})
domains!: string[];
@TaskInput({
title: "证书密码",
component: {
name: "input-password",
vModel: "value",
},
required: false,
order: 100,
helper: "PFX、jks格式证书是否加密\njks必须设置密码不传则默认123456\npfx不传则为空密码",
})
pfxPassword!: string;
@TaskInput({
title: "PFX证书转换参数",
value: "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES",
component: {
name: "a-auto-complete",
vModel: "value",
options: [
{ value: "", label: "兼容 Windows Server 最新" },
{ value: "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES", label: "兼容 Windows Server 2016" },
{ value: "-nomac -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES", label: "兼容 Windows Server 2008" },
],
},
required: false,
order: 100,
helper: "兼容Windows Server各个版本",
})
pfxArgs = "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES";
userContext!: IContext;
lastStatus!: Step;
@TaskOutput({
title: "域名证书",
})
cert?: CertInfo;
async onInstance() {
this.userContext = this.ctx.userContext;
this.lastStatus = this.ctx.lastStatus as Step;
await this.onInit();
}
abstract onInit(): Promise<void>;
async output(certReader: CertReader, isNew: boolean) {
const cert: CertInfo = certReader.toCertInfo();
this.cert = cert;
this._result.pipelineVars.certExpiresTime = dayjs(certReader.detail.notAfter).valueOf();
if (!this._result.pipelinePrivateVars) {
this._result.pipelinePrivateVars = {};
}
this._result.pipelinePrivateVars.cert = cert;
if (isNew) {
try {
const converter = new CertConverter({ logger: this.logger });
const res = await converter.convert({
cert,
pfxPassword: this.pfxPassword,
pfxArgs: this.pfxArgs,
});
if (cert.pfx == null && res.pfx) {
cert.pfx = res.pfx;
}
if (cert.der == null && res.der) {
cert.der = res.der;
}
if (cert.jks == null && res.jks) {
cert.jks = res.jks;
}
this.logger.info("转换证书格式成功");
} catch (e) {
this.logger.error("转换证书格式失败", e);
}
}
if (isNew) {
const zipFileName = certReader.buildCertFileName("zip", certReader.detail.notBefore);
await this.zipCert(cert, zipFileName);
} else {
this.extendsFiles();
}
}
async zipCert(cert: CertInfo, filename: string) {
const zip = new JSZip();
zip.file("证书.pem", cert.crt);
zip.file("私钥.pem", cert.key);
zip.file("中间证书.pem", cert.ic);
zip.file("cert.crt", cert.crt);
zip.file("cert.key", cert.key);
zip.file("intermediate.crt", cert.ic);
zip.file("origin.crt", cert.oc);
zip.file("one.pem", cert.one);
if (cert.pfx) {
zip.file("cert.pfx", Buffer.from(cert.pfx, "base64"));
}
if (cert.der) {
zip.file("cert.der", Buffer.from(cert.der, "base64"));
}
if (cert.jks) {
zip.file("cert.jks", Buffer.from(cert.jks, "base64"));
}
zip.file(
"说明.txt",
`证书文件说明
cert.crtpem
cert.keypem
intermediate.crtpem
origin.crtpem
one.pem pemcrt+key
cert.pfxpfxiis使
cert.derder
cert.jksjksjava使
`
);
const content = await zip.generateAsync({ type: "nodebuffer" });
this.saveFile(filename, content);
this.logger.info(`已保存文件:${filename}`);
}
formatCert(pem: string) {
pem = pem.replace(/\r/g, "");
pem = pem.replace(/\n\n/g, "\n");
pem = pem.replace(/\n$/g, "");
return pem;
}
formatCerts(cert: { crt: string; key: string; csr: string }) {
const newCert: CertInfo = {
crt: this.formatCert(cert.crt),
key: this.formatCert(cert.key),
csr: this.formatCert(cert.csr),
};
return newCert;
}
}

View File

@ -1,10 +1,8 @@
import { AbstractTaskPlugin, IContext, NotificationBody, Step, TaskEmitter, TaskInput, TaskOutput } from "@certd/pipeline"; import { NotificationBody, Step, TaskEmitter, TaskInput } from "@certd/pipeline";
import dayjs from "dayjs"; import dayjs from "dayjs";
import type { CertInfo } from "./acme.js";
import { CertReader } from "./cert-reader.js"; import { CertReader } from "./cert-reader.js";
import JSZip from "jszip";
import { CertConverter } from "./convert.js";
import { pick } from "lodash-es"; import { pick } from "lodash-es";
import { CertApplyBaseConvertPlugin } from "./base-convert.js";
export const EVENT_CERT_APPLY_SUCCESS = "CertApply.success"; export const EVENT_CERT_APPLY_SUCCESS = "CertApply.success";
@ -12,30 +10,7 @@ export async function emitCertApplySuccess(emitter: TaskEmitter, cert: CertReade
await emitter.emit(EVENT_CERT_APPLY_SUCCESS, cert); await emitter.emit(EVENT_CERT_APPLY_SUCCESS, cert);
} }
export abstract class CertApplyBasePlugin extends AbstractTaskPlugin { export abstract class CertApplyBasePlugin extends CertApplyBaseConvertPlugin {
@TaskInput({
title: "域名",
component: {
name: "a-select",
vModel: "value",
mode: "tags",
open: false,
placeholder: "foo.com / *.foo.com / *.bar.com",
tokenSeparators: [",", " ", "", "、", "|"],
},
rules: [{ type: "domains" }],
required: true,
col: {
span: 24,
},
order: -999,
helper:
"1、支持多个域名打到一个证书上例如 foo.com*.foo.com*.bar.com\n" +
"2、子域名被通配符包含的不要填写例如www.foo.com已经被*.foo.com包含不要填写www.foo.com\n" +
"3、泛域名只能通配*号那一级(*.foo.com的证书不能用于xxx.yyy.foo.com、不能用于foo.com\n" +
"4、输入一个空格之后再输入下一个",
})
domains!: string[];
@TaskInput({ @TaskInput({
title: "邮箱", title: "邮箱",
@ -50,36 +25,6 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
}) })
email!: string; email!: string;
@TaskInput({
title: "证书密码",
component: {
name: "input-password",
vModel: "value",
},
required: false,
order: 100,
helper: "PFX、jks格式证书是否加密\njks必须设置密码不传则默认123456\npfx不传则为空密码",
})
pfxPassword!: string;
@TaskInput({
title: "PFX证书转换参数",
value: "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES",
component: {
name: "a-auto-complete",
vModel: "value",
options: [
{ value: "", label: "兼容 Windows Server 最新" },
{ value: "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES", label: "兼容 Windows Server 2016" },
{ value: "-nomac -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES", label: "兼容 Windows Server 2008" },
],
},
required: false,
order: 100,
helper: "兼容Windows Server各个版本",
})
pfxArgs = "-macalg SHA1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES";
@TaskInput({ @TaskInput({
title: "更新天数", title: "更新天数",
value: 35, value: 35,
@ -111,14 +56,6 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
// }) // })
csrInfo!: string; csrInfo!: string;
userContext!: IContext;
lastStatus!: Step;
@TaskOutput({
title: "域名证书",
})
cert?: CertInfo;
async onInstance() { async onInstance() {
this.userContext = this.ctx.userContext; this.userContext = this.ctx.userContext;
this.lastStatus = this.ctx.lastStatus as Step; this.lastStatus = this.ctx.lastStatus as Step;
@ -151,89 +88,6 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
} }
} }
async output(certReader: CertReader, isNew: boolean) {
const cert: CertInfo = certReader.toCertInfo();
this.cert = cert;
this._result.pipelineVars.certExpiresTime = dayjs(certReader.detail.notAfter).valueOf();
if (!this._result.pipelinePrivateVars) {
this._result.pipelinePrivateVars = {};
}
this._result.pipelinePrivateVars.cert = cert;
if (isNew) {
try {
const converter = new CertConverter({ logger: this.logger });
const res = await converter.convert({
cert,
pfxPassword: this.pfxPassword,
pfxArgs: this.pfxArgs,
});
if (cert.pfx == null && res.pfx) {
cert.pfx = res.pfx;
}
if (cert.der == null && res.der) {
cert.der = res.der;
}
if (cert.jks == null && res.jks) {
cert.jks = res.jks;
}
this.logger.info("转换证书格式成功");
} catch (e) {
this.logger.error("转换证书格式失败", e);
}
}
if (isNew) {
const zipFileName = certReader.buildCertFileName("zip", certReader.detail.notBefore);
await this.zipCert(cert, zipFileName);
} else {
this.extendsFiles();
}
}
async zipCert(cert: CertInfo, filename: string) {
const zip = new JSZip();
zip.file("证书.pem", cert.crt);
zip.file("私钥.pem", cert.key);
zip.file("中间证书.pem", cert.ic);
zip.file("cert.crt", cert.crt);
zip.file("cert.key", cert.key);
zip.file("intermediate.crt", cert.ic);
zip.file("origin.crt", cert.oc);
zip.file("one.pem", cert.one);
if (cert.pfx) {
zip.file("cert.pfx", Buffer.from(cert.pfx, "base64"));
}
if (cert.der) {
zip.file("cert.der", Buffer.from(cert.der, "base64"));
}
if (cert.jks) {
zip.file("cert.jks", Buffer.from(cert.jks, "base64"));
}
zip.file(
"说明.txt",
`证书文件说明
cert.crtpem
cert.keypem
intermediate.crtpem
origin.crtpem
one.pem pemcrt+key
cert.pfxpfxiis使
cert.derder
cert.jksjksjava使
`
);
const content = await zip.generateAsync({ type: "nodebuffer" });
this.saveFile(filename, content);
this.logger.info(`已保存文件:${filename}`);
}
/** /**
* *
*/ */
@ -279,22 +133,6 @@ cert.jksjks格式证书文件java服务器使用
return null; return null;
} }
formatCert(pem: string) {
pem = pem.replace(/\r/g, "");
pem = pem.replace(/\n\n/g, "\n");
pem = pem.replace(/\n$/g, "");
return pem;
}
formatCerts(cert: { crt: string; key: string; csr: string }) {
const newCert: CertInfo = {
crt: this.formatCert(cert.crt),
key: this.formatCert(cert.key),
csr: this.formatCert(cert.csr),
};
return newCert;
}
async readLastCert(): Promise<CertReader | undefined> { async readLastCert(): Promise<CertReader | undefined> {
const cert = this.lastStatus?.status?.output?.cert; const cert = this.lastStatus?.status?.output?.cert;
if (cert == null) { if (cert == null) {

View File

@ -1,38 +1,53 @@
import { IsTaskPlugin, pluginGroups, RunStrategy, Step, TaskInput } from "@certd/pipeline"; import { IsTaskPlugin, pluginGroups, RunStrategy, Step, TaskInput, TaskOutput } from "@certd/pipeline";
import type { CertInfo } from "../acme.js"; import type { CertInfo } from "../acme.js";
import { CertReader } from "../cert-reader.js"; import { CertReader } from "../cert-reader.js";
import { CertApplyBasePlugin } from "../base.js"; import { CertApplyBaseConvertPlugin } from "../base-convert.js";
import dayjs from "dayjs";
export { CertReader }; export { CertReader };
export type { CertInfo }; export type { CertInfo };
@IsTaskPlugin({ @IsTaskPlugin({
name: "CertUpload", name: "CertApplyUpload",
icon: "ph:certificate", icon: "ph:certificate",
title: "证书手动上传", title: "证书手动上传",
group: pluginGroups.cert.key, group: pluginGroups.cert.key,
desc: "在证书仓库手动上传后触发部署证书", desc: "在证书仓库手动上传后触发部署证书",
default: { default: {
input: {
renewDays: 35,
forceUpdate: false,
},
strategy: { strategy: {
runStrategy: RunStrategy.AlwaysRun, runStrategy: RunStrategy.AlwaysRun,
}, },
}, },
}) })
export class CertUploadPlugin extends CertApplyBasePlugin { export class CertApplyUploadPlugin extends CertApplyBaseConvertPlugin {
@TaskInput({ @TaskInput({
title: "证书仓库ID", title: "证书仓库ID",
component: { component: {
name: "a-cert-select", name: "cert-info-selector",
vModel: "value", vModel: "modelValue",
}, },
order: -9999,
required: true, required: true,
mergeScript: `
return {
component:{
on:{
selectedChange(scope){
console.log(scope)
scope.form.input.domains = scope.$event?.domains
}
}
}
}
`,
}) })
certInfoId!: string; certInfoId!: string;
@TaskOutput({
title: "证书MD5",
})
certMd5?: string;
async onInstance() { async onInstance() {
this.accessService = this.ctx.accessService; this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger; this.logger = this.ctx.logger;
@ -41,21 +56,45 @@ export class CertUploadPlugin extends CertApplyBasePlugin {
} }
async onInit(): Promise<void> {} async onInit(): Promise<void> {}
async doCertApply() { async getCertFromStore() {
const siteInfoService = this.ctx.serviceContainer["CertInfoService"]; const siteInfoService = await this.ctx.serviceGetter.get("CertInfoService");
const certInfo = await siteInfoService.getCertInfo({ const certInfo = await siteInfoService.getCertInfo({
certId: this.certInfoId, certId: this.certInfoId,
userid: this.pipeline.userId, userId: this.pipeline.userId,
}); });
const certReader = new CertReader(certInfo); const certReader = new CertReader(certInfo);
if (!certReader.expires && certReader.expires < new Date().getTime()) { if (!certReader.expires && certReader.expires < new Date().getTime()) {
throw new Error("证书已过期,停止部署"); throw new Error("证书已过期,停止部署,请重新上传证书");
} }
return certReader; return certReader;
} }
async execute(): Promise<string | void> {
const certReader = await this.getCertFromStore();
const crtMd5 = this.ctx.utils.hash.md5(certReader.cert.crt);
const leftDays = dayjs(certReader.expires).diff(dayjs(), "day");
this.logger.info(`证书过期时间${dayjs(certReader.expires).format("YYYY-MM-DD HH:mm:ss")},剩余${leftDays}`);
const lastCrtMd5 = this.lastStatus.status.output?.certMd5;
this.logger.info("证书MD5", crtMd5);
this.logger.info("上次证书MD5", lastCrtMd5);
if (lastCrtMd5 === crtMd5) {
this.logger.info("证书无变化,跳过");
//输出证书MD5
this.certMd5 = crtMd5;
await this.output(certReader, false);
return "skip";
}
this.logger.info("证书有变化,重新部署");
this.clearLastStatus();
//输出证书MD5
this.certMd5 = crtMd5;
await this.output(certReader, true);
return;
}
} }
new CertUploadPlugin(); new CertApplyUploadPlugin();

View File

@ -1,2 +1,4 @@
export * from "./cert-plugin/index.js"; export * from "./cert-plugin/index.js";
export * from "./cert-plugin/lego/index.js"; export * from "./cert-plugin/lego/index.js";
export * from "./cert-plugin/custom/index.js";
export const CertApplyPluginNames = ["CertApply", "CertApplyLego", "CertApplyUpload"];

View File

@ -17,7 +17,6 @@
"@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-empty-function": "off",
// "no-unused-expressions": "off", "@typescript-eslint/no-unused-vars": "off"
"max-len": [0, 160, 2, { "ignoreUrls": true }]
} }
} }

View File

@ -1,3 +1,7 @@
{ {
"printWidth": 160 "printWidth": 220,
"bracketSpacing": true,
"singleQuote": false,
"trailingComma": "es5",
"arrowParens": "avoid"
} }

View File

@ -3,34 +3,34 @@ module.exports = {
env: { env: {
browser: true, browser: true,
node: true, node: true,
es6: true es6: true,
}, },
parser: "vue-eslint-parser", parser: 'vue-eslint-parser',
parserOptions: { parserOptions: {
parser: "@typescript-eslint/parser", parser: '@typescript-eslint/parser',
ecmaVersion: 2020, ecmaVersion: 2020,
sourceType: "module", sourceType: 'module',
jsxPragma: "React", jsxPragma: 'React',
ecmaFeatures: { ecmaFeatures: {
jsx: true, jsx: true,
tsx: true tsx: true,
} },
}, },
extends: ["plugin:vue/vue3-recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended", "prettier"], extends: ['plugin:vue/vue3-recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', 'prettier'],
rules: { rules: {
//"max-len": [0, 200, 2, { ignoreUrls: true }], //"max-len": [0, 200, 2, { ignoreUrls: true }],
"@typescript-eslint/no-unused-vars": "off", '@typescript-eslint/no-unused-vars': 'off',
"no-unused-vars": "off", 'no-unused-vars': 'off',
"@typescript-eslint/ban-ts-ignore": "off", '@typescript-eslint/ban-ts-ignore': 'off',
"@typescript-eslint/ban-ts-comment": "off", '@typescript-eslint/ban-ts-comment': 'off',
"@typescript-eslint/ban-types": "off", '@typescript-eslint/ban-types': 'off',
"@typescript-eslint/explicit-function-return-type": "off", '@typescript-eslint/explicit-function-return-type': 'off',
"@typescript-eslint/no-explicit-any": "off", '@typescript-eslint/no-explicit-any': 'off',
"@typescript-eslint/no-var-requires": "off", '@typescript-eslint/no-var-requires': 'off',
"@typescript-eslint/no-empty-function": "off", '@typescript-eslint/no-empty-function': 'off',
"@typescript-eslint/no-use-before-define": "off", '@typescript-eslint/no-use-before-define': 'off',
"@typescript-eslint/no-non-null-assertion": "off", '@typescript-eslint/no-non-null-assertion': 'off',
"@typescript-eslint/explicit-module-boundary-types": "off" '@typescript-eslint/explicit-module-boundary-types': 'off',
// "@typescript-eslint/no-unused-vars": [ // "@typescript-eslint/no-unused-vars": [
// "error", // "error",
// { // {
@ -69,5 +69,5 @@ module.exports = {
// math: "always", // math: "always",
// }, // },
// ], // ],
} },
}; };

View File

@ -1,5 +1,7 @@
{ {
"printWidth": 220,
"trailingComma": "none", "bracketSpacing": true,
"printWidth": 220 "singleQuote": false,
"trailingComma": "es5",
"arrowParens": "avoid"
} }

View File

@ -5,6 +5,7 @@ import OutputSelector from "/@/components/plugins/common/output-selector/index.v
import DnsProviderSelector from "/@/components/plugins/cert/dns-provider-selector/index.vue"; import DnsProviderSelector from "/@/components/plugins/cert/dns-provider-selector/index.vue";
import DomainsVerifyPlanEditor from "/@/components/plugins/cert/domains-verify-plan-editor/index.vue"; import DomainsVerifyPlanEditor from "/@/components/plugins/cert/domains-verify-plan-editor/index.vue";
import AccessSelector from "/@/views/certd/access/access-selector/index.vue"; import AccessSelector from "/@/views/certd/access/access-selector/index.vue";
import CertInfoSelector from "/@/views/certd/monitor/cert/selector/index.vue";
import InputPassword from "./common/input-password.vue"; import InputPassword from "./common/input-password.vue";
import ApiTest from "./common/api-test.vue"; import ApiTest from "./common/api-test.vue";
export * from "./cert/index.js"; export * from "./cert/index.js";
@ -14,6 +15,8 @@ export default {
app.component("DnsProviderSelector", DnsProviderSelector); app.component("DnsProviderSelector", DnsProviderSelector);
app.component("DomainsVerifyPlanEditor", DomainsVerifyPlanEditor); app.component("DomainsVerifyPlanEditor", DomainsVerifyPlanEditor);
app.component("AccessSelector", AccessSelector); app.component("AccessSelector", AccessSelector);
app.component("CertInfoSelector", CertInfoSelector);
app.component("ApiTest", ApiTest); app.component("ApiTest", ApiTest);
app.component("SynologyDeviceIdGetter", SynologyIdDeviceGetter); app.component("SynologyDeviceIdGetter", SynologyIdDeviceGetter);

View File

@ -7,7 +7,7 @@ export const certInfoApi = {
return await request({ return await request({
url: apiPrefix + "/page", url: apiPrefix + "/page",
method: "post", method: "post",
data: query data: query,
}); });
}, },
@ -15,7 +15,7 @@ export const certInfoApi = {
return await request({ return await request({
url: apiPrefix + "/add", url: apiPrefix + "/add",
method: "post", method: "post",
data: obj data: obj,
}); });
}, },
@ -23,7 +23,7 @@ export const certInfoApi = {
return await request({ return await request({
url: apiPrefix + "/update", url: apiPrefix + "/update",
method: "post", method: "post",
data: obj data: obj,
}); });
}, },
@ -31,7 +31,7 @@ export const certInfoApi = {
return await request({ return await request({
url: apiPrefix + "/delete", url: apiPrefix + "/delete",
method: "post", method: "post",
params: { id } params: { id },
}); });
}, },
@ -39,27 +39,35 @@ export const certInfoApi = {
return await request({ return await request({
url: apiPrefix + "/info", url: apiPrefix + "/info",
method: "post", method: "post",
params: { id } params: { id },
}); });
}, },
async ListAll() { async ListAll() {
return await request({ return await request({
url: apiPrefix + "/all", url: apiPrefix + "/all",
method: "post" method: "post",
}); });
}, },
async Upload(body: { id?: number; cert: { crt: string; key: string } }) { async Upload(body: { id?: number; cert: { crt: string; key: string } }) {
return await request({ return await request({
url: apiPrefix + "/upload", url: apiPrefix + "/upload",
method: "post", method: "post",
data: body data: body,
}); });
}, },
async GetCert(id: number): Promise<CertInfo> { async GetCert(id: number): Promise<CertInfo> {
return await request({ return await request({
url: apiPrefix + "/getCert", url: apiPrefix + "/getCert",
method: "post", method: "post",
params: { id: id } params: { id: id },
}); });
} },
async GetOptionsByIds(ids: number[]): Promise<any[]> {
return await request({
url: apiPrefix + "/getOptionsByIds",
method: "post",
data: { ids },
});
},
}; };

View File

@ -1,6 +1,17 @@
// @ts-ignore // @ts-ignore
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, useFormWrapper, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; import {
AddReq,
compute,
CreateCrudOptionsProps,
CreateCrudOptionsRet,
DelReq,
dict,
EditReq,
useFormWrapper,
UserPageQuery,
UserPageRes
} from "@fast-crud/fast-crud";
import { certInfoApi } from "./api"; import { certInfoApi } from "./api";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
@ -9,7 +20,6 @@ import { notification } from "ant-design-vue";
import CertView from "/@/views/certd/pipeline/cert-view.vue"; import CertView from "/@/views/certd/pipeline/cert-view.vue";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
const api = certInfoApi; const api = certInfoApi;
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => { const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query); return await api.GetList(query);
@ -48,7 +58,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
width: 800, width: 800,
content: () => { content: () => {
return <CertView cert={cert}></CertView>; return <CertView cert={cert}></CertView>;
} },
}); });
}; };
@ -69,35 +79,35 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
title: "ID", title: "ID",
type: "number", type: "number",
form: { form: {
show: false show: false,
} },
}, },
"cert.crt": { "cert.crt": {
title: "证书", title: "证书",
type: "textarea", type: "textarea",
form: { form: {
component: { component: {
rows: 4 rows: 4,
}, },
rules: [{ required: true, message: "此项必填" }], rules: [{ required: true, message: "此项必填" }],
col: { span: 24 } col: { span: 24 },
} },
}, },
"cert.key": { "cert.key": {
title: "私钥", title: "私钥",
type: "textarea", type: "textarea",
form: { form: {
component: { component: {
rows: 4 rows: 4,
}, },
rules: [{ required: true, message: "此项必填" }], rules: [{ required: true, message: "此项必填" }],
col: { span: 24 } col: { span: 24 },
} },
} },
}, },
form: { form: {
wrapper: { wrapper: {
title: "上传自定义证书" title: "上传自定义证书",
}, },
async doSubmit({ form }: any) { async doSubmit({ form }: any) {
if (!id) { if (!id) {
@ -106,9 +116,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
form.id = id; form.id = id;
} }
return await api.Upload(form); return await api.Upload(form);
} },
} },
} },
}; };
} }
const { crudOptions } = createCrudOptions(); const { crudOptions } = createCrudOptions();
@ -121,22 +131,22 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
pageRequest, pageRequest,
addRequest, addRequest,
editRequest, editRequest,
delRequest delRequest,
}, },
form: { form: {
labelCol: { labelCol: {
//固定label宽度 //固定label宽度
span: null, span: null,
style: { style: {
width: "100px" width: "100px",
} },
}, },
col: { col: {
span: 22 span: 22,
}, },
wrapper: { wrapper: {
width: 600 width: 600,
} },
}, },
actionbar: { actionbar: {
show: true, show: true,
@ -147,13 +157,13 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
show: true, show: true,
async click() { async click() {
await openUpload(); await openUpload();
} },
} },
} },
}, },
tabs: { tabs: {
name: "fromType", name: "fromType",
show: true show: true,
}, },
rowHandle: { rowHandle: {
width: 140, width: 140,
@ -167,7 +177,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
icon: "ph:certificate", icon: "ph:certificate",
async click({ row }) { async click({ row }) {
await viewCert(row); await viewCert(row);
} },
}, },
copy: { show: false }, copy: { show: false },
edit: { show: false }, edit: { show: false },
@ -181,15 +191,15 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
icon: "ph:upload", icon: "ph:upload",
async click({ row }) { async click({ row }) {
await openUpload(row.id); await openUpload(row.id);
} },
}, },
remove: { remove: {
order: 10, order: 10,
show: compute(({ row }) => { show: compute(({ row }) => {
return row.fromType === "upload"; return row.fromType === "upload";
}) }),
} },
} },
}, },
columns: { columns: {
id: { id: {
@ -197,85 +207,85 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
key: "id", key: "id",
type: "number", type: "number",
search: { search: {
show: false show: false,
}, },
column: { column: {
width: 100, width: 100,
editable: { editable: {
disabled: true disabled: true,
} },
}, },
form: { form: {
show: false show: false,
} },
}, },
fromType: { fromType: {
title: "来源", title: "来源",
search: { search: {
show: true show: true,
}, },
type: "dict-select", type: "dict-select",
dict: dict({ dict: dict({
data: [ data: [
{ label: "流水线", value: "pipeline" }, { label: "流水线", value: "pipeline" },
{ label: "手动上传", value: "upload" } { label: "手动上传", value: "upload" },
] ],
}), }),
form: { form: {
show: false show: false,
}, },
column: { column: {
width: 100, width: 100,
sorter: true, sorter: true,
component: { component: {
color: "auto" color: "auto",
}, },
conditionalRender: false conditionalRender: false,
}, },
valueBuilder({ value, row, key }) { valueBuilder({ value, row, key }) {
if (!value) { if (!value) {
row[key] = "pipeline"; row[key] = "pipeline";
} }
} },
}, },
domains: { domains: {
title: "域名", title: "域名",
search: { search: {
show: true show: true,
}, },
type: "text", type: "text",
form: { form: {
rules: [{ required: true, message: "请输入域名" }] rules: [{ required: true, message: "请输入域名" }],
}, },
column: { column: {
width: 450, width: 450,
sorter: true, sorter: true,
component: { component: {
name: "fs-values-format", name: "fs-values-format",
color: "auto" color: "auto",
} },
} },
}, },
domainCount: { domainCount: {
title: "域名数量", title: "域名数量",
type: "number", type: "number",
form: { form: {
show: false show: false,
}, },
column: { column: {
width: 120, width: 120,
sorter: true, sorter: true,
show: false show: false,
} },
}, },
expiresLeft: { expiresLeft: {
title: "有效天数", title: "有效天数",
search: { search: {
show: false show: false,
}, },
type: "date", type: "date",
form: { form: {
show: false show: false,
}, },
column: { column: {
sorter: true, sorter: true,
@ -290,54 +300,54 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
const color = leftDays < 20 ? "red" : "#389e0d"; const color = leftDays < 20 ? "red" : "#389e0d";
const percent = (leftDays / 90) * 100; const percent = (leftDays / 90) * 100;
return <a-progress title={expireDate + "过期"} percent={percent} strokeColor={color} format={(percent: number) => `${leftDays}`} />; return <a-progress title={expireDate + "过期"} percent={percent} strokeColor={color} format={(percent: number) => `${leftDays}`} />;
} },
} },
}, },
expiresTime: { expiresTime: {
title: "过期时间", title: "过期时间",
search: { search: {
show: false show: false,
}, },
type: "datetime", type: "datetime",
form: { form: {
show: false show: false,
}, },
column: { column: {
sorter: true sorter: true,
} },
}, },
certProvider: { certProvider: {
title: "证书颁发机构", title: "证书颁发机构",
search: { search: {
show: false show: false,
}, },
type: "text", type: "text",
form: { form: {
show: false show: false,
}, },
column: { column: {
width: 200 width: 200,
} },
}, },
applyTime: { applyTime: {
title: "申请时间", title: "申请时间",
search: { search: {
show: false show: false,
}, },
type: "datetime", type: "datetime",
form: { form: {
show: false show: false,
}, },
column: { column: {
sorter: true sorter: true,
} },
}, },
"pipeline.title": { "pipeline.title": {
title: "关联流水线", title: "关联流水线",
search: { show: false }, search: { show: false },
type: "link", type: "link",
form: { form: {
show: false show: false,
}, },
column: { column: {
width: 350, width: 350,
@ -346,12 +356,12 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
on: { on: {
onClick({ row }) { onClick({ row }) {
router.push({ path: "/certd/pipeline/detail", query: { id: row.pipelineId, editMode: "false" } }); router.push({ path: "/certd/pipeline/detail", query: { id: row.pipelineId, editMode: "false" } });
} },
} },
} },
} },
} },
} },
} },
}; };
} }

View File

@ -0,0 +1,123 @@
<template>
<div class="cert-info-selector w-full">
<div class="flex-o w-full">
<fs-table-select
ref="tableSelectRef"
class="flex-0"
:model-value="modelValue"
:dict="optionsDictRef"
:create-crud-options="createCrudOptions"
:crud-options-override="{
search: { show: false },
table: {
scroll: {
x: 540,
},
},
}"
:show-current="false"
:show-select="false"
:dialog="{ width: 960 }"
:destroy-on-close="false"
height="400px"
@update:model-value="onChange"
@dialog-closed="doRefresh"
@selected-change="onSelectedChange"
/>
</div>
</div>
</template>
<script lang="tsx" setup>
import { inject, ref, Ref, watch } from "vue";
import { message } from "ant-design-vue";
import createCrudOptions from "../crud";
import { dict } from "@fast-crud/fast-crud";
import { certInfoApi } from "../api";
defineOptions({
name: "CertInfoSelector",
});
const props = defineProps<{
modelValue?: number | string;
type?: string;
placeholder?: string;
size?: string;
disabled?: boolean;
}>();
const onChange = async (value: number) => {
await emitValue(value);
};
const emit = defineEmits(["update:modelValue", "selectedChange", "change"]);
const tableSelectRef = ref();
const optionsDictRef = dict({
value: "id",
label: "domain",
getNodesByValues: async (values: any[]) => {
return await certInfoApi.GetOptionsByIds(values);
},
});
// async function openTableSelectDialog() {
// await tableSelectRef.value.open({});
// await tableSelectRef.value.crudExpose.openAdd({});
// }
const target: Ref<any> = ref({});
function clear() {
if (props.disabled) {
return;
}
emitValue(null);
}
async function emitValue(value: any) {
target.value = optionsDictRef.dataMap[value];
if (value !== 0 && pipeline?.value && target && pipeline.value.userId !== target.value.userId) {
message.error("对不起您不能修改他人流水线的证书仓库ID");
return;
}
emit("change", value);
emit("update:modelValue", value);
}
function onSelectedChange(value: any) {
if (value && value.length > 0) {
emit("selectedChange", value[0]);
} else {
emit("selectedChange", null);
}
}
// watch(
// () => {
// return props.modelValue;
// },
// async value => {
// await optionsDictRef.loadDict();
// target.value = optionsDictRef.dataMap[value];
// emit("selectedChange", target.value);
// },
// {
// immediate: true,
// }
// );
//pipeline
const pipeline = inject("pipeline", null);
async function doRefresh() {
await optionsDictRef.reloadDict();
}
</script>
<style lang="less">
.cert-info-selector {
width: 100%;
}
</style>

View File

@ -1,16 +1,7 @@
<template> <template>
<div class="notification-selector"> <div class="notification-selector">
<div class="flex-o w-100"> <div class="flex-o w-100">
<fs-dict-select <fs-dict-select class="flex-1" :value="modelValue" :dict="optionsDictRef" :disabled="disabled" :render-label="renderLabel" :slots="selectSlots" :allow-clear="true" @update:value="onChange" />
class="flex-1"
:value="modelValue"
:dict="optionsDictRef"
:disabled="disabled"
:render-label="renderLabel"
:slots="selectSlots"
:allow-clear="true"
@update:value="onChange"
/>
<fs-table-select <fs-table-select
ref="tableSelectRef" ref="tableSelectRef"
class="flex-0" class="flex-0"
@ -18,12 +9,12 @@
:dict="optionsDictRef" :dict="optionsDictRef"
:create-crud-options="createCrudOptions" :create-crud-options="createCrudOptions"
:crud-options-override="{ :crud-options-override="{
search: { show: false }, search: { show: false, initialForm: { fromType: 'upload' } },
table: { table: {
scroll: { scroll: {
x: 540 x: 540,
} },
} },
}" }"
:show-current="false" :show-current="false"
:show-select="false" :show-select="false"
@ -50,7 +41,7 @@ import createCrudOptions from "../crud";
import { notificationProvide } from "/@/views/certd/notification/common"; import { notificationProvide } from "/@/views/certd/notification/common";
defineOptions({ defineOptions({
name: "NotificationSelector" name: "NotificationSelector",
}); });
const props = defineProps<{ const props = defineProps<{
@ -89,12 +80,12 @@ const optionsDictRef = dict({
{ {
id: 0, id: 0,
name: "使用默认通知", name: "使用默认通知",
icon: "ion:notifications" icon: "ion:notifications",
}, },
...dict.data ...dict.data,
]; ];
dict.setData(data); dict.setData(data);
} },
}); });
const renderLabel = (option: any) => { const renderLabel = (option: any) => {
return <span>{option.name}</span>; return <span>{option.name}</span>;
@ -115,7 +106,7 @@ const selectSlots = ref({
// res.push(<a-space style="padding: 4px 8px" />); // res.push(<a-space style="padding: 4px 8px" />);
// res.push(<fs-button class="w-100" type="text" icon="plus-outlined" text="" onClick={openTableSelectDialog}></fs-button>); // res.push(<fs-button class="w-100" type="text" icon="plus-outlined" text="" onClick={openTableSelectDialog}></fs-button>);
return res; return res;
} },
}); });
const target: Ref<any> = ref({}); const target: Ref<any> = ref({});
@ -141,13 +132,13 @@ watch(
() => { () => {
return props.modelValue; return props.modelValue;
}, },
async (value) => { async value => {
await optionsDictRef.loadDict(); await optionsDictRef.loadDict();
target.value = optionsDictRef.dataMap[value]; target.value = optionsDictRef.dataMap[value];
emit("selectedChange", target.value); emit("selectedChange", target.value);
}, },
{ {
immediate: true immediate: true,
} }
); );

View File

@ -27,7 +27,7 @@ export default function (certPlugins: any[], formWrapperRef: any): CreateCrudOpt
title: inputDefine.title, title: inputDefine.title,
form: { form: {
...inputDefine, ...inputDefine,
show: compute((ctx) => { show: compute(ctx => {
const form = formWrapperRef.value.getFormData(); const form = formWrapperRef.value.getFormData();
if (!form) { if (!form) {
return false; return false;
@ -43,8 +43,8 @@ export default function (certPlugins: any[], formWrapperRef: any): CreateCrudOpt
} }
} }
return form?.certApplyPlugin === plugin.name && inputDefineShow; return form?.certApplyPlugin === plugin.name && inputDefineShow;
}) }),
} },
}; };
} }
} }
@ -57,17 +57,17 @@ export default function (certPlugins: any[], formWrapperRef: any): CreateCrudOpt
wrapper: { wrapper: {
width: 1350, width: 1350,
saveRemind: false, saveRemind: false,
title: "创建证书流水线" title: "创建证书流水线",
}, },
group: { group: {
groups: { groups: {
more: { more: {
header: "更多参数", header: "更多参数",
columns: moreParams, columns: moreParams,
collapsed: true collapsed: true,
} },
} },
} },
}, },
columns: { columns: {
certApplyPlugin: { certApplyPlugin: {
@ -76,8 +76,8 @@ export default function (certPlugins: any[], formWrapperRef: any): CreateCrudOpt
dict: dict({ dict: dict({
data: [ data: [
{ value: "CertApply", label: "JS-ACME" }, { value: "CertApply", label: "JS-ACME" },
{ value: "CertApplyLego", label: "Lego-ACME" } { value: "CertApplyLego", label: "Lego-ACME" },
] ],
}), }),
form: { form: {
order: 0, order: 0,
@ -90,21 +90,21 @@ export default function (certPlugins: any[], formWrapperRef: any): CreateCrudOpt
<li>Lego-ACMELegoDNSLEGO使</li> <li>Lego-ACMELegoDNSLEGO使</li>
</ul> </ul>
); );
} },
}, },
valueChange: { valueChange: {
handle: async ({ form, value }) => { handle: async ({ form, value }) => {
const config = await api.GetPluginConfig({ const config = await api.GetPluginConfig({
name: value, name: value,
type: "builtIn" type: "builtIn",
}); });
if (config.sysSetting?.input) { if (config.sysSetting?.input) {
merge(form, config.sysSetting.input); merge(form, config.sysSetting.input);
} }
}, },
immediate: true immediate: true,
} },
} },
}, },
...inputs, ...inputs,
triggerCron: { triggerCron: {
@ -115,11 +115,11 @@ export default function (certPlugins: any[], formWrapperRef: any): CreateCrudOpt
component: { component: {
name: "cron-editor", name: "cron-editor",
vModel: "modelValue", vModel: "modelValue",
placeholder: "0 0 4 * * *" placeholder: "0 0 4 * * *",
}, },
helper: "点击上面的按钮,选择每天几点定时执行。\n建议设置为每天触发一次证书未到期之前任务会跳过不会重复执行", helper: "点击上面的按钮,选择每天几点定时执行。\n建议设置为每天触发一次证书未到期之前任务会跳过不会重复执行",
order: 100 order: 100,
} },
}, },
notification: { notification: {
title: "失败通知", title: "失败通知",
@ -132,14 +132,14 @@ export default function (certPlugins: any[], formWrapperRef: any): CreateCrudOpt
on: { on: {
selectedChange({ $event, form }) { selectedChange({ $event, form }) {
form.notificationTarget = $event; form.notificationTarget = $event;
} },
} },
}, },
order: 101, order: 101,
helper: "任务执行失败实时提醒" helper: "任务执行失败实时提醒",
} },
} },
} },
} },
}; };
} }

View File

@ -76,7 +76,7 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
const addRequest = async ({ form }: AddReq) => { const addRequest = async ({ form }: AddReq) => {
if (form.content == null) { if (form.content == null) {
form.content = JSON.stringify({ form.content = JSON.stringify({
title: form.title title: form.title,
}); });
} else { } else {
//复制的流水线 //复制的流水线
@ -106,7 +106,7 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
const max = suiteDetail.pipelineCount.max; const max = suiteDetail.pipelineCount.max;
if (max != -1 && max <= suiteDetail.pipelineCount.used) { if (max != -1 && max <= suiteDetail.pipelineCount.used) {
notification.error({ notification.error({
message: `对不起,您最多只能创建${max}条流水线,请购买或升级套餐` message: `对不起,您最多只能创建${max}条流水线,请购买或升级套餐`,
}); });
return; return;
} }
@ -124,7 +124,7 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
type: "custom", type: "custom",
when: ["error", "turnToSuccess", "success"], when: ["error", "turnToSuccess", "success"],
notificationId: form.notification, notificationId: form.notification,
title: form.notificationTarget?.name || "自定义通知" title: form.notificationTarget?.name || "自定义通知",
}); });
} }
let pipeline = { let pipeline = {
@ -145,20 +145,20 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
runnableType: "step", runnableType: "step",
input: { input: {
renewDays: 35, renewDays: 35,
...form ...form,
}, },
strategy: { strategy: {
runStrategy: 0 // 正常执行 runStrategy: 0, // 正常执行
}, },
type: form.certApplyPlugin type: form.certApplyPlugin,
} },
] ],
} },
] ],
} },
], ],
triggers, triggers,
notifications notifications,
}; };
pipeline = setRunnableIds(pipeline); pipeline = setRunnableIds(pipeline);
@ -173,7 +173,7 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
content: JSON.stringify(pipeline), content: JSON.stringify(pipeline),
keepHistoryCount: 30, keepHistoryCount: 30,
type: "cert", type: "cert",
from: "custom" from: "custom",
}); });
message.success("创建成功,请添加证书部署任务"); message.success("创建成功,请添加证书部署任务");
router.push({ path: "/certd/pipeline/detail", query: { id, editMode: "true" } }); router.push({ path: "/certd/pipeline/detail", query: { id, editMode: "true" } });
@ -195,7 +195,7 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
width: 800, width: 800,
content: () => { content: () => {
return <CertView cert={cert}></CertView>; return <CertView cert={cert}></CertView>;
} },
}); });
}; };
@ -230,7 +230,7 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
<div> {children}</div> <div> {children}</div>
</div> </div>
); );
} },
}); });
}; };
const userStore = useUserStore(); const userStore = useUserStore();
@ -242,7 +242,7 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
pageRequest, pageRequest,
addRequest, addRequest,
editRequest, editRequest,
delRequest delRequest,
}, },
settings: { settings: {
plugins: { plugins: {
@ -259,16 +259,16 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
selectedRowKeys, selectedRowKeys,
onSelectedChanged(selected) { onSelectedChanged(selected) {
console.log("已选择变化:", selected); console.log("已选择变化:", selected);
} },
} },
} },
} },
}, },
actionbar: { actionbar: {
buttons: { buttons: {
add: { add: {
order: 5, order: 5,
text: "自定义流水线" text: "自定义流水线",
}, },
addCertd: { addCertd: {
order: 1, order: 1,
@ -276,29 +276,29 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
type: "primary", type: "primary",
click() { click() {
addCertdPipeline(); addCertdPipeline();
} },
} },
} },
}, },
form: { form: {
afterSubmit({ form, res, mode }) { afterSubmit({ form, res, mode }) {
if (mode === "add") { if (mode === "add") {
router.push({ path: "/certd/pipeline/detail", query: { id: res.id, editMode: "true" } }); router.push({ path: "/certd/pipeline/detail", query: { id: res.id, editMode: "true" } });
} }
} },
}, },
table: { table: {
scroll: { x: 1500 } scroll: { x: 1500 },
}, },
tabs: { tabs: {
name: "groupId", name: "groupId",
show: true show: true,
}, },
rowHandle: { rowHandle: {
width: 200, width: 200,
fixed: "right", fixed: "right",
dropdown: { dropdown: {
show: true show: true,
}, },
buttons: { buttons: {
play: { play: {
@ -313,18 +313,18 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
async onOk() { async onOk() {
await api.Trigger(row.id); await api.Trigger(row.id);
notification.success({ message: "管道已经开始运行" }); notification.success({ message: "管道已经开始运行" });
} },
}); });
} },
}, },
view: { view: {
show: false, show: false,
click({ row }) { click({ row }) {
router.push({ path: "/certd/pipeline/detail", query: { id: row.id, editMode: "false" } }); router.push({ path: "/certd/pipeline/detail", query: { id: row.id, editMode: "false" } });
} },
}, },
copy: { copy: {
click: async (context) => { click: async context => {
settingStore.checkPlus(); settingStore.checkPlus();
const { ui } = useUi(); const { ui } = useUi();
// @ts-ignore // @ts-ignore
@ -333,10 +333,10 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
row.title = row.title + "_copy"; row.title = row.title + "_copy";
await crudExpose.openCopy({ await crudExpose.openCopy({
row: row, row: row,
index: context.index index: context.index,
}); });
}, },
class: "need-plus" class: "need-plus",
}, },
config: { config: {
order: 1, order: 1,
@ -346,13 +346,13 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
icon: "ant-design:edit-outlined", icon: "ant-design:edit-outlined",
click({ row }) { click({ row }) {
router.push({ path: "/certd/pipeline/detail", query: { id: row.id, editMode: "true" } }); router.push({ path: "/certd/pipeline/detail", query: { id: row.id, editMode: "true" } });
} },
}, },
edit: { edit: {
order: 2, order: 2,
title: "修改配置/分组", title: "修改配置/分组",
icon: "ant-design:setting-outlined", icon: "ant-design:setting-outlined",
dropdown: true dropdown: true,
}, },
viewCert: { viewCert: {
order: 3, order: 3,
@ -361,7 +361,7 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
icon: "ph:certificate", icon: "ph:certificate",
async click({ row }) { async click({ row }) {
await viewCert(row); await viewCert(row);
} },
}, },
download: { download: {
order: 4, order: 4,
@ -370,13 +370,13 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
icon: "ant-design:download-outlined", icon: "ant-design:download-outlined",
async click({ row }) { async click({ row }) {
await downloadCert(row); await downloadCert(row);
} },
}, },
remove: { remove: {
order: 5, order: 5,
dropdown: true dropdown: true,
} },
} },
}, },
columns: { columns: {
id: { id: {
@ -384,14 +384,14 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
key: "id", key: "id",
type: "number", type: "number",
search: { search: {
show: true show: true,
}, },
column: { column: {
width: 100 width: 100,
}, },
form: { form: {
show: false show: false,
} },
}, },
userId: { userId: {
title: "用户Id", title: "用户Id",
@ -399,17 +399,17 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
search: { search: {
show: computed(() => { show: computed(() => {
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline; return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
}) }),
}, },
form: { form: {
show: false show: false,
}, },
column: { column: {
show: computed(() => { show: computed(() => {
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline; return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
}), }),
width: 100 width: 100,
} },
}, },
title: { title: {
title: "流水线名称", title: "流水线名称",
@ -418,11 +418,11 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
show: true, show: true,
title: "关键字", title: "关键字",
component: { component: {
name: "a-input" name: "a-input",
} },
}, },
form: { form: {
rules: [{ required: true, message: "此项必填" }] rules: [{ required: true, message: "此项必填" }],
}, },
column: { column: {
width: 350, width: 350,
@ -432,16 +432,16 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
// 注意必须要on前缀 // 注意必须要on前缀
onClick({ row }) { onClick({ row }) {
router.push({ path: "/certd/pipeline/detail", query: { id: row.id, editMode: "false" } }); router.push({ path: "/certd/pipeline/detail", query: { id: row.id, editMode: "false" } });
} },
} },
} },
} },
}, },
content: { content: {
title: "流水线内容", title: "流水线内容",
form: { show: false }, form: { show: false },
column: { column: {
show: false show: false,
}, },
valueBuilder({ row }) { valueBuilder({ row }) {
if (row.content) { if (row.content) {
@ -463,18 +463,18 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
if (row.content) { if (row.content) {
row.content = JSON.stringify(row.content); row.content = JSON.stringify(row.content);
} }
} },
}, },
_triggerCount: { _triggerCount: {
title: "定时任务数", title: "定时任务数",
type: "number", type: "number",
column: { column: {
align: "center", align: "center",
width: 100 width: 100,
}, },
form: { form: {
show: false show: false,
} },
}, },
_stepCount: { _stepCount: {
title: "部署任务数", title: "部署任务数",
@ -482,14 +482,14 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
form: { show: false }, form: { show: false },
column: { column: {
align: "center", align: "center",
width: 100 width: 100,
} },
}, },
lastVars: { lastVars: {
title: "到期剩余", title: "到期剩余",
type: "number", type: "number",
form: { form: {
show: false show: false,
}, },
column: { column: {
cellRender({ row }) { cellRender({ row }) {
@ -501,52 +501,52 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
const percent = (leftDays / 90) * 100; const percent = (leftDays / 90) * 100;
return <a-progress percent={percent} strokeColor={color} format={(percent: number) => `${leftDays}`} />; return <a-progress percent={percent} strokeColor={color} format={(percent: number) => `${leftDays}`} />;
}, },
width: 150 width: 150,
} },
}, },
"lastVars.certExpiresTime": { "lastVars.certExpiresTime": {
title: "过期时间", title: "过期时间",
search: { search: {
show: false show: false,
}, },
type: "datetime", type: "datetime",
form: { form: {
show: false show: false,
}, },
column: { column: {
sorter: true, sorter: true,
align: "center" align: "center",
} },
}, },
status: { status: {
title: "状态", title: "状态",
type: "dict-select", type: "dict-select",
search: { search: {
show: true show: true,
}, },
dict: dict({ dict: dict({
data: statusUtil.getOptions() data: statusUtil.getOptions(),
}), }),
form: { form: {
show: false show: false,
}, },
column: { column: {
sorter: true, sorter: true,
width: 120, width: 120,
align: "center" align: "center",
} },
}, },
lastHistoryTime: { lastHistoryTime: {
title: "最后运行", title: "最后运行",
type: "datetime", type: "datetime",
form: { form: {
show: false show: false,
}, },
column: { column: {
sorter: true, sorter: true,
width: 150, width: 150,
align: "center" align: "center",
} },
}, },
disabled: { disabled: {
title: "启用", title: "启用",
@ -554,12 +554,12 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
dict: dict({ dict: dict({
data: [ data: [
{ value: false, label: "启用" }, { value: false, label: "启用" },
{ value: true, label: "禁用" } { value: true, label: "禁用" },
] ],
}), }),
form: { form: {
value: false, value: false,
show: false show: false,
}, },
column: { column: {
sorter: true, sorter: true,
@ -567,30 +567,30 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
align: "center", align: "center",
component: { component: {
name: "fs-dict-switch", name: "fs-dict-switch",
vModel: "checked" vModel: "checked",
}, },
async valueChange({ row, key, value }) { async valueChange({ row, key, value }) {
return await api.UpdateObj({ return await api.UpdateObj({
id: row.id, id: row.id,
disabled: row[key] disabled: row[key],
}); });
} },
} },
}, },
groupId: { groupId: {
title: "分组", title: "分组",
type: "dict-select", type: "dict-select",
search: { search: {
show: true show: true,
}, },
dict: groupDictRef, dict: groupDictRef,
column: { column: {
width: 130, width: 130,
align: "center", align: "center",
component: { component: {
color: "auto" color: "auto",
} },
} },
}, },
order: { order: {
title: "排序号", title: "排序号",
@ -598,48 +598,48 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
column: { column: {
sorter: true, sorter: true,
align: "center", align: "center",
width: 80 width: 80,
}, },
form: { form: {
value: 0 value: 0,
} },
}, },
keepHistoryCount: { keepHistoryCount: {
title: "历史记录保持数", title: "历史记录保持数",
type: "number", type: "number",
form: { form: {
value: 20, value: 20,
helper: "历史记录保持条数,多余的会被删除" helper: "历史记录保持条数,多余的会被删除",
}, },
column: { column: {
width: 130, width: 130,
show: false show: false,
} },
}, },
createTime: { createTime: {
title: "创建时间", title: "创建时间",
type: "datetime", type: "datetime",
form: { form: {
show: false show: false,
}, },
column: { column: {
sorter: true, sorter: true,
width: 155, width: 155,
align: "center" align: "center",
} },
}, },
updateTime: { updateTime: {
title: "更新时间", title: "更新时间",
type: "datetime", type: "datetime",
form: { form: {
show: false show: false,
}, },
column: { column: {
width: 125, width: 125,
show: false show: false,
} },
} },
} },
} },
}; };
} }

View File

@ -16,8 +16,6 @@
"@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-empty-function": "off"
// "no-unused-expressions": "off",
"max-len": [0, 160, 2, { "ignoreUrls": true }]
} }
} }

View File

@ -0,0 +1,7 @@
{
"printWidth": 220,
"bracketSpacing": true,
"singleQuote": false,
"trailingComma": "es5",
"arrowParens": "avoid"
}

View File

@ -3,6 +3,9 @@ import { Constants, CrudController } from '@certd/lib-server';
import { AuthService } from '../../../modules/sys/authority/service/auth-service.js'; import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
import { CertInfoService } from '../../../modules/monitor/index.js'; import { CertInfoService } from '../../../modules/monitor/index.js';
import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js'; import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
import { SelectQueryBuilder } from "typeorm";
import { CertUploadService } from "../../../modules/monitor/service/cert-upload-service.js";
import { CertInfo } from "@certd/plugin-cert";
/** /**
*/ */
@ -14,6 +17,8 @@ export class CertInfoController extends CrudController<CertInfoService> {
@Inject() @Inject()
authService: AuthService; authService: AuthService;
@Inject() @Inject()
certUploadService: CertUploadService;
@Inject()
pipelineService: PipelineService; pipelineService: PipelineService;
getService(): CertInfoService { getService(): CertInfoService {
@ -57,6 +62,31 @@ export class CertInfoController extends CrudController<CertInfoService> {
return await super.list(body); return await super.list(body);
} }
@Post('/getOptionsByIds', { summary: Constants.per.authOnly })
async getOptionsByIds(@Body(ALL) body: {ids:any[]}) {
const list = await this.service.list({
query:{
userId: this.getUserId(),
},
buildQuery: (bq: SelectQueryBuilder<any>) => {
bq.andWhere('id in (:...ids)', { ids: body.ids });
}
})
const safeList =list.map((item:any) => {
const domainsArr = item.domains? item.domains.split(',') : [];
return {
id: item.id,
domain: item.domain,
domains:domainsArr,
userId: item.userId,
}
})
return this.ok(safeList);
}
@Post('/add', { summary: Constants.per.authOnly }) @Post('/add', { summary: Constants.per.authOnly })
async add(@Body(ALL) bean: any) { async add(@Body(ALL) bean: any) {
bean.userId = this.getUserId(); bean.userId = this.getUserId();
@ -92,18 +122,25 @@ export class CertInfoController extends CrudController<CertInfoService> {
} }
@Post('/upload', { summary: Constants.per.authOnly }) @Post('/upload', { summary: Constants.per.authOnly })
async upload(@Body(ALL) body: any) { async upload(@Body(ALL) body: {cert: CertInfo, pipeline: any, id?: number}) {
if (body.id) { if (body.id) {
//修改 //修改
await this.service.checkUserId(body.id, this.getUserId()); await this.service.checkUserId(body.id, this.getUserId());
await this.certUploadService.updateCert({
id: body.id,
userId: this.getUserId(),
cert: body.cert,
});
}else{ }else{
//添加 //添加
body.userId = this.getUserId(); await this.certUploadService.createUploadCertPipeline({
userId: this.getUserId(),
cert: body.cert,
});
} }
const res = await this.service.upload(body); return this.ok();
return this.ok(res);
} }
@Post('/getCert', { summary: Constants.per.authOnly }) @Post('/getCert', { summary: Constants.per.authOnly })

View File

@ -1,10 +1,10 @@
import { Provide, Scope, ScopeEnum } from '@midwayjs/core'; import { Provide, Scope, ScopeEnum } from "@midwayjs/core";
import { BaseService, CodeException, CommonException, Constants, PageReq } from '@certd/lib-server'; import { BaseService, CodeException, Constants, PageReq } from "@certd/lib-server";
import { InjectEntityModel } from '@midwayjs/typeorm'; import { InjectEntityModel } from "@midwayjs/typeorm";
import { Repository } from 'typeorm'; import { Repository } from "typeorm";
import { CertInfoEntity } from '../entity/cert-info.js'; import { CertInfoEntity } from "../entity/cert-info.js";
import { utils } from '@certd/basic'; import { utils } from "@certd/basic";
import { CertInfo, CertReader } from '@certd/plugin-cert'; import { CertInfo, CertReader } from "@certd/plugin-cert";
export type UploadCertReq = { export type UploadCertReq = {
id?: number; id?: number;
@ -13,6 +13,7 @@ export type UploadCertReq = {
userId?: number; userId?: number;
}; };
@Provide("CertInfoService") @Provide("CertInfoService")
@Scope(ScopeEnum.Request, { allowDowngrade: true }) @Scope(ScopeEnum.Request, { allowDowngrade: true })
export class CertInfoService extends BaseService<CertInfoEntity> { export class CertInfoService extends BaseService<CertInfoEntity> {
@ -168,17 +169,4 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
return bean; return bean;
} }
async upload(body: { id?: number; userId?:number ;cert: CertInfo }) {
const { id, userId, cert } = body;
if (!cert) {
throw new CommonException("cert can't be empty");
}
const res = await this.updateCert({
id,
certReader: new CertReader(cert),
fromType: 'upload',
userId
});
return res.id;
}
} }

View File

@ -0,0 +1,178 @@
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
import { BaseService, CommonException } from "@certd/lib-server";
import { InjectEntityModel } from "@midwayjs/typeorm";
import { EntityManager, Repository } from "typeorm";
import { CertInfoEntity } from "../entity/cert-info.js";
import { logger } from "@certd/basic";
import { CertInfo, CertReader } from "@certd/plugin-cert";
import { PipelineService } from "../../pipeline/service/pipeline-service.js";
import { CertInfoService } from "./cert-info-service.js";
import { PipelineEntity } from "../../pipeline/entity/pipeline.js";
import { nanoid } from "nanoid";
export type UploadCertReq = {
id?: number;
certReader: CertReader;
fromType?: string;
userId?: number;
};
export type UpdateCertReq = {
id: number;
cert: CertInfo;
userId?: number;
};
export type CreateUploadPipelineReq = {
cert: CertInfo;
userId: number;
};
@Provide("CertUploadService")
@Scope(ScopeEnum.Request, { allowDowngrade: true })
export class CertUploadService extends BaseService<CertInfoEntity> {
@InjectEntityModel(CertInfoEntity)
repository: Repository<CertInfoEntity>;
@Inject()
pipelineService: PipelineService;
@Inject()
certInfoService: CertInfoService;
//@ts-ignore
getRepository() {
return this.repository;
}
/**
* 线
* @param req
*/
async updateCert(req: UpdateCertReq) {
const certInfoEntity = await this.certInfoService.info(req.id);
if (!certInfoEntity) {
throw new CommonException("cert not found");
}
if(certInfoEntity.fromType !== 'upload') {
throw new CommonException("cert can't be custom upload");
}
await this.uploadCert(this.repository.manager,{
id: req.id,
fromType: 'upload',
userId: req.userId,
certReader: new CertReader(req.cert)
})
if (certInfoEntity.pipelineId) {
logger.info( `触发流水线部署:${certInfoEntity.pipelineId}`)
await this.pipelineService.trigger(certInfoEntity.pipelineId)
}
}
async createUploadCertPipeline(body:CreateUploadPipelineReq) {
const { userId, cert } = body;
if (!cert) {
throw new CommonException("cert can't be empty");
}
const certReader = new CertReader(cert)
return await this.transaction(async (tx:EntityManager)=>{
const newCertInfo = await this.uploadCert(tx,{
certReader: certReader,
fromType: 'upload',
userId
});
const pipelineTitle = certReader.getAllDomains()[0] +"上传证书自动部署";
const notifications = [];
notifications.push({
type: "custom",
when: ["error", "turnToSuccess", "success"],
notificationId: 0,
title: "默认通知",
});
let pipeline = {
id: nanoid(10),
title: pipelineTitle,
runnableType: "pipeline",
stages: [
{
id: nanoid(10),
title: "上传证书解析阶段",
maxTaskCount: 1,
runnableType: "stage",
tasks: [
{
id: nanoid(10),
title: "上传证书解析任务",
runnableType: "task",
steps: [
{
id: nanoid(10),
title: "上传证书解析",
runnableType: "step",
input: {
certInfoId: newCertInfo.id,
domains: newCertInfo.domains.split(','),
},
strategy: {
runStrategy: 0, // 正常执行
},
type: "CertApplyUpload",
},
],
},
],
},
],
triggers:[],
notifications,
}
const newPipeline = await tx.getRepository(PipelineEntity).save({
userId,
title: pipelineTitle,
type:"cert",
from:"cert_upload",
content: JSON.stringify(pipeline),
keepHistory:20,
})
newCertInfo.pipelineId = newPipeline.id;
await tx.getRepository(CertInfoEntity).save({
id: newCertInfo.id,
pipelineId: newPipeline.id
});
return newCertInfo.id
})
}
private async uploadCert(tx:EntityManager,req: UploadCertReq) {
const bean = new CertInfoEntity();
const { id, fromType,userId, certReader } = req;
if (id) {
bean.id = id;
} else {
bean.fromType = fromType;
bean.userId = userId
}
const certInfo = certReader.toCertInfo();
bean.certInfo = JSON.stringify(certInfo);
bean.applyTime = new Date().getTime();
const domains = certReader.detail.domains.altNames;
bean.domains = domains.join(',');
bean.domain = domains[0];
bean.domainCount = domains.length;
bean.expiresTime = certReader.expires;
bean.certProvider = certReader.detail.issuer.commonName;
await tx.getRepository(CertInfoEntity).save(bean);
return bean;
}
}

View File

@ -1,6 +1,6 @@
import { Config, Inject, Provide, Scope, ScopeEnum, sleep } from '@midwayjs/core'; import { Config, Inject, Provide, Scope, ScopeEnum, sleep } from "@midwayjs/core";
import { InjectEntityModel } from '@midwayjs/typeorm'; import { InjectEntityModel } from "@midwayjs/typeorm";
import { In, MoreThan, Repository } from 'typeorm'; import { In, MoreThan, Repository } from "typeorm";
import { import {
AccessGetter, AccessGetter,
AccessService, AccessService,
@ -10,35 +10,37 @@ import {
PageReq, PageReq,
SysPublicSettings, SysPublicSettings,
SysSettingsService, SysSettingsService,
SysSiteInfo, SysSiteInfo
} from '@certd/lib-server'; } from "@certd/lib-server";
import { PipelineEntity } from '../entity/pipeline.js'; import { PipelineEntity } from "../entity/pipeline.js";
import { PipelineDetail } from '../entity/vo/pipeline-detail.js'; import { PipelineDetail } from "../entity/vo/pipeline-detail.js";
import { Executor, Pipeline, ResultType, RunHistory, RunnableCollection, SysInfo, UserInfo } from '@certd/pipeline'; import { Executor, Pipeline, ResultType, RunHistory, RunnableCollection, SysInfo, UserInfo } from "@certd/pipeline";
import { DbStorage } from './db-storage.js'; import { DbStorage } from "./db-storage.js";
import { StorageService } from './storage-service.js'; import { StorageService } from "./storage-service.js";
import { Cron } from '../../cron/cron.js'; import { Cron } from "../../cron/cron.js";
import { HistoryService } from './history-service.js'; import { HistoryService } from "./history-service.js";
import { HistoryEntity } from '../entity/history.js'; import { HistoryEntity } from "../entity/history.js";
import { HistoryLogEntity } from '../entity/history-log.js'; import { HistoryLogEntity } from "../entity/history-log.js";
import { HistoryLogService } from './history-log-service.js'; import { HistoryLogService } from "./history-log-service.js";
import { EmailService } from '../../basic/service/email-service.js'; import { EmailService } from "../../basic/service/email-service.js";
import { UserService } from '../../sys/authority/service/user-service.js'; import { UserService } from "../../sys/authority/service/user-service.js";
import { CnameRecordService } from '../../cname/service/cname-record-service.js'; import { CnameRecordService } from "../../cname/service/cname-record-service.js";
import { CnameProxyService } from './cname-proxy-service.js'; import { CnameProxyService } from "./cname-proxy-service.js";
import { PluginConfigGetter } from '../../plugin/service/plugin-config-getter.js'; import { PluginConfigGetter } from "../../plugin/service/plugin-config-getter.js";
import dayjs from 'dayjs'; import dayjs from "dayjs";
import { DbAdapter } from '../../db/index.js'; import { DbAdapter } from "../../db/index.js";
import { isComm } from '@certd/plus-core'; import { isComm } from "@certd/plus-core";
import { logger } from '@certd/basic'; import { logger } from "@certd/basic";
import { UrlService } from './url-service.js'; import { UrlService } from "./url-service.js";
import { NotificationService } from './notification-service.js'; import { NotificationService } from "./notification-service.js";
import { NotificationGetter } from './notification-getter.js'; import { NotificationGetter } from "./notification-getter.js";
import { UserSuiteEntity, UserSuiteService } from '@certd/commercial-core'; import { UserSuiteEntity, UserSuiteService } from "@certd/commercial-core";
import { CertInfoService } from '../../monitor/service/cert-info-service.js'; import { CertInfoService } from "../../monitor/service/cert-info-service.js";
const runningTasks: Map<string | number, Executor> = new Map(); const runningTasks: Map<string | number, Executor> = new Map();
/** /**
* *
*/ */
@ -191,7 +193,10 @@ export class PipelineService extends BaseService<PipelineEntity> {
await this.registerTriggerById(bean.id); await this.registerTriggerById(bean.id);
//保存域名信息到certInfo表 //保存域名信息到certInfo表
await this.certInfoService.updateDomains(pipeline.id, pipeline.userId || bean.userId, domains); if(bean.from !== 'cert_upload'){
await this.certInfoService.updateDomains(pipeline.id, pipeline.userId || bean.userId, domains);
}
return bean; return bean;
} }
@ -478,8 +483,10 @@ export class PipelineService extends BaseService<PipelineEntity> {
const serviceContainer = { const serviceContainer = {
CertInfoService: this.certInfoService CertInfoService: this.certInfoService
} }
const serviceGetter = (name: string) => { const serviceGetter = {
return serviceContainer[name] get:(name: string) => {
return serviceContainer[name]
}
} }
const executor = new Executor({ const executor = new Executor({
user, user,
@ -684,4 +691,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
}, },
}); });
} }
} }

View File

@ -1,5 +1,5 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo ,CertApplyPluginNames} from '@certd/plugin-cert';
import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
@IsTaskPlugin({ @IsTaskPlugin({
@ -21,7 +21,7 @@ export class AliyunDeployCertToALB extends AbstractTaskPlugin {
helper: '请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID可以减少上传到阿里云的证书数量', helper: '请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID可以减少上传到阿里云的证书数量',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego', 'uploadCertToAliyun'], from: [...CertApplyPluginNames, 'uploadCertToAliyun'],
}, },
required: true, required: true,
}) })

View File

@ -1,7 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
import { optionsUtils } from '@certd/basic/dist/utils/util.options.js'; import { optionsUtils } from '@certd/basic/dist/utils/util.options.js';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'DeployCertToAliyunCDN', name: 'DeployCertToAliyunCDN',
title: '阿里云-部署证书至CDN', title: '阿里云-部署证书至CDN',
@ -36,7 +36,7 @@ export class DeployCertToAliyunCDN extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego', 'uploadCertToAliyun'], from: [...CertApplyPluginNames, 'uploadCertToAliyun'],
}, },
required: true, required: true,
}) })

View File

@ -2,7 +2,7 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { AliyunAccess, AliyunClient, createCertDomainGetterInputDefine } from '@certd/plugin-lib'; import { AliyunAccess, AliyunClient, createCertDomainGetterInputDefine } from '@certd/plugin-lib';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'DeployCertToAliyunDCDN', name: 'DeployCertToAliyunDCDN',
title: '阿里云-部署证书至DCDN', title: '阿里云-部署证书至DCDN',
@ -21,7 +21,7 @@ export class DeployCertToAliyunDCDN extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego', 'uploadCertToAliyun'], from: [...CertApplyPluginNames, 'uploadCertToAliyun'],
}, },
required: true, required: true,
}) })

View File

@ -2,7 +2,7 @@ import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipel
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { AliyunAccess, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { AliyunAccess, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'AliyunDeployCertToFC', name: 'AliyunDeployCertToFC',
title: '阿里云-部署至阿里云FC(3.0)', title: '阿里云-部署至阿里云FC(3.0)',
@ -22,7 +22,7 @@ export class AliyunDeployCertToFC extends AbstractPlusTaskPlugin {
helper: '请选择证书申请任务输出的域名证书', helper: '请选择证书申请任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -1,7 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'AliyunDeployCertToNLB', name: 'AliyunDeployCertToNLB',
title: '阿里云-部署至NLB网络负载均衡', title: '阿里云-部署至NLB网络负载均衡',
@ -21,7 +21,7 @@ export class AliyunDeployCertToNLB extends AbstractTaskPlugin {
helper: '请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID可以减少上传到阿里云的证书数量', helper: '请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID可以减少上传到阿里云的证书数量',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego', 'uploadCertToAliyun'], from: [...CertApplyPluginNames, 'uploadCertToAliyun'],
}, },
required: true, required: true,
}) })

View File

@ -1,6 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { AliyunAccess } from '@certd/plugin-lib'; import { AliyunAccess } from '@certd/plugin-lib';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'DeployCertToAliyunOSS', name: 'DeployCertToAliyunOSS',
title: '阿里云-部署证书至OSS', title: '阿里云-部署证书至OSS',
@ -81,7 +82,7 @@ export class DeployCertToAliyunOSS extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -1,7 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { AliyunAccess, AliyunClient, AliyunSslClient, CasCertInfo, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { AliyunAccess, AliyunClient, AliyunSslClient, CasCertInfo, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'AliyunDeployCertToSLB', name: 'AliyunDeployCertToSLB',
title: '阿里云-部署至SLB(传统负载均衡)', title: '阿里云-部署至SLB(传统负载均衡)',
@ -21,7 +21,7 @@ export class AliyunDeployCertToSLB extends AbstractTaskPlugin {
helper: '请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID可以减少上传到阿里云的证书数量', helper: '请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID可以减少上传到阿里云的证书数量',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego', 'uploadCertToAliyun'], from: [...CertApplyPluginNames, 'uploadCertToAliyun'],
}, },
required: true, required: true,
}) })

View File

@ -2,7 +2,7 @@ import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipel
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { AliyunAccess, AliyunClient, AliyunSslClient, createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'AliyunDeployCertToWaf', name: 'AliyunDeployCertToWaf',
title: '阿里云-部署至阿里云WAF', title: '阿里云-部署至阿里云WAF',
@ -22,7 +22,7 @@ export class AliyunDeployCertToWaf extends AbstractPlusTaskPlugin {
helper: '请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID可以减少上传到阿里云的证书数量', helper: '请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID可以减少上传到阿里云的证书数量',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego', 'uploadCertToAliyun'], from: [...CertApplyPluginNames, 'uploadCertToAliyun'],
}, },
required: true, required: true,
}) })

View File

@ -1,7 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
import { AliyunAccess } from '@certd/plugin-lib'; import { AliyunAccess } from '@certd/plugin-lib';
import { AliyunSslClient } from '@certd/plugin-lib'; import { AliyunSslClient } from '@certd/plugin-lib';
import { CertApplyPluginNames} from '@certd/plugin-cert';
/** /**
* 1 cn-hangzhou cas.aliyuncs.com cas-vpc.cn-hangzhou.aliyuncs.com * 1 cn-hangzhou cas.aliyuncs.com cas-vpc.cn-hangzhou.aliyuncs.com
* 西 ap-southeast-3 cas.ap-southeast-3.aliyuncs.com cas-vpc.ap-southeast-3.aliyuncs.com * 西 ap-southeast-3 cas.ap-southeast-3.aliyuncs.com cas-vpc.ap-southeast-3.aliyuncs.com
@ -57,7 +57,7 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -5,7 +5,7 @@ import { AwsAcmClient } from '../libs/aws-acm-client.js';
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
import { optionsUtils } from '@certd/basic/dist/utils/util.options.js'; import { optionsUtils } from '@certd/basic/dist/utils/util.options.js';
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'AwsDeployToCloudFront', name: 'AwsDeployToCloudFront',
title: 'AWS-部署证书到CloudFront', title: 'AWS-部署证书到CloudFront',
@ -25,7 +25,7 @@ export class AwsDeployToCloudFront extends AbstractPlusTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego', 'AwsUploadToACM'], from: [...CertApplyPluginNames, 'AwsUploadToACM'],
}, },
required: true, required: true,
}) })

View File

@ -2,7 +2,7 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput,
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { AwsAccess, AwsRegions } from '../access.js'; import { AwsAccess, AwsRegions } from '../access.js';
import { AwsAcmClient } from '../libs/aws-acm-client.js'; import { AwsAcmClient } from '../libs/aws-acm-client.js';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'AwsUploadToACM', name: 'AwsUploadToACM',
title: 'AWS-上传证书到ACM', title: 'AWS-上传证书到ACM',
@ -21,7 +21,7 @@ export class AwsUploadToACM extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -1,7 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { CacheflyAccess } from '../access.js'; import { CacheflyAccess } from '../access.js';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'CacheFly', name: 'CacheFly',
title: 'CacheFly-部署证书到CacheFly', title: 'CacheFly-部署证书到CacheFly',
@ -20,7 +20,7 @@ export class CacheFlyPlugin extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -2,7 +2,7 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput
import { CertInfo, CertReader } from '@certd/plugin-cert'; import { CertInfo, CertReader } from '@certd/plugin-cert';
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
import { optionsUtils } from '@certd/basic/dist/utils/util.options.js'; import { optionsUtils } from '@certd/basic/dist/utils/util.options.js';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
//命名规范,插件名称+功能就是目录plugin-demo中的demo大写字母开头驼峰命名 //命名规范,插件名称+功能就是目录plugin-demo中的demo大写字母开头驼峰命名
name: 'DemoTest', name: 'DemoTest',
@ -97,7 +97,7 @@ export class DemoTest extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
// required: true, // 必填 // required: true, // 必填
}) })

View File

@ -2,7 +2,7 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { DogeClient } from '../../lib/index.js'; import { DogeClient } from '../../lib/index.js';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'DogeCloudDeployToCDN', name: 'DogeCloudDeployToCDN',
title: '多吉云-部署到多吉云CDN', title: '多吉云-部署到多吉云CDN',
@ -27,7 +27,7 @@ export class DogeCloudDeployToCDNPlugin extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -1,7 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { GcoreAccess } from '../access.js'; import { GcoreAccess } from '../access.js';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'Gcoreflush', name: 'Gcoreflush',
title: 'Gcore-刷新Gcore证书', title: 'Gcore-刷新Gcore证书',
@ -30,7 +30,7 @@ export class GcoreflushPlugin extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -1,7 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { GcoreAccess } from '../access.js'; import { GcoreAccess } from '../access.js';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'Gcoreupload', name: 'Gcoreupload',
title: 'Gcore-部署证书到Gcore', title: 'Gcore-部署证书到Gcore',
@ -26,7 +26,7 @@ export class GcoreuploadPlugin extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -3,7 +3,7 @@ import { CertInfo, CertReader } from '@certd/plugin-cert';
import * as fs from 'fs'; import * as fs from 'fs';
import { Constants } from '@certd/lib-server'; import { Constants } from '@certd/lib-server';
import path from 'path'; import path from 'path';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'CopyToLocal', name: 'CopyToLocal',
title: '主机-复制到本机', title: '主机-复制到本机',
@ -22,7 +22,7 @@ export class CopyCertToLocalPlugin extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -1,6 +1,5 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { SshClient } from '@certd/plugin-lib'; import { SshClient } from '@certd/plugin-lib';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'hostShellExecute', name: 'hostShellExecute',
title: '主机-执行远程主机脚本命令', title: '主机-执行远程主机脚本命令',

View File

@ -2,7 +2,7 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput,
import { CertInfo, CertReader, CertReaderHandleContext } from '@certd/plugin-cert'; import { CertInfo, CertReader, CertReaderHandleContext } from '@certd/plugin-cert';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { SshAccess, SshClient } from '@certd/plugin-lib'; import { SshAccess, SshClient } from '@certd/plugin-lib';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'uploadCertToHost', name: 'uploadCertToHost',
title: '主机-部署证书到SSH主机', title: '主机-部署证书到SSH主机',
@ -21,7 +21,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -3,7 +3,7 @@ import { HuaweiAccess } from '../../access/index.js';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
import { resetLogConfigure } from '@certd/basic'; import { resetLogConfigure } from '@certd/basic';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'HauweiDeployCertToCDN', name: 'HauweiDeployCertToCDN',
title: '华为云-部署证书至CDN', title: '华为云-部署证书至CDN',
@ -22,7 +22,7 @@ export class HauweiDeployCertToCDN extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -1,6 +1,6 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskInstanceContext } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskInstanceContext } from '@certd/pipeline';
import { CertInfo, CertReader } from '@certd/plugin-cert'; import { CertInfo, CertReader } from '@certd/plugin-cert';
import { CertApplyPluginNames} from '@certd/plugin-cert';
export type CustomScriptContext = { export type CustomScriptContext = {
CertReader: typeof CertReader; CertReader: typeof CertReader;
self: CustomScriptPlugin; self: CustomScriptPlugin;
@ -37,7 +37,7 @@ export class CustomScriptPlugin extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: false, required: false,
}) })

View File

@ -3,7 +3,7 @@ import { CertInfo } from '@certd/plugin-cert';
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
import { ProxmoxAccess } from '../access.js'; import { ProxmoxAccess } from '../access.js';
import { createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { createRemoteSelectInputDefine } from '@certd/plugin-lib';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
//命名规范,插件名称+功能就是目录plugin-demo中的demo大写字母开头驼峰命名 //命名规范,插件名称+功能就是目录plugin-demo中的demo大写字母开头驼峰命名
name: 'ProxmoxUploadCert', name: 'ProxmoxUploadCert',
@ -27,7 +27,7 @@ export class ProxmoxUploadCert extends AbstractPlusTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
// required: true, // 必填 // required: true, // 必填
}) })

View File

@ -2,7 +2,7 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine, QiniuAccess, QiniuClient } from '@certd/plugin-lib'; import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine, QiniuAccess, QiniuClient } from '@certd/plugin-lib';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { optionsUtils } from '@certd/basic/dist/utils/util.options.js'; import { optionsUtils } from '@certd/basic/dist/utils/util.options.js';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'QiniuDeployCertToCDN', name: 'QiniuDeployCertToCDN',
title: '七牛云-部署证书至CDN', title: '七牛云-部署证书至CDN',
@ -21,7 +21,7 @@ export class QiniuDeployCertToCDN extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书或者上传到七牛云的证书id', helper: '请选择前置任务输出的域名证书或者上传到七牛云的证书id',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego', 'QiniuCertUpload'], from: [...CertApplyPluginNames, 'QiniuCertUpload'],
}, },
required: true, required: true,
}) })

View File

@ -1,7 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { QiniuAccess, QiniuClient } from '@certd/plugin-lib'; import { QiniuAccess, QiniuClient } from '@certd/plugin-lib';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'QiniuCertUpload', name: 'QiniuCertUpload',
title: '七牛云-上传证书到七牛云', title: '七牛云-上传证书到七牛云',
@ -26,7 +26,7 @@ export class QiniuCertUpload extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -4,7 +4,7 @@ import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
import { tmpdir } from 'node:os'; import { tmpdir } from 'node:os';
import fs from 'fs'; import fs from 'fs';
import { SshAccess, SshClient } from '@certd/plugin-lib'; import { SshAccess, SshClient } from '@certd/plugin-lib';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'QnapDeploy', name: 'QnapDeploy',
title: '威联通-部署证书到威联通', title: '威联通-部署证书到威联通',
@ -25,7 +25,7 @@ export class QnapDeploy extends AbstractPlusTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -2,6 +2,7 @@ import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { createRemoteSelectInputDefine } from '@certd/plugin-lib';
import { TencentAccess, TencentSslClient } from '@certd/plugin-lib'; import { TencentAccess, TencentSslClient } from '@certd/plugin-lib';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'TencentDeployCertToCDNv2', name: 'TencentDeployCertToCDNv2',
title: '腾讯云-部署到CDN-v2', title: '腾讯云-部署到CDN-v2',
@ -41,7 +42,7 @@ export class TencentDeployCertToCDNv2 extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书或者选择前置任务“上传证书到腾讯云”任务的证书ID', helper: '请选择前置任务输出的域名证书或者选择前置任务“上传证书到腾讯云”任务的证书ID',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego', 'UploadCertToTencent'], from: [...CertApplyPluginNames, 'UploadCertToTencent'],
}, },
required: true, required: true,
}) })

View File

@ -1,6 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { TencentAccess } from '@certd/plugin-lib'; import { TencentAccess } from '@certd/plugin-lib';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'DeployCertToTencentCDN', name: 'DeployCertToTencentCDN',
title: '腾讯云-部署到CDN废弃', title: '腾讯云-部署到CDN废弃',
@ -19,7 +20,7 @@ export class DeployToCdnPlugin extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -1,6 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { TencentAccess } from '@certd/plugin-lib'; import { TencentAccess } from '@certd/plugin-lib';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'DeployCertToTencentCLB', name: 'DeployCertToTencentCLB',
title: '腾讯云-部署到CLB', title: '腾讯云-部署到CLB',
@ -81,7 +82,7 @@ export class DeployCertToTencentCLB extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -1,7 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { createRemoteSelectInputDefine, TencentSslClient } from '@certd/plugin-lib'; import { createRemoteSelectInputDefine, TencentSslClient } from '@certd/plugin-lib';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'DeployCertToTencentCosPlugin', name: 'DeployCertToTencentCosPlugin',
title: '腾讯云-部署证书到COS', title: '腾讯云-部署证书到COS',
@ -90,7 +90,7 @@ export class DeployCertToTencentCosPlugin extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书或者选择前置任务“上传证书到腾讯云”任务的证书ID', helper: '请选择前置任务输出的域名证书或者选择前置任务“上传证书到腾讯云”任务的证书ID',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego', 'UploadCertToTencent'], from: [...CertApplyPluginNames, 'UploadCertToTencent'],
}, },
required: true, required: true,
}) })

View File

@ -1,5 +1,6 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
import { TencentAccess } from '@certd/plugin-lib'; import { TencentAccess } from "@certd/plugin-lib";
@IsTaskPlugin({ @IsTaskPlugin({
name: 'DeployCertToTencentEO', name: 'DeployCertToTencentEO',
title: '腾讯云-部署到腾讯云EO', title: '腾讯云-部署到腾讯云EO',

View File

@ -2,7 +2,7 @@ import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipel
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { createRemoteSelectInputDefine, TencentAccess, TencentSslClient } from '@certd/plugin-lib'; import { createRemoteSelectInputDefine, TencentAccess, TencentSslClient } from '@certd/plugin-lib';
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'TencentDeployCertToLive', name: 'TencentDeployCertToLive',
title: '腾讯云-部署到腾讯云直播', title: '腾讯云-部署到腾讯云直播',
@ -43,7 +43,7 @@ export class TencentDeployCertToLive extends AbstractPlusTaskPlugin {
helper: '请选择前置任务输出的域名证书或者选择前置任务“上传证书到腾讯云”任务的证书ID', helper: '请选择前置任务输出的域名证书或者选择前置任务“上传证书到腾讯云”任务的证书ID',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego', 'UploadCertToTencent'], from: [...CertApplyPluginNames, 'UploadCertToTencent'],
}, },
required: true, required: true,
}) })

View File

@ -3,7 +3,7 @@ import { utils } from '@certd/basic';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'DeployCertToTencentTKEIngress', name: 'DeployCertToTencentTKEIngress',
title: '腾讯云-部署到TKE-ingress', title: '腾讯云-部署到TKE-ingress',
@ -95,7 +95,7 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractPlusTaskPlugin
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
mergeScript: ` mergeScript: `
return { return {

View File

@ -1,7 +1,5 @@
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
import { AbstractTaskPlugin } from '@certd/pipeline'; import { createRemoteSelectInputDefine, TencentAccess } from "@certd/plugin-lib";
import { TencentAccess } from '@certd/plugin-lib';
import { createRemoteSelectInputDefine } from '@certd/plugin-lib';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'TencentActionInstancesPlugin', name: 'TencentActionInstancesPlugin',

View File

@ -1,6 +1,6 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'UploadCertToTencent', name: 'UploadCertToTencent',
title: '腾讯云-上传证书到腾讯云', title: '腾讯云-上传证书到腾讯云',
@ -33,7 +33,7 @@ export class UploadCertToTencent extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })

View File

@ -1,7 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo } from '@certd/plugin-cert'; import { CertInfo } from '@certd/plugin-cert';
import { WoaiAccess } from '../access.js'; import { WoaiAccess } from '../access.js';
import { CertApplyPluginNames} from '@certd/plugin-cert';
@IsTaskPlugin({ @IsTaskPlugin({
name: 'WoaiCDN', name: 'WoaiCDN',
title: '我爱云-部署证书到我爱云CDN', title: '我爱云-部署证书到我爱云CDN',
@ -34,7 +34,7 @@ export class WoaiCdnPlugin extends AbstractTaskPlugin {
helper: '请选择前置任务输出的域名证书', helper: '请选择前置任务输出的域名证书',
component: { component: {
name: 'output-selector', name: 'output-selector',
from: ['CertApply', 'CertApplyLego'], from: [...CertApplyPluginNames],
}, },
required: true, required: true,
}) })