Feat: Add Barebones certificate info display

This commit is contained in:
Nelson Chan 2021-07-21 12:09:09 +08:00
parent d556509d07
commit 803f0d6219
4 changed files with 107 additions and 1 deletions

View File

@ -6,7 +6,7 @@ dayjs.extend(utc)
dayjs.extend(timezone) dayjs.extend(timezone)
const axios = require("axios"); const axios = require("axios");
const {UP, DOWN, PENDING} = require("../util"); const {UP, DOWN, PENDING} = require("../util");
const {tcping, ping} = require("../util-server"); const {tcping, ping, checkCertificate} = require("../util-server");
const {R} = require("redbean-node"); const {R} = require("redbean-node");
const {BeanModel} = require("redbean-node/dist/bean-model"); const {BeanModel} = require("redbean-node/dist/bean-model");
const {Notification} = require("../notification") const {Notification} = require("../notification")
@ -79,6 +79,9 @@ class Monitor extends BeanModel {
}) })
bean.msg = `${res.status} - ${res.statusText}` bean.msg = `${res.status} - ${res.statusText}`
bean.ping = dayjs().valueOf() - startTime; bean.ping = dayjs().valueOf() - startTime;
if (this.url.startsWith("https")) {
Monitor.sendCertInfo(checkCertificate(res), io, this.id, this.user_id);
}
if (this.type === "http") { if (this.type === "http") {
bean.status = UP; bean.status = UP;
@ -218,6 +221,14 @@ class Monitor extends BeanModel {
io.to(userID).emit("avgPing", monitorID, avgPing); io.to(userID).emit("avgPing", monitorID, avgPing);
} }
/**
*
* @param checkCertificateResult : Object return result of checkCertificate
*/
static async sendCertInfo(checkCertificateResult, io, monitorID, userID) {
io.to(userID).emit("certInfo", monitorID, checkCertificateResult);
}
/** /**
* Uptime with calculation * Uptime with calculation
* Calculation based on: * Calculation based on:

View File

@ -70,3 +70,53 @@ exports.getSettings = async function (type) {
return result; return result;
} }
// ssl-checker by @dyaa
// param: res - response object from axios
// return an object containing the certificate information
const getDaysBetween = (validFrom, validTo) =>
Math.round(Math.abs(+validFrom - +validTo) / 8.64e7);
const getDaysRemaining = (validFrom, validTo) => {
const daysRemaining = getDaysBetween(validFrom, validTo);
if (new Date(validTo).getTime() < new Date().getTime()) {
return -daysRemaining;
}
return daysRemaining;
};
exports.checkCertificate = function (res) {
const {
valid_from,
valid_to,
subjectaltname,
issuer,
fingerprint,
} = res.request.res.socket.getPeerCertificate(false);
if (!valid_from || !valid_to || !subjectaltname) {
reject(new Error('No certificate'));
return;
}
const valid = res.request.res.socket.authorized || false;
const validTo = new Date(valid_to);
const validFor = subjectaltname
.replace(/DNS:|IP Address:/g, "")
.split(", ");
const daysRemaining = getDaysRemaining(new Date(), validTo);
return {
valid,
validFor,
validTo,
daysRemaining,
issuer,
fingerprint,
};
}

View File

@ -25,6 +25,7 @@ export default {
importantHeartbeatList: { }, importantHeartbeatList: { },
avgPingList: { }, avgPingList: { },
uptimeList: { }, uptimeList: { },
certInfoList: {},
notificationList: [], notificationList: [],
windowWidth: window.innerWidth, windowWidth: window.innerWidth,
showListMobile: false, showListMobile: false,
@ -114,6 +115,10 @@ export default {
this.uptimeList[`${monitorID}_${type}`] = data this.uptimeList[`${monitorID}_${type}`] = data
}); });
socket.on('certInfo', (monitorID, data) => {
this.certInfoList[monitorID] = data
});
socket.on('importantHeartbeatList', (monitorID, data) => { socket.on('importantHeartbeatList', (monitorID, data) => {
if (! (monitorID in this.importantHeartbeatList)) { if (! (monitorID in this.importantHeartbeatList)) {
this.importantHeartbeatList[monitorID] = data; this.importantHeartbeatList[monitorID] = data;

View File

@ -54,6 +54,38 @@
</div> </div>
</div> </div>
<div class="shadow-box big-padding text-center stats" v-if="monitor.type === 'http' && monitor.url.startsWith('https') && certInfo != null">
<div class="row">
<div class="col">
<h4>Certificate Info</h4>
<table class="text-start">
<tbody>
<tr class="my-3">
<td class="px-3">Valid: </td>
<td>{{ certInfo.valid }}</td>
</tr>
<tr class="my-3">
<td class="px-3">Valid To: </td>
<td>{{ certInfo.validTo ? new Date(certInfo.validTo).toLocaleString() : "" }}</td>
</tr>
<tr class="my-3">
<td class="px-3">Days Remaining: </td>
<td>{{ certInfo.daysRemaining }}</td>
</tr>
<tr class="my-3">
<td class="px-3">Issuer: </td>
<td>{{ certInfo.issuer }}</td>
</tr>
<tr class="my-3">
<td class="px-3">Fingerprint: </td>
<td>{{ certInfo.fingerprint }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="shadow-box"> <div class="shadow-box">
<table class="table table-borderless table-hover"> <table class="table table-borderless table-hover">
<thead> <thead>
@ -180,6 +212,14 @@ export default {
} }
}, },
certInfo() {
if (this.$root.certInfoList[this.monitor.id]) {
return this.$root.certInfoList[this.monitor.id]
} else {
return { }
}
},
displayedRecords() { displayedRecords() {
const startIndex = this.perPage * (this.page - 1); const startIndex = this.perPage * (this.page - 1);
const endIndex = startIndex + this.perPage; const endIndex = startIndex + this.perPage;