mirror of
				https://github.com/louislam/uptime-kuma.git
				synced 2025-11-01 03:49:24 +08:00 
			
		
		
		
	Merge pull request #781 from louislam/cert-notification
Certificate renewal notifications
This commit is contained in:
		
							
								
								
									
										18
									
								
								db/patch-notification_sent_history.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								db/patch-notification_sent_history.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| -- You should not modify if this have pushed to Github, unless it does serious wrong with the db. | ||||
| BEGIN TRANSACTION; | ||||
|  | ||||
| CREATE TABLE [notification_sent_history] ( | ||||
|     [id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, | ||||
|     [type] VARCHAR(50) NOT NULL, | ||||
|     [monitor_id] INTEGER NOT NULL, | ||||
|     [days] INTEGER NOT NULL, | ||||
|     UNIQUE([type], [monitor_id], [days]) | ||||
| ); | ||||
|  | ||||
| CREATE INDEX [good_index] ON [notification_sent_history] ( | ||||
|     [type], | ||||
|     [monitor_id], | ||||
|     [days] | ||||
| ); | ||||
|  | ||||
| COMMIT; | ||||
| @@ -51,6 +51,7 @@ class Database { | ||||
|         "patch-monitor-push_token.sql": true, | ||||
|         "patch-http-monitor-method-body-and-headers.sql": true, | ||||
|         "patch-2fa-invalidate-used-token.sql": true, | ||||
|         "patch-notification_sent_history.sql": true, | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -6,7 +6,7 @@ const jobs = [ | ||||
|     { | ||||
|         name: "clear-old-data", | ||||
|         interval: "at 03:14", | ||||
|     } | ||||
|     }, | ||||
| ]; | ||||
|  | ||||
| const initBackgroundJobs = function (args) { | ||||
|   | ||||
| @@ -168,7 +168,14 @@ class Monitor extends BeanModel { | ||||
|                     let certInfoStartTime = dayjs().valueOf(); | ||||
|                     if (this.getUrl()?.protocol === "https:") { | ||||
|                         try { | ||||
|                             tlsInfo = await this.updateTlsInfo(checkCertificate(res)); | ||||
|                             let tlsInfoObject = checkCertificate(res); | ||||
|                             tlsInfo = await this.updateTlsInfo(tlsInfoObject); | ||||
|  | ||||
|                             if (!this.getIgnoreTls()) { | ||||
|                                 debug("call sendCertNotification"); | ||||
|                                 await this.sendCertNotification(tlsInfoObject); | ||||
|                             } | ||||
|  | ||||
|                         } catch (e) { | ||||
|                             if (e.message !== "No TLS certificate in response") { | ||||
|                                 console.error(e.message); | ||||
| @@ -444,10 +451,36 @@ class Monitor extends BeanModel { | ||||
|         let tls_info_bean = await R.findOne("monitor_tls_info", "monitor_id = ?", [ | ||||
|             this.id, | ||||
|         ]); | ||||
|  | ||||
|         if (tls_info_bean == null) { | ||||
|             tls_info_bean = R.dispense("monitor_tls_info"); | ||||
|             tls_info_bean.monitor_id = this.id; | ||||
|         } else { | ||||
|  | ||||
|             // Clear sent history if the cert changed. | ||||
|             try { | ||||
|                 let oldCertInfo = JSON.parse(tls_info_bean.info_json); | ||||
|  | ||||
|                 let isValidObjects = oldCertInfo && oldCertInfo.certInfo && checkCertificateResult && checkCertificateResult.certInfo; | ||||
|  | ||||
|                 if (isValidObjects) { | ||||
|                     if (oldCertInfo.certInfo.fingerprint256 !== checkCertificateResult.certInfo.fingerprint256) { | ||||
|                         debug("Resetting sent_history"); | ||||
|                         await R.exec("DELETE FROM notification_sent_history WHERE type = 'certificate' AND monitor_id = ?", [ | ||||
|                             this.id | ||||
|                         ]); | ||||
|                     } else { | ||||
|                         debug("No need to reset sent_history"); | ||||
|                         debug(oldCertInfo.certInfo.fingerprint256); | ||||
|                         debug(checkCertificateResult.certInfo.fingerprint256); | ||||
|                     } | ||||
|                 } else { | ||||
|                     debug("Not valid object"); | ||||
|                 } | ||||
|             } catch (e) { } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         tls_info_bean.info_json = JSON.stringify(checkCertificateResult); | ||||
|         await R.store(tls_info_bean); | ||||
|  | ||||
| @@ -595,9 +628,7 @@ class Monitor extends BeanModel { | ||||
|  | ||||
|     static async sendNotification(isFirstBeat, monitor, bean) { | ||||
|         if (!isFirstBeat || bean.status === DOWN) { | ||||
|             let notificationList = await R.getAll("SELECT notification.* FROM notification, monitor_notification WHERE monitor_id = ? AND monitor_notification.notification_id = notification.id ", [ | ||||
|                 monitor.id, | ||||
|             ]); | ||||
|             const notificationList = await Monitor.getNotificationList(monitor); | ||||
|  | ||||
|             let text; | ||||
|             if (bean.status === UP) { | ||||
| @@ -619,6 +650,70 @@ class Monitor extends BeanModel { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     static async getNotificationList(monitor) { | ||||
|         let notificationList = await R.getAll("SELECT notification.* FROM notification, monitor_notification WHERE monitor_id = ? AND monitor_notification.notification_id = notification.id ", [ | ||||
|             monitor.id, | ||||
|         ]); | ||||
|         return notificationList; | ||||
|     } | ||||
|  | ||||
|     async sendCertNotification(tlsInfoObject) { | ||||
|         if (tlsInfoObject && tlsInfoObject.certInfo && tlsInfoObject.certInfo.daysRemaining) { | ||||
|             const notificationList = await Monitor.getNotificationList(this); | ||||
|  | ||||
|             debug("call sendCertNotificationByTargetDays"); | ||||
|             await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 21, notificationList); | ||||
|             await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 14, notificationList); | ||||
|             await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 7, notificationList); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async sendCertNotificationByTargetDays(daysRemaining, targetDays, notificationList) { | ||||
|  | ||||
|         if (daysRemaining > targetDays) { | ||||
|             debug(`No need to send cert notification. ${daysRemaining} > ${targetDays}`); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (notificationList.length > 0) { | ||||
|  | ||||
|             let row = await R.getRow("SELECT * FROM notification_sent_history WHERE type = ? AND monitor_id = ? AND days = ?", [ | ||||
|                 "certificate", | ||||
|                 this.id, | ||||
|                 targetDays, | ||||
|             ]); | ||||
|  | ||||
|             // Sent already, no need to send again | ||||
|             if (row) { | ||||
|                 debug("Sent already, no need to send again"); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             let sent = false; | ||||
|             debug("Send certificate notification"); | ||||
|  | ||||
|             for (let notification of notificationList) { | ||||
|                 try { | ||||
|                     debug("Sending to " + notification.name); | ||||
|                     await Notification.send(JSON.parse(notification.config), `[${this.name}][${this.url}] Certificate will be expired in ${daysRemaining} days`); | ||||
|                     sent = true; | ||||
|                 } catch (e) { | ||||
|                     console.error("Cannot send cert notification to " + notification.name); | ||||
|                     console.error(e); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (sent) { | ||||
|                 await R.exec("INSERT INTO notification_sent_history (type, monitor_id, days) VALUES(?, ?, ?)", [ | ||||
|                     "certificate", | ||||
|                     this.id, | ||||
|                     targetDays, | ||||
|                 ]); | ||||
|             } | ||||
|         } else { | ||||
|             debug("No notification, no need to send cert notification"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| module.exports = Monitor; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user