From 4ea5771f9795edd44cef4b1698c31b635e52e872 Mon Sep 17 00:00:00 2001 From: Tarun Singh Date: Tue, 4 Jul 2023 19:37:45 -0400 Subject: [PATCH] Status page certificate expiry --- ...tch-add-certificate-expiry-status-page.sql | 7 ++++ server/database.js | 1 + server/model/group.js | 4 +-- server/model/monitor.js | 34 ++++++++++++++++++- server/model/status_page.js | 9 +++-- .../status-page-socket-handler.js | 1 + src/components/PublicGroupList.vue | 18 ++++++++++ src/pages/StatusPage.vue | 8 ++++- 8 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 db/patch-add-certificate-expiry-status-page.sql diff --git a/db/patch-add-certificate-expiry-status-page.sql b/db/patch-add-certificate-expiry-status-page.sql new file mode 100644 index 000000000..63a20105b --- /dev/null +++ b/db/patch-add-certificate-expiry-status-page.sql @@ -0,0 +1,7 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE status_page + ADD show_certificate_expiry BOOLEAN default 0 NOT NULL; + +COMMIT; diff --git a/server/database.js b/server/database.js index a8e486894..7a8d268f6 100644 --- a/server/database.js +++ b/server/database.js @@ -72,6 +72,7 @@ class Database { "patch-monitor-tls.sql": true, "patch-maintenance-cron.sql": true, "patch-add-parent-monitor.sql": true, + "patch-add-certificate-expiry-status-page.sql": true, }; /** diff --git a/server/model/group.js b/server/model/group.js index 3f3b3b129..5b712aceb 100644 --- a/server/model/group.js +++ b/server/model/group.js @@ -9,12 +9,12 @@ class Group extends BeanModel { * @param {boolean} [showTags=false] Should the JSON include monitor tags * @returns {Object} */ - async toPublicJSON(showTags = false) { + async toPublicJSON(showTags = false, certExpiry = false) { let monitorBeanList = await this.getMonitorList(); let monitorList = []; for (let bean of monitorBeanList) { - monitorList.push(await bean.toPublicJSON(showTags)); + monitorList.push(await bean.toPublicJSON(showTags, certExpiry)); } return { diff --git a/server/model/monitor.js b/server/model/monitor.js index 27e2bcdf7..ed9505ba9 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -36,7 +36,7 @@ class Monitor extends BeanModel { * Only show necessary data to public * @returns {Object} */ - async toPublicJSON(showTags = false) { + async toPublicJSON(showTags = false, certExpiry = false) { let obj = { id: this.id, name: this.name, @@ -50,6 +50,13 @@ class Monitor extends BeanModel { if (showTags) { obj.tags = await this.getTags(); } + + if (certExpiry) { + const { certExpiryDaysRemaining, validCert } = await this.getCertExpiry(this.id); + obj.certExpiryDaysRemaining = certExpiryDaysRemaining; + obj.validCert = validCert; + } + return obj; } @@ -174,6 +181,31 @@ class Monitor extends BeanModel { return await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ? ORDER BY tag.name", [ this.id ]); } + /** + * Gets certificate expiry for this monitor + * @param {number} monitorID ID of monitor to send + * @returns {Promise>} + */ + async getCertExpiry(monitorID) { + let tlsInfoBean = await R.findOne("monitor_tls_info", "monitor_id = ?", [ + monitorID, + ]); + let tlsInfo; + if (tlsInfoBean) { + tlsInfo = JSON.parse(tlsInfoBean?.info_json); + if (tlsInfo?.valid && tlsInfo?.certInfo?.daysRemaining) { + return { + certExpiryDaysRemaining: tlsInfo.certInfo.daysRemaining, + validCert: true + }; + } + } + return { + certExpiryDaysRemaining: "No/Bad Cert", + validCert: false + }; + } + /** * Encode user and password to Base64 encoding * for HTTP "basic" auth, as per RFC-7617 diff --git a/server/model/status_page.js b/server/model/status_page.js index 65b77367e..e69441328 100644 --- a/server/model/status_page.js +++ b/server/model/status_page.js @@ -90,6 +90,9 @@ class StatusPage extends BeanModel { * @param {StatusPage} statusPage */ static async getStatusPageData(statusPage) { + + const config = await statusPage.toPublicJSON(); + // Incident let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [ statusPage.id, @@ -110,13 +113,13 @@ class StatusPage extends BeanModel { ]); for (let groupBean of list) { - let monitorGroup = await groupBean.toPublicJSON(showTags); + let monitorGroup = await groupBean.toPublicJSON(showTags, config?.showCertificateExpiry); publicGroupList.push(monitorGroup); } // Response return { - config: await statusPage.toPublicJSON(), + config, incident, publicGroupList, maintenanceList, @@ -234,6 +237,7 @@ class StatusPage extends BeanModel { footerText: this.footer_text, showPoweredBy: !!this.show_powered_by, googleAnalyticsId: this.google_analytics_tag_id, + showCertificateExpiry: !!this.show_certificate_expiry, }; } @@ -255,6 +259,7 @@ class StatusPage extends BeanModel { footerText: this.footer_text, showPoweredBy: !!this.show_powered_by, googleAnalyticsId: this.google_analytics_tag_id, + showCertificateExpiry: !!this.show_certificate_expiry, }; } diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js index 411bda556..eba40daec 100644 --- a/server/socket-handlers/status-page-socket-handler.js +++ b/server/socket-handlers/status-page-socket-handler.js @@ -162,6 +162,7 @@ module.exports.statusPageSocketHandler = (socket) => { statusPage.footer_text = config.footerText; statusPage.custom_css = config.customCSS; statusPage.show_powered_by = config.showPoweredBy; + statusPage.show_certificate_expiry = config.showCertificateExpiry; statusPage.modified_date = R.isoDateTime(); statusPage.google_analytics_tag_id = config.googleAnalyticsId; diff --git a/src/components/PublicGroupList.vue b/src/components/PublicGroupList.vue index 00f38c5b9..3f93d8a5b 100644 --- a/src/components/PublicGroupList.vue +++ b/src/components/PublicGroupList.vue @@ -60,6 +60,7 @@ @click="$refs.monitorSettingDialog.show(group, monitor)" /> +

Expiry: {{ formatExpiry(monitor) }}

@@ -103,6 +104,10 @@ export default { /** Should tags be shown? */ showTags: { type: Boolean, + }, + /** Should expiry be shown? */ + showCertificateExpiry: { + type: Boolean, } }, data() { @@ -154,6 +159,19 @@ export default { } return monitor.element.sendUrl && monitor.element.url && monitor.element.url !== "https://" && !this.editMode; }, + + /** + * Returns formatted certificate expiry or Bad cert message + * @param {Object} monitor Monitor to show expiry for + * @returns {string} + */ + formatExpiry(monitor) { + if (monitor?.element?.validCert) { + return monitor.element.certExpiryDaysRemaining + " days"; + } else { + return monitor.element.certExpiryDaysRemaining; + } + }, } }; diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue index ca684a1a0..2f86ab173 100644 --- a/src/pages/StatusPage.vue +++ b/src/pages/StatusPage.vue @@ -54,6 +54,12 @@
+ +
+ + +
+
@@ -309,7 +315,7 @@ 👀 {{ $t("statusPageNothing") }}
- +