Feat: Add Barebones certificate info display
This commit is contained in:
		
							parent
							
								
									d556509d07
								
							
						
					
					
						commit
						803f0d6219
					
				
					 4 changed files with 107 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -6,7 +6,7 @@ dayjs.extend(utc)
 | 
			
		|||
dayjs.extend(timezone)
 | 
			
		||||
const axios = require("axios");
 | 
			
		||||
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 {BeanModel} = require("redbean-node/dist/bean-model");
 | 
			
		||||
const {Notification} = require("../notification")
 | 
			
		||||
| 
						 | 
				
			
			@ -79,6 +79,9 @@ class Monitor extends BeanModel {
 | 
			
		|||
                    })
 | 
			
		||||
                    bean.msg = `${res.status} - ${res.statusText}`
 | 
			
		||||
                    bean.ping = dayjs().valueOf() - startTime;
 | 
			
		||||
                    if (this.url.startsWith("https")) {
 | 
			
		||||
                        Monitor.sendCertInfo(checkCertificate(res), io, this.id, this.user_id);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (this.type === "http") {
 | 
			
		||||
                        bean.status = UP;
 | 
			
		||||
| 
						 | 
				
			
			@ -218,6 +221,14 @@ class Monitor extends BeanModel {
 | 
			
		|||
        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
 | 
			
		||||
     * Calculation based on:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,3 +70,53 @@ exports.getSettings = async function (type) {
 | 
			
		|||
 | 
			
		||||
    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,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -25,6 +25,7 @@ export default {
 | 
			
		|||
            importantHeartbeatList: { },
 | 
			
		||||
            avgPingList: { },
 | 
			
		||||
            uptimeList: { },
 | 
			
		||||
            certInfoList: {},
 | 
			
		||||
            notificationList: [],
 | 
			
		||||
            windowWidth: window.innerWidth,
 | 
			
		||||
            showListMobile: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -114,6 +115,10 @@ export default {
 | 
			
		|||
            this.uptimeList[`${monitorID}_${type}`] = data
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        socket.on('certInfo', (monitorID, data) => {
 | 
			
		||||
            this.certInfoList[monitorID] = data
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        socket.on('importantHeartbeatList', (monitorID, data) => {
 | 
			
		||||
            if (! (monitorID in this.importantHeartbeatList)) {
 | 
			
		||||
                this.importantHeartbeatList[monitorID] = data;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,6 +54,38 @@
 | 
			
		|||
        </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">
 | 
			
		||||
        <table class="table table-borderless table-hover">
 | 
			
		||||
            <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() {
 | 
			
		||||
            const startIndex = this.perPage * (this.page - 1);
 | 
			
		||||
            const endIndex = startIndex + this.perPage;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue