Files
certd/packages/plugins/plugin-cert/src/plugin/cert-plugin/custom/index.ts
T

159 lines
4.3 KiB
TypeScript
Raw Normal View History

2025-03-18 00:52:50 +08:00
import { IsTaskPlugin, pluginGroups, RunStrategy, Step, TaskInput, TaskOutput } from "@certd/pipeline";
2025-03-17 00:19:01 +08:00
import type { CertInfo } from "../acme.js";
import { CertReader } from "../cert-reader.js";
2025-03-18 00:52:50 +08:00
import { CertApplyBaseConvertPlugin } from "../base-convert.js";
2025-03-21 12:23:59 +08:00
import dayjs from "dayjs";
2025-03-22 02:06:02 +08:00
2025-03-17 00:19:01 +08:00
export { CertReader };
export type { CertInfo };
@IsTaskPlugin({
2025-03-18 00:52:50 +08:00
name: "CertApplyUpload",
2025-03-17 00:19:01 +08:00
icon: "ph:certificate",
title: "证书手动上传",
group: pluginGroups.cert.key,
desc: "在证书仓库手动上传后触发部署证书",
default: {
strategy: {
runStrategy: RunStrategy.AlwaysRun,
},
},
shortcut: {
certUpdate: {
2025-03-21 12:23:59 +08:00
title: "更新证书",
2025-03-21 23:11:58 +08:00
icon: "ion:upload",
action: "onCertUpdate",
form: {
columns: {
crt: {
title: "证书",
2025-03-21 12:23:59 +08:00
type: "text",
form: {
component: {
name: "pem-input",
vModel: "modelValue",
textarea: {
2025-03-21 12:23:59 +08:00
rows: 4,
placeholder: "-----BEGIN CERTIFICATE-----\n...\n...\n-----END CERTIFICATE-----",
},
},
rules: [{ required: true, message: "此项必填" }],
col: { span: 24 },
},
},
key: {
title: "私钥",
2025-03-21 12:23:59 +08:00
type: "text",
form: {
component: {
name: "pem-input",
vModel: "modelValue",
textarea: {
2025-03-21 12:23:59 +08:00
rows: 4,
placeholder: "-----BEGIN PRIVATE KEY-----\n...\n...\n-----END PRIVATE KEY----- ",
},
},
rules: [{ required: true, message: "此项必填" }],
col: { span: 24 },
},
},
},
},
},
},
2025-03-17 00:19:01 +08:00
})
2025-03-18 00:52:50 +08:00
export class CertApplyUploadPlugin extends CertApplyBaseConvertPlugin {
2025-03-17 00:19:01 +08:00
@TaskInput({
2025-03-21 23:11:58 +08:00
title: "手动上传证书",
2025-03-17 00:19:01 +08:00
component: {
2025-03-21 23:11:58 +08:00
name: "cert-info-updater",
2025-03-18 00:52:50 +08:00
vModel: "modelValue",
2025-03-17 00:19:01 +08:00
},
2025-03-21 23:11:58 +08:00
helper: "手动上传证书",
2025-03-18 00:52:50 +08:00
order: -9999,
2025-03-17 00:19:01 +08:00
required: true,
2025-03-18 00:52:50 +08:00
mergeScript: `
return {
component:{
on:{
2025-03-21 23:11:58 +08:00
updated(scope){
2025-03-18 00:52:50 +08:00
scope.form.input.domains = scope.$event?.domains
}
}
}
}
`,
2025-03-17 00:19:01 +08:00
})
2025-03-22 02:06:02 +08:00
uploadCert!: CertInfo;
2025-03-17 00:19:01 +08:00
2025-03-18 00:52:50 +08:00
@TaskOutput({
title: "证书MD5",
})
certMd5?: string;
2025-03-17 00:19:01 +08:00
async onInstance() {
this.accessService = this.ctx.accessService;
this.logger = this.ctx.logger;
this.userContext = this.ctx.userContext;
this.lastStatus = this.ctx.lastStatus as Step;
}
async onInit(): Promise<void> {}
2025-03-18 00:52:50 +08:00
async getCertFromStore() {
2025-03-22 02:06:02 +08:00
const certReader = new CertReader(this.uploadCert);
2025-03-17 00:19:01 +08:00
if (!certReader.expires && certReader.expires < new Date().getTime()) {
2025-03-18 00:52:50 +08:00
throw new Error("证书已过期,停止部署,请重新上传证书");
2025-03-17 00:19:01 +08:00
}
return certReader;
}
2025-03-18 00:52:50 +08:00
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}`);
2025-03-22 02:06:02 +08:00
if (!this.ctx.inputChanged) {
this.logger.info("输入参数无变化");
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("证书有变化,重新部署");
} else {
this.logger.info("输入参数有变化,重新部署");
2025-03-18 00:52:50 +08:00
}
2025-03-22 02:06:02 +08:00
2025-03-18 00:52:50 +08:00
this.clearLastStatus();
//输出证书MD5
this.certMd5 = crtMd5;
await this.output(certReader, true);
2025-03-22 02:06:02 +08:00
//必须output之后执行
await this.emitCertApplySuccess();
2025-03-18 00:52:50 +08:00
return;
}
2025-03-21 12:23:59 +08:00
async onCertUpdate(data: any) {
2025-03-22 02:06:02 +08:00
const certReader = new CertReader(data);
2025-03-21 23:11:58 +08:00
return {
input: {
2025-03-22 02:06:02 +08:00
uploadCert: {
crt: data.crt,
key: data.key,
},
domains: certReader.getAllDomains(),
2025-03-21 23:11:58 +08:00
},
};
2025-03-21 12:23:59 +08:00
}
2025-03-17 00:19:01 +08:00
}
2025-03-18 00:52:50 +08:00
new CertApplyUploadPlugin();