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-monitor-push_token.sql": true, | ||||||
|         "patch-http-monitor-method-body-and-headers.sql": true, |         "patch-http-monitor-method-body-and-headers.sql": true, | ||||||
|         "patch-2fa-invalidate-used-token.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", |         name: "clear-old-data", | ||||||
|         interval: "at 03:14", |         interval: "at 03:14", | ||||||
|     } |     }, | ||||||
| ]; | ]; | ||||||
|  |  | ||||||
| const initBackgroundJobs = function (args) { | const initBackgroundJobs = function (args) { | ||||||
|   | |||||||
| @@ -168,7 +168,14 @@ class Monitor extends BeanModel { | |||||||
|                     let certInfoStartTime = dayjs().valueOf(); |                     let certInfoStartTime = dayjs().valueOf(); | ||||||
|                     if (this.getUrl()?.protocol === "https:") { |                     if (this.getUrl()?.protocol === "https:") { | ||||||
|                         try { |                         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) { |                         } catch (e) { | ||||||
|                             if (e.message !== "No TLS certificate in response") { |                             if (e.message !== "No TLS certificate in response") { | ||||||
|                                 console.error(e.message); |                                 console.error(e.message); | ||||||
| @@ -444,10 +451,36 @@ class Monitor extends BeanModel { | |||||||
|         let tls_info_bean = await R.findOne("monitor_tls_info", "monitor_id = ?", [ |         let tls_info_bean = await R.findOne("monitor_tls_info", "monitor_id = ?", [ | ||||||
|             this.id, |             this.id, | ||||||
|         ]); |         ]); | ||||||
|  |  | ||||||
|         if (tls_info_bean == null) { |         if (tls_info_bean == null) { | ||||||
|             tls_info_bean = R.dispense("monitor_tls_info"); |             tls_info_bean = R.dispense("monitor_tls_info"); | ||||||
|             tls_info_bean.monitor_id = this.id; |             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); |         tls_info_bean.info_json = JSON.stringify(checkCertificateResult); | ||||||
|         await R.store(tls_info_bean); |         await R.store(tls_info_bean); | ||||||
|  |  | ||||||
| @@ -595,9 +628,7 @@ class Monitor extends BeanModel { | |||||||
|  |  | ||||||
|     static async sendNotification(isFirstBeat, monitor, bean) { |     static async sendNotification(isFirstBeat, monitor, bean) { | ||||||
|         if (!isFirstBeat || bean.status === DOWN) { |         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 ", [ |             const notificationList = await Monitor.getNotificationList(monitor); | ||||||
|                 monitor.id, |  | ||||||
|             ]); |  | ||||||
|  |  | ||||||
|             let text; |             let text; | ||||||
|             if (bean.status === UP) { |             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; | module.exports = Monitor; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user