mirror of https://github.com/certd/certd
perf: 证书到期剩余天数进度条根据实际证书有效期计算 (#528) nicheng-he
* Create FUNDING.yml * Update FUNDING.yml * Update README.md * Update README.md * Update README.md * Update README.md * Update README_en.md * 证书到期剩余天数进度条根据实际证书时间计算 --------- Co-authored-by: greper <xiaojunnuo@qq.com>v2
parent
1476b9cb9c
commit
2d4586b1c4
|
@ -0,0 +1,5 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: greper
|
||||
buy_me_a_coffee: greper
|
||||
custom: ['https://afdian.com/a/greper']
|
|
@ -171,6 +171,7 @@ https://afdian.com/a/greper
|
|||
| 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署、宝塔、1Panel等大部分插件 | 群晖 |
|
||||
| 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、钉钉、飞书、anpush、server酱等 |
|
||||
|
||||
************************
|
||||
|
||||
************************
|
||||
|
||||
|
|
|
@ -134,6 +134,8 @@ You can also add the author as a friend.
|
|||
| QR Code | <img height="230" src="./docs/guide/contact/images/me.png"> |
|
||||
|
||||
## 8. Donation
|
||||
************************
|
||||
[](https://github.com/sponsors/greper)
|
||||
************************
|
||||
Support open-source projects and contribute with love. I've joined Afdian.
|
||||
https://afdian.com/a/greper
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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: "申请时间",
|
||||
|
|
|
@ -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 <span style={{ color: textColor }}>{`${leftDays}${t("certd.days")}`}</span>;
|
||||
};
|
||||
// console.log('cellRender', 'effectiveDays', effectiveDays, 'expiresTime', expiresTime, 'applyTime', applyTime, 'percent', percent, row)
|
||||
return <a-progress title={expireDate + t("certd.expires")} percent={percent} strokeColor={color} format={format} />;
|
||||
},
|
||||
},
|
||||
},
|
||||
effectiveTime: {
|
||||
title: t("certd.effectiveTime"),
|
||||
search: {
|
||||
show: false,
|
||||
},
|
||||
type: "datetime",
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
expiresTime: {
|
||||
title: t("certd.expireTime"),
|
||||
search: {
|
||||
|
|
|
@ -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 <a-progress title={expireDate + t("certd.monitor.expired")} percent={percent} strokeColor={color} format={(percent: number) => `${leftDays}${t("certd.monitor.days")}`} />;
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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 <span style={{ color: textColor }}>{`${leftDays}${t("certd.days")}`}</span>;
|
||||
};
|
||||
// console.log('cellRender', 'effectiveDays', effectiveDays, 'expiresTime', expiresTime, 'applyTime', applyTime, 'percent', percent, row)
|
||||
return <a-progress title={expireDate + t("certd.expires")} percent={percent} strokeColor={color} format={format} />;
|
||||
},
|
||||
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: {
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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: '上次检查时间' })
|
||||
|
|
|
@ -164,6 +164,7 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
|
|||
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
|
||||
|
|
|
@ -134,6 +134,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
|||
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<SiteInfoEntity> {
|
|||
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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue