diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..d19e4746 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,5 @@ +# These are supported funding model platforms + +github: greper +buy_me_a_coffee: greper +custom: ['https://afdian.com/a/greper'] diff --git a/README.md b/README.md index 4ebbc0d0..f0960aaf 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ https://certd.handfree.work/ ## 八、捐赠 ************************ -支持开源,为爱发电,我已入驻爱发电 +支持开源,为爱发电,我已入驻爱发电 https://afdian.com/a/greper 发电权益: @@ -171,6 +171,7 @@ https://afdian.com/a/greper | 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署、宝塔、1Panel等大部分插件 | 群晖 | | 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、钉钉、飞书、anpush、server酱等 | +************************ ************************ diff --git a/README_en.md b/README_en.md index 66f67a04..d665a982 100644 --- a/README_en.md +++ b/README_en.md @@ -134,6 +134,8 @@ You can also add the author as a friend. | QR Code | | ## 8. Donation +************************ + [![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-red)](https://github.com/sponsors/greper) ************************ Support open-source projects and contribute with love. I've joined Afdian. https://afdian.com/a/greper diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/base-convert.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/base-convert.ts index e9d59313..e8ad9d75 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/base-convert.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/base-convert.ts @@ -99,6 +99,7 @@ export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin { const cert: CertInfo = certReader.toCertInfo(); this.cert = cert; + this._result.pipelineVars.certEffectiveTime = dayjs(certReader.detail.notBefore).valueOf(); this._result.pipelineVars.certExpiresTime = dayjs(certReader.detail.notAfter).valueOf(); if (!this._result.pipelinePrivateVars) { this._result.pipelinePrivateVars = {}; diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts index b2151871..8fbaa32d 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts @@ -35,6 +35,7 @@ export class CertReader { detail: CertificateInfo; //毫秒时间戳 + effective: number; expires: number; constructor(certInfo: CertInfo) { this.cert = certInfo; @@ -52,8 +53,9 @@ export class CertReader { } try { - const { detail, expires } = this.getCrtDetail(this.cert.crt); + const { detail, effective, expires } = this.getCrtDetail(this.cert.crt); this.detail = detail; + this.effective = effective.getTime(); this.expires = expires.getTime(); } catch (e) { throw new Error("证书解析失败:" + e.message); @@ -102,8 +104,9 @@ export class CertReader { static readCertDetail(crt: string) { const detail = crypto.readCertificateInfo(crt.toString()); + const effective = detail.notBefore; const expires = detail.notAfter; - return { detail, expires }; + return { detail, effective, expires }; } getAllDomains() { diff --git a/packages/ui/certd-client/src/locales/langs/en-US/certd.ts b/packages/ui/certd-client/src/locales/langs/en-US/certd.ts index e26e524e..2dbc451a 100644 --- a/packages/ui/certd-client/src/locales/langs/en-US/certd.ts +++ b/packages/ui/certd-client/src/locales/langs/en-US/certd.ts @@ -119,6 +119,7 @@ export default { scheduledTaskCount: "Scheduled Task Count", deployTaskCount: "Deployment Task Count", remainingValidity: "Remaining Validity", + effectiveTime: "Effective time", expiryTime: "Expiry Time", status: "Status", lastRun: "Last Run", @@ -250,7 +251,9 @@ export default { ok: "Valid", expired: "Expired", }, + certEffectiveTime: "Certificate Effective", certExpiresTime: "Certificate Expiration", + remainingValidity: "Remaining Validity", expired: "expired", days: "days", lastCheckTime: "Last Check Time", @@ -465,6 +468,7 @@ export default { validDays: "Valid Days", expires: " expires", days: " days", + effectiveTime: "Effective Time", expireTime: "Expiration Time", certIssuer: "Certificate Issuer", applyTime: "Application Time", diff --git a/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts b/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts index 75005bd9..49fb9d13 100644 --- a/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts +++ b/packages/ui/certd-client/src/locales/langs/zh-CN/certd.ts @@ -125,6 +125,7 @@ export default { scheduledTaskCount: "定时任务数", deployTaskCount: "部署任务数", remainingValidity: "到期剩余", + effectiveTime: "生效时间", expiryTime: "过期时间", status: "状态", lastRun: "最后运行", @@ -255,7 +256,9 @@ export default { ok: "正常", expired: "过期", }, + certEffectiveTime: "证书生效时间", certExpiresTime: "证书到期时间", + remainingValidity: "到期剩余", expired: "过期", days: "天", lastCheckTime: "上次检查时间", @@ -471,6 +474,7 @@ export default { validDays: "有效天数", expires: "过期", days: "天", + effectiveTime: "生效时间", expireTime: "过期时间", certIssuer: "证书颁发机构", applyTime: "申请时间", diff --git a/packages/ui/certd-client/src/views/certd/monitor/cert/crud.tsx b/packages/ui/certd-client/src/views/certd/monitor/cert/crud.tsx index 97e9754d..23fae996 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/cert/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/monitor/cert/crud.tsx @@ -220,22 +220,47 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat sorter: true, conditionalRender: false, cellRender({ row }) { - const value = row.expiresTime; - if (!value) { + const { + applyTime, + effectiveTime, + expiresTime, + } = row || {}; + if (!expiresTime) { return "-"; } - const expireDate = dayjs(value).format("YYYY-MM-DD"); - const leftDays = dayjs(value).diff(dayjs(), "day"); + // 申请时间 ps:此处为证书在certd创建的时间而非实际证书申请时间 + const applyDate = dayjs(effectiveTime ?? applyTime ?? Date.now()).format("YYYY-MM-DD"); + // 失效时间 + const expireDate = dayjs(expiresTime).format("YYYY-MM-DD"); + // 有效天数 ps:此处证书最小设置为90d + const effectiveDays = Math.max(90, dayjs(expiresTime).diff(applyDate, "day")); + // 距离失效时间剩余天数 + const leftDays = dayjs(expiresTime).diff(dayjs(), "day"); const color = leftDays < 20 ? "red" : "#389e0d"; - const percent = (leftDays / 90) * 100; + const percent = (leftDays / effectiveDays) * 100; const textColor = leftDays < 20 ? "red" : leftDays > 60 ? "#389e0d" : ""; const format = () => { return {`${leftDays}${t("certd.days")}`}; }; + // console.log('cellRender', 'effectiveDays', effectiveDays, 'expiresTime', expiresTime, 'applyTime', applyTime, 'percent', percent, row) return ; }, }, }, + effectiveTime: { + title: t("certd.effectiveTime"), + search: { + show: false, + }, + type: "datetime", + form: { + show: false, + }, + column: { + sorter: true, + show: false, + }, + }, expiresTime: { title: t("certd.expireTime"), search: { diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx b/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx index c53a3214..e1189083 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx @@ -345,25 +345,64 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat align: "center", }, }, + certEffectiveTime: { + title: t("certd.monitor.certEffectiveTime"), + search: { + show: false, + }, + type: "datetime", + form: { + show: false, + }, + column: { + sorter: true, + width: 155, + }, + }, certExpiresTime: { title: t("certd.monitor.certExpiresTime"), search: { show: false, }, + type: "datetime", + form: { + show: false, + }, + column: { + sorter: true, + width: 155, + }, + }, + remainingValidity: { + title: t("certd.monitor.remainingValidity"), + search: { + show: false, + }, type: "date", form: { show: false, }, column: { - sorter: true, - cellRender({ value }) { - if (!value) { + conditionalRender: false, + cellRender({ row }) { + const { + certEffectiveTime: effectiveTime, + certExpiresTime: expiresTime, + } = row || {}; + if (!expiresTime) { return "-"; } - const expireDate = dayjs(value).format("YYYY-MM-DD"); - const leftDays = dayjs(value).diff(dayjs(), "day"); + // 申请时间 ps:此处为证书在certd创建的时间而非实际证书申请时间 + const applyDate = dayjs(effectiveTime ?? Date.now()).format("YYYY-MM-DD"); + // 失效时间 + const expireDate = dayjs(expiresTime).format("YYYY-MM-DD"); + // 有效天数 ps:此处证书最小设置为90d + const effectiveDays = Math.max(90, dayjs(expiresTime).diff(applyDate, "day")); + // 距离失效时间剩余天数 + const leftDays = dayjs(expiresTime).diff(dayjs(), "day"); const color = leftDays < 20 ? "red" : "#389e0d"; - const percent = (leftDays / 90) * 100; + const percent = (leftDays / effectiveDays) * 100; + // console.log('cellRender', 'effectiveDays', effectiveDays, 'expiresTime', expiresTime, 'applyTime', applyTime, 'percent', percent, row) return `${leftDays}${t("certd.monitor.days")}`} />; }, }, diff --git a/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx b/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx index 9e11102d..8ce42f4c 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx @@ -366,23 +366,49 @@ export default function ({ crudExpose, context: { groupDictRef, selectedRowKeys }, column: { cellRender({ row }) { - const value = row.lastVars?.certExpiresTime; - if (!value) { + const { + certEffectiveTime: effectiveTime, + certExpiresTime: expiresTime, + } = row?.lastVars || {}; + if (!expiresTime) { return "-"; } - const expireDate = dayjs(value).format("YYYY-MM-DD"); - const leftDays = dayjs(value).diff(dayjs(), "day"); + // 申请时间 ps:此处为证书在certd创建的时间而非实际证书申请时间 + const applyDate = dayjs(effectiveTime ?? Date.now()).format("YYYY-MM-DD"); + // 失效时间 + const expireDate = dayjs(expiresTime).format("YYYY-MM-DD"); + // 有效天数 ps:此处证书最小设置为90d + const effectiveDays = Math.max(90, dayjs(expiresTime).diff(applyDate, "day")); + // 距离失效时间剩余天数 + const leftDays = dayjs(expiresTime).diff(dayjs(), "day"); const color = leftDays < 20 ? "red" : "#389e0d"; - const percent = (leftDays / 90) * 100; + const percent = (leftDays / effectiveDays) * 100; const textColor = leftDays < 20 ? "red" : leftDays > 60 ? "#389e0d" : ""; const format = () => { return {`${leftDays}${t("certd.days")}`}; }; + // console.log('cellRender', 'effectiveDays', effectiveDays, 'expiresTime', expiresTime, 'applyTime', applyTime, 'percent', percent, row) return ; }, width: 150, }, }, + "lastVars.certEffectiveTime": { + title: t("certd.fields.effectiveTime"), + search: { + show: false, + }, + type: "datetime", + form: { + show: false, + }, + column: { + sorter: false, + show: false, + width: 150, + align: "center", + }, + }, "lastVars.certExpiresTime": { title: t("certd.fields.expiryTime"), search: { diff --git a/packages/ui/certd-server/db/migration-mysql/v10029__cert_effective_time.sql b/packages/ui/certd-server/db/migration-mysql/v10029__cert_effective_time.sql new file mode 100644 index 00000000..b38feb3c --- /dev/null +++ b/packages/ui/certd-server/db/migration-mysql/v10029__cert_effective_time.sql @@ -0,0 +1,2 @@ +ALTER TABLE cd_cert_info ADD COLUMN effective_time INTEGER; +ALTER TABLE cd_site_info ADD COLUMN cert_effective_time INTEGER; diff --git a/packages/ui/certd-server/db/migration-pg/v10029__cert_effective_time.sql b/packages/ui/certd-server/db/migration-pg/v10029__cert_effective_time.sql new file mode 100644 index 00000000..b38feb3c --- /dev/null +++ b/packages/ui/certd-server/db/migration-pg/v10029__cert_effective_time.sql @@ -0,0 +1,2 @@ +ALTER TABLE cd_cert_info ADD COLUMN effective_time INTEGER; +ALTER TABLE cd_site_info ADD COLUMN cert_effective_time INTEGER; diff --git a/packages/ui/certd-server/db/migration/v10029__cert_effective_time.sql b/packages/ui/certd-server/db/migration/v10029__cert_effective_time.sql new file mode 100644 index 00000000..b38feb3c --- /dev/null +++ b/packages/ui/certd-server/db/migration/v10029__cert_effective_time.sql @@ -0,0 +1,2 @@ +ALTER TABLE cd_cert_info ADD COLUMN effective_time INTEGER; +ALTER TABLE cd_site_info ADD COLUMN cert_effective_time INTEGER; diff --git a/packages/ui/certd-server/src/modules/monitor/entity/cert-info.ts b/packages/ui/certd-server/src/modules/monitor/entity/cert-info.ts index f16ca87d..807489c9 100644 --- a/packages/ui/certd-server/src/modules/monitor/entity/cert-info.ts +++ b/packages/ui/certd-server/src/modules/monitor/entity/cert-info.ts @@ -30,6 +30,9 @@ export class CertInfoEntity { @Column({ name: 'cert_provider', comment: '证书颁发机构' }) certProvider: string; + @Column({ name: 'effective_time', comment: '生效时间' }) + effectiveTime: number; + @Column({ name: 'expires_time', comment: '过期时间' }) expiresTime: number; diff --git a/packages/ui/certd-server/src/modules/monitor/entity/site-info.ts b/packages/ui/certd-server/src/modules/monitor/entity/site-info.ts index 1c1e4eda..f4dc9501 100644 --- a/packages/ui/certd-server/src/modules/monitor/entity/site-info.ts +++ b/packages/ui/certd-server/src/modules/monitor/entity/site-info.ts @@ -26,6 +26,8 @@ export class SiteInfoEntity { @Column({ name: 'cert_provider', comment: '证书颁发机构', length: 100 }) certProvider: string; + @Column({ name: 'cert_effective_time', comment: '证书生效时间' }) + certEffectiveTime: number; @Column({ name: 'cert_expires_time', comment: '证书到期时间' }) certExpiresTime: number; @Column({ name: 'last_check_time', comment: '上次检查时间' }) diff --git a/packages/ui/certd-server/src/modules/monitor/service/cert-info-service.ts b/packages/ui/certd-server/src/modules/monitor/service/cert-info-service.ts index 8bb2e8ac..4819bda9 100644 --- a/packages/ui/certd-server/src/modules/monitor/service/cert-info-service.ts +++ b/packages/ui/certd-server/src/modules/monitor/service/cert-info-service.ts @@ -164,6 +164,7 @@ export class CertInfoService extends BaseService { bean.domains = domains.join(','); bean.domain = domains[0]; bean.domainCount = domains.length; + bean.effectiveTime = certReader.effective; bean.expiresTime = certReader.expires; bean.certProvider = certReader.detail.issuer.commonName; bean.userId = userId diff --git a/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts b/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts index 4f9f7f9f..8c21d9d4 100644 --- a/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts +++ b/packages/ui/certd-server/src/modules/monitor/service/site-info-service.ts @@ -134,6 +134,7 @@ export class SiteInfoService extends BaseService { if (!certi) { throw new Error("没有发现证书"); } + const effective = certi.valid_from; const expires = certi.valid_to; const allDomains = certi.subjectaltname?.replaceAll("DNS:", "").split(",") || []; const mainDomain = certi.subject?.CN; @@ -149,12 +150,13 @@ export class SiteInfoService extends BaseService { certDomains: domains.join(","), certStatus: status, certProvider: issuer, + certEffectiveTime: dayjs(effective).valueOf(), certExpiresTime: dayjs(expires).valueOf(), lastCheckTime: dayjs().valueOf(), error: null, checkStatus: "ok" }; - logger.info(`测试站点成功:id=${updateData.id},site=${site.name},expiresTime=${updateData.certExpiresTime}`) + logger.info(`测试站点成功:id=${updateData.id},site=${site.name},certEffectiveTime=${updateData.certEffectiveTime},expiresTime=${updateData.certExpiresTime}`) if (site.ipCheck) { delete updateData.checkStatus }