mirror of
				https://github.com/louislam/uptime-kuma.git
				synced 2025-10-25 07:39:22 +08:00 
			
		
		
		
	introduce consistent logging
This commit is contained in:
		| @@ -2,7 +2,6 @@ const basicAuth = require("express-basic-auth"); | |||||||
| const passwordHash = require("./password-hash"); | const passwordHash = require("./password-hash"); | ||||||
| const { R } = require("redbean-node"); | const { R } = require("redbean-node"); | ||||||
| const { setting } = require("./util-server"); | const { setting } = require("./util-server"); | ||||||
| const { debug } = require("../src/util"); |  | ||||||
| const { loginRateLimiter } = require("./rate-limiter"); | const { loginRateLimiter } = require("./rate-limiter"); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| const fs = require("fs"); | const fs = require("fs"); | ||||||
| const { R } = require("redbean-node"); | const { R } = require("redbean-node"); | ||||||
| const { setSetting, setting } = require("./util-server"); | const { setSetting, setting } = require("./util-server"); | ||||||
| const { debug, sleep } = require("../src/util"); | const { log, sleep } = require("../src/util"); | ||||||
| const dayjs = require("dayjs"); | const dayjs = require("dayjs"); | ||||||
| const knex = require("knex"); | const knex = require("knex"); | ||||||
|  |  | ||||||
| @@ -76,7 +76,7 @@ class Database { | |||||||
|             fs.mkdirSync(Database.uploadDir, { recursive: true }); |             fs.mkdirSync(Database.uploadDir, { recursive: true }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         console.log(`Data Dir: ${Database.dataDir}`); |         log("db", `Data Dir: ${Database.dataDir}`); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static async connect() { |     static async connect() { | ||||||
| @@ -117,10 +117,10 @@ class Database { | |||||||
|         await R.exec("PRAGMA cache_size = -12000"); |         await R.exec("PRAGMA cache_size = -12000"); | ||||||
|         await R.exec("PRAGMA auto_vacuum = FULL"); |         await R.exec("PRAGMA auto_vacuum = FULL"); | ||||||
|  |  | ||||||
|         console.log("SQLite config:"); |         log("db", "SQLite config:"); | ||||||
|         console.log(await R.getAll("PRAGMA journal_mode")); |         log("db", await R.getAll("PRAGMA journal_mode")); | ||||||
|         console.log(await R.getAll("PRAGMA cache_size")); |         log("db", await R.getAll("PRAGMA cache_size")); | ||||||
|         console.log("SQLite Version: " + await R.getCell("SELECT sqlite_version()")); |         log("db","SQLite Version: " + await R.getCell("SELECT sqlite_version()")); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static async patch() { |     static async patch() { | ||||||
| @@ -130,15 +130,15 @@ class Database { | |||||||
|             version = 0; |             version = 0; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         console.info("Your database version: " + version); |         log("db", "Your database version: " + version); | ||||||
|         console.info("Latest database version: " + this.latestVersion); |         log("db", "Latest database version: " + this.latestVersion); | ||||||
|  |  | ||||||
|         if (version === this.latestVersion) { |         if (version === this.latestVersion) { | ||||||
|             console.info("Database patch not needed"); |             log("db", "Database patch not needed"); | ||||||
|         } else if (version > this.latestVersion) { |         } else if (version > this.latestVersion) { | ||||||
|             console.info("Warning: Database version is newer than expected"); |             log("db", "Warning: Database version is newer than expected"); | ||||||
|         } else { |         } else { | ||||||
|             console.info("Database patch is needed"); |             log("db", "Database patch is needed"); | ||||||
|  |  | ||||||
|             this.backup(version); |             this.backup(version); | ||||||
|  |  | ||||||
| @@ -146,17 +146,17 @@ class Database { | |||||||
|             try { |             try { | ||||||
|                 for (let i = version + 1; i <= this.latestVersion; i++) { |                 for (let i = version + 1; i <= this.latestVersion; i++) { | ||||||
|                     const sqlFile = `./db/patch${i}.sql`; |                     const sqlFile = `./db/patch${i}.sql`; | ||||||
|                     console.info(`Patching ${sqlFile}`); |                     log("db", `Patching ${sqlFile}`); | ||||||
|                     await Database.importSQLFile(sqlFile); |                     await Database.importSQLFile(sqlFile); | ||||||
|                     console.info(`Patched ${sqlFile}`); |                     log("db", `Patched ${sqlFile}`); | ||||||
|                     await setSetting("database_version", i); |                     await setSetting("database_version", i); | ||||||
|                 } |                 } | ||||||
|             } catch (ex) { |             } catch (ex) { | ||||||
|                 await Database.close(); |                 await Database.close(); | ||||||
|  |  | ||||||
|                 console.error(ex); |                 log("db", ex, "error"); | ||||||
|                 console.error("Start Uptime-Kuma failed due to issue patching the database"); |                 log("db", "Start Uptime-Kuma failed due to issue patching the database", "error"); | ||||||
|                 console.error("Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); |                 log("db", "Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues", "error"); | ||||||
|  |  | ||||||
|                 this.restore(); |                 this.restore(); | ||||||
|                 process.exit(1); |                 process.exit(1); | ||||||
| @@ -171,15 +171,15 @@ class Database { | |||||||
|      * @returns {Promise<void>} |      * @returns {Promise<void>} | ||||||
|      */ |      */ | ||||||
|     static async patch2() { |     static async patch2() { | ||||||
|         console.log("Database Patch 2.0 Process"); |         log("db", "Database Patch 2.0 Process"); | ||||||
|         let databasePatchedFiles = await setting("databasePatchedFiles"); |         let databasePatchedFiles = await setting("databasePatchedFiles"); | ||||||
|  |  | ||||||
|         if (! databasePatchedFiles) { |         if (! databasePatchedFiles) { | ||||||
|             databasePatchedFiles = {}; |             databasePatchedFiles = {}; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         debug("Patched files:"); |         log("db", "Patched files:", "debug"); | ||||||
|         debug(databasePatchedFiles); |         log("db", databasePatchedFiles, "debug"); | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             for (let sqlFilename in this.patchList) { |             for (let sqlFilename in this.patchList) { | ||||||
| @@ -187,15 +187,15 @@ class Database { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (this.patched) { |             if (this.patched) { | ||||||
|                 console.log("Database Patched Successfully"); |                 log("db", "Database Patched Successfully"); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|         } catch (ex) { |         } catch (ex) { | ||||||
|             await Database.close(); |             await Database.close(); | ||||||
|  |  | ||||||
|             console.error(ex); |             log("db", ex, "error"); | ||||||
|             console.error("Start Uptime-Kuma failed due to issue patching the database"); |             log("db", "Start Uptime-Kuma failed due to issue patching the database", "error"); | ||||||
|             console.error("Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); |             log("db", "Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues", "error"); | ||||||
|  |  | ||||||
|             this.restore(); |             this.restore(); | ||||||
|  |  | ||||||
| @@ -214,16 +214,16 @@ class Database { | |||||||
|         let value = this.patchList[sqlFilename]; |         let value = this.patchList[sqlFilename]; | ||||||
|  |  | ||||||
|         if (! value) { |         if (! value) { | ||||||
|             console.log(sqlFilename + " skip"); |             log("db", sqlFilename + " skip"); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Check if patched |         // Check if patched | ||||||
|         if (! databasePatchedFiles[sqlFilename]) { |         if (! databasePatchedFiles[sqlFilename]) { | ||||||
|             console.log(sqlFilename + " is not patched"); |             log("db", sqlFilename + " is not patched"); | ||||||
|  |  | ||||||
|             if (value.parents) { |             if (value.parents) { | ||||||
|                 console.log(sqlFilename + " need parents"); |                 log("db", sqlFilename + " need parents"); | ||||||
|                 for (let parentSQLFilename of value.parents) { |                 for (let parentSQLFilename of value.parents) { | ||||||
|                     await this.patch2Recursion(parentSQLFilename, databasePatchedFiles); |                     await this.patch2Recursion(parentSQLFilename, databasePatchedFiles); | ||||||
|                 } |                 } | ||||||
| @@ -231,14 +231,14 @@ class Database { | |||||||
|  |  | ||||||
|             this.backup(dayjs().format("YYYYMMDDHHmmss")); |             this.backup(dayjs().format("YYYYMMDDHHmmss")); | ||||||
|  |  | ||||||
|             console.log(sqlFilename + " is patching"); |             log("db", sqlFilename + " is patching"); | ||||||
|             this.patched = true; |             this.patched = true; | ||||||
|             await this.importSQLFile("./db/" + sqlFilename); |             await this.importSQLFile("./db/" + sqlFilename); | ||||||
|             databasePatchedFiles[sqlFilename] = true; |             databasePatchedFiles[sqlFilename] = true; | ||||||
|             console.log(sqlFilename + " was patched successfully"); |             log("db", sqlFilename + " was patched successfully"); | ||||||
|  |  | ||||||
|         } else { |         } else { | ||||||
|             debug(sqlFilename + " is already patched, skip"); |             log("db", sqlFilename + " is already patched, skip", "debug"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -290,7 +290,7 @@ class Database { | |||||||
|         }; |         }; | ||||||
|         process.addListener("unhandledRejection", listener); |         process.addListener("unhandledRejection", listener); | ||||||
|  |  | ||||||
|         console.log("Closing the database"); |         log("db", "Closing the database"); | ||||||
|  |  | ||||||
|         while (true) { |         while (true) { | ||||||
|             Database.noReject = true; |             Database.noReject = true; | ||||||
| @@ -300,10 +300,10 @@ class Database { | |||||||
|             if (Database.noReject) { |             if (Database.noReject) { | ||||||
|                 break; |                 break; | ||||||
|             } else { |             } else { | ||||||
|                 console.log("Waiting to close the database"); |                 log("db", "Waiting to close the database"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         console.log("SQLite closed"); |         log("db", "SQLite closed"); | ||||||
|  |  | ||||||
|         process.removeListener("unhandledRejection", listener); |         process.removeListener("unhandledRejection", listener); | ||||||
|     } |     } | ||||||
| @@ -315,7 +315,7 @@ class Database { | |||||||
|      */ |      */ | ||||||
|     static backup(version) { |     static backup(version) { | ||||||
|         if (! this.backupPath) { |         if (! this.backupPath) { | ||||||
|             console.info("Backing up the database"); |             log("db", "Backing up the database"); | ||||||
|             this.backupPath = this.dataDir + "kuma.db.bak" + version; |             this.backupPath = this.dataDir + "kuma.db.bak" + version; | ||||||
|             fs.copyFileSync(Database.path, this.backupPath); |             fs.copyFileSync(Database.path, this.backupPath); | ||||||
|  |  | ||||||
| @@ -338,7 +338,7 @@ class Database { | |||||||
|      */ |      */ | ||||||
|     static restore() { |     static restore() { | ||||||
|         if (this.backupPath) { |         if (this.backupPath) { | ||||||
|             console.error("Patching the database failed!!! Restoring the backup"); |             log("db", "Patching the database failed!!! Restoring the backup", "error"); | ||||||
|  |  | ||||||
|             const shmPath = Database.path + "-shm"; |             const shmPath = Database.path + "-shm"; | ||||||
|             const walPath = Database.path + "-wal"; |             const walPath = Database.path + "-wal"; | ||||||
| @@ -357,7 +357,7 @@ class Database { | |||||||
|                     fs.unlinkSync(walPath); |                     fs.unlinkSync(walPath); | ||||||
|                 } |                 } | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 console.log("Restore failed; you may need to restore the backup manually"); |                 log("db", "Restore failed; you may need to restore the backup manually", "error"); | ||||||
|                 process.exit(1); |                 process.exit(1); | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -373,14 +373,14 @@ class Database { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|         } else { |         } else { | ||||||
|             console.log("Nothing to restore"); |             log("db", "Nothing to restore"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static getSize() { |     static getSize() { | ||||||
|         debug("Database.getSize()"); |         log("db", "Database.getSize()", "debug"); | ||||||
|         let stats = fs.statSync(Database.path); |         let stats = fs.statSync(Database.path); | ||||||
|         debug(stats); |         log("db", stats, "debug"); | ||||||
|         return stats.size; |         return stats.size; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,12 +3,13 @@ | |||||||
|     Modified with 0 dependencies |     Modified with 0 dependencies | ||||||
|  */ |  */ | ||||||
| let fs = require("fs"); | let fs = require("fs"); | ||||||
|  | const { log } = require("../src/util"); | ||||||
|  |  | ||||||
| let ImageDataURI = (() => { | let ImageDataURI = (() => { | ||||||
|  |  | ||||||
|     function decode(dataURI) { |     function decode(dataURI) { | ||||||
|         if (!/data:image\//.test(dataURI)) { |         if (!/data:image\//.test(dataURI)) { | ||||||
|             console.log("ImageDataURI :: Error :: It seems that it is not an Image Data URI. Couldn't match \"data:image/\""); |             log("image-data-uri", "It seems that it is not an Image Data URI. Couldn't match \"data:image/\"", "error"); | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -22,7 +23,7 @@ let ImageDataURI = (() => { | |||||||
|  |  | ||||||
|     function encode(data, mediaType) { |     function encode(data, mediaType) { | ||||||
|         if (!data || !mediaType) { |         if (!data || !mediaType) { | ||||||
|             console.log("ImageDataURI :: Error :: Missing some of the required params: data, mediaType "); |             log("image-data-uri", "Missing some of the required params: data, mediaType", "error"); | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| const path = require("path"); | const path = require("path"); | ||||||
| const Bree = require("bree"); | const Bree = require("bree"); | ||||||
| const { SHARE_ENV } = require("worker_threads"); | const { SHARE_ENV } = require("worker_threads"); | ||||||
|  | const { log } = require("../src/util"); | ||||||
|  |  | ||||||
| const jobs = [ | const jobs = [ | ||||||
|     { |     { | ||||||
| @@ -18,7 +19,7 @@ const initBackgroundJobs = function (args) { | |||||||
|             workerData: args, |             workerData: args, | ||||||
|         }, |         }, | ||||||
|         workerMessageHandler: (message) => { |         workerMessageHandler: (message) => { | ||||||
|             console.log("[Background Job]:", message); |             log("jobs", message); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ dayjs.extend(utc); | |||||||
| dayjs.extend(timezone); | dayjs.extend(timezone); | ||||||
| const axios = require("axios"); | const axios = require("axios"); | ||||||
| const { Prometheus } = require("../prometheus"); | const { Prometheus } = require("../prometheus"); | ||||||
| const { debug, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); | const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); | ||||||
| const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, errorLog } = require("../util-server"); | const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, errorLog } = 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"); | ||||||
| @@ -141,7 +141,7 @@ class Monitor extends BeanModel { | |||||||
|                     // Do not do any queries/high loading things before the "bean.ping" |                     // Do not do any queries/high loading things before the "bean.ping" | ||||||
|                     let startTime = dayjs().valueOf(); |                     let startTime = dayjs().valueOf(); | ||||||
|  |  | ||||||
|                     debug(`[${this.name}] Prepare Options for axios`); |                     log("monitor", `[${this.name}] Prepare Options for axios`, "debug"); | ||||||
|                     const options = { |                     const options = { | ||||||
|                         url: this.url, |                         url: this.url, | ||||||
|                         method: (this.method || "get").toLowerCase(), |                         method: (this.method || "get").toLowerCase(), | ||||||
| @@ -162,7 +162,7 @@ class Monitor extends BeanModel { | |||||||
|                         }, |                         }, | ||||||
|                     }; |                     }; | ||||||
|  |  | ||||||
|                     debug(`[${this.name}] Axios Request`); |                     log("monitor", `[${this.name}] Axios Request`, "debug"); | ||||||
|                     let res = await axios.request(options); |                     let res = await axios.request(options); | ||||||
|                     bean.msg = `${res.status} - ${res.statusText}`; |                     bean.msg = `${res.status} - ${res.statusText}`; | ||||||
|                     bean.ping = dayjs().valueOf() - startTime; |                     bean.ping = dayjs().valueOf() - startTime; | ||||||
| @@ -170,29 +170,30 @@ class Monitor extends BeanModel { | |||||||
|                     // Check certificate if https is used |                     // Check certificate if https is used | ||||||
|                     let certInfoStartTime = dayjs().valueOf(); |                     let certInfoStartTime = dayjs().valueOf(); | ||||||
|                     if (this.getUrl()?.protocol === "https:") { |                     if (this.getUrl()?.protocol === "https:") { | ||||||
|                         debug(`[${this.name}] Check cert`); |                         log("monitor", `[${this.name}] Check cert`, "debug"); | ||||||
|                         try { |                         try { | ||||||
|                             let tlsInfoObject = checkCertificate(res); |                             let tlsInfoObject = checkCertificate(res); | ||||||
|                             tlsInfo = await this.updateTlsInfo(tlsInfoObject); |                             tlsInfo = await this.updateTlsInfo(tlsInfoObject); | ||||||
|  |  | ||||||
|                             if (!this.getIgnoreTls()) { |                             if (!this.getIgnoreTls()) { | ||||||
|                                 debug(`[${this.name}] call sendCertNotification`); |                                 log("monitor", `[${this.name}] call sendCertNotification`, "debug"); | ||||||
|                                 await this.sendCertNotification(tlsInfoObject); |                                 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); |                                 log("monitor", "Caught error", "error"); | ||||||
|  |                                 log("monitor", e.message, "error"); | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     if (process.env.TIMELOGGER === "1") { |                     if (process.env.TIMELOGGER === "1") { | ||||||
|                         debug("Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms"); |                         log("monitor", "Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms", "debug"); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID == this.id) { |                     if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID == this.id) { | ||||||
|                         console.log(res.data); |                         log("monitor", res.data); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     if (this.type === "http") { |                     if (this.type === "http") { | ||||||
| @@ -272,7 +273,7 @@ class Monitor extends BeanModel { | |||||||
|                         time |                         time | ||||||
|                     ]); |                     ]); | ||||||
|  |  | ||||||
|                     debug("heartbeatCount" + heartbeatCount + " " + time); |                     log("monitor", "heartbeatCount" + heartbeatCount + " " + time, "debug"); | ||||||
|  |  | ||||||
|                     if (heartbeatCount <= 0) { |                     if (heartbeatCount <= 0) { | ||||||
|                         throw new Error("No heartbeat in the time window"); |                         throw new Error("No heartbeat in the time window"); | ||||||
| @@ -355,7 +356,7 @@ class Monitor extends BeanModel { | |||||||
|  |  | ||||||
|             let beatInterval = this.interval; |             let beatInterval = this.interval; | ||||||
|  |  | ||||||
|             debug(`[${this.name}] Check isImportant`); |             log("monitor", `[${this.name}] Check isImportant`, "debug"); | ||||||
|             let isImportant = Monitor.isImportantBeat(isFirstBeat, previousBeat?.status, bean.status); |             let isImportant = Monitor.isImportantBeat(isFirstBeat, previousBeat?.status, bean.status); | ||||||
|  |  | ||||||
|             // Mark as important if status changed, ignore pending pings, |             // Mark as important if status changed, ignore pending pings, | ||||||
| @@ -363,11 +364,11 @@ class Monitor extends BeanModel { | |||||||
|             if (isImportant) { |             if (isImportant) { | ||||||
|                 bean.important = true; |                 bean.important = true; | ||||||
|  |  | ||||||
|                 debug(`[${this.name}] sendNotification`); |                 log("monitor", `[${this.name}] sendNotification`, "debug"); | ||||||
|                 await Monitor.sendNotification(isFirstBeat, this, bean); |                 await Monitor.sendNotification(isFirstBeat, this, bean); | ||||||
|  |  | ||||||
|                 // Clear Status Page Cache |                 // Clear Status Page Cache | ||||||
|                 debug(`[${this.name}] apicache clear`); |                 log("monitor", `[${this.name}] apicache clear`, "debug"); | ||||||
|                 apicache.clear(); |                 apicache.clear(); | ||||||
|  |  | ||||||
|             } else { |             } else { | ||||||
| @@ -375,24 +376,24 @@ class Monitor extends BeanModel { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (bean.status === UP) { |             if (bean.status === UP) { | ||||||
|                 console.info(`Monitor #${this.id} '${this.name}': Successful Response: ${bean.ping} ms | Interval: ${beatInterval} seconds | Type: ${this.type}`); |                 log("monitor", `Monitor #${this.id} '${this.name}': Successful Response: ${bean.ping} ms | Interval: ${beatInterval} seconds | Type: ${this.type}`); | ||||||
|             } else if (bean.status === PENDING) { |             } else if (bean.status === PENDING) { | ||||||
|                 if (this.retryInterval > 0) { |                 if (this.retryInterval > 0) { | ||||||
|                     beatInterval = this.retryInterval; |                     beatInterval = this.retryInterval; | ||||||
|                 } |                 } | ||||||
|                 console.warn(`Monitor #${this.id} '${this.name}': Pending: ${bean.msg} | Max retries: ${this.maxretries} | Retry: ${retries} | Retry Interval: ${beatInterval} seconds | Type: ${this.type}`); |                 log("monitor", `Monitor #${this.id} '${this.name}': Pending: ${bean.msg} | Max retries: ${this.maxretries} | Retry: ${retries} | Retry Interval: ${beatInterval} seconds | Type: ${this.type}`, "warn"); | ||||||
|             } else { |             } else { | ||||||
|                 console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`); |                 log("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`, "warn"); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             debug(`[${this.name}] Send to socket`); |             log("monitor", `[${this.name}] Send to socket`, "debug"); | ||||||
|             io.to(this.user_id).emit("heartbeat", bean.toJSON()); |             io.to(this.user_id).emit("heartbeat", bean.toJSON()); | ||||||
|             Monitor.sendStats(io, this.id, this.user_id); |             Monitor.sendStats(io, this.id, this.user_id); | ||||||
|  |  | ||||||
|             debug(`[${this.name}] Store`); |             log("monitor", `[${this.name}] Store`, "debug"); | ||||||
|             await R.store(bean); |             await R.store(bean); | ||||||
|  |  | ||||||
|             debug(`[${this.name}] prometheus.update`); |             log("monitor", `[${this.name}] prometheus.update`, "debug"); | ||||||
|             prometheus.update(bean, tlsInfo); |             prometheus.update(bean, tlsInfo); | ||||||
|  |  | ||||||
|             previousBeat = bean; |             previousBeat = bean; | ||||||
| @@ -401,15 +402,15 @@ class Monitor extends BeanModel { | |||||||
|  |  | ||||||
|                 if (demoMode) { |                 if (demoMode) { | ||||||
|                     if (beatInterval < 20) { |                     if (beatInterval < 20) { | ||||||
|                         console.log("beat interval too low, reset to 20s"); |                         log("monitor", "beat interval too low, reset to 20s"); | ||||||
|                         beatInterval = 20; |                         beatInterval = 20; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 debug(`[${this.name}] SetTimeout for next check.`); |                 log("monitor", `[${this.name}] SetTimeout for next check.`, "debug"); | ||||||
|                 this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000); |                 this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000); | ||||||
|             } else { |             } else { | ||||||
|                 console.log(`[${this.name}] isStop = true, no next check.`); |                 log("monitor", `[${this.name}] isStop = true, no next check.`); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|         }; |         }; | ||||||
| @@ -420,10 +421,10 @@ class Monitor extends BeanModel { | |||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 console.trace(e); |                 console.trace(e); | ||||||
|                 errorLog(e, false); |                 errorLog(e, false); | ||||||
|                 console.error("Please report to https://github.com/louislam/uptime-kuma/issues"); |                 log("monitor", "Please report to https://github.com/louislam/uptime-kuma/issues", "error"); | ||||||
|  |  | ||||||
|                 if (! this.isStop) { |                 if (! this.isStop) { | ||||||
|                     console.log("Try to restart the monitor"); |                     log("monitor", "Try to restart the monitor"); | ||||||
|                     this.heartbeatInterval = setTimeout(safeBeat, this.interval * 1000); |                     this.heartbeatInterval = setTimeout(safeBeat, this.interval * 1000); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @@ -481,17 +482,17 @@ class Monitor extends BeanModel { | |||||||
|  |  | ||||||
|                 if (isValidObjects) { |                 if (isValidObjects) { | ||||||
|                     if (oldCertInfo.certInfo.fingerprint256 !== checkCertificateResult.certInfo.fingerprint256) { |                     if (oldCertInfo.certInfo.fingerprint256 !== checkCertificateResult.certInfo.fingerprint256) { | ||||||
|                         debug("Resetting sent_history"); |                         log("monitor", "Resetting sent_history", "debug"); | ||||||
|                         await R.exec("DELETE FROM notification_sent_history WHERE type = 'certificate' AND monitor_id = ?", [ |                         await R.exec("DELETE FROM notification_sent_history WHERE type = 'certificate' AND monitor_id = ?", [ | ||||||
|                             this.id |                             this.id | ||||||
|                         ]); |                         ]); | ||||||
|                     } else { |                     } else { | ||||||
|                         debug("No need to reset sent_history"); |                         log("monitor", "No need to reset sent_history", "debug"); | ||||||
|                         debug(oldCertInfo.certInfo.fingerprint256); |                         log("monitor", oldCertInfo.certInfo.fingerprint256, "debug"); | ||||||
|                         debug(checkCertificateResult.certInfo.fingerprint256); |                         log("monitor", checkCertificateResult.certInfo.fingerprint256, "debug"); | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     debug("Not valid object"); |                     log("monitor", "Not valid object", "debug"); | ||||||
|                 } |                 } | ||||||
|             } catch (e) { } |             } catch (e) { } | ||||||
|  |  | ||||||
| @@ -512,7 +513,7 @@ class Monitor extends BeanModel { | |||||||
|             await Monitor.sendUptime(24 * 30, io, monitorID, userID); |             await Monitor.sendUptime(24 * 30, io, monitorID, userID); | ||||||
|             await Monitor.sendCertInfo(io, monitorID, userID); |             await Monitor.sendCertInfo(io, monitorID, userID); | ||||||
|         } else { |         } else { | ||||||
|             debug("No clients in the room, no need to send stats"); |             log("monitor", "No clients in the room, no need to send stats", "debug"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -659,8 +660,8 @@ class Monitor extends BeanModel { | |||||||
|                 try { |                 try { | ||||||
|                     await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(), bean.toJSON()); |                     await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(), bean.toJSON()); | ||||||
|                 } catch (e) { |                 } catch (e) { | ||||||
|                     console.error("Cannot send notification to " + notification.name); |                     log("monitor", "Cannot send notification to " + notification.name, "error"); | ||||||
|                     console.log(e); |                     log("monitor", e, "error"); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -677,7 +678,7 @@ class Monitor extends BeanModel { | |||||||
|         if (tlsInfoObject && tlsInfoObject.certInfo && tlsInfoObject.certInfo.daysRemaining) { |         if (tlsInfoObject && tlsInfoObject.certInfo && tlsInfoObject.certInfo.daysRemaining) { | ||||||
|             const notificationList = await Monitor.getNotificationList(this); |             const notificationList = await Monitor.getNotificationList(this); | ||||||
|  |  | ||||||
|             debug("call sendCertNotificationByTargetDays"); |             log("monitor", "call sendCertNotificationByTargetDays", "debug"); | ||||||
|             await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 21, notificationList); |             await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 21, notificationList); | ||||||
|             await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 14, notificationList); |             await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 14, notificationList); | ||||||
|             await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 7, notificationList); |             await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 7, notificationList); | ||||||
| @@ -687,7 +688,7 @@ class Monitor extends BeanModel { | |||||||
|     async sendCertNotificationByTargetDays(daysRemaining, targetDays, notificationList) { |     async sendCertNotificationByTargetDays(daysRemaining, targetDays, notificationList) { | ||||||
|  |  | ||||||
|         if (daysRemaining > targetDays) { |         if (daysRemaining > targetDays) { | ||||||
|             debug(`No need to send cert notification. ${daysRemaining} > ${targetDays}`); |             log("monitor", `No need to send cert notification. ${daysRemaining} > ${targetDays}`, "debug"); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -701,21 +702,21 @@ class Monitor extends BeanModel { | |||||||
|  |  | ||||||
|             // Sent already, no need to send again |             // Sent already, no need to send again | ||||||
|             if (row) { |             if (row) { | ||||||
|                 debug("Sent already, no need to send again"); |                 log("monitor", "Sent already, no need to send again", "debug"); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             let sent = false; |             let sent = false; | ||||||
|             debug("Send certificate notification"); |             log("monitor", "Send certificate notification", "debug"); | ||||||
|  |  | ||||||
|             for (let notification of notificationList) { |             for (let notification of notificationList) { | ||||||
|                 try { |                 try { | ||||||
|                     debug("Sending to " + notification.name); |                     log("monitor", "Sending to " + notification.name, "debug"); | ||||||
|                     await Notification.send(JSON.parse(notification.config), `[${this.name}][${this.url}] Certificate will be expired in ${daysRemaining} days`); |                     await Notification.send(JSON.parse(notification.config), `[${this.name}][${this.url}] Certificate will be expired in ${daysRemaining} days`); | ||||||
|                     sent = true; |                     sent = true; | ||||||
|                 } catch (e) { |                 } catch (e) { | ||||||
|                     console.error("Cannot send cert notification to " + notification.name); |                     log("monitor", "Cannot send cert notification to " + notification.name, "error"); | ||||||
|                     console.error(e); |                     log("monitor", e, "error"); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -727,7 +728,7 @@ class Monitor extends BeanModel { | |||||||
|                 ]); |                 ]); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             debug("No notification, no need to send cert notification"); |             log("monitor", "No notification, no need to send cert notification", "debug"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| const NotificationProvider = require("./notification-provider"); | const NotificationProvider = require("./notification-provider"); | ||||||
| const axios = require("axios"); | const axios = require("axios"); | ||||||
| const Crypto = require("crypto"); | const Crypto = require("crypto"); | ||||||
| const { debug } = require("../../src/util"); | const { log } = require("../../src/util"); | ||||||
|  |  | ||||||
| class Matrix extends NotificationProvider { | class Matrix extends NotificationProvider { | ||||||
|     name = "matrix"; |     name = "matrix"; | ||||||
| @@ -17,11 +17,11 @@ class Matrix extends NotificationProvider { | |||||||
|                 .slice(0, size) |                 .slice(0, size) | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         debug("Random String: " + randomString); |         log("notification", "Random String: " + randomString, "debug"); | ||||||
|  |  | ||||||
|         const roomId = encodeURIComponent(notification.internalRoomId); |         const roomId = encodeURIComponent(notification.internalRoomId); | ||||||
|  |  | ||||||
|         debug("Matrix Room ID: " + roomId); |         log("notification", "Matrix Room ID: " + roomId, "debug"); | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             let config = { |             let config = { | ||||||
|   | |||||||
| @@ -23,13 +23,14 @@ const Feishu = require("./notification-providers/feishu"); | |||||||
| const AliyunSms = require("./notification-providers/aliyun-sms"); | const AliyunSms = require("./notification-providers/aliyun-sms"); | ||||||
| const DingDing = require("./notification-providers/dingding"); | const DingDing = require("./notification-providers/dingding"); | ||||||
| const Bark = require("./notification-providers/bark"); | const Bark = require("./notification-providers/bark"); | ||||||
|  | const { log } = require("../src/util"); | ||||||
|  |  | ||||||
| class Notification { | class Notification { | ||||||
|  |  | ||||||
|     providerList = {}; |     providerList = {}; | ||||||
|  |  | ||||||
|     static init() { |     static init() { | ||||||
|         console.log("Prepare Notification Providers"); |         log("notification", "Prepare Notification Providers"); | ||||||
|  |  | ||||||
|         this.providerList = {}; |         this.providerList = {}; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| const PrometheusClient = require("prom-client"); | const PrometheusClient = require("prom-client"); | ||||||
|  | const { log } = require("../src/util"); | ||||||
|  |  | ||||||
| const commonLabels = [ | const commonLabels = [ | ||||||
|     "monitor_name", |     "monitor_name", | ||||||
| @@ -56,20 +57,23 @@ class Prometheus { | |||||||
|                 } |                 } | ||||||
|                 monitor_cert_is_valid.set(this.monitorLabelValues, is_valid); |                 monitor_cert_is_valid.set(this.monitorLabelValues, is_valid); | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 console.error(e); |                 log("prometheus", "Caught error", "error"); | ||||||
|  |                 log("prometheus", e, "error"); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             try { |             try { | ||||||
|                 monitor_cert_days_remaining.set(this.monitorLabelValues, tlsInfo.certInfo.daysRemaining); |                 monitor_cert_days_remaining.set(this.monitorLabelValues, tlsInfo.certInfo.daysRemaining); | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 console.error(e); |                 log("prometheus", "Caught error", "error"); | ||||||
|  |                 log("prometheus", e, "error"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             monitor_status.set(this.monitorLabelValues, heartbeat.status); |             monitor_status.set(this.monitorLabelValues, heartbeat.status); | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|             console.error(e); |             log("prometheus", "Caught error", "error"); | ||||||
|  |             log("prometheus", e, "error"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
| @@ -80,7 +84,8 @@ class Prometheus { | |||||||
|                 monitor_response_time.set(this.monitorLabelValues, -1); |                 monitor_response_time.set(this.monitorLabelValues, -1); | ||||||
|             } |             } | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|             console.error(e); |             log("prometheus", "Caught error", "error"); | ||||||
|  |             log("prometheus", e, "error"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| const { RateLimiter } = require("limiter"); | const { RateLimiter } = require("limiter"); | ||||||
| const { debug } = require("../src/util"); | const { log } = require("../src/util"); | ||||||
|  |  | ||||||
| class KumaRateLimiter { | class KumaRateLimiter { | ||||||
|     constructor(config) { |     constructor(config) { | ||||||
| @@ -9,7 +9,7 @@ class KumaRateLimiter { | |||||||
|  |  | ||||||
|     async pass(callback, num = 1) { |     async pass(callback, num = 1) { | ||||||
|         const remainingRequests = await this.removeTokens(num); |         const remainingRequests = await this.removeTokens(num); | ||||||
|         debug("Rate Limit (remainingRequests):" + remainingRequests); |         log("rate-limit", "remaining requests: " + remainingRequests); | ||||||
|         if (remainingRequests < 0) { |         if (remainingRequests < 0) { | ||||||
|             if (callback) { |             if (callback) { | ||||||
|                 callback({ |                 callback({ | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ const server = require("../server"); | |||||||
| const apicache = require("../modules/apicache"); | const apicache = require("../modules/apicache"); | ||||||
| const Monitor = require("../model/monitor"); | const Monitor = require("../model/monitor"); | ||||||
| const dayjs = require("dayjs"); | const dayjs = require("dayjs"); | ||||||
| const { UP, flipStatus, debug } = require("../../src/util"); | const { UP, flipStatus, log } = require("../../src/util"); | ||||||
| let router = express.Router(); | let router = express.Router(); | ||||||
|  |  | ||||||
| let cache = apicache.middleware; | let cache = apicache.middleware; | ||||||
| @@ -56,8 +56,8 @@ router.get("/api/push/:pushToken", async (request, response) => { | |||||||
|             duration = dayjs(bean.time).diff(dayjs(previousHeartbeat.time), "second"); |             duration = dayjs(bean.time).diff(dayjs(previousHeartbeat.time), "second"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         debug("PreviousStatus: " + previousStatus); |         log("router", "PreviousStatus: " + previousStatus, "debug"); | ||||||
|         debug("Current Status: " + status); |         log("router", "Current Status: " + status, "debug"); | ||||||
|  |  | ||||||
|         bean.important = Monitor.isImportantBeat(isFirstBeat, previousStatus, status); |         bean.important = Monitor.isImportantBeat(isFirstBeat, previousStatus, status); | ||||||
|         bean.monitor_id = monitor.id; |         bean.monitor_id = monitor.id; | ||||||
|   | |||||||
							
								
								
									
										168
									
								
								server/server.js
									
									
									
									
									
								
							
							
						
						
									
										168
									
								
								server/server.js
									
									
									
									
									
								
							| @@ -1,56 +1,57 @@ | |||||||
| console.log("Welcome to Uptime Kuma"); |  | ||||||
| const args = require("args-parser")(process.argv); | const args = require("args-parser")(process.argv); | ||||||
| const { sleep, debug, getRandomInt, genSecret } = require("../src/util"); | const { sleep, log, getRandomInt, genSecret } = require("../src/util"); | ||||||
| const config = require("./config"); | const config = require("./config"); | ||||||
|  |  | ||||||
| debug(args); | log("server", "Welcome to Uptime Kuma"); | ||||||
|  | log("server", "Arguments", "debug"); | ||||||
|  | log("server", args, "debug"); | ||||||
|  |  | ||||||
| if (! process.env.NODE_ENV) { | if (! process.env.NODE_ENV) { | ||||||
|     process.env.NODE_ENV = "production"; |     process.env.NODE_ENV = "production"; | ||||||
| } | } | ||||||
|  |  | ||||||
| console.log("Node Env: " + process.env.NODE_ENV); | log("server", "Node Env: " + process.env.NODE_ENV); | ||||||
|  |  | ||||||
| console.log("Importing Node libraries"); | log("server", "Importing Node libraries"); | ||||||
| const fs = require("fs"); | const fs = require("fs"); | ||||||
| const http = require("http"); | const http = require("http"); | ||||||
| const https = require("https"); | const https = require("https"); | ||||||
|  |  | ||||||
| console.log("Importing 3rd-party libraries"); | log("server", "Importing 3rd-party libraries"); | ||||||
| debug("Importing express"); | log("server", "Importing express", "debug"); | ||||||
| const express = require("express"); | const express = require("express"); | ||||||
| debug("Importing socket.io"); | log("server", "Importing socket.io", "debug"); | ||||||
| const { Server } = require("socket.io"); | const { Server } = require("socket.io"); | ||||||
| debug("Importing redbean-node"); | log("server", "Importing redbean-node", "debug"); | ||||||
| const { R } = require("redbean-node"); | const { R } = require("redbean-node"); | ||||||
| debug("Importing jsonwebtoken"); | log("server", "Importing jsonwebtoken", "debug"); | ||||||
| const jwt = require("jsonwebtoken"); | const jwt = require("jsonwebtoken"); | ||||||
| debug("Importing http-graceful-shutdown"); | log("server", "Importing http-graceful-shutdown", "debug"); | ||||||
| const gracefulShutdown = require("http-graceful-shutdown"); | const gracefulShutdown = require("http-graceful-shutdown"); | ||||||
| debug("Importing prometheus-api-metrics"); | log("server", "Importing prometheus-api-metrics", "debug"); | ||||||
| const prometheusAPIMetrics = require("prometheus-api-metrics"); | const prometheusAPIMetrics = require("prometheus-api-metrics"); | ||||||
| debug("Importing compare-versions"); | log("server", "Importing compare-versions", "debug"); | ||||||
| const compareVersions = require("compare-versions"); | const compareVersions = require("compare-versions"); | ||||||
| const { passwordStrength } = require("check-password-strength"); | const { passwordStrength } = require("check-password-strength"); | ||||||
|  |  | ||||||
| debug("Importing 2FA Modules"); | log("server", "Importing 2FA Modules", "debug"); | ||||||
| const notp = require("notp"); | const notp = require("notp"); | ||||||
| const base32 = require("thirty-two"); | const base32 = require("thirty-two"); | ||||||
|  |  | ||||||
| console.log("Importing this project modules"); | log("server", "Importing this project modules"); | ||||||
| debug("Importing Monitor"); | log("server", "Importing Monitor", "debug"); | ||||||
| const Monitor = require("./model/monitor"); | const Monitor = require("./model/monitor"); | ||||||
| debug("Importing Settings"); | log("server", "Importing Settings", "debug"); | ||||||
| const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, errorLog } = require("./util-server"); | const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, errorLog } = require("./util-server"); | ||||||
|  |  | ||||||
| debug("Importing Notification"); | log("server", "Importing Notification", "debug"); | ||||||
| const { Notification } = require("./notification"); | const { Notification } = require("./notification"); | ||||||
| Notification.init(); | Notification.init(); | ||||||
|  |  | ||||||
| debug("Importing Database"); | log("server", "Importing Database", "debug"); | ||||||
| const Database = require("./database"); | const Database = require("./database"); | ||||||
|  |  | ||||||
| debug("Importing Background Jobs"); | log("server", "Importing Background Jobs", "debug"); | ||||||
| const { initBackgroundJobs } = require("./jobs"); | const { initBackgroundJobs } = require("./jobs"); | ||||||
| const { loginRateLimiter } = require("./rate-limiter"); | const { loginRateLimiter } = require("./rate-limiter"); | ||||||
|  |  | ||||||
| @@ -59,7 +60,7 @@ const { login } = require("./auth"); | |||||||
| const passwordHash = require("./password-hash"); | const passwordHash = require("./password-hash"); | ||||||
|  |  | ||||||
| const checkVersion = require("./check-version"); | const checkVersion = require("./check-version"); | ||||||
| console.info("Version: " + checkVersion.version); | log("server", "Version: " + checkVersion.version); | ||||||
|  |  | ||||||
| // If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available and the unspecified IPv4 address (0.0.0.0) otherwise. | // If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available and the unspecified IPv4 address (0.0.0.0) otherwise. | ||||||
| // Dual-stack support for (::) | // Dual-stack support for (::) | ||||||
| @@ -71,7 +72,7 @@ if (!hostname && !FBSD) { | |||||||
| } | } | ||||||
|  |  | ||||||
| if (hostname) { | if (hostname) { | ||||||
|     console.log("Custom hostname: " + hostname); |     log("server", "Custom hostname: " + hostname); | ||||||
| } | } | ||||||
|  |  | ||||||
| const port = parseInt(process.env.UPTIME_KUMA_PORT || process.env.PORT || args.port || 3001); | const port = parseInt(process.env.UPTIME_KUMA_PORT || process.env.PORT || args.port || 3001); | ||||||
| @@ -94,22 +95,22 @@ const twofa_verification_opts = { | |||||||
| const testMode = !!args["test"] || false; | const testMode = !!args["test"] || false; | ||||||
|  |  | ||||||
| if (config.demoMode) { | if (config.demoMode) { | ||||||
|     console.log("==== Demo Mode ===="); |     log("server", "==== Demo Mode ===="); | ||||||
| } | } | ||||||
|  |  | ||||||
| console.log("Creating express and socket.io instance"); | log("server", "Creating express and socket.io instance"); | ||||||
| const app = express(); | const app = express(); | ||||||
|  |  | ||||||
| let server; | let server; | ||||||
|  |  | ||||||
| if (sslKey && sslCert) { | if (sslKey && sslCert) { | ||||||
|     console.log("Server Type: HTTPS"); |     log("server", "Server Type: HTTPS"); | ||||||
|     server = https.createServer({ |     server = https.createServer({ | ||||||
|         key: fs.readFileSync(sslKey), |         key: fs.readFileSync(sslKey), | ||||||
|         cert: fs.readFileSync(sslCert) |         cert: fs.readFileSync(sslCert) | ||||||
|     }, app); |     }, app); | ||||||
| } else { | } else { | ||||||
|     console.log("Server Type: HTTP"); |     log("server", "Server Type: HTTP"); | ||||||
|     server = http.createServer(app); |     server = http.createServer(app); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -167,7 +168,7 @@ try { | |||||||
| } catch (e) { | } catch (e) { | ||||||
|     // "dist/index.html" is not necessary for development |     // "dist/index.html" is not necessary for development | ||||||
|     if (process.env.NODE_ENV !== "development") { |     if (process.env.NODE_ENV !== "development") { | ||||||
|         console.error("Error: Cannot find 'dist/index.html', did you install correctly?"); |         log("server", "Error: Cannot find 'dist/index.html', did you install correctly?", "error"); | ||||||
|         process.exit(1); |         process.exit(1); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -180,7 +181,7 @@ exports.entryPage = "dashboard"; | |||||||
|  |  | ||||||
|     exports.entryPage = await setting("entryPage"); |     exports.entryPage = await setting("entryPage"); | ||||||
|  |  | ||||||
|     console.log("Adding route"); |     log("server", "Adding route"); | ||||||
|  |  | ||||||
|     // *************************** |     // *************************** | ||||||
|     // Normal Router here |     // Normal Router here | ||||||
| @@ -233,7 +234,7 @@ exports.entryPage = "dashboard"; | |||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     console.log("Adding socket handler"); |     log("server", "Adding socket handler"); | ||||||
|     io.on("connection", async (socket) => { |     io.on("connection", async (socket) => { | ||||||
|  |  | ||||||
|         sendInfo(socket); |         sendInfo(socket); | ||||||
| @@ -241,7 +242,7 @@ exports.entryPage = "dashboard"; | |||||||
|         totalClient++; |         totalClient++; | ||||||
|  |  | ||||||
|         if (needSetup) { |         if (needSetup) { | ||||||
|             console.log("Redirect to setup page"); |             log("server", "Redirect to setup page"); | ||||||
|             socket.emit("setup"); |             socket.emit("setup"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -254,33 +255,40 @@ exports.entryPage = "dashboard"; | |||||||
|         // *************************** |         // *************************** | ||||||
|  |  | ||||||
|         socket.on("loginByToken", async (token, callback) => { |         socket.on("loginByToken", async (token, callback) => { | ||||||
|  |             log("auth", `Login by token. IP=${getClientIp(socket)}`); | ||||||
|  |  | ||||||
|             try { |             try { | ||||||
|                 let decoded = jwt.verify(token, jwtSecret); |                 let decoded = jwt.verify(token, jwtSecret); | ||||||
|  |  | ||||||
|                 console.log("Username from JWT: " + decoded.username); |                 log("auth", "Username from JWT: " + decoded.username); | ||||||
|  |  | ||||||
|                 let user = await R.findOne("user", " username = ? AND active = 1 ", [ |                 let user = await R.findOne("user", " username = ? AND active = 1 ", [ | ||||||
|                     decoded.username, |                     decoded.username, | ||||||
|                 ]); |                 ]); | ||||||
|  |  | ||||||
|                 if (user) { |                 if (user) { | ||||||
|                     debug("afterLogin"); |                     log("auth", "afterLogin", "debug"); | ||||||
|  |  | ||||||
|                     afterLogin(socket, user); |                     afterLogin(socket, user); | ||||||
|  |                     log("auth", "afterLogin ok", "debug"); | ||||||
|  |  | ||||||
|                     debug("afterLogin ok"); |                     log("auth", `Successfully logged in user ${decoded.username}. IP=${getClientIp(socket)}`); | ||||||
|  |  | ||||||
|                     callback({ |                     callback({ | ||||||
|                         ok: true, |                         ok: true, | ||||||
|                     }); |                     }); | ||||||
|                 } else { |                 } else { | ||||||
|  |  | ||||||
|  |                     log("auth", `Inactive or deleted user ${decoded.username}. IP=${getClientIp(socket)}`); | ||||||
|  |  | ||||||
|                     callback({ |                     callback({ | ||||||
|                         ok: false, |                         ok: false, | ||||||
|                         msg: "The user is inactive or deleted.", |                         msg: "The user is inactive or deleted.", | ||||||
|                     }); |                     }); | ||||||
|                 } |                 } | ||||||
|             } catch (error) { |             } catch (error) { | ||||||
|  |  | ||||||
|  |                 log("auth", `Invalid token for user ${decoded.username}. IP=${getClientIp(socket)}`, "error"); | ||||||
|  |  | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: false, |                     ok: false, | ||||||
|                     msg: "Invalid token.", |                     msg: "Invalid token.", | ||||||
| @@ -290,10 +298,11 @@ exports.entryPage = "dashboard"; | |||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         socket.on("login", async (data, callback) => { |         socket.on("login", async (data, callback) => { | ||||||
|             console.log("Login"); |             log("auth", `Login by username + password. IP=${getClientIp(socket)}`); | ||||||
|  |  | ||||||
|             // Login Rate Limit |             // Login Rate Limit | ||||||
|             if (! await loginRateLimiter.pass(callback)) { |             if (! await loginRateLimiter.pass(callback)) { | ||||||
|  |                 log("auth", `Too many failed requests for user ${data.username}. IP=${getClientIp(socket)}`); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -302,6 +311,9 @@ exports.entryPage = "dashboard"; | |||||||
|             if (user) { |             if (user) { | ||||||
|                 if (user.twofa_status == 0) { |                 if (user.twofa_status == 0) { | ||||||
|                     afterLogin(socket, user); |                     afterLogin(socket, user); | ||||||
|  |  | ||||||
|  |                     log("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); | ||||||
|  |  | ||||||
|                     callback({ |                     callback({ | ||||||
|                         ok: true, |                         ok: true, | ||||||
|                         token: jwt.sign({ |                         token: jwt.sign({ | ||||||
| @@ -311,6 +323,9 @@ exports.entryPage = "dashboard"; | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 if (user.twofa_status == 1 && !data.token) { |                 if (user.twofa_status == 1 && !data.token) { | ||||||
|  |  | ||||||
|  |                     log("auth", `2FA token required for user ${data.username}. IP=${getClientIp(socket)}`); | ||||||
|  |  | ||||||
|                     callback({ |                     callback({ | ||||||
|                         tokenRequired: true, |                         tokenRequired: true, | ||||||
|                     }); |                     }); | ||||||
| @@ -327,6 +342,8 @@ exports.entryPage = "dashboard"; | |||||||
|                             socket.userID, |                             socket.userID, | ||||||
|                         ]); |                         ]); | ||||||
|  |  | ||||||
|  |                         log("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); | ||||||
|  |  | ||||||
|                         callback({ |                         callback({ | ||||||
|                             ok: true, |                             ok: true, | ||||||
|                             token: jwt.sign({ |                             token: jwt.sign({ | ||||||
| @@ -334,6 +351,9 @@ exports.entryPage = "dashboard"; | |||||||
|                             }, jwtSecret), |                             }, jwtSecret), | ||||||
|                         }); |                         }); | ||||||
|                     } else { |                     } else { | ||||||
|  |  | ||||||
|  |                         log("auth", `Invalid token provided for user ${data.username}. IP=${getClientIp(socket)}`, "warn"); | ||||||
|  |  | ||||||
|                         callback({ |                         callback({ | ||||||
|                             ok: false, |                             ok: false, | ||||||
|                             msg: "Invalid Token!", |                             msg: "Invalid Token!", | ||||||
| @@ -341,6 +361,9 @@ exports.entryPage = "dashboard"; | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|  |  | ||||||
|  |                 log("auth", `Incorrect username or password for user ${data.username}. IP=${getClientIp(socket)}`, "warn"); | ||||||
|  |  | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: false, |                     ok: false, | ||||||
|                     msg: "Incorrect username or password.", |                     msg: "Incorrect username or password.", | ||||||
| @@ -405,11 +428,16 @@ exports.entryPage = "dashboard"; | |||||||
|                     socket.userID, |                     socket.userID, | ||||||
|                 ]); |                 ]); | ||||||
|  |  | ||||||
|  |                 log("auth", `Saved 2FA token for user ${data.username}. IP=${getClientIp(socket)}`); | ||||||
|  |  | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: true, |                     ok: true, | ||||||
|                     msg: "2FA Enabled.", |                     msg: "2FA Enabled.", | ||||||
|                 }); |                 }); | ||||||
|             } catch (error) { |             } catch (error) { | ||||||
|  |  | ||||||
|  |                 log("auth", `Error changing 2FA token for user ${data.username}. IP=${getClientIp(socket)}`, "error"); | ||||||
|  |  | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: false, |                     ok: false, | ||||||
|                     msg: "Error while trying to change 2FA.", |                     msg: "Error while trying to change 2FA.", | ||||||
| @@ -425,14 +453,19 @@ exports.entryPage = "dashboard"; | |||||||
|                     socket.userID, |                     socket.userID, | ||||||
|                 ]); |                 ]); | ||||||
|  |  | ||||||
|  |                 log("auth", `Disabled 2FA token for user ${data.username}. IP=${getClientIp(socket)}`); | ||||||
|  |  | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: true, |                     ok: true, | ||||||
|                     msg: "2FA Disabled.", |                     msg: "2FA Disabled.", | ||||||
|                 }); |                 }); | ||||||
|             } catch (error) { |             } catch (error) { | ||||||
|  |  | ||||||
|  |                 log("auth", `Error disabling 2FA token for user ${data.username}. IP=${getClientIp(socket)}`, "error"); | ||||||
|  |  | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: false, |                     ok: false, | ||||||
|                     msg: "Error while trying to change 2FA.", |                     msg: "Error while trying to disable 2FA.", | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| @@ -544,6 +577,8 @@ exports.entryPage = "dashboard"; | |||||||
|                 await startMonitor(socket.userID, bean.id); |                 await startMonitor(socket.userID, bean.id); | ||||||
|                 await sendMonitorList(socket); |                 await sendMonitorList(socket); | ||||||
|  |  | ||||||
|  |                 log("monitor", `Added Monitor: ${monitorID} User ID: ${socket.userID}`); | ||||||
|  |  | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: true, |                     ok: true, | ||||||
|                     msg: "Added Successfully.", |                     msg: "Added Successfully.", | ||||||
| @@ -551,6 +586,9 @@ exports.entryPage = "dashboard"; | |||||||
|                 }); |                 }); | ||||||
|  |  | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|  |  | ||||||
|  |                 log("monitor", `Error adding Monitor: ${monitorID} User ID: ${socket.userID}`, "error"); | ||||||
|  |  | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: false, |                     ok: false, | ||||||
|                     msg: e.message, |                     msg: e.message, | ||||||
| @@ -634,7 +672,7 @@ exports.entryPage = "dashboard"; | |||||||
|             try { |             try { | ||||||
|                 checkLogin(socket); |                 checkLogin(socket); | ||||||
|  |  | ||||||
|                 console.log(`Get Monitor: ${monitorID} User ID: ${socket.userID}`); |                 log("monitor", `Get Monitor: ${monitorID} User ID: ${socket.userID}`); | ||||||
|  |  | ||||||
|                 let bean = await R.findOne("monitor", " id = ? AND user_id = ? ", [ |                 let bean = await R.findOne("monitor", " id = ? AND user_id = ? ", [ | ||||||
|                     monitorID, |                     monitorID, | ||||||
| @@ -658,7 +696,7 @@ exports.entryPage = "dashboard"; | |||||||
|             try { |             try { | ||||||
|                 checkLogin(socket); |                 checkLogin(socket); | ||||||
|  |  | ||||||
|                 console.log(`Get Monitor Beats: ${monitorID} User ID: ${socket.userID}`); |                 log("monitor", `Get Monitor Beats: ${monitorID} User ID: ${socket.userID}`); | ||||||
|  |  | ||||||
|                 if (period == null) { |                 if (period == null) { | ||||||
|                     throw new Error("Invalid period."); |                     throw new Error("Invalid period."); | ||||||
| @@ -729,7 +767,7 @@ exports.entryPage = "dashboard"; | |||||||
|             try { |             try { | ||||||
|                 checkLogin(socket); |                 checkLogin(socket); | ||||||
|  |  | ||||||
|                 console.log(`Delete Monitor: ${monitorID} User ID: ${socket.userID}`); |                 log("manage", `Delete Monitor: ${monitorID} User ID: ${socket.userID}`); | ||||||
|  |  | ||||||
|                 if (monitorID in monitorList) { |                 if (monitorID in monitorList) { | ||||||
|                     monitorList[monitorID].stop(); |                     monitorList[monitorID].stop(); | ||||||
| @@ -1065,7 +1103,7 @@ exports.entryPage = "dashboard"; | |||||||
|  |  | ||||||
|                 let backupData = JSON.parse(uploadedJSON); |                 let backupData = JSON.parse(uploadedJSON); | ||||||
|  |  | ||||||
|                 console.log(`Importing Backup, User ID: ${socket.userID}, Version: ${backupData.version}`); |                 log("manage", `Importing Backup, User ID: ${socket.userID}, Version: ${backupData.version}`); | ||||||
|  |  | ||||||
|                 let notificationListData = backupData.notificationList; |                 let notificationListData = backupData.notificationList; | ||||||
|                 let monitorListData = backupData.monitorList; |                 let monitorListData = backupData.monitorList; | ||||||
| @@ -1237,7 +1275,7 @@ exports.entryPage = "dashboard"; | |||||||
|             try { |             try { | ||||||
|                 checkLogin(socket); |                 checkLogin(socket); | ||||||
|  |  | ||||||
|                 console.log(`Clear Events Monitor: ${monitorID} User ID: ${socket.userID}`); |                 log("manage", `Clear Events Monitor: ${monitorID} User ID: ${socket.userID}`); | ||||||
|  |  | ||||||
|                 await R.exec("UPDATE heartbeat SET msg = ?, important = ? WHERE monitor_id = ? ", [ |                 await R.exec("UPDATE heartbeat SET msg = ?, important = ? WHERE monitor_id = ? ", [ | ||||||
|                     "", |                     "", | ||||||
| @@ -1263,7 +1301,7 @@ exports.entryPage = "dashboard"; | |||||||
|             try { |             try { | ||||||
|                 checkLogin(socket); |                 checkLogin(socket); | ||||||
|  |  | ||||||
|                 console.log(`Clear Heartbeats Monitor: ${monitorID} User ID: ${socket.userID}`); |                 log("manage", `Clear Heartbeats Monitor: ${monitorID} User ID: ${socket.userID}`); | ||||||
|  |  | ||||||
|                 await R.exec("DELETE FROM heartbeat WHERE monitor_id = ?", [ |                 await R.exec("DELETE FROM heartbeat WHERE monitor_id = ?", [ | ||||||
|                     monitorID |                     monitorID | ||||||
| @@ -1287,7 +1325,7 @@ exports.entryPage = "dashboard"; | |||||||
|             try { |             try { | ||||||
|                 checkLogin(socket); |                 checkLogin(socket); | ||||||
|  |  | ||||||
|                 console.log(`Clear Statistics User ID: ${socket.userID}`); |                 log("manage", `Clear Statistics User ID: ${socket.userID}`); | ||||||
|  |  | ||||||
|                 await R.exec("DELETE FROM heartbeat"); |                 await R.exec("DELETE FROM heartbeat"); | ||||||
|  |  | ||||||
| @@ -1307,24 +1345,24 @@ exports.entryPage = "dashboard"; | |||||||
|         statusPageSocketHandler(socket); |         statusPageSocketHandler(socket); | ||||||
|         databaseSocketHandler(socket); |         databaseSocketHandler(socket); | ||||||
|  |  | ||||||
|         debug("added all socket handlers"); |         log("server", "added all socket handlers", "debug"); | ||||||
|  |  | ||||||
|         // *************************** |         // *************************** | ||||||
|         // Better do anything after added all socket handlers here |         // Better do anything after added all socket handlers here | ||||||
|         // *************************** |         // *************************** | ||||||
|  |  | ||||||
|         debug("check auto login"); |         log("auth", "check auto login", "debug"); | ||||||
|         if (await setting("disableAuth")) { |         if (await setting("disableAuth")) { | ||||||
|             console.log("Disabled Auth: auto login to admin"); |             log("auth", "Disabled Auth: auto login to admin"); | ||||||
|             afterLogin(socket, await R.findOne("user")); |             afterLogin(socket, await R.findOne("user")); | ||||||
|             socket.emit("autoLogin"); |             socket.emit("autoLogin"); | ||||||
|         } else { |         } else { | ||||||
|             debug("need auth"); |             log("auth", "need auth", "debug"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     console.log("Init the server"); |     log("server", "Init the server"); | ||||||
|  |  | ||||||
|     server.once("error", async (err) => { |     server.once("error", async (err) => { | ||||||
|         console.error("Cannot listen: " + err.message); |         console.error("Cannot listen: " + err.message); | ||||||
| @@ -1333,9 +1371,9 @@ exports.entryPage = "dashboard"; | |||||||
|  |  | ||||||
|     server.listen(port, hostname, () => { |     server.listen(port, hostname, () => { | ||||||
|         if (hostname) { |         if (hostname) { | ||||||
|             console.log(`Listening on ${hostname}:${port}`); |             log("server", `Listening on ${hostname}:${port}`); | ||||||
|         } else { |         } else { | ||||||
|             console.log(`Listening on ${port}`); |             log("server", `Listening on ${port}`); | ||||||
|         } |         } | ||||||
|         startMonitors(); |         startMonitors(); | ||||||
|         checkVersion.startInterval(); |         checkVersion.startInterval(); | ||||||
| @@ -1419,13 +1457,13 @@ async function getMonitorJSONList(userID) { | |||||||
|  |  | ||||||
| async function initDatabase() { | async function initDatabase() { | ||||||
|     if (! fs.existsSync(Database.path)) { |     if (! fs.existsSync(Database.path)) { | ||||||
|         console.log("Copying Database"); |         log("server", "Copying Database"); | ||||||
|         fs.copyFileSync(Database.templatePath, Database.path); |         fs.copyFileSync(Database.templatePath, Database.path); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     console.log("Connecting to the Database"); |     log("server", "Connecting to the Database"); | ||||||
|     await Database.connect(); |     await Database.connect(); | ||||||
|     console.log("Connected"); |     log("server", "Connected"); | ||||||
|  |  | ||||||
|     // Patch the database |     // Patch the database | ||||||
|     await Database.patch(); |     await Database.patch(); | ||||||
| @@ -1435,16 +1473,16 @@ async function initDatabase() { | |||||||
|     ]); |     ]); | ||||||
|  |  | ||||||
|     if (! jwtSecretBean) { |     if (! jwtSecretBean) { | ||||||
|         console.log("JWT secret is not found, generate one."); |         log("server", "JWT secret is not found, generate one."); | ||||||
|         jwtSecretBean = await initJWTSecret(); |         jwtSecretBean = await initJWTSecret(); | ||||||
|         console.log("Stored JWT secret into database"); |         log("server", "Stored JWT secret into database"); | ||||||
|     } else { |     } else { | ||||||
|         console.log("Load JWT secret from database."); |         log("server", "Load JWT secret from database."); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // If there is no record in user table, it is a new Uptime Kuma instance, need to setup |     // If there is no record in user table, it is a new Uptime Kuma instance, need to setup | ||||||
|     if ((await R.count("user")) === 0) { |     if ((await R.count("user")) === 0) { | ||||||
|         console.log("No user, need setup"); |         log("server", "No user, need setup"); | ||||||
|         needSetup = true; |         needSetup = true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1454,7 +1492,7 @@ async function initDatabase() { | |||||||
| async function startMonitor(userID, monitorID) { | async function startMonitor(userID, monitorID) { | ||||||
|     await checkOwner(userID, monitorID); |     await checkOwner(userID, monitorID); | ||||||
|  |  | ||||||
|     console.log(`Resume Monitor: ${monitorID} User ID: ${userID}`); |     log("manage", `Resume Monitor: ${monitorID} User ID: ${userID}`); | ||||||
|  |  | ||||||
|     await R.exec("UPDATE monitor SET active = 1 WHERE id = ? AND user_id = ? ", [ |     await R.exec("UPDATE monitor SET active = 1 WHERE id = ? AND user_id = ? ", [ | ||||||
|         monitorID, |         monitorID, | ||||||
| @@ -1480,7 +1518,7 @@ async function restartMonitor(userID, monitorID) { | |||||||
| async function pauseMonitor(userID, monitorID) { | async function pauseMonitor(userID, monitorID) { | ||||||
|     await checkOwner(userID, monitorID); |     await checkOwner(userID, monitorID); | ||||||
|  |  | ||||||
|     console.log(`Pause Monitor: ${monitorID} User ID: ${userID}`); |     log("manage", `Pause Monitor: ${monitorID} User ID: ${userID}`); | ||||||
|  |  | ||||||
|     await R.exec("UPDATE monitor SET active = 0 WHERE id = ? AND user_id = ? ", [ |     await R.exec("UPDATE monitor SET active = 0 WHERE id = ? AND user_id = ? ", [ | ||||||
|         monitorID, |         monitorID, | ||||||
| @@ -1510,10 +1548,10 @@ async function startMonitors() { | |||||||
| } | } | ||||||
|  |  | ||||||
| async function shutdownFunction(signal) { | async function shutdownFunction(signal) { | ||||||
|     console.log("Shutdown requested"); |     log("server", "Shutdown requested"); | ||||||
|     console.log("Called signal: " + signal); |     log("server", "Called signal: " + signal); | ||||||
|  |  | ||||||
|     console.log("Stopping all monitors"); |     log("server", "Stopping all monitors"); | ||||||
|     for (let id in monitorList) { |     for (let id in monitorList) { | ||||||
|         let monitor = monitorList[id]; |         let monitor = monitorList[id]; | ||||||
|         monitor.stop(); |         monitor.stop(); | ||||||
| @@ -1522,8 +1560,12 @@ async function shutdownFunction(signal) { | |||||||
|     await Database.close(); |     await Database.close(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function getClientIp(socket) { | ||||||
|  |     return socket.client.conn.remoteAddress.replace(/^.*:/, "") | ||||||
|  | } | ||||||
|  |  | ||||||
| function finalFunction() { | function finalFunction() { | ||||||
|     console.log("Graceful shutdown successful!"); |     log("server", "Graceful shutdown successful!"); | ||||||
| } | } | ||||||
|  |  | ||||||
| gracefulShutdown(server, { | gracefulShutdown(server, { | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| const { R } = require("redbean-node"); | const { R } = require("redbean-node"); | ||||||
| const { checkLogin, setSettings } = require("../util-server"); | const { checkLogin, setSettings } = require("../util-server"); | ||||||
| const dayjs = require("dayjs"); | const dayjs = require("dayjs"); | ||||||
| const { debug } = require("../../src/util"); | const { log } = require("../../src/util"); | ||||||
| const ImageDataURI = require("../image-data-uri"); | const ImageDataURI = require("../image-data-uri"); | ||||||
| const Database = require("../database"); | const Database = require("../database"); | ||||||
| const apicache = require("../modules/apicache"); | const apicache = require("../modules/apicache"); | ||||||
| @@ -138,8 +138,8 @@ module.exports.statusPageSocketHandler = (socket) => { | |||||||
|                 group.id = groupBean.id; |                 group.id = groupBean.id; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Delete groups that not in the list |             // Delete groups that are not in the list | ||||||
|             debug("Delete groups that not in the list"); |             log("socket", "Delete groups that are not in the list", "debug"); | ||||||
|             const slots = groupIDList.map(() => "?").join(","); |             const slots = groupIDList.map(() => "?").join(","); | ||||||
|             await R.exec(`DELETE FROM \`group\` WHERE id NOT IN (${slots})`, groupIDList); |             await R.exec(`DELETE FROM \`group\` WHERE id NOT IN (${slots})`, groupIDList); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| const tcpp = require("tcp-ping"); | const tcpp = require("tcp-ping"); | ||||||
| const Ping = require("./ping-lite"); | const Ping = require("./ping-lite"); | ||||||
| const { R } = require("redbean-node"); | const { R } = require("redbean-node"); | ||||||
| const { debug } = require("../src/util"); | const { log } = require("../src/util"); | ||||||
| const passwordHash = require("./password-hash"); | const passwordHash = require("./password-hash"); | ||||||
| const dayjs = require("dayjs"); | const dayjs = require("dayjs"); | ||||||
| const { Resolver } = require("dns"); | const { Resolver } = require("dns"); | ||||||
| @@ -119,7 +119,7 @@ exports.setting = async function (key) { | |||||||
|  |  | ||||||
|     try { |     try { | ||||||
|         const v = JSON.parse(value); |         const v = JSON.parse(value); | ||||||
|         debug(`Get Setting: ${key}: ${v}`); |         log("util", `Get Setting: ${key}: ${v}`, "debug"); | ||||||
|         return v; |         return v; | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|         return value; |         return value; | ||||||
| @@ -206,7 +206,7 @@ const parseCertificateInfo = function (info) { | |||||||
|     const existingList = {}; |     const existingList = {}; | ||||||
|  |  | ||||||
|     while (link) { |     while (link) { | ||||||
|         debug(`[${i}] ${link.fingerprint}`); |         log("util", `[${i}] ${link.fingerprint}`, "debug"); | ||||||
|  |  | ||||||
|         if (!link.valid_from || !link.valid_to) { |         if (!link.valid_from || !link.valid_to) { | ||||||
|             break; |             break; | ||||||
| @@ -221,7 +221,7 @@ const parseCertificateInfo = function (info) { | |||||||
|         if (link.issuerCertificate == null) { |         if (link.issuerCertificate == null) { | ||||||
|             break; |             break; | ||||||
|         } else if (link.issuerCertificate.fingerprint in existingList) { |         } else if (link.issuerCertificate.fingerprint in existingList) { | ||||||
|             debug(`[Last] ${link.issuerCertificate.fingerprint}`); |             log("util", `[Last] ${link.issuerCertificate.fingerprint}`, "debug"); | ||||||
|             link.issuerCertificate = null; |             link.issuerCertificate = null; | ||||||
|             break; |             break; | ||||||
|         } else { |         } else { | ||||||
| @@ -242,7 +242,7 @@ exports.checkCertificate = function (res) { | |||||||
|     const info = res.request.res.socket.getPeerCertificate(true); |     const info = res.request.res.socket.getPeerCertificate(true); | ||||||
|     const valid = res.request.res.socket.authorized || false; |     const valid = res.request.res.socket.authorized || false; | ||||||
|  |  | ||||||
|     debug("Parsing Certificate Info"); |     log("util", "Parsing Certificate Info", "debug"); | ||||||
|     const parsedInfo = parseCertificateInfo(info); |     const parsedInfo = parseCertificateInfo(info); | ||||||
|  |  | ||||||
|     return { |     return { | ||||||
| @@ -345,7 +345,7 @@ exports.startUnitTest = async () => { | |||||||
|  */ |  */ | ||||||
| exports.convertToUTF8 = (body) => { | exports.convertToUTF8 = (body) => { | ||||||
|     const guessEncoding = chardet.detect(body); |     const guessEncoding = chardet.detect(body); | ||||||
|     //debug("Guess Encoding: " + guessEncoding); |     //log("util", "Guess Encoding: " + guessEncoding, "debug"); | ||||||
|     const str = iconv.decode(body, guessEncoding); |     const str = iconv.decode(body, guessEncoding); | ||||||
|     return str.toString(); |     return str.toString(); | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										86
									
								
								src/util.js
									
									
									
									
									
								
							
							
						
						
									
										86
									
								
								src/util.js
									
									
									
									
									
								
							| @@ -6,10 +6,10 @@ | |||||||
| // | // | ||||||
| // Backend uses the compiled file util.js | // Backend uses the compiled file util.js | ||||||
| // Frontend uses util.ts | // Frontend uses util.ts | ||||||
| Object.defineProperty(exports, "__esModule", { value: true }); | exports.__esModule = true; | ||||||
| exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isDev = void 0; | exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.ucfirst = exports.sleep = exports.flipStatus = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isDev = void 0; | ||||||
| const _dayjs = require("dayjs"); | var _dayjs = require("dayjs"); | ||||||
| const dayjs = _dayjs; | var dayjs = _dayjs; | ||||||
| exports.isDev = process.env.NODE_ENV === "development"; | exports.isDev = process.env.NODE_ENV === "development"; | ||||||
| exports.appName = "Uptime Kuma"; | exports.appName = "Uptime Kuma"; | ||||||
| exports.DOWN = 0; | exports.DOWN = 0; | ||||||
| @@ -29,7 +29,7 @@ function flipStatus(s) { | |||||||
| } | } | ||||||
| exports.flipStatus = flipStatus; | exports.flipStatus = flipStatus; | ||||||
| function sleep(ms) { | function sleep(ms) { | ||||||
|     return new Promise(resolve => setTimeout(resolve, ms)); |     return new Promise(function (resolve) { return setTimeout(resolve, ms); }); | ||||||
| } | } | ||||||
| exports.sleep = sleep; | exports.sleep = sleep; | ||||||
| /** | /** | ||||||
| @@ -40,16 +40,36 @@ function ucfirst(str) { | |||||||
|     if (!str) { |     if (!str) { | ||||||
|         return str; |         return str; | ||||||
|     } |     } | ||||||
|     const firstLetter = str.substr(0, 1); |     var firstLetter = str.substr(0, 1); | ||||||
|     return firstLetter.toUpperCase() + str.substr(1); |     return firstLetter.toUpperCase() + str.substr(1); | ||||||
| } | } | ||||||
| exports.ucfirst = ucfirst; | exports.ucfirst = ucfirst; | ||||||
| function debug(msg) { | // log levels = info / warn / error / debug | ||||||
|     if (exports.isDev) { | function log(module, msg, level) { | ||||||
|         console.log(msg); |     if (level === void 0) { level = "info"; } | ||||||
|  |     module = module.toUpperCase(); | ||||||
|  |     level = level.toUpperCase(); | ||||||
|  |     var now = new Date().toISOString(); | ||||||
|  |     var formattedMessage = (typeof msg === "string") ? now + " [" + module + "] " + level + ": " + msg : msg; | ||||||
|  |     if (level === "INFO") { | ||||||
|  |         console.log(formattedMessage); | ||||||
|  |     } | ||||||
|  |     else if (level === "WARN") { | ||||||
|  |         console.warn(formattedMessage); | ||||||
|  |     } | ||||||
|  |     else if (level === "ERROR") { | ||||||
|  |         console.error(formattedMessage); | ||||||
|  |     } | ||||||
|  |     else if (level === "DEBUG") { | ||||||
|  |         if (exports.isDev) { | ||||||
|  |             console.debug(formattedMessage); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         console.log(formattedMessage); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| exports.debug = debug; | exports.log = log; | ||||||
| function polyfill() { | function polyfill() { | ||||||
|     /** |     /** | ||||||
|      * String.prototype.replaceAll() polyfill |      * String.prototype.replaceAll() polyfill | ||||||
| @@ -69,16 +89,17 @@ function polyfill() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| exports.polyfill = polyfill; | exports.polyfill = polyfill; | ||||||
| class TimeLogger { | var TimeLogger = /** @class */ (function () { | ||||||
|     constructor() { |     function TimeLogger() { | ||||||
|         this.startTime = dayjs().valueOf(); |         this.startTime = dayjs().valueOf(); | ||||||
|     } |     } | ||||||
|     print(name) { |     TimeLogger.prototype.print = function (name) { | ||||||
|         if (exports.isDev && process.env.TIMELOGGER === "1") { |         if (exports.isDev && process.env.TIMELOGGER === "1") { | ||||||
|             console.log(name + ": " + (dayjs().valueOf() - this.startTime) + "ms"); |             console.log(name + ": " + (dayjs().valueOf() - this.startTime) + "ms"); | ||||||
|         } |         } | ||||||
|     } |     }; | ||||||
| } |     return TimeLogger; | ||||||
|  | }()); | ||||||
| exports.TimeLogger = TimeLogger; | exports.TimeLogger = TimeLogger; | ||||||
| /** | /** | ||||||
|  * Returns a random number between min (inclusive) and max (exclusive) |  * Returns a random number between min (inclusive) and max (exclusive) | ||||||
| @@ -106,12 +127,12 @@ exports.getRandomInt = getRandomInt; | |||||||
|  * Returns either the NodeJS crypto.randomBytes() function or its |  * Returns either the NodeJS crypto.randomBytes() function or its | ||||||
|  * browser equivalent implemented via window.crypto.getRandomValues() |  * browser equivalent implemented via window.crypto.getRandomValues() | ||||||
|  */ |  */ | ||||||
| let getRandomBytes = ((typeof window !== 'undefined' && window.crypto) | var getRandomBytes = ((typeof window !== 'undefined' && window.crypto) | ||||||
|     // Browsers |     // Browsers | ||||||
|     ? function () { |     ? function () { | ||||||
|         return (numBytes) => { |         return function (numBytes) { | ||||||
|             let randomBytes = new Uint8Array(numBytes); |             var randomBytes = new Uint8Array(numBytes); | ||||||
|             for (let i = 0; i < numBytes; i += 65536) { |             for (var i = 0; i < numBytes; i += 65536) { | ||||||
|                 window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536))); |                 window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536))); | ||||||
|             } |             } | ||||||
|             return randomBytes; |             return randomBytes; | ||||||
| @@ -123,13 +144,13 @@ let getRandomBytes = ((typeof window !== 'undefined' && window.crypto) | |||||||
|     })(); |     })(); | ||||||
| function getCryptoRandomInt(min, max) { | function getCryptoRandomInt(min, max) { | ||||||
|     // synchronous version of: https://github.com/joepie91/node-random-number-csprng |     // synchronous version of: https://github.com/joepie91/node-random-number-csprng | ||||||
|     const range = max - min; |     var range = max - min; | ||||||
|     if (range >= Math.pow(2, 32)) |     if (range >= Math.pow(2, 32)) | ||||||
|         console.log("Warning! Range is too large."); |         console.log("Warning! Range is too large."); | ||||||
|     let tmpRange = range; |     var tmpRange = range; | ||||||
|     let bitsNeeded = 0; |     var bitsNeeded = 0; | ||||||
|     let bytesNeeded = 0; |     var bytesNeeded = 0; | ||||||
|     let mask = 1; |     var mask = 1; | ||||||
|     while (tmpRange > 0) { |     while (tmpRange > 0) { | ||||||
|         if (bitsNeeded % 8 === 0) |         if (bitsNeeded % 8 === 0) | ||||||
|             bytesNeeded += 1; |             bytesNeeded += 1; | ||||||
| @@ -137,9 +158,9 @@ function getCryptoRandomInt(min, max) { | |||||||
|         mask = mask << 1 | 1; |         mask = mask << 1 | 1; | ||||||
|         tmpRange = tmpRange >>> 1; |         tmpRange = tmpRange >>> 1; | ||||||
|     } |     } | ||||||
|     const randomBytes = getRandomBytes(bytesNeeded); |     var randomBytes = getRandomBytes(bytesNeeded); | ||||||
|     let randomValue = 0; |     var randomValue = 0; | ||||||
|     for (let i = 0; i < bytesNeeded; i++) { |     for (var i = 0; i < bytesNeeded; i++) { | ||||||
|         randomValue |= randomBytes[i] << 8 * i; |         randomValue |= randomBytes[i] << 8 * i; | ||||||
|     } |     } | ||||||
|     randomValue = randomValue & mask; |     randomValue = randomValue & mask; | ||||||
| @@ -151,11 +172,12 @@ function getCryptoRandomInt(min, max) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| exports.getCryptoRandomInt = getCryptoRandomInt; | exports.getCryptoRandomInt = getCryptoRandomInt; | ||||||
| function genSecret(length = 64) { | function genSecret(length) { | ||||||
|     let secret = ""; |     if (length === void 0) { length = 64; } | ||||||
|     const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; |     var secret = ""; | ||||||
|     const charsLength = chars.length; |     var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | ||||||
|     for (let i = 0; i < length; i++) { |     var charsLength = chars.length; | ||||||
|  |     for (var i = 0; i < length; i++) { | ||||||
|         secret += chars.charAt(getCryptoRandomInt(0, charsLength - 1)); |         secret += chars.charAt(getCryptoRandomInt(0, charsLength - 1)); | ||||||
|     } |     } | ||||||
|     return secret; |     return secret; | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								src/util.ts
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/util.ts
									
									
									
									
									
								
							| @@ -49,9 +49,26 @@ export function ucfirst(str: string) { | |||||||
|     return firstLetter.toUpperCase() + str.substr(1); |     return firstLetter.toUpperCase() + str.substr(1); | ||||||
| } | } | ||||||
|  |  | ||||||
| export function debug(msg: any) { | // log levels = info / warn / error / debug | ||||||
|     if (isDev) { | export function log(module: string, msg: any, level:string = "info") { | ||||||
|         console.log(msg); |     module = module.toUpperCase(); | ||||||
|  |     level = level.toUpperCase(); | ||||||
|  |  | ||||||
|  |     const now = new Date().toISOString(); | ||||||
|  |     const formattedMessage = (typeof msg === "string") ? `${now} [${module}] ${level}: ${msg}` : msg; | ||||||
|  |  | ||||||
|  |     if (level === "INFO") { | ||||||
|  |         console.log(formattedMessage); | ||||||
|  |     } else if (level === "WARN") { | ||||||
|  |         console.warn(formattedMessage); | ||||||
|  |     } else if (level === "ERROR") { | ||||||
|  |         console.error(formattedMessage); | ||||||
|  |     } else if (level === "DEBUG") { | ||||||
|  |         if (isDev) { | ||||||
|  |             console.debug(formattedMessage); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         console.log(formattedMessage); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user