diff --git a/server/model/monitor.js b/server/model/monitor.js index cdc9f5324..2848a0cb9 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -512,10 +512,16 @@ class Monitor extends BeanModel { } } - let tlsInfo; - // Store tlsInfo when key material is received - options.httpsAgent.on("keylog", (line, tlsSocket) => { - tlsInfo = checkCertificate(tlsSocket); + let tlsInfo = {}; + // Store tlsInfo when secureConnect event is emitted + // The keylog event listener is a workaround to access the tlsSocket + options.httpsAgent.once("keylog", async (line, tlsSocket) => { + tlsSocket.once("secureConnect", async () => { + tlsInfo = checkCertificate(tlsSocket); + tlsInfo.valid = tlsSocket.authorized || false; + + await this.handleTlsInfo(tlsInfo); + }); }); log.debug("monitor", `[${this.name}] Axios Options: ${JSON.stringify(options)}`); @@ -527,19 +533,16 @@ class Monitor extends BeanModel { bean.msg = `${res.status} - ${res.statusText}`; bean.ping = dayjs().valueOf() - startTime; - // Store certificate and check for expiry if https is used - if (this.getUrl()?.protocol === "https:") { - // No way to listen for the `secureConnection` event, so we do it here - const tlssocket = res.request.res.socket; + // fallback for if kelog event is not emitted, but we may still have tlsInfo, + // e.g. if the connection is made through a proxy + if (this.getUrl()?.protocol === "https:" && tlsInfo.valid === undefined) { + const tlsSocket = res.request.res.socket; - if (tlssocket) { - tlsInfo.valid = tlssocket.authorized || false; - } + if (tlsSocket) { + tlsInfo = checkCertificate(tlsSocket); + tlsInfo.valid = tlsSocket.authorized || false; - await this.updateTlsInfo(tlsInfo); - if (!this.getIgnoreTls() && this.isEnabledExpiryNotification()) { - log.debug("monitor", `[${this.name}] call checkCertExpiryNotifications`); - await this.checkCertExpiryNotifications(tlsInfo); + await this.handleTlsInfo(tlsInfo); } } @@ -1679,6 +1682,21 @@ class Monitor extends BeanModel { const parentActive = await Monitor.isParentActive(parent.id); return parent.active && parentActive; } + + /** + * Store TLS certificate information and check for expiry + * @param {Object} tlsInfo Information about the TLS connection + * @returns {Promise} + */ + async handleTlsInfo(tlsInfo) { + await this.updateTlsInfo(tlsInfo); + this.prometheus?.update(null, tlsInfo); + + if (!this.getIgnoreTls() && this.isEnabledExpiryNotification()) { + log.debug("monitor", `[${this.name}] call checkCertExpiryNotifications`); + await this.checkCertExpiryNotifications(tlsInfo); + } + } } module.exports = Monitor; diff --git a/server/prometheus.js b/server/prometheus.js index dd04394ae..fa7f60855 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -79,23 +79,25 @@ class Prometheus { } } - try { - monitorStatus.set(this.monitorLabelValues, heartbeat.status); - } catch (e) { - log.error("prometheus", "Caught error"); - log.error("prometheus", e); - } - - try { - if (typeof heartbeat.ping === "number") { - monitorResponseTime.set(this.monitorLabelValues, heartbeat.ping); - } else { - // Is it good? - monitorResponseTime.set(this.monitorLabelValues, -1); + if (heartbeat) { + try { + monitorStatus.set(this.monitorLabelValues, heartbeat.status); + } catch (e) { + log.error("prometheus", "Caught error"); + log.error("prometheus", e); + } + + try { + if (typeof heartbeat.ping === "number") { + monitorResponseTime.set(this.monitorLabelValues, heartbeat.ping); + } else { + // Is it good? + monitorResponseTime.set(this.monitorLabelValues, -1); + } + } catch (e) { + log.error("prometheus", "Caught error"); + log.error("prometheus", e); } - } catch (e) { - log.error("prometheus", "Caught error"); - log.error("prometheus", e); } }