mirror of https://github.com/certd/certd
				
				
				
			perf: 支持手动上传证书并部署
							parent
							
								
									0069c0e399
								
							
						
					
					
						commit
						a9fffa5180
					
				| 
						 | 
				
			
			@ -33,6 +33,7 @@ export type ExecutorOptions = {
 | 
			
		|||
  user: UserInfo;
 | 
			
		||||
  baseURL?: string;
 | 
			
		||||
  sysInfo?: SysInfo;
 | 
			
		||||
  serviceGetter: (name: string) => any;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export class Executor {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,6 +114,9 @@ export type TaskInstanceContext = {
 | 
			
		|||
  user: UserInfo;
 | 
			
		||||
 | 
			
		||||
  emitter: TaskEmitter;
 | 
			
		||||
 | 
			
		||||
  //service 容器
 | 
			
		||||
  serviceContainer?: Record<string, any>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export abstract class AbstractTaskPlugin implements ITaskPlugin {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ export class CertReader {
 | 
			
		|||
  cert: CertInfo;
 | 
			
		||||
 | 
			
		||||
  detail: CertificateInfo;
 | 
			
		||||
  //毫秒时间戳
 | 
			
		||||
  expires: number;
 | 
			
		||||
  constructor(certInfo: CertInfo) {
 | 
			
		||||
    this.cert = certInfo;
 | 
			
		||||
| 
						 | 
				
			
			@ -39,9 +40,13 @@ export class CertReader {
 | 
			
		|||
      this.cert.one = this.cert.crt + "\n" + this.cert.key;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const { detail, expires } = this.getCrtDetail(this.cert.crt);
 | 
			
		||||
      this.detail = detail;
 | 
			
		||||
      this.expires = expires.getTime();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      throw new Error("证书解析失败:" + e.message);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getIc() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
import { IsTaskPlugin, pluginGroups, RunStrategy, Step, TaskInput } from "@certd/pipeline";
 | 
			
		||||
import type { CertInfo } from "../acme.js";
 | 
			
		||||
import { CertReader } from "../cert-reader.js";
 | 
			
		||||
import { CertApplyBasePlugin } from "../base.js";
 | 
			
		||||
 | 
			
		||||
export { CertReader };
 | 
			
		||||
export type { CertInfo };
 | 
			
		||||
 | 
			
		||||
@IsTaskPlugin({
 | 
			
		||||
  name: "CertUpload",
 | 
			
		||||
  icon: "ph:certificate",
 | 
			
		||||
  title: "证书手动上传",
 | 
			
		||||
  group: pluginGroups.cert.key,
 | 
			
		||||
  desc: "在证书仓库手动上传后触发部署证书",
 | 
			
		||||
  default: {
 | 
			
		||||
    input: {
 | 
			
		||||
      renewDays: 35,
 | 
			
		||||
      forceUpdate: false,
 | 
			
		||||
    },
 | 
			
		||||
    strategy: {
 | 
			
		||||
      runStrategy: RunStrategy.AlwaysRun,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
})
 | 
			
		||||
export class CertUploadPlugin extends CertApplyBasePlugin {
 | 
			
		||||
  @TaskInput({
 | 
			
		||||
    title: "证书仓库ID",
 | 
			
		||||
    component: {
 | 
			
		||||
      name: "a-cert-select",
 | 
			
		||||
      vModel: "value",
 | 
			
		||||
    },
 | 
			
		||||
    required: true,
 | 
			
		||||
  })
 | 
			
		||||
  certInfoId!: string;
 | 
			
		||||
 | 
			
		||||
  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> {}
 | 
			
		||||
 | 
			
		||||
  async doCertApply() {
 | 
			
		||||
    const siteInfoService = this.ctx.serviceContainer["CertInfoService"];
 | 
			
		||||
 | 
			
		||||
    const certInfo = await siteInfoService.getCertInfo({
 | 
			
		||||
      certId: this.certInfoId,
 | 
			
		||||
      userid: this.pipeline.userId,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const certReader = new CertReader(certInfo);
 | 
			
		||||
    if (!certReader.expires && certReader.expires < new Date().getTime()) {
 | 
			
		||||
      throw new Error("证书已过期,停止部署");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return certReader;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
new CertUploadPlugin();
 | 
			
		||||
| 
						 | 
				
			
			@ -4,6 +4,10 @@ export function createAccessApi(from = "user") {
 | 
			
		|||
  const apiPrefix = from === "sys" ? "/sys/access" : "/pi/access";
 | 
			
		||||
  return {
 | 
			
		||||
    async GetList(query: any) {
 | 
			
		||||
      if (query?.query) {
 | 
			
		||||
        delete query.query.access;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return await request({
 | 
			
		||||
        url: apiPrefix + "/page",
 | 
			
		||||
        method: "post",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,7 +77,7 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
 | 
			
		|||
      type: "dict-select",
 | 
			
		||||
      dict: AccessTypeDictRef,
 | 
			
		||||
      search: {
 | 
			
		||||
        show: false
 | 
			
		||||
        show: true
 | 
			
		||||
      },
 | 
			
		||||
      column: {
 | 
			
		||||
        width: 200,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,10 @@
 | 
			
		|||
// @ts-ignore
 | 
			
		||||
import { useI18n } from "vue-i18n";
 | 
			
		||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, 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 dayjs from "dayjs";
 | 
			
		||||
import { useUserStore } from "/@/store/modules/user";
 | 
			
		||||
import { useRouter } from "vue-router";
 | 
			
		||||
import { useModal } from "/@/use/use-modal";
 | 
			
		||||
import * as api from "/@/views/certd/pipeline/api";
 | 
			
		||||
import { notification } from "ant-design-vue";
 | 
			
		||||
import CertView from "/@/views/certd/pipeline/cert-view.vue";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +52,69 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  async function openUpload(id?: any) {
 | 
			
		||||
    function createCrudOptions() {
 | 
			
		||||
      return {
 | 
			
		||||
        crudOptions: {
 | 
			
		||||
          request: {
 | 
			
		||||
            // addRequest: async (form: any) => {
 | 
			
		||||
            //   return await api.Upload(form);
 | 
			
		||||
            // },
 | 
			
		||||
            // editRequest: async (form: any) => {
 | 
			
		||||
            //   return await api.Upload(form);
 | 
			
		||||
            // }
 | 
			
		||||
          },
 | 
			
		||||
          columns: {
 | 
			
		||||
            id: {
 | 
			
		||||
              title: "ID",
 | 
			
		||||
              type: "number",
 | 
			
		||||
              form: {
 | 
			
		||||
                show: false
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            "cert.crt": {
 | 
			
		||||
              title: "证书",
 | 
			
		||||
              type: "textarea",
 | 
			
		||||
              form: {
 | 
			
		||||
                component: {
 | 
			
		||||
                  rows: 4
 | 
			
		||||
                },
 | 
			
		||||
                rules: [{ required: true, message: "此项必填" }],
 | 
			
		||||
                col: { span: 24 }
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            "cert.key": {
 | 
			
		||||
              title: "私钥",
 | 
			
		||||
              type: "textarea",
 | 
			
		||||
              form: {
 | 
			
		||||
                component: {
 | 
			
		||||
                  rows: 4
 | 
			
		||||
                },
 | 
			
		||||
                rules: [{ required: true, message: "此项必填" }],
 | 
			
		||||
                col: { span: 24 }
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          form: {
 | 
			
		||||
            wrapper: {
 | 
			
		||||
              title: "上传自定义证书"
 | 
			
		||||
            },
 | 
			
		||||
            async doSubmit({ form }: any) {
 | 
			
		||||
              if (!id) {
 | 
			
		||||
                delete form.id;
 | 
			
		||||
              } else {
 | 
			
		||||
                form.id = id;
 | 
			
		||||
              }
 | 
			
		||||
              return await api.Upload(form);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
    const { crudOptions } = createCrudOptions();
 | 
			
		||||
    const wrapperRef = await openCrudFormDialog({ crudOptions });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    crudOptions: {
 | 
			
		||||
      request: {
 | 
			
		||||
| 
						 | 
				
			
			@ -83,64 +144,19 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
          add: {
 | 
			
		||||
            text: "上传自定义证书",
 | 
			
		||||
            type: "primary",
 | 
			
		||||
            show: false,
 | 
			
		||||
            show: true,
 | 
			
		||||
            async click() {
 | 
			
		||||
              function createCrudOptions() {
 | 
			
		||||
                return {
 | 
			
		||||
                  crudOptions: {
 | 
			
		||||
                    request: {
 | 
			
		||||
                      addRequest: async (form: any) => {
 | 
			
		||||
                        return await api.Upload(form);
 | 
			
		||||
                      },
 | 
			
		||||
                      editRequest: async (form: any) => {
 | 
			
		||||
                        return await api.Upload(form);
 | 
			
		||||
              await openUpload();
 | 
			
		||||
            }
 | 
			
		||||
                    },
 | 
			
		||||
                    columns: {
 | 
			
		||||
                      id: {
 | 
			
		||||
                        title: "ID",
 | 
			
		||||
                        type: "number",
 | 
			
		||||
                        form: {
 | 
			
		||||
                          show: false
 | 
			
		||||
                        }
 | 
			
		||||
                      },
 | 
			
		||||
                      "cert.crt": {
 | 
			
		||||
                        title: "证书",
 | 
			
		||||
                        type: "textarea",
 | 
			
		||||
                        form: {
 | 
			
		||||
                          component: {
 | 
			
		||||
                            rows: 4
 | 
			
		||||
                          },
 | 
			
		||||
                          rules: [{ required: true, message: "此项必填" }]
 | 
			
		||||
                        }
 | 
			
		||||
                      },
 | 
			
		||||
                      "cert.key": {
 | 
			
		||||
                        title: "私钥",
 | 
			
		||||
                        type: "textarea",
 | 
			
		||||
                        form: {
 | 
			
		||||
                          component: {
 | 
			
		||||
                            rows: 4
 | 
			
		||||
                          },
 | 
			
		||||
                          rules: [{ required: true, message: "此项必填" }]
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
                    form: {
 | 
			
		||||
                      wrapper: {
 | 
			
		||||
                        title: "上传自定义证书"
 | 
			
		||||
                      }
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                };
 | 
			
		||||
              }
 | 
			
		||||
              const { crudOptions } = createCrudOptions();
 | 
			
		||||
              const wrapperRef = await openCrudFormDialog({ crudOptions });
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      tabs: {
 | 
			
		||||
        name: "fromType",
 | 
			
		||||
        show: true
 | 
			
		||||
      },
 | 
			
		||||
      rowHandle: {
 | 
			
		||||
        width: 100,
 | 
			
		||||
        width: 140,
 | 
			
		||||
        fixed: "right",
 | 
			
		||||
        buttons: {
 | 
			
		||||
          view: { show: false },
 | 
			
		||||
| 
						 | 
				
			
			@ -155,7 +171,24 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
          },
 | 
			
		||||
          copy: { show: false },
 | 
			
		||||
          edit: { show: false },
 | 
			
		||||
          remove: { show: false }
 | 
			
		||||
          upload: {
 | 
			
		||||
            show: compute(({ row }) => {
 | 
			
		||||
              return row.fromType === "upload";
 | 
			
		||||
            }),
 | 
			
		||||
            order: 4,
 | 
			
		||||
            title: "更新证书",
 | 
			
		||||
            type: "link",
 | 
			
		||||
            icon: "ph:upload",
 | 
			
		||||
            async click({ row }) {
 | 
			
		||||
              await openUpload(row.id);
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          remove: {
 | 
			
		||||
            order: 10,
 | 
			
		||||
            show: compute(({ row }) => {
 | 
			
		||||
              return row.fromType === "upload";
 | 
			
		||||
            })
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      columns: {
 | 
			
		||||
| 
						 | 
				
			
			@ -176,25 +209,37 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
            show: false
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        // domain: {
 | 
			
		||||
        //   title: "主域名",
 | 
			
		||||
        //   search: {
 | 
			
		||||
        //     show: true
 | 
			
		||||
        //   },
 | 
			
		||||
        //   type: "text",
 | 
			
		||||
        //   form: {
 | 
			
		||||
        //     show: false
 | 
			
		||||
        //   },
 | 
			
		||||
        //   column: {
 | 
			
		||||
        //     width: 180,
 | 
			
		||||
        //     sorter: true,
 | 
			
		||||
        //     component: {
 | 
			
		||||
        //       name: "fs-values-format"
 | 
			
		||||
        //     }
 | 
			
		||||
        //   }
 | 
			
		||||
        // },
 | 
			
		||||
        fromType: {
 | 
			
		||||
          title: "来源",
 | 
			
		||||
          search: {
 | 
			
		||||
            show: true
 | 
			
		||||
          },
 | 
			
		||||
          type: "dict-select",
 | 
			
		||||
          dict: dict({
 | 
			
		||||
            data: [
 | 
			
		||||
              { label: "流水线", value: "pipeline" },
 | 
			
		||||
              { label: "手动上传", value: "upload" }
 | 
			
		||||
            ]
 | 
			
		||||
          }),
 | 
			
		||||
          form: {
 | 
			
		||||
            show: false
 | 
			
		||||
          },
 | 
			
		||||
          column: {
 | 
			
		||||
            width: 100,
 | 
			
		||||
            sorter: true,
 | 
			
		||||
            component: {
 | 
			
		||||
              color: "auto"
 | 
			
		||||
            },
 | 
			
		||||
            conditionalRender: false
 | 
			
		||||
          },
 | 
			
		||||
          valueBuilder({ value, row, key }) {
 | 
			
		||||
            if (!value) {
 | 
			
		||||
              row[key] = "pipeline";
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        domains: {
 | 
			
		||||
          title: "全部域名",
 | 
			
		||||
          title: "域名",
 | 
			
		||||
          search: {
 | 
			
		||||
            show: true
 | 
			
		||||
          },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -177,13 +177,13 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
          },
 | 
			
		||||
          column: {
 | 
			
		||||
            align: "center",
 | 
			
		||||
            width: 100
 | 
			
		||||
            width: 110
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        certDomains: {
 | 
			
		||||
          title: "证书域名",
 | 
			
		||||
          search: {
 | 
			
		||||
            show: false
 | 
			
		||||
            show: true
 | 
			
		||||
          },
 | 
			
		||||
          type: "text",
 | 
			
		||||
          form: {
 | 
			
		||||
| 
						 | 
				
			
			@ -294,7 +294,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
            show: false
 | 
			
		||||
          },
 | 
			
		||||
          column: {
 | 
			
		||||
            width: 100,
 | 
			
		||||
            width: 110,
 | 
			
		||||
            align: "center",
 | 
			
		||||
            sorter: true
 | 
			
		||||
          }
 | 
			
		||||
| 
						 | 
				
			
			@ -358,7 +358,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
 | 
			
		|||
            value: false
 | 
			
		||||
          },
 | 
			
		||||
          column: {
 | 
			
		||||
            width: 90,
 | 
			
		||||
            width: 110,
 | 
			
		||||
            sorter: true
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@
 | 
			
		|||
      <div class="title flex items-center">
 | 
			
		||||
        站点证书监控
 | 
			
		||||
        <div class="sub flex-1">
 | 
			
		||||
          <div>每天0点,检查网站证书的过期时间,并发出提醒;</div>
 | 
			
		||||
          <div>每天0点,检查网站证书的过期时间,到期前10天时将发出提醒(使用默认通知渠道);</div>
 | 
			
		||||
          <div class="flex items-center">基础版限制1条,专业版以上无限制,当前<vip-button class="ml-5" mode="nav"></vip-button></div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -504,6 +504,20 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
 | 
			
		|||
            width: 150
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "lastVars.certExpiresTime": {
 | 
			
		||||
          title: "过期时间",
 | 
			
		||||
          search: {
 | 
			
		||||
            show: false
 | 
			
		||||
          },
 | 
			
		||||
          type: "datetime",
 | 
			
		||||
          form: {
 | 
			
		||||
            show: false
 | 
			
		||||
          },
 | 
			
		||||
          column: {
 | 
			
		||||
            sorter: true,
 | 
			
		||||
            align: "center"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        status: {
 | 
			
		||||
          title: "状态",
 | 
			
		||||
          type: "dict-select",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,11 +24,17 @@ export class CertInfoController extends CrudController<CertInfoService> {
 | 
			
		|||
  async page(@Body(ALL) body: any) {
 | 
			
		||||
    body.query = body.query ?? {};
 | 
			
		||||
    body.query.userId = this.getUserId();
 | 
			
		||||
 | 
			
		||||
    const domains = body.query?.domains;
 | 
			
		||||
    delete body.query.domains;
 | 
			
		||||
    const res = await this.service.page({
 | 
			
		||||
      query: body.query,
 | 
			
		||||
      page: body.page,
 | 
			
		||||
      sort: body.sort,
 | 
			
		||||
      buildQuery: (bq) => {
 | 
			
		||||
        if (domains) {
 | 
			
		||||
          bq.andWhere('domains like :domains', { domains: `%${domains}%` });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const records = res.records;
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +94,11 @@ export class CertInfoController extends CrudController<CertInfoService> {
 | 
			
		|||
  @Post('/upload', { summary: Constants.per.authOnly })
 | 
			
		||||
  async upload(@Body(ALL) body: any) {
 | 
			
		||||
    if (body.id) {
 | 
			
		||||
      //修改
 | 
			
		||||
      await this.service.checkUserId(body.id, this.getUserId());
 | 
			
		||||
    }else{
 | 
			
		||||
      //添加
 | 
			
		||||
      body.userId = this.getUserId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const res = await this.service.upload(body);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,9 +10,10 @@ export type UploadCertReq = {
 | 
			
		|||
  id?: number;
 | 
			
		||||
  certReader: CertReader;
 | 
			
		||||
  fromType?: string;
 | 
			
		||||
  userId?: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@Provide()
 | 
			
		||||
@Provide("CertInfoService")
 | 
			
		||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
 | 
			
		||||
export class CertInfoService extends BaseService<CertInfoEntity> {
 | 
			
		||||
  @InjectEntityModel(CertInfoEntity)
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +148,7 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
 | 
			
		|||
 | 
			
		||||
  private async updateCert(req: UploadCertReq) {
 | 
			
		||||
    const bean = new CertInfoEntity();
 | 
			
		||||
    const { id, fromType, certReader } = req;
 | 
			
		||||
    const { id, fromType,userId, certReader } = req;
 | 
			
		||||
    if (id) {
 | 
			
		||||
      bean.id = id;
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -162,13 +163,13 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
 | 
			
		|||
    bean.domainCount = domains.length;
 | 
			
		||||
    bean.expiresTime = certReader.expires;
 | 
			
		||||
    bean.certProvider = certReader.detail.issuer.commonName;
 | 
			
		||||
 | 
			
		||||
    bean.userId = userId
 | 
			
		||||
    await this.addOrUpdate(bean);
 | 
			
		||||
    return bean;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async upload(body: { id?: number; cert: CertInfo }) {
 | 
			
		||||
    const { id, cert } = body;
 | 
			
		||||
  async upload(body: { id?: number; userId?:number ;cert: CertInfo }) {
 | 
			
		||||
    const { id, userId, cert } = body;
 | 
			
		||||
    if (!cert) {
 | 
			
		||||
      throw new CommonException("cert can't be empty");
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -176,6 +177,7 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
 | 
			
		|||
      id,
 | 
			
		||||
      certReader: new CertReader(cert),
 | 
			
		||||
      fromType: 'upload',
 | 
			
		||||
      userId
 | 
			
		||||
    });
 | 
			
		||||
    return res.id;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -182,6 +182,9 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
 | 
			
		|||
    );
 | 
			
		||||
  }
 | 
			
		||||
  async sendExpiresNotify(site: SiteInfoEntity) {
 | 
			
		||||
 | 
			
		||||
    const tipDays = 10
 | 
			
		||||
 | 
			
		||||
    const expires = site.certExpiresTime;
 | 
			
		||||
    const validDays = dayjs(expires).diff(dayjs(), 'day');
 | 
			
		||||
    const url = await this.notificationService.getBindUrl('#/monitor/site');
 | 
			
		||||
| 
						 | 
				
			
			@ -190,7 +193,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
 | 
			
		|||
证书域名: ${site.certDomains} \n
 | 
			
		||||
证书颁发者: ${site.certProvider} \n
 | 
			
		||||
过期时间: ${dayjs(site.certExpiresTime).format('YYYY-MM-DD')} \n`;
 | 
			
		||||
    if (validDays >= 0 && validDays < 10) {
 | 
			
		||||
    if (validDays >= 0 && validDays < tipDays) {
 | 
			
		||||
      // 发通知
 | 
			
		||||
      await this.notificationService.send(
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -475,6 +475,12 @@ export class PipelineService extends BaseService<PipelineEntity> {
 | 
			
		|||
      const siteInfo = await this.sysSettingsService.getSetting<SysSiteInfo>(SysSiteInfo);
 | 
			
		||||
      sysInfo.title = siteInfo.title;
 | 
			
		||||
    }
 | 
			
		||||
    const serviceContainer = {
 | 
			
		||||
      CertInfoService: this.certInfoService
 | 
			
		||||
    }
 | 
			
		||||
    const serviceGetter = (name: string) => {
 | 
			
		||||
      return serviceContainer[name]
 | 
			
		||||
    }
 | 
			
		||||
    const executor = new Executor({
 | 
			
		||||
      user,
 | 
			
		||||
      pipeline,
 | 
			
		||||
| 
						 | 
				
			
			@ -488,6 +494,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
 | 
			
		|||
      notificationService: notificationGetter,
 | 
			
		||||
      fileRootDir: this.certdConfig.fileRootDir,
 | 
			
		||||
      sysInfo,
 | 
			
		||||
      serviceGetter
 | 
			
		||||
    });
 | 
			
		||||
    try {
 | 
			
		||||
      runningTasks.set(historyId, executor);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue