Status page certificate expiry

This commit is contained in:
Tarun Singh 2023-07-04 19:37:45 -04:00
parent c583037dff
commit 4ea5771f97
8 changed files with 76 additions and 6 deletions

View file

@ -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;

View file

@ -72,6 +72,7 @@ class Database {
"patch-monitor-tls.sql": true, "patch-monitor-tls.sql": true,
"patch-maintenance-cron.sql": true, "patch-maintenance-cron.sql": true,
"patch-add-parent-monitor.sql": true, "patch-add-parent-monitor.sql": true,
"patch-add-certificate-expiry-status-page.sql": true,
}; };
/** /**

View file

@ -9,12 +9,12 @@ class Group extends BeanModel {
* @param {boolean} [showTags=false] Should the JSON include monitor tags * @param {boolean} [showTags=false] Should the JSON include monitor tags
* @returns {Object} * @returns {Object}
*/ */
async toPublicJSON(showTags = false) { async toPublicJSON(showTags = false, certExpiry = false) {
let monitorBeanList = await this.getMonitorList(); let monitorBeanList = await this.getMonitorList();
let monitorList = []; let monitorList = [];
for (let bean of monitorBeanList) { for (let bean of monitorBeanList) {
monitorList.push(await bean.toPublicJSON(showTags)); monitorList.push(await bean.toPublicJSON(showTags, certExpiry));
} }
return { return {

View file

@ -36,7 +36,7 @@ class Monitor extends BeanModel {
* Only show necessary data to public * Only show necessary data to public
* @returns {Object} * @returns {Object}
*/ */
async toPublicJSON(showTags = false) { async toPublicJSON(showTags = false, certExpiry = false) {
let obj = { let obj = {
id: this.id, id: this.id,
name: this.name, name: this.name,
@ -50,6 +50,13 @@ class Monitor extends BeanModel {
if (showTags) { if (showTags) {
obj.tags = await this.getTags(); obj.tags = await this.getTags();
} }
if (certExpiry) {
const { certExpiryDaysRemaining, validCert } = await this.getCertExpiry(this.id);
obj.certExpiryDaysRemaining = certExpiryDaysRemaining;
obj.validCert = validCert;
}
return obj; 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 ]); 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<LooseObject<any>>}
*/
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 * Encode user and password to Base64 encoding
* for HTTP "basic" auth, as per RFC-7617 * for HTTP "basic" auth, as per RFC-7617

View file

@ -90,6 +90,9 @@ class StatusPage extends BeanModel {
* @param {StatusPage} statusPage * @param {StatusPage} statusPage
*/ */
static async getStatusPageData(statusPage) { static async getStatusPageData(statusPage) {
const config = await statusPage.toPublicJSON();
// Incident // Incident
let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [ let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [
statusPage.id, statusPage.id,
@ -110,13 +113,13 @@ class StatusPage extends BeanModel {
]); ]);
for (let groupBean of list) { for (let groupBean of list) {
let monitorGroup = await groupBean.toPublicJSON(showTags); let monitorGroup = await groupBean.toPublicJSON(showTags, config?.showCertificateExpiry);
publicGroupList.push(monitorGroup); publicGroupList.push(monitorGroup);
} }
// Response // Response
return { return {
config: await statusPage.toPublicJSON(), config,
incident, incident,
publicGroupList, publicGroupList,
maintenanceList, maintenanceList,
@ -234,6 +237,7 @@ class StatusPage extends BeanModel {
footerText: this.footer_text, footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by, showPoweredBy: !!this.show_powered_by,
googleAnalyticsId: this.google_analytics_tag_id, googleAnalyticsId: this.google_analytics_tag_id,
showCertificateExpiry: !!this.show_certificate_expiry,
}; };
} }
@ -255,6 +259,7 @@ class StatusPage extends BeanModel {
footerText: this.footer_text, footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by, showPoweredBy: !!this.show_powered_by,
googleAnalyticsId: this.google_analytics_tag_id, googleAnalyticsId: this.google_analytics_tag_id,
showCertificateExpiry: !!this.show_certificate_expiry,
}; };
} }

View file

@ -162,6 +162,7 @@ module.exports.statusPageSocketHandler = (socket) => {
statusPage.footer_text = config.footerText; statusPage.footer_text = config.footerText;
statusPage.custom_css = config.customCSS; statusPage.custom_css = config.customCSS;
statusPage.show_powered_by = config.showPoweredBy; statusPage.show_powered_by = config.showPoweredBy;
statusPage.show_certificate_expiry = config.showCertificateExpiry;
statusPage.modified_date = R.isoDateTime(); statusPage.modified_date = R.isoDateTime();
statusPage.google_analytics_tag_id = config.googleAnalyticsId; statusPage.google_analytics_tag_id = config.googleAnalyticsId;

View file

@ -60,6 +60,7 @@
@click="$refs.monitorSettingDialog.show(group, monitor)" @click="$refs.monitorSettingDialog.show(group, monitor)"
/> />
</span> </span>
<p v-if="showCertificateExpiry" class="item-name"> Expiry: {{ formatExpiry(monitor) }} </p>
</div> </div>
<div v-if="showTags" class="tags"> <div v-if="showTags" class="tags">
<Tag v-for="tag in monitor.element.tags" :key="tag" :item="tag" :size="'sm'" /> <Tag v-for="tag in monitor.element.tags" :key="tag" :item="tag" :size="'sm'" />
@ -103,6 +104,10 @@ export default {
/** Should tags be shown? */ /** Should tags be shown? */
showTags: { showTags: {
type: Boolean, type: Boolean,
},
/** Should expiry be shown? */
showCertificateExpiry: {
type: Boolean,
} }
}, },
data() { data() {
@ -154,6 +159,19 @@ export default {
} }
return monitor.element.sendUrl && monitor.element.url && monitor.element.url !== "https://" && !this.editMode; 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;
}
},
} }
}; };
</script> </script>

View file

@ -54,6 +54,12 @@
<label class="form-check-label" for="show-powered-by">{{ $t("Show Powered By") }}</label> <label class="form-check-label" for="show-powered-by">{{ $t("Show Powered By") }}</label>
</div> </div>
<!-- Show certificate expiry -->
<div class="my-3 form-check form-switch">
<input id="show-certificate-expiry" v-model="config.showCertificateExpiry" class="form-check-input" type="checkbox">
<label class="form-check-label" for="show-certificate-expiry">{{ $t("Show Certificate Expiry") }}</label>
</div>
<div v-if="false" class="my-3"> <div v-if="false" class="my-3">
<label for="password" class="form-label">{{ $t("Password") }} <sup>{{ $t("Coming Soon") }}</sup></label> <label for="password" class="form-label">{{ $t("Password") }} <sup>{{ $t("Coming Soon") }}</sup></label>
<input id="password" v-model="config.password" disabled type="password" autocomplete="new-password" class="form-control"> <input id="password" v-model="config.password" disabled type="password" autocomplete="new-password" class="form-control">
@ -309,7 +315,7 @@
👀 {{ $t("statusPageNothing") }} 👀 {{ $t("statusPageNothing") }}
</div> </div>
<PublicGroupList :edit-mode="enableEditMode" :show-tags="config.showTags" /> <PublicGroupList :edit-mode="enableEditMode" :show-tags="config.showTags" :show-certificate-expiry="config.showCertificateExpiry" />
</div> </div>
<footer class="mt-5 mb-4"> <footer class="mt-5 mb-4">