From f55350bebc13035e8ca54a54d84e7d8c40aec2a0 Mon Sep 17 00:00:00 2001 From: Calum Bird Date: Tue, 9 Nov 2021 21:24:31 -0800 Subject: [PATCH 01/40] Generated documentation :) --- extra/download-dist.js | 6 +++ extra/update-version.js | 19 ++++++++ server/auth.js | 7 +++ server/client.js | 12 +++++ server/image-data-uri.js | 20 +++++++++ server/modules/apicache/apicache.js | 70 +++++++++++++++++++++++++++++ server/notification.js | 7 +++ server/ping-lite.js | 12 +++++ server/server.js | 53 ++++++++++++++++++++++ src/util-frontend.js | 15 ++++++- src/util.js | 14 ++++++ 11 files changed, 234 insertions(+), 1 deletion(-) diff --git a/extra/download-dist.js b/extra/download-dist.js index dc64166c4..a9c630239 100644 --- a/extra/download-dist.js +++ b/extra/download-dist.js @@ -11,6 +11,12 @@ const filename = "dist.tar.gz"; const url = `https://github.com/louislam/uptime-kuma/releases/download/${version}/${filename}`; download(url); +/** + * Downloads the latest version of the dist from a GitHub release. + * @param {string} url The URL to download from. + * + * Generated by Trelent + */ function download(url) { console.log(url); diff --git a/extra/update-version.js b/extra/update-version.js index 2e3b42da8..34b46281f 100644 --- a/extra/update-version.js +++ b/extra/update-version.js @@ -37,6 +37,12 @@ if (! exists) { console.log("version exists"); } +/** + * Updates the version number in package.json and commits it to git + * @param {string} version - The new version number + * + * Generated by Trelent + */ function commit(version) { let msg = "update to " + version; @@ -54,6 +60,12 @@ function tag(version) { console.log(res.stdout.toString().trim()); } +/** + * Checks if a given version is already tagged in the git repository. + * @param {string} version - The version to check for. + * + * Generated by Trelent + */ function tagExists(version) { if (! version) { throw new Error("invalid version"); @@ -64,6 +76,13 @@ function tagExists(version) { return res.stdout.toString().trim() === version; } +/** + * Update the How-to-Update.md file in the wiki to reflect a new version of Kuma. + * @param {string} oldVersion The previous version of Kuma that was released. + * @param {string} newVersion The current version of Kuma that is being released. + * + * Generated by Trelent + */ function updateWiki(oldVersion, newVersion) { const wikiDir = "./tmp/wiki"; const howToUpdateFilename = "./tmp/wiki/🆙-How-to-Update.md"; diff --git a/server/auth.js b/server/auth.js index c476ea1e3..2cb71e93c 100644 --- a/server/auth.js +++ b/server/auth.js @@ -30,6 +30,13 @@ exports.login = async function (username, password) { return null; }; +/** + * A function that checks if a user is logged in. + * @param {string} username The username of the user to check for. + * @param {function} callback The callback to call when done, with an error and result parameter. + * + * Generated by Trelent + */ function myAuthorizer(username, password, callback) { setting("disableAuth").then((result) => { if (result) { diff --git a/server/client.js b/server/client.js index c7b3bc162..04a6abcd8 100644 --- a/server/client.js +++ b/server/client.js @@ -7,6 +7,12 @@ const { io } = require("./server"); const { setting } = require("./util-server"); const checkVersion = require("./check-version"); +/** + * Send a list of notifications to the user. + * @param {Socket} socket The socket object that is connected to the client. + * + * Generated by Trelent + */ async function sendNotificationList(socket) { const timeLogger = new TimeLogger(); @@ -83,6 +89,12 @@ async function sendImportantHeartbeatList(socket, monitorID, toUser = false, ove } +/** + * Emits the version information to the client. + * @param {Socket} socket The socket object that is connected to the client. + * + * Generated by Trelent + */ async function sendInfo(socket) { socket.emit("info", { version: checkVersion.version, diff --git a/server/image-data-uri.js b/server/image-data-uri.js index 3ccaab7d5..1ab499c15 100644 --- a/server/image-data-uri.js +++ b/server/image-data-uri.js @@ -6,6 +6,12 @@ let fs = require("fs"); let ImageDataURI = (() => { + /** + * @param {string} dataURI - A string that is a valid Data URI. + * @returns {?Object} An object with properties "imageType" and "dataBase64". The former is the image type, e.g., "png", and the latter is a base64 encoded string of the image's binary data. If it fails to parse, returns null instead of an object. + * + * Generated by Trelent + */ function decode(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/\""); @@ -20,6 +26,13 @@ let ImageDataURI = (() => { }; } + /** + * @param {Buffer} data - The image data to be encoded. + * @param {String} mediaType - The type of the image, e.g., "image/png". + * @returns {String|null} A string representing the base64-encoded version of the given Buffer object or null if an error occurred. + * + * Generated by Trelent + */ function encode(data, mediaType) { if (!data || !mediaType) { console.log("ImageDataURI :: Error :: Missing some of the required params: data, mediaType "); @@ -33,6 +46,13 @@ let ImageDataURI = (() => { return dataImgBase64; } + /** + * Converts a data URI to a file path. + * @param {string} dataURI The Data URI of the image. + * @param {string} [filePath] The path where the image will be saved, defaults to "./". + * + * Generated by Trelent + */ function outputFile(dataURI, filePath) { filePath = filePath || "./"; return new Promise((resolve, reject) => { diff --git a/server/modules/apicache/apicache.js b/server/modules/apicache/apicache.js index 22d1fed71..25f0a54f5 100644 --- a/server/modules/apicache/apicache.js +++ b/server/modules/apicache/apicache.js @@ -68,6 +68,15 @@ function ApiCache() { instances.push(this); this.id = instances.length; + /** + * Logs a message to the console if the `DEBUG` environment variable is set. + * @param {string} a - The first argument to log. + * @param {string} b - The second argument to log. + * @param {string} c - The third argument to log. + * @param {string} d - The fourth argument to log, and so on... (optional) + * + * Generated by Trelent + */ function debug(a, b, c, d) { let arr = ["\x1b[36m[apicache]\x1b[0m", a, b, c, d].filter(function (arg) { return arg !== undefined; @@ -77,6 +86,13 @@ function ApiCache() { return (globalOptions.debug || debugEnv) && console.log.apply(null, arr); } + /** + * Returns true if the given request and response should be logged. + * @param {Object} request The HTTP request object. + * @param {Object} response The HTTP response object. + * + * Generated by Trelent + */ function shouldCacheResponse(request, response, toggle) { let opt = globalOptions; let codes = opt.statusCodes; @@ -99,6 +115,12 @@ function ApiCache() { return true; } + /** + * Adds a key to the index. + * @param {string} key The key to add. + * + * Generated by Trelent + */ function addIndexEntries(key, req) { let groupName = req.apicacheGroup; @@ -111,6 +133,13 @@ function ApiCache() { index.all.unshift(key); } + /** + * Returns a new object containing only the whitelisted headers. + * @param {Object} headers The original object of header names and values. + * @param {Array.} globalOptions.headerWhitelist An array of strings representing the whitelisted header names to keep in the output object. + * + * Generated by Trelent + */ function filterBlacklistedHeaders(headers) { return Object.keys(headers) .filter(function (key) { @@ -122,6 +151,12 @@ function ApiCache() { }, {}); } + /** + * @param {Object} headers The response headers to filter. + * @returns {Object} A new object containing only the whitelisted response headers. + * + * Generated by Trelent + */ function createCacheObject(status, headers, data, encoding) { return { status: status, @@ -132,6 +167,14 @@ function ApiCache() { }; } + /** + * Sets a cache value for the given key. + * @param {string} key The cache key to set. + * @param {*} value The cache value to set. + * @param {number} duration How long in milliseconds the cached response should be valid for (defaults to 1 hour). + * + * Generated by Trelent + */ function cacheResponse(key, value, duration) { let redis = globalOptions.redisClient; let expireCallback = globalOptions.events.expire; @@ -154,6 +197,12 @@ function ApiCache() { }, Math.min(duration, 2147483647)); } + /** + * Appends content to the response. + * @param {string|Buffer} content The content to append. + * + * Generated by Trelent + */ function accumulateContent(res, content) { if (content) { if (typeof content == "string") { @@ -179,6 +228,13 @@ function ApiCache() { } } + /** + * Monkeypatches the response object to add cache control headers and create a cache object. + * @param {Object} req - The request object. + * @param {Object} res - The response object. + * + * Generated by Trelent + */ function makeResponseCacheable(req, res, next, key, duration, strDuration, toggle) { // monkeypatch res.end to create cache object res._apicache = { @@ -245,6 +301,13 @@ function ApiCache() { next(); } + /** + * @param {Request} request + * @param {Response} response + * @returns {boolean|undefined} true if the request should be cached, false otherwise. If undefined, defaults to true. + * + * Generated by Trelent + */ function sendCachedResponse(request, response, cacheObject, toggle, next, duration) { if (toggle && !toggle(request, response)) { return next(); @@ -365,6 +428,13 @@ function ApiCache() { return this.getIndex(); }; + /** + * Converts a duration string to an integer number of milliseconds. + * @param {string} duration - The string to convert. + * @returns {number} The converted value in milliseconds, or the defaultDuration if it can't be parsed. + * + * Generated by Trelent + */ function parseDuration(duration, defaultDuration) { if (typeof duration === "number") { return duration; diff --git a/server/notification.js b/server/notification.js index 18c823b2b..136c95532 100644 --- a/server/notification.js +++ b/server/notification.js @@ -140,6 +140,13 @@ class Notification { } +/** + * Adds a new monitor to the database. + * @param {number} userID The ID of the user that owns this monitor. + * @param {string} name The name of this monitor. + * + * Generated by Trelent + */ async function applyNotificationEveryMonitor(notificationID, userID) { let monitors = await R.getAll("SELECT id FROM monitor WHERE user_id = ?", [ userID diff --git a/server/ping-lite.js b/server/ping-lite.js index b2d6405ad..ea3f67ed7 100644 --- a/server/ping-lite.js +++ b/server/ping-lite.js @@ -8,6 +8,13 @@ const util = require("./util-server"); module.exports = Ping; +/** + * @param {string} host - The host to ping + * @param {object} [options] - Options for the ping command + * @param {array|string} [options.args] - Arguments to pass to the ping command + * + * Generated by Trelent + */ function Ping(host, options) { if (!host) { throw new Error("You must specify a host to ping!"); @@ -125,6 +132,11 @@ Ping.prototype.send = function (callback) { } }); + /** + * @param {Function} callback + * + * Generated by Trelent + */ function onEnd() { let stdout = this.stdout._stdout; let stderr = this.stderr._stderr; diff --git a/server/server.js b/server/server.js index d1fd7ff29..536d0926c 100644 --- a/server/server.js +++ b/server/server.js @@ -1349,6 +1349,13 @@ exports.entryPage = "dashboard"; })(); +/** + * Adds or removes notifications from a monitor. + * @param {number} monitorID The ID of the monitor to add/remove notifications from. + * @param {Array.} notificationIDList An array of IDs for the notifications to add/remove. + * + * Generated by Trelent + */ async function updateMonitorNotification(monitorID, notificationIDList) { await R.exec("DELETE FROM monitor_notification WHERE monitor_id = ? ", [ monitorID, @@ -1364,6 +1371,13 @@ async function updateMonitorNotification(monitorID, notificationIDList) { } } +/** + * This function checks if the user owns a monitor with the given ID. + * @param {number} monitorID - The ID of the monitor to check ownership for. + * @param {number} userID - The ID of the user who is trying to access this data. + * + * Generated by Trelent + */ async function checkOwner(userID, monitorID) { let row = await R.getRow("SELECT id FROM monitor WHERE id = ? AND user_id = ? ", [ monitorID, @@ -1381,6 +1395,13 @@ async function sendMonitorList(socket) { return list; } +/** + * This function is used to send the heartbeat list of a monitor. + * @param {Socket} socket - The socket object that will be used to send the data. + * @param {String} monitorID - The ID of the monitor that will have its heartbeat list sent. + * + * Generated by Trelent + */ async function afterLogin(socket, user) { socket.userID = user.id; socket.join(user.id); @@ -1403,6 +1424,13 @@ async function afterLogin(socket, user) { } } +/** + * Get a list of monitors for the given user. + * @param {string} userID - The ID of the user to get monitors for. + * @returns {Promise} A promise that resolves to an object with monitor IDs as keys and monitor objects as values. + * + * Generated by Trelent + */ async function getMonitorJSONList(userID) { let result = {}; @@ -1417,6 +1445,11 @@ async function getMonitorJSONList(userID) { return result; } +/** + * Connect to the database and patch it if necessary. + * + * Generated by Trelent + */ async function initDatabase() { if (! fs.existsSync(Database.path)) { console.log("Copying Database"); @@ -1451,6 +1484,13 @@ async function initDatabase() { jwtSecret = jwtSecretBean.value; } +/** + * Resume a monitor. + * @param {string} userID - The ID of the user who owns the monitor. + * @param {string} monitorID - The ID of the monitor to resume. + * + * Generated by Trelent + */ async function startMonitor(userID, monitorID) { await checkOwner(userID, monitorID); @@ -1477,6 +1517,13 @@ async function restartMonitor(userID, monitorID) { return await startMonitor(userID, monitorID); } +/** + * Pause a monitor. + * @param {string} userID - The ID of the user who owns the monitor. + * @param {string} monitorID - The ID of the monitor to pause. + * + * Generated by Trelent + */ async function pauseMonitor(userID, monitorID) { await checkOwner(userID, monitorID); @@ -1509,6 +1556,12 @@ async function startMonitors() { } } +/** + * Stops all monitors and closes the database connection. + * @param {string} signal The signal that triggered this function to be called. + * + * Generated by Trelent + */ async function shutdownFunction(signal) { console.log("Shutdown requested"); console.log("Called signal: " + signal); diff --git a/src/util-frontend.js b/src/util-frontend.js index 9094dda43..dff6d679b 100644 --- a/src/util-frontend.js +++ b/src/util-frontend.js @@ -7,6 +7,12 @@ import { localeDirection, currentLocale } from "./i18n"; dayjs.extend(utc); dayjs.extend(timezone); +/** + * Returns the offset from UTC in hours for the current locale. + * @returns {number} The offset from UTC in hours. + * + * Generated by Trelent + */ function getTimezoneOffset(timeZone) { const now = new Date(); const tzString = now.toLocaleString("en-US", { @@ -18,7 +24,14 @@ function getTimezoneOffset(timeZone) { return -offset; } -export function timezoneList() { +export /** + * Returns a list of timezones sorted by their offset from UTC. + * @param {Array} timezones - An array of timezone objects. + * @returns {Array} A list of the given timezones sorted by their offset from UTC. + * + * Generated by Trelent + */ +function timezoneList() { let result = []; for (let timezone of timezones) { diff --git a/src/util.js b/src/util.js index b2df7ac79..9945d7cfb 100644 --- a/src/util.js +++ b/src/util.js @@ -121,6 +121,13 @@ let getRandomBytes = ((typeof window !== 'undefined' && window.crypto) : function () { return require("crypto").randomBytes; })(); +/** + * Returns a random integer between min (inclusive) and max (exclusive). + * @param {number} min The minimum value. + * @param {number} max The maximum value. + * + * Generated by Trelent + */ function getCryptoRandomInt(min, max) { // synchronous version of: https://github.com/joepie91/node-random-number-csprng const range = max - min; @@ -151,6 +158,13 @@ function getCryptoRandomInt(min, max) { } } exports.getCryptoRandomInt = getCryptoRandomInt; +/** + * Generates a random string of length `length` from the characters in `chars`. + * @param {number} length The number of characters to generate. + * @param {string} chars A string containing all the possible characters to use for generating the random string. + * + * Generated by Trelent + */ function genSecret(length = 64) { let secret = ""; const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; From bdcdf47e52938662c497f6d76e13593a06cb3f7b Mon Sep 17 00:00:00 2001 From: Andreas Brett Date: Thu, 11 Nov 2021 12:31:28 +0100 Subject: [PATCH 02/40] introduce consistent logging --- server/auth.js | 1 - server/database.js | 76 ++++---- server/image-data-uri.js | 5 +- server/jobs.js | 3 +- server/model/monitor.js | 79 ++++---- server/notification-providers/matrix.js | 6 +- server/notification.js | 3 +- server/prometheus.js | 13 +- server/rate-limiter.js | 4 +- server/routers/api-router.js | 6 +- server/server.js | 168 +++++++++++------- .../status-page-socket-handler.js | 6 +- server/util-server.js | 12 +- src/util.js | 86 +++++---- src/util.ts | 23 ++- 15 files changed, 290 insertions(+), 201 deletions(-) diff --git a/server/auth.js b/server/auth.js index c476ea1e3..ea1e55e27 100644 --- a/server/auth.js +++ b/server/auth.js @@ -2,7 +2,6 @@ const basicAuth = require("express-basic-auth"); const passwordHash = require("./password-hash"); const { R } = require("redbean-node"); const { setting } = require("./util-server"); -const { debug } = require("../src/util"); const { loginRateLimiter } = require("./rate-limiter"); /** diff --git a/server/database.js b/server/database.js index 41d91e858..53fd3ef96 100644 --- a/server/database.js +++ b/server/database.js @@ -1,7 +1,7 @@ const fs = require("fs"); const { R } = require("redbean-node"); const { setSetting, setting } = require("./util-server"); -const { debug, sleep } = require("../src/util"); +const { log, sleep } = require("../src/util"); const dayjs = require("dayjs"); const knex = require("knex"); @@ -76,7 +76,7 @@ class Database { fs.mkdirSync(Database.uploadDir, { recursive: true }); } - console.log(`Data Dir: ${Database.dataDir}`); + log("db", `Data Dir: ${Database.dataDir}`); } static async connect() { @@ -117,10 +117,10 @@ class Database { await R.exec("PRAGMA cache_size = -12000"); await R.exec("PRAGMA auto_vacuum = FULL"); - console.log("SQLite config:"); - console.log(await R.getAll("PRAGMA journal_mode")); - console.log(await R.getAll("PRAGMA cache_size")); - console.log("SQLite Version: " + await R.getCell("SELECT sqlite_version()")); + log("db", "SQLite config:"); + log("db", await R.getAll("PRAGMA journal_mode")); + log("db", await R.getAll("PRAGMA cache_size")); + log("db","SQLite Version: " + await R.getCell("SELECT sqlite_version()")); } static async patch() { @@ -130,15 +130,15 @@ class Database { version = 0; } - console.info("Your database version: " + version); - console.info("Latest database version: " + this.latestVersion); + log("db", "Your database version: " + version); + log("db", "Latest database version: " + this.latestVersion); if (version === this.latestVersion) { - console.info("Database patch not needed"); + log("db", "Database patch not needed"); } else if (version > this.latestVersion) { - console.info("Warning: Database version is newer than expected"); + log("db", "Warning: Database version is newer than expected"); } else { - console.info("Database patch is needed"); + log("db", "Database patch is needed"); this.backup(version); @@ -146,17 +146,17 @@ class Database { try { for (let i = version + 1; i <= this.latestVersion; i++) { const sqlFile = `./db/patch${i}.sql`; - console.info(`Patching ${sqlFile}`); + log("db", `Patching ${sqlFile}`); await Database.importSQLFile(sqlFile); - console.info(`Patched ${sqlFile}`); + log("db", `Patched ${sqlFile}`); await setSetting("database_version", i); } } catch (ex) { await Database.close(); - console.error(ex); - console.error("Start Uptime-Kuma failed due to issue patching the database"); - console.error("Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); + log("db", ex, "error"); + log("db", "Start Uptime-Kuma failed due to issue patching the database", "error"); + 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(); process.exit(1); @@ -171,15 +171,15 @@ class Database { * @returns {Promise} */ static async patch2() { - console.log("Database Patch 2.0 Process"); + log("db", "Database Patch 2.0 Process"); let databasePatchedFiles = await setting("databasePatchedFiles"); if (! databasePatchedFiles) { databasePatchedFiles = {}; } - debug("Patched files:"); - debug(databasePatchedFiles); + log("db", "Patched files:", "debug"); + log("db", databasePatchedFiles, "debug"); try { for (let sqlFilename in this.patchList) { @@ -187,15 +187,15 @@ class Database { } if (this.patched) { - console.log("Database Patched Successfully"); + log("db", "Database Patched Successfully"); } } catch (ex) { await Database.close(); - console.error(ex); - console.error("Start Uptime-Kuma failed due to issue patching the database"); - console.error("Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); + log("db", ex, "error"); + log("db", "Start Uptime-Kuma failed due to issue patching the database", "error"); + 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(); @@ -214,16 +214,16 @@ class Database { let value = this.patchList[sqlFilename]; if (! value) { - console.log(sqlFilename + " skip"); + log("db", sqlFilename + " skip"); return; } // Check if patched if (! databasePatchedFiles[sqlFilename]) { - console.log(sqlFilename + " is not patched"); + log("db", sqlFilename + " is not patched"); if (value.parents) { - console.log(sqlFilename + " need parents"); + log("db", sqlFilename + " need parents"); for (let parentSQLFilename of value.parents) { await this.patch2Recursion(parentSQLFilename, databasePatchedFiles); } @@ -231,14 +231,14 @@ class Database { this.backup(dayjs().format("YYYYMMDDHHmmss")); - console.log(sqlFilename + " is patching"); + log("db", sqlFilename + " is patching"); this.patched = true; await this.importSQLFile("./db/" + sqlFilename); databasePatchedFiles[sqlFilename] = true; - console.log(sqlFilename + " was patched successfully"); + log("db", sqlFilename + " was patched successfully"); } 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); - console.log("Closing the database"); + log("db", "Closing the database"); while (true) { Database.noReject = true; @@ -300,10 +300,10 @@ class Database { if (Database.noReject) { break; } 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); } @@ -315,7 +315,7 @@ class Database { */ static backup(version) { if (! this.backupPath) { - console.info("Backing up the database"); + log("db", "Backing up the database"); this.backupPath = this.dataDir + "kuma.db.bak" + version; fs.copyFileSync(Database.path, this.backupPath); @@ -338,7 +338,7 @@ class Database { */ static restore() { 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 walPath = Database.path + "-wal"; @@ -357,7 +357,7 @@ class Database { fs.unlinkSync(walPath); } } 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); } @@ -373,14 +373,14 @@ class Database { } } else { - console.log("Nothing to restore"); + log("db", "Nothing to restore"); } } static getSize() { - debug("Database.getSize()"); + log("db", "Database.getSize()", "debug"); let stats = fs.statSync(Database.path); - debug(stats); + log("db", stats, "debug"); return stats.size; } diff --git a/server/image-data-uri.js b/server/image-data-uri.js index 3ccaab7d5..6aa4387ab 100644 --- a/server/image-data-uri.js +++ b/server/image-data-uri.js @@ -3,12 +3,13 @@ Modified with 0 dependencies */ let fs = require("fs"); +const { log } = require("../src/util"); let ImageDataURI = (() => { function decode(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; } @@ -22,7 +23,7 @@ let ImageDataURI = (() => { function encode(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; } diff --git a/server/jobs.js b/server/jobs.js index 0469d5cab..56a67b0fa 100644 --- a/server/jobs.js +++ b/server/jobs.js @@ -1,6 +1,7 @@ const path = require("path"); const Bree = require("bree"); const { SHARE_ENV } = require("worker_threads"); +const { log } = require("../src/util"); const jobs = [ { @@ -18,7 +19,7 @@ const initBackgroundJobs = function (args) { workerData: args, }, workerMessageHandler: (message) => { - console.log("[Background Job]:", message); + log("jobs", message); } }); diff --git a/server/model/monitor.js b/server/model/monitor.js index 980e0ac69..f7d17f292 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -6,7 +6,7 @@ dayjs.extend(utc); dayjs.extend(timezone); const axios = require("axios"); 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 { R } = require("redbean-node"); 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" let startTime = dayjs().valueOf(); - debug(`[${this.name}] Prepare Options for axios`); + log("monitor", `[${this.name}] Prepare Options for axios`, "debug"); const options = { url: this.url, 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); bean.msg = `${res.status} - ${res.statusText}`; bean.ping = dayjs().valueOf() - startTime; @@ -170,29 +170,30 @@ class Monitor extends BeanModel { // Check certificate if https is used let certInfoStartTime = dayjs().valueOf(); if (this.getUrl()?.protocol === "https:") { - debug(`[${this.name}] Check cert`); + log("monitor", `[${this.name}] Check cert`, "debug"); try { let tlsInfoObject = checkCertificate(res); tlsInfo = await this.updateTlsInfo(tlsInfoObject); if (!this.getIgnoreTls()) { - debug(`[${this.name}] call sendCertNotification`); + log("monitor", `[${this.name}] call sendCertNotification`, "debug"); await this.sendCertNotification(tlsInfoObject); } } catch (e) { 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") { - 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) { - console.log(res.data); + log("monitor", res.data); } if (this.type === "http") { @@ -272,7 +273,7 @@ class Monitor extends BeanModel { time ]); - debug("heartbeatCount" + heartbeatCount + " " + time); + log("monitor", "heartbeatCount" + heartbeatCount + " " + time, "debug"); if (heartbeatCount <= 0) { throw new Error("No heartbeat in the time window"); @@ -355,7 +356,7 @@ class Monitor extends BeanModel { 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); // Mark as important if status changed, ignore pending pings, @@ -363,11 +364,11 @@ class Monitor extends BeanModel { if (isImportant) { bean.important = true; - debug(`[${this.name}] sendNotification`); + log("monitor", `[${this.name}] sendNotification`, "debug"); await Monitor.sendNotification(isFirstBeat, this, bean); // Clear Status Page Cache - debug(`[${this.name}] apicache clear`); + log("monitor", `[${this.name}] apicache clear`, "debug"); apicache.clear(); } else { @@ -375,24 +376,24 @@ class Monitor extends BeanModel { } 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) { if (this.retryInterval > 0) { 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 { - 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()); Monitor.sendStats(io, this.id, this.user_id); - debug(`[${this.name}] Store`); + log("monitor", `[${this.name}] Store`, "debug"); await R.store(bean); - debug(`[${this.name}] prometheus.update`); + log("monitor", `[${this.name}] prometheus.update`, "debug"); prometheus.update(bean, tlsInfo); previousBeat = bean; @@ -401,15 +402,15 @@ class Monitor extends BeanModel { if (demoMode) { if (beatInterval < 20) { - console.log("beat interval too low, reset to 20s"); + log("monitor", "beat interval too low, reset to 20s"); beatInterval = 20; } } - debug(`[${this.name}] SetTimeout for next check.`); + log("monitor", `[${this.name}] SetTimeout for next check.`, "debug"); this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000); } 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) { console.trace(e); 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) { - console.log("Try to restart the monitor"); + log("monitor", "Try to restart the monitor"); this.heartbeatInterval = setTimeout(safeBeat, this.interval * 1000); } } @@ -481,17 +482,17 @@ class Monitor extends BeanModel { if (isValidObjects) { 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 = ?", [ this.id ]); } else { - debug("No need to reset sent_history"); - debug(oldCertInfo.certInfo.fingerprint256); - debug(checkCertificateResult.certInfo.fingerprint256); + log("monitor", "No need to reset sent_history", "debug"); + log("monitor", oldCertInfo.certInfo.fingerprint256, "debug"); + log("monitor", checkCertificateResult.certInfo.fingerprint256, "debug"); } } else { - debug("Not valid object"); + log("monitor", "Not valid object", "debug"); } } catch (e) { } @@ -512,7 +513,7 @@ class Monitor extends BeanModel { await Monitor.sendUptime(24 * 30, io, monitorID, userID); await Monitor.sendCertInfo(io, monitorID, userID); } 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 { await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(), bean.toJSON()); } catch (e) { - console.error("Cannot send notification to " + notification.name); - console.log(e); + log("monitor", "Cannot send notification to " + notification.name, "error"); + log("monitor", e, "error"); } } } @@ -677,7 +678,7 @@ class Monitor extends BeanModel { if (tlsInfoObject && tlsInfoObject.certInfo && tlsInfoObject.certInfo.daysRemaining) { 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, 14, notificationList); await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 7, notificationList); @@ -687,7 +688,7 @@ class Monitor extends BeanModel { async sendCertNotificationByTargetDays(daysRemaining, targetDays, notificationList) { if (daysRemaining > targetDays) { - debug(`No need to send cert notification. ${daysRemaining} > ${targetDays}`); + log("monitor", `No need to send cert notification. ${daysRemaining} > ${targetDays}`, "debug"); return; } @@ -701,21 +702,21 @@ class Monitor extends BeanModel { // Sent already, no need to send again if (row) { - debug("Sent already, no need to send again"); + log("monitor", "Sent already, no need to send again", "debug"); return; } let sent = false; - debug("Send certificate notification"); + log("monitor", "Send certificate notification", "debug"); for (let notification of notificationList) { 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`); sent = true; } catch (e) { - console.error("Cannot send cert notification to " + notification.name); - console.error(e); + log("monitor", "Cannot send cert notification to " + notification.name, "error"); + log("monitor", e, "error"); } } @@ -727,7 +728,7 @@ class Monitor extends BeanModel { ]); } } else { - debug("No notification, no need to send cert notification"); + log("monitor", "No notification, no need to send cert notification", "debug"); } } } diff --git a/server/notification-providers/matrix.js b/server/notification-providers/matrix.js index c1054fce6..1aaf56924 100644 --- a/server/notification-providers/matrix.js +++ b/server/notification-providers/matrix.js @@ -1,7 +1,7 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); const Crypto = require("crypto"); -const { debug } = require("../../src/util"); +const { log } = require("../../src/util"); class Matrix extends NotificationProvider { name = "matrix"; @@ -17,11 +17,11 @@ class Matrix extends NotificationProvider { .slice(0, size) ); - debug("Random String: " + randomString); + log("notification", "Random String: " + randomString, "debug"); const roomId = encodeURIComponent(notification.internalRoomId); - debug("Matrix Room ID: " + roomId); + log("notification", "Matrix Room ID: " + roomId, "debug"); try { let config = { diff --git a/server/notification.js b/server/notification.js index 18c823b2b..e0325759f 100644 --- a/server/notification.js +++ b/server/notification.js @@ -23,13 +23,14 @@ const Feishu = require("./notification-providers/feishu"); const AliyunSms = require("./notification-providers/aliyun-sms"); const DingDing = require("./notification-providers/dingding"); const Bark = require("./notification-providers/bark"); +const { log } = require("../src/util"); class Notification { providerList = {}; static init() { - console.log("Prepare Notification Providers"); + log("notification", "Prepare Notification Providers"); this.providerList = {}; diff --git a/server/prometheus.js b/server/prometheus.js index 870581d2e..e7e39881f 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -1,4 +1,5 @@ const PrometheusClient = require("prom-client"); +const { log } = require("../src/util"); const commonLabels = [ "monitor_name", @@ -56,20 +57,23 @@ class Prometheus { } monitor_cert_is_valid.set(this.monitorLabelValues, is_valid); } catch (e) { - console.error(e); + log("prometheus", "Caught error", "error"); + log("prometheus", e, "error"); } try { monitor_cert_days_remaining.set(this.monitorLabelValues, tlsInfo.certInfo.daysRemaining); } catch (e) { - console.error(e); + log("prometheus", "Caught error", "error"); + log("prometheus", e, "error"); } } try { monitor_status.set(this.monitorLabelValues, heartbeat.status); } catch (e) { - console.error(e); + log("prometheus", "Caught error", "error"); + log("prometheus", e, "error"); } try { @@ -80,7 +84,8 @@ class Prometheus { monitor_response_time.set(this.monitorLabelValues, -1); } } catch (e) { - console.error(e); + log("prometheus", "Caught error", "error"); + log("prometheus", e, "error"); } } diff --git a/server/rate-limiter.js b/server/rate-limiter.js index 0bacc14c7..10db259da 100644 --- a/server/rate-limiter.js +++ b/server/rate-limiter.js @@ -1,5 +1,5 @@ const { RateLimiter } = require("limiter"); -const { debug } = require("../src/util"); +const { log } = require("../src/util"); class KumaRateLimiter { constructor(config) { @@ -9,7 +9,7 @@ class KumaRateLimiter { async pass(callback, num = 1) { const remainingRequests = await this.removeTokens(num); - debug("Rate Limit (remainingRequests):" + remainingRequests); + log("rate-limit", "remaining requests: " + remainingRequests); if (remainingRequests < 0) { if (callback) { callback({ diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 79e828378..2991e5cad 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -5,7 +5,7 @@ const server = require("../server"); const apicache = require("../modules/apicache"); const Monitor = require("../model/monitor"); const dayjs = require("dayjs"); -const { UP, flipStatus, debug } = require("../../src/util"); +const { UP, flipStatus, log } = require("../../src/util"); let router = express.Router(); 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"); } - debug("PreviousStatus: " + previousStatus); - debug("Current Status: " + status); + log("router", "PreviousStatus: " + previousStatus, "debug"); + log("router", "Current Status: " + status, "debug"); bean.important = Monitor.isImportantBeat(isFirstBeat, previousStatus, status); bean.monitor_id = monitor.id; diff --git a/server/server.js b/server/server.js index d1fd7ff29..e4cd56c1b 100644 --- a/server/server.js +++ b/server/server.js @@ -1,56 +1,57 @@ -console.log("Welcome to Uptime Kuma"); 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"); -debug(args); +log("server", "Welcome to Uptime Kuma"); +log("server", "Arguments", "debug"); +log("server", args, "debug"); if (! process.env.NODE_ENV) { 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 http = require("http"); const https = require("https"); -console.log("Importing 3rd-party libraries"); -debug("Importing express"); +log("server", "Importing 3rd-party libraries"); +log("server", "Importing express", "debug"); const express = require("express"); -debug("Importing socket.io"); +log("server", "Importing socket.io", "debug"); const { Server } = require("socket.io"); -debug("Importing redbean-node"); +log("server", "Importing redbean-node", "debug"); const { R } = require("redbean-node"); -debug("Importing jsonwebtoken"); +log("server", "Importing jsonwebtoken", "debug"); const jwt = require("jsonwebtoken"); -debug("Importing http-graceful-shutdown"); +log("server", "Importing http-graceful-shutdown", "debug"); const gracefulShutdown = require("http-graceful-shutdown"); -debug("Importing prometheus-api-metrics"); +log("server", "Importing prometheus-api-metrics", "debug"); const prometheusAPIMetrics = require("prometheus-api-metrics"); -debug("Importing compare-versions"); +log("server", "Importing compare-versions", "debug"); const compareVersions = require("compare-versions"); const { passwordStrength } = require("check-password-strength"); -debug("Importing 2FA Modules"); +log("server", "Importing 2FA Modules", "debug"); const notp = require("notp"); const base32 = require("thirty-two"); -console.log("Importing this project modules"); -debug("Importing Monitor"); +log("server", "Importing this project modules"); +log("server", "Importing Monitor", "debug"); 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"); -debug("Importing Notification"); +log("server", "Importing Notification", "debug"); const { Notification } = require("./notification"); Notification.init(); -debug("Importing Database"); +log("server", "Importing Database", "debug"); const Database = require("./database"); -debug("Importing Background Jobs"); +log("server", "Importing Background Jobs", "debug"); const { initBackgroundJobs } = require("./jobs"); const { loginRateLimiter } = require("./rate-limiter"); @@ -59,7 +60,7 @@ const { login } = require("./auth"); const passwordHash = require("./password-hash"); 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. // Dual-stack support for (::) @@ -71,7 +72,7 @@ if (!hostname && !FBSD) { } 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); @@ -94,22 +95,22 @@ const twofa_verification_opts = { const testMode = !!args["test"] || false; 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(); let server; if (sslKey && sslCert) { - console.log("Server Type: HTTPS"); + log("server", "Server Type: HTTPS"); server = https.createServer({ key: fs.readFileSync(sslKey), cert: fs.readFileSync(sslCert) }, app); } else { - console.log("Server Type: HTTP"); + log("server", "Server Type: HTTP"); server = http.createServer(app); } @@ -167,7 +168,7 @@ try { } catch (e) { // "dist/index.html" is not necessary for 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); } } @@ -180,7 +181,7 @@ exports.entryPage = "dashboard"; exports.entryPage = await setting("entryPage"); - console.log("Adding route"); + log("server", "Adding route"); // *************************** // 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) => { sendInfo(socket); @@ -241,7 +242,7 @@ exports.entryPage = "dashboard"; totalClient++; if (needSetup) { - console.log("Redirect to setup page"); + log("server", "Redirect to setup page"); socket.emit("setup"); } @@ -254,33 +255,40 @@ exports.entryPage = "dashboard"; // *************************** socket.on("loginByToken", async (token, callback) => { + log("auth", `Login by token. IP=${getClientIp(socket)}`); try { 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 ", [ decoded.username, ]); if (user) { - debug("afterLogin"); - + log("auth", "afterLogin", "debug"); afterLogin(socket, user); + log("auth", "afterLogin ok", "debug"); - debug("afterLogin ok"); + log("auth", `Successfully logged in user ${decoded.username}. IP=${getClientIp(socket)}`); callback({ ok: true, }); } else { + + log("auth", `Inactive or deleted user ${decoded.username}. IP=${getClientIp(socket)}`); + callback({ ok: false, msg: "The user is inactive or deleted.", }); } } catch (error) { + + log("auth", `Invalid token for user ${decoded.username}. IP=${getClientIp(socket)}`, "error"); + callback({ ok: false, msg: "Invalid token.", @@ -290,10 +298,11 @@ exports.entryPage = "dashboard"; }); socket.on("login", async (data, callback) => { - console.log("Login"); + log("auth", `Login by username + password. IP=${getClientIp(socket)}`); // Login Rate Limit if (! await loginRateLimiter.pass(callback)) { + log("auth", `Too many failed requests for user ${data.username}. IP=${getClientIp(socket)}`); return; } @@ -302,6 +311,9 @@ exports.entryPage = "dashboard"; if (user) { if (user.twofa_status == 0) { afterLogin(socket, user); + + log("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); + callback({ ok: true, token: jwt.sign({ @@ -311,6 +323,9 @@ exports.entryPage = "dashboard"; } if (user.twofa_status == 1 && !data.token) { + + log("auth", `2FA token required for user ${data.username}. IP=${getClientIp(socket)}`); + callback({ tokenRequired: true, }); @@ -327,6 +342,8 @@ exports.entryPage = "dashboard"; socket.userID, ]); + log("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); + callback({ ok: true, token: jwt.sign({ @@ -334,6 +351,9 @@ exports.entryPage = "dashboard"; }, jwtSecret), }); } else { + + log("auth", `Invalid token provided for user ${data.username}. IP=${getClientIp(socket)}`, "warn"); + callback({ ok: false, msg: "Invalid Token!", @@ -341,6 +361,9 @@ exports.entryPage = "dashboard"; } } } else { + + log("auth", `Incorrect username or password for user ${data.username}. IP=${getClientIp(socket)}`, "warn"); + callback({ ok: false, msg: "Incorrect username or password.", @@ -405,11 +428,16 @@ exports.entryPage = "dashboard"; socket.userID, ]); + log("auth", `Saved 2FA token for user ${data.username}. IP=${getClientIp(socket)}`); + callback({ ok: true, msg: "2FA Enabled.", }); } catch (error) { + + log("auth", `Error changing 2FA token for user ${data.username}. IP=${getClientIp(socket)}`, "error"); + callback({ ok: false, msg: "Error while trying to change 2FA.", @@ -425,14 +453,19 @@ exports.entryPage = "dashboard"; socket.userID, ]); + log("auth", `Disabled 2FA token for user ${data.username}. IP=${getClientIp(socket)}`); + callback({ ok: true, msg: "2FA Disabled.", }); } catch (error) { + + log("auth", `Error disabling 2FA token for user ${data.username}. IP=${getClientIp(socket)}`, "error"); + callback({ 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 sendMonitorList(socket); + log("monitor", `Added Monitor: ${monitorID} User ID: ${socket.userID}`); + callback({ ok: true, msg: "Added Successfully.", @@ -551,6 +586,9 @@ exports.entryPage = "dashboard"; }); } catch (e) { + + log("monitor", `Error adding Monitor: ${monitorID} User ID: ${socket.userID}`, "error"); + callback({ ok: false, msg: e.message, @@ -634,7 +672,7 @@ exports.entryPage = "dashboard"; try { 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 = ? ", [ monitorID, @@ -658,7 +696,7 @@ exports.entryPage = "dashboard"; try { 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) { throw new Error("Invalid period."); @@ -729,7 +767,7 @@ exports.entryPage = "dashboard"; try { checkLogin(socket); - console.log(`Delete Monitor: ${monitorID} User ID: ${socket.userID}`); + log("manage", `Delete Monitor: ${monitorID} User ID: ${socket.userID}`); if (monitorID in monitorList) { monitorList[monitorID].stop(); @@ -1065,7 +1103,7 @@ exports.entryPage = "dashboard"; 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 monitorListData = backupData.monitorList; @@ -1237,7 +1275,7 @@ exports.entryPage = "dashboard"; try { 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 = ? ", [ "", @@ -1263,7 +1301,7 @@ exports.entryPage = "dashboard"; try { 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 = ?", [ monitorID @@ -1287,7 +1325,7 @@ exports.entryPage = "dashboard"; try { checkLogin(socket); - console.log(`Clear Statistics User ID: ${socket.userID}`); + log("manage", `Clear Statistics User ID: ${socket.userID}`); await R.exec("DELETE FROM heartbeat"); @@ -1307,24 +1345,24 @@ exports.entryPage = "dashboard"; statusPageSocketHandler(socket); databaseSocketHandler(socket); - debug("added all socket handlers"); + log("server", "added all socket handlers", "debug"); // *************************** // Better do anything after added all socket handlers here // *************************** - debug("check auto login"); + log("auth", "check auto login", "debug"); 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")); socket.emit("autoLogin"); } else { - debug("need auth"); + log("auth", "need auth", "debug"); } }); - console.log("Init the server"); + log("server", "Init the server"); server.once("error", async (err) => { console.error("Cannot listen: " + err.message); @@ -1333,9 +1371,9 @@ exports.entryPage = "dashboard"; server.listen(port, hostname, () => { if (hostname) { - console.log(`Listening on ${hostname}:${port}`); + log("server", `Listening on ${hostname}:${port}`); } else { - console.log(`Listening on ${port}`); + log("server", `Listening on ${port}`); } startMonitors(); checkVersion.startInterval(); @@ -1419,13 +1457,13 @@ async function getMonitorJSONList(userID) { async function initDatabase() { if (! fs.existsSync(Database.path)) { - console.log("Copying Database"); + log("server", "Copying Database"); fs.copyFileSync(Database.templatePath, Database.path); } - console.log("Connecting to the Database"); + log("server", "Connecting to the Database"); await Database.connect(); - console.log("Connected"); + log("server", "Connected"); // Patch the database await Database.patch(); @@ -1435,16 +1473,16 @@ async function initDatabase() { ]); if (! jwtSecretBean) { - console.log("JWT secret is not found, generate one."); + log("server", "JWT secret is not found, generate one."); jwtSecretBean = await initJWTSecret(); - console.log("Stored JWT secret into database"); + log("server", "Stored JWT secret into database"); } 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 ((await R.count("user")) === 0) { - console.log("No user, need setup"); + log("server", "No user, need setup"); needSetup = true; } @@ -1454,7 +1492,7 @@ async function initDatabase() { async function startMonitor(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 = ? ", [ monitorID, @@ -1480,7 +1518,7 @@ async function restartMonitor(userID, monitorID) { async function pauseMonitor(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 = ? ", [ monitorID, @@ -1510,10 +1548,10 @@ async function startMonitors() { } async function shutdownFunction(signal) { - console.log("Shutdown requested"); - console.log("Called signal: " + signal); + log("server", "Shutdown requested"); + log("server", "Called signal: " + signal); - console.log("Stopping all monitors"); + log("server", "Stopping all monitors"); for (let id in monitorList) { let monitor = monitorList[id]; monitor.stop(); @@ -1522,8 +1560,12 @@ async function shutdownFunction(signal) { await Database.close(); } +function getClientIp(socket) { + return socket.client.conn.remoteAddress.replace(/^.*:/, "") +} + function finalFunction() { - console.log("Graceful shutdown successful!"); + log("server", "Graceful shutdown successful!"); } gracefulShutdown(server, { diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js index 5826277c7..a05b311d3 100644 --- a/server/socket-handlers/status-page-socket-handler.js +++ b/server/socket-handlers/status-page-socket-handler.js @@ -1,7 +1,7 @@ const { R } = require("redbean-node"); const { checkLogin, setSettings } = require("../util-server"); const dayjs = require("dayjs"); -const { debug } = require("../../src/util"); +const { log } = require("../../src/util"); const ImageDataURI = require("../image-data-uri"); const Database = require("../database"); const apicache = require("../modules/apicache"); @@ -138,8 +138,8 @@ module.exports.statusPageSocketHandler = (socket) => { group.id = groupBean.id; } - // Delete groups that not in the list - debug("Delete groups that not in the list"); + // Delete groups that are not in the list + log("socket", "Delete groups that are not in the list", "debug"); const slots = groupIDList.map(() => "?").join(","); await R.exec(`DELETE FROM \`group\` WHERE id NOT IN (${slots})`, groupIDList); diff --git a/server/util-server.js b/server/util-server.js index 68f59f67f..6b1fc522e 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -1,7 +1,7 @@ const tcpp = require("tcp-ping"); const Ping = require("./ping-lite"); const { R } = require("redbean-node"); -const { debug } = require("../src/util"); +const { log } = require("../src/util"); const passwordHash = require("./password-hash"); const dayjs = require("dayjs"); const { Resolver } = require("dns"); @@ -119,7 +119,7 @@ exports.setting = async function (key) { try { const v = JSON.parse(value); - debug(`Get Setting: ${key}: ${v}`); + log("util", `Get Setting: ${key}: ${v}`, "debug"); return v; } catch (e) { return value; @@ -206,7 +206,7 @@ const parseCertificateInfo = function (info) { const existingList = {}; while (link) { - debug(`[${i}] ${link.fingerprint}`); + log("util", `[${i}] ${link.fingerprint}`, "debug"); if (!link.valid_from || !link.valid_to) { break; @@ -221,7 +221,7 @@ const parseCertificateInfo = function (info) { if (link.issuerCertificate == null) { break; } else if (link.issuerCertificate.fingerprint in existingList) { - debug(`[Last] ${link.issuerCertificate.fingerprint}`); + log("util", `[Last] ${link.issuerCertificate.fingerprint}`, "debug"); link.issuerCertificate = null; break; } else { @@ -242,7 +242,7 @@ exports.checkCertificate = function (res) { const info = res.request.res.socket.getPeerCertificate(true); const valid = res.request.res.socket.authorized || false; - debug("Parsing Certificate Info"); + log("util", "Parsing Certificate Info", "debug"); const parsedInfo = parseCertificateInfo(info); return { @@ -345,7 +345,7 @@ exports.startUnitTest = async () => { */ exports.convertToUTF8 = (body) => { const guessEncoding = chardet.detect(body); - //debug("Guess Encoding: " + guessEncoding); + //log("util", "Guess Encoding: " + guessEncoding, "debug"); const str = iconv.decode(body, guessEncoding); return str.toString(); }; diff --git a/src/util.js b/src/util.js index b2df7ac79..1b8020df7 100644 --- a/src/util.js +++ b/src/util.js @@ -6,10 +6,10 @@ // // Backend uses the compiled file util.js // Frontend uses util.ts -Object.defineProperty(exports, "__esModule", { value: 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; -const _dayjs = require("dayjs"); -const dayjs = _dayjs; +exports.__esModule = true; +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; +var _dayjs = require("dayjs"); +var dayjs = _dayjs; exports.isDev = process.env.NODE_ENV === "development"; exports.appName = "Uptime Kuma"; exports.DOWN = 0; @@ -29,7 +29,7 @@ function flipStatus(s) { } exports.flipStatus = flipStatus; function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise(function (resolve) { return setTimeout(resolve, ms); }); } exports.sleep = sleep; /** @@ -40,16 +40,36 @@ function ucfirst(str) { if (!str) { return str; } - const firstLetter = str.substr(0, 1); + var firstLetter = str.substr(0, 1); return firstLetter.toUpperCase() + str.substr(1); } exports.ucfirst = ucfirst; -function debug(msg) { - if (exports.isDev) { - console.log(msg); +// log levels = info / warn / error / debug +function log(module, msg, level) { + 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() { /** * String.prototype.replaceAll() polyfill @@ -69,16 +89,17 @@ function polyfill() { } } exports.polyfill = polyfill; -class TimeLogger { - constructor() { +var TimeLogger = /** @class */ (function () { + function TimeLogger() { this.startTime = dayjs().valueOf(); } - print(name) { + TimeLogger.prototype.print = function (name) { if (exports.isDev && process.env.TIMELOGGER === "1") { console.log(name + ": " + (dayjs().valueOf() - this.startTime) + "ms"); } - } -} + }; + return TimeLogger; +}()); exports.TimeLogger = TimeLogger; /** * 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 * browser equivalent implemented via window.crypto.getRandomValues() */ -let getRandomBytes = ((typeof window !== 'undefined' && window.crypto) +var getRandomBytes = ((typeof window !== 'undefined' && window.crypto) // Browsers ? function () { - return (numBytes) => { - let randomBytes = new Uint8Array(numBytes); - for (let i = 0; i < numBytes; i += 65536) { + return function (numBytes) { + var randomBytes = new Uint8Array(numBytes); + for (var i = 0; i < numBytes; i += 65536) { window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536))); } return randomBytes; @@ -123,13 +144,13 @@ let getRandomBytes = ((typeof window !== 'undefined' && window.crypto) })(); function getCryptoRandomInt(min, max) { // 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)) console.log("Warning! Range is too large."); - let tmpRange = range; - let bitsNeeded = 0; - let bytesNeeded = 0; - let mask = 1; + var tmpRange = range; + var bitsNeeded = 0; + var bytesNeeded = 0; + var mask = 1; while (tmpRange > 0) { if (bitsNeeded % 8 === 0) bytesNeeded += 1; @@ -137,9 +158,9 @@ function getCryptoRandomInt(min, max) { mask = mask << 1 | 1; tmpRange = tmpRange >>> 1; } - const randomBytes = getRandomBytes(bytesNeeded); - let randomValue = 0; - for (let i = 0; i < bytesNeeded; i++) { + var randomBytes = getRandomBytes(bytesNeeded); + var randomValue = 0; + for (var i = 0; i < bytesNeeded; i++) { randomValue |= randomBytes[i] << 8 * i; } randomValue = randomValue & mask; @@ -151,11 +172,12 @@ function getCryptoRandomInt(min, max) { } } exports.getCryptoRandomInt = getCryptoRandomInt; -function genSecret(length = 64) { - let secret = ""; - const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - const charsLength = chars.length; - for (let i = 0; i < length; i++) { +function genSecret(length) { + if (length === void 0) { length = 64; } + var secret = ""; + var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + var charsLength = chars.length; + for (var i = 0; i < length; i++) { secret += chars.charAt(getCryptoRandomInt(0, charsLength - 1)); } return secret; diff --git a/src/util.ts b/src/util.ts index 633d933ea..6fde8f3f3 100644 --- a/src/util.ts +++ b/src/util.ts @@ -49,9 +49,26 @@ export function ucfirst(str: string) { return firstLetter.toUpperCase() + str.substr(1); } -export function debug(msg: any) { - if (isDev) { - console.log(msg); +// log levels = info / warn / error / debug +export function log(module: string, msg: any, level:string = "info") { + 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); } } From d21f7971b585d91bac8ac226ec7f3fd7b5a9a347 Mon Sep 17 00:00:00 2001 From: Andreas Brett Date: Thu, 11 Nov 2021 12:56:53 +0100 Subject: [PATCH 03/40] missed settings --- src/pages/Settings.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index 9d501407d..3e013a08b 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -435,7 +435,7 @@ dayjs.extend(timezone); import { timezoneList, setPageLocale } from "../util-frontend"; import { useToast } from "vue-toastification"; -import { debug } from "../util.ts"; +import { log } from "../util.ts"; const toast = useToast(); @@ -639,20 +639,20 @@ export default { this.loadDatabaseSize(); toast.success("Done"); } else { - debug(res); + log("settings", res, "debug"); } }); }, loadDatabaseSize() { - debug("load database size"); + log("settings", "load database size", "debug"); this.$root.getSocket().emit("getDatabaseSize", (res) => { if (res.ok) { this.databaseSize = res.size; - debug("database size: " + res.size); + log("settings", "database size: " + res.size, "debug"); } else { - debug(res); + log("settings", res, "debug"); } }); From e5913c5abc01b9d5b9c3bef98274b52fe5640fd0 Mon Sep 17 00:00:00 2001 From: Andreas Brett Date: Mon, 15 Nov 2021 17:52:28 +0100 Subject: [PATCH 04/40] separate log functions --- server/database.js | 76 ++++----- server/image-data-uri.js | 6 +- server/jobs.js | 4 +- server/model/monitor.js | 80 ++++----- server/notification-providers/matrix.js | 6 +- server/notification.js | 4 +- server/prometheus.js | 18 +- server/rate-limiter.js | 4 +- server/routers/api-router.js | 6 +- server/server.js | 160 +++++++++--------- .../status-page-socket-handler.js | 8 +- server/util-server.js | 12 +- src/pages/Settings.vue | 10 +- src/util.js | 21 ++- src/util.ts | 18 +- 15 files changed, 230 insertions(+), 203 deletions(-) diff --git a/server/database.js b/server/database.js index 53fd3ef96..3151540b2 100644 --- a/server/database.js +++ b/server/database.js @@ -1,7 +1,7 @@ const fs = require("fs"); const { R } = require("redbean-node"); const { setSetting, setting } = require("./util-server"); -const { log, sleep } = require("../src/util"); +const { log_info, log_debug, log_error, sleep } = require("../src/util"); const dayjs = require("dayjs"); const knex = require("knex"); @@ -76,7 +76,7 @@ class Database { fs.mkdirSync(Database.uploadDir, { recursive: true }); } - log("db", `Data Dir: ${Database.dataDir}`); + log_info("db", `Data Dir: ${Database.dataDir}`); } static async connect() { @@ -117,10 +117,10 @@ class Database { await R.exec("PRAGMA cache_size = -12000"); await R.exec("PRAGMA auto_vacuum = FULL"); - log("db", "SQLite config:"); - log("db", await R.getAll("PRAGMA journal_mode")); - log("db", await R.getAll("PRAGMA cache_size")); - log("db","SQLite Version: " + await R.getCell("SELECT sqlite_version()")); + log_info("db", "SQLite config:"); + log_info("db", await R.getAll("PRAGMA journal_mode")); + log_info("db", await R.getAll("PRAGMA cache_size")); + log_info("db","SQLite Version: " + await R.getCell("SELECT sqlite_version()")); } static async patch() { @@ -130,15 +130,15 @@ class Database { version = 0; } - log("db", "Your database version: " + version); - log("db", "Latest database version: " + this.latestVersion); + log_info("db", "Your database version: " + version); + log_info("db", "Latest database version: " + this.latestVersion); if (version === this.latestVersion) { - log("db", "Database patch not needed"); + log_info("db", "Database patch not needed"); } else if (version > this.latestVersion) { - log("db", "Warning: Database version is newer than expected"); + log_info("db", "Warning: Database version is newer than expected"); } else { - log("db", "Database patch is needed"); + log_info("db", "Database patch is needed"); this.backup(version); @@ -146,17 +146,17 @@ class Database { try { for (let i = version + 1; i <= this.latestVersion; i++) { const sqlFile = `./db/patch${i}.sql`; - log("db", `Patching ${sqlFile}`); + log_info("db", `Patching ${sqlFile}`); await Database.importSQLFile(sqlFile); - log("db", `Patched ${sqlFile}`); + log_info("db", `Patched ${sqlFile}`); await setSetting("database_version", i); } } catch (ex) { await Database.close(); - log("db", ex, "error"); - log("db", "Start Uptime-Kuma failed due to issue patching the database", "error"); - log("db", "Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues", "error"); + log_error("db", ex); + log_error("db", "Start Uptime-Kuma failed due to issue patching the database"); + log_error("db", "Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); this.restore(); process.exit(1); @@ -171,15 +171,15 @@ class Database { * @returns {Promise} */ static async patch2() { - log("db", "Database Patch 2.0 Process"); + log_info("db", "Database Patch 2.0 Process"); let databasePatchedFiles = await setting("databasePatchedFiles"); if (! databasePatchedFiles) { databasePatchedFiles = {}; } - log("db", "Patched files:", "debug"); - log("db", databasePatchedFiles, "debug"); + log_debug("db", "Patched files:"); + log_debug("db", databasePatchedFiles); try { for (let sqlFilename in this.patchList) { @@ -187,15 +187,15 @@ class Database { } if (this.patched) { - log("db", "Database Patched Successfully"); + log_info("db", "Database Patched Successfully"); } } catch (ex) { await Database.close(); - log("db", ex, "error"); - log("db", "Start Uptime-Kuma failed due to issue patching the database", "error"); - log("db", "Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues", "error"); + log_error("db", ex); + log_error("db", "Start Uptime-Kuma failed due to issue patching the database"); + log_error("db", "Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues"); this.restore(); @@ -214,16 +214,16 @@ class Database { let value = this.patchList[sqlFilename]; if (! value) { - log("db", sqlFilename + " skip"); + log_info("db", sqlFilename + " skip"); return; } // Check if patched if (! databasePatchedFiles[sqlFilename]) { - log("db", sqlFilename + " is not patched"); + log_info("db", sqlFilename + " is not patched"); if (value.parents) { - log("db", sqlFilename + " need parents"); + log_info("db", sqlFilename + " need parents"); for (let parentSQLFilename of value.parents) { await this.patch2Recursion(parentSQLFilename, databasePatchedFiles); } @@ -231,14 +231,14 @@ class Database { this.backup(dayjs().format("YYYYMMDDHHmmss")); - log("db", sqlFilename + " is patching"); + log_info("db", sqlFilename + " is patching"); this.patched = true; await this.importSQLFile("./db/" + sqlFilename); databasePatchedFiles[sqlFilename] = true; - log("db", sqlFilename + " was patched successfully"); + log_info("db", sqlFilename + " was patched successfully"); } else { - log("db", sqlFilename + " is already patched, skip", "debug"); + log_debug("db", sqlFilename + " is already patched, skip"); } } @@ -290,7 +290,7 @@ class Database { }; process.addListener("unhandledRejection", listener); - log("db", "Closing the database"); + log_info("db", "Closing the database"); while (true) { Database.noReject = true; @@ -300,10 +300,10 @@ class Database { if (Database.noReject) { break; } else { - log("db", "Waiting to close the database"); + log_info("db", "Waiting to close the database"); } } - log("db", "SQLite closed"); + log_info("db", "SQLite closed"); process.removeListener("unhandledRejection", listener); } @@ -315,7 +315,7 @@ class Database { */ static backup(version) { if (! this.backupPath) { - log("db", "Backing up the database"); + log_info("db", "Backing up the database"); this.backupPath = this.dataDir + "kuma.db.bak" + version; fs.copyFileSync(Database.path, this.backupPath); @@ -338,7 +338,7 @@ class Database { */ static restore() { if (this.backupPath) { - log("db", "Patching the database failed!!! Restoring the backup", "error"); + log_error("db", "Patching the database failed!!! Restoring the backup"); const shmPath = Database.path + "-shm"; const walPath = Database.path + "-wal"; @@ -357,7 +357,7 @@ class Database { fs.unlinkSync(walPath); } } catch (e) { - log("db", "Restore failed; you may need to restore the backup manually", "error"); + log_error("db", "Restore failed; you may need to restore the backup manually"); process.exit(1); } @@ -373,14 +373,14 @@ class Database { } } else { - log("db", "Nothing to restore"); + log_info("db", "Nothing to restore"); } } static getSize() { - log("db", "Database.getSize()", "debug"); + log_debug("db", "Database.getSize()"); let stats = fs.statSync(Database.path); - log("db", stats, "debug"); + log_debug("db", stats); return stats.size; } diff --git a/server/image-data-uri.js b/server/image-data-uri.js index 6aa4387ab..84d2990a5 100644 --- a/server/image-data-uri.js +++ b/server/image-data-uri.js @@ -3,13 +3,13 @@ Modified with 0 dependencies */ let fs = require("fs"); -const { log } = require("../src/util"); +const { log_error } = require("../src/util"); let ImageDataURI = (() => { function decode(dataURI) { if (!/data:image\//.test(dataURI)) { - log("image-data-uri", "It seems that it is not an Image Data URI. Couldn't match \"data:image/\"", "error"); + log_error("image-data-uri", "It seems that it is not an Image Data URI. Couldn't match \"data:image/\""); return null; } @@ -23,7 +23,7 @@ let ImageDataURI = (() => { function encode(data, mediaType) { if (!data || !mediaType) { - log("image-data-uri", "Missing some of the required params: data, mediaType", "error"); + log_error("image-data-uri", "Missing some of the required params: data, mediaType"); return null; } diff --git a/server/jobs.js b/server/jobs.js index 56a67b0fa..92023c034 100644 --- a/server/jobs.js +++ b/server/jobs.js @@ -1,7 +1,7 @@ const path = require("path"); const Bree = require("bree"); const { SHARE_ENV } = require("worker_threads"); -const { log } = require("../src/util"); +const { log_info } = require("../src/util"); const jobs = [ { @@ -19,7 +19,7 @@ const initBackgroundJobs = function (args) { workerData: args, }, workerMessageHandler: (message) => { - log("jobs", message); + log_info("jobs", message); } }); diff --git a/server/model/monitor.js b/server/model/monitor.js index f7d17f292..652b4a00f 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -6,7 +6,7 @@ dayjs.extend(utc); dayjs.extend(timezone); const axios = require("axios"); const { Prometheus } = require("../prometheus"); -const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); +const { log_info, log_debug, log_error, log_warn, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, errorLog } = require("../util-server"); const { R } = require("redbean-node"); 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" let startTime = dayjs().valueOf(); - log("monitor", `[${this.name}] Prepare Options for axios`, "debug"); + log_debug("monitor", `[${this.name}] Prepare Options for axios`); const options = { url: this.url, method: (this.method || "get").toLowerCase(), @@ -162,7 +162,7 @@ class Monitor extends BeanModel { }, }; - log("monitor", `[${this.name}] Axios Request`, "debug"); + log_debug("monitor", `[${this.name}] Axios Request`); let res = await axios.request(options); bean.msg = `${res.status} - ${res.statusText}`; bean.ping = dayjs().valueOf() - startTime; @@ -170,30 +170,30 @@ class Monitor extends BeanModel { // Check certificate if https is used let certInfoStartTime = dayjs().valueOf(); if (this.getUrl()?.protocol === "https:") { - log("monitor", `[${this.name}] Check cert`, "debug"); + log_debug("monitor", `[${this.name}] Check cert`); try { let tlsInfoObject = checkCertificate(res); tlsInfo = await this.updateTlsInfo(tlsInfoObject); if (!this.getIgnoreTls()) { - log("monitor", `[${this.name}] call sendCertNotification`, "debug"); + log_debug("monitor", `[${this.name}] call sendCertNotification`); await this.sendCertNotification(tlsInfoObject); } } catch (e) { if (e.message !== "No TLS certificate in response") { - log("monitor", "Caught error", "error"); - log("monitor", e.message, "error"); + log_error("monitor", "Caught error"); + log_error("monitor", e.message); } } } if (process.env.TIMELOGGER === "1") { - log("monitor", "Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms", "debug"); + log_debug("monitor", "Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms"); } if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID == this.id) { - log("monitor", res.data); + log_info("monitor", res.data); } if (this.type === "http") { @@ -273,7 +273,7 @@ class Monitor extends BeanModel { time ]); - log("monitor", "heartbeatCount" + heartbeatCount + " " + time, "debug"); + log_debug("monitor", "heartbeatCount" + heartbeatCount + " " + time); if (heartbeatCount <= 0) { throw new Error("No heartbeat in the time window"); @@ -356,7 +356,7 @@ class Monitor extends BeanModel { let beatInterval = this.interval; - log("monitor", `[${this.name}] Check isImportant`, "debug"); + log_debug("monitor", `[${this.name}] Check isImportant`); let isImportant = Monitor.isImportantBeat(isFirstBeat, previousBeat?.status, bean.status); // Mark as important if status changed, ignore pending pings, @@ -364,11 +364,11 @@ class Monitor extends BeanModel { if (isImportant) { bean.important = true; - log("monitor", `[${this.name}] sendNotification`, "debug"); + log_debug("monitor", `[${this.name}] sendNotification`); await Monitor.sendNotification(isFirstBeat, this, bean); // Clear Status Page Cache - log("monitor", `[${this.name}] apicache clear`, "debug"); + log_debug("monitor", `[${this.name}] apicache clear`); apicache.clear(); } else { @@ -376,24 +376,24 @@ class Monitor extends BeanModel { } if (bean.status === UP) { - log("monitor", `Monitor #${this.id} '${this.name}': Successful Response: ${bean.ping} ms | Interval: ${beatInterval} seconds | Type: ${this.type}`); + log_info("monitor", `Monitor #${this.id} '${this.name}': Successful Response: ${bean.ping} ms | Interval: ${beatInterval} seconds | Type: ${this.type}`); } else if (bean.status === PENDING) { if (this.retryInterval > 0) { beatInterval = this.retryInterval; } - log("monitor", `Monitor #${this.id} '${this.name}': Pending: ${bean.msg} | Max retries: ${this.maxretries} | Retry: ${retries} | Retry Interval: ${beatInterval} seconds | Type: ${this.type}`, "warn"); + log_warn("monitor", `Monitor #${this.id} '${this.name}': Pending: ${bean.msg} | Max retries: ${this.maxretries} | Retry: ${retries} | Retry Interval: ${beatInterval} seconds | Type: ${this.type}`); } else { - log("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`, "warn"); + log_warn("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`); } - log("monitor", `[${this.name}] Send to socket`, "debug"); + log_debug("monitor", `[${this.name}] Send to socket`); io.to(this.user_id).emit("heartbeat", bean.toJSON()); Monitor.sendStats(io, this.id, this.user_id); - log("monitor", `[${this.name}] Store`, "debug"); + log_debug("monitor", `[${this.name}] Store`); await R.store(bean); - log("monitor", `[${this.name}] prometheus.update`, "debug"); + log_debug("monitor", `[${this.name}] prometheus.update`); prometheus.update(bean, tlsInfo); previousBeat = bean; @@ -402,15 +402,15 @@ class Monitor extends BeanModel { if (demoMode) { if (beatInterval < 20) { - log("monitor", "beat interval too low, reset to 20s"); + log_info("monitor", "beat interval too low, reset to 20s"); beatInterval = 20; } } - log("monitor", `[${this.name}] SetTimeout for next check.`, "debug"); + log_debug("monitor", `[${this.name}] SetTimeout for next check.`); this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000); } else { - log("monitor", `[${this.name}] isStop = true, no next check.`); + log_info("monitor", `[${this.name}] isStop = true, no next check.`); } }; @@ -421,10 +421,10 @@ class Monitor extends BeanModel { } catch (e) { console.trace(e); errorLog(e, false); - log("monitor", "Please report to https://github.com/louislam/uptime-kuma/issues", "error"); + log_error("monitor", "Please report to https://github.com/louislam/uptime-kuma/issues"); if (! this.isStop) { - log("monitor", "Try to restart the monitor"); + log_info("monitor", "Try to restart the monitor"); this.heartbeatInterval = setTimeout(safeBeat, this.interval * 1000); } } @@ -482,17 +482,17 @@ class Monitor extends BeanModel { if (isValidObjects) { if (oldCertInfo.certInfo.fingerprint256 !== checkCertificateResult.certInfo.fingerprint256) { - log("monitor", "Resetting sent_history", "debug"); + log_debug("monitor", "Resetting sent_history"); await R.exec("DELETE FROM notification_sent_history WHERE type = 'certificate' AND monitor_id = ?", [ this.id ]); } else { - log("monitor", "No need to reset sent_history", "debug"); - log("monitor", oldCertInfo.certInfo.fingerprint256, "debug"); - log("monitor", checkCertificateResult.certInfo.fingerprint256, "debug"); + log_debug("monitor", "No need to reset sent_history"); + log_debug("monitor", oldCertInfo.certInfo.fingerprint256); + log_debug("monitor", checkCertificateResult.certInfo.fingerprint256); } } else { - log("monitor", "Not valid object", "debug"); + log_debug("monitor", "Not valid object"); } } catch (e) { } @@ -513,7 +513,7 @@ class Monitor extends BeanModel { await Monitor.sendUptime(24 * 30, io, monitorID, userID); await Monitor.sendCertInfo(io, monitorID, userID); } else { - log("monitor", "No clients in the room, no need to send stats", "debug"); + log_debug("monitor", "No clients in the room, no need to send stats"); } } @@ -660,8 +660,8 @@ class Monitor extends BeanModel { try { await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(), bean.toJSON()); } catch (e) { - log("monitor", "Cannot send notification to " + notification.name, "error"); - log("monitor", e, "error"); + log_error("monitor", "Cannot send notification to " + notification.name); + log_error("monitor", e); } } } @@ -678,7 +678,7 @@ class Monitor extends BeanModel { if (tlsInfoObject && tlsInfoObject.certInfo && tlsInfoObject.certInfo.daysRemaining) { const notificationList = await Monitor.getNotificationList(this); - log("monitor", "call sendCertNotificationByTargetDays", "debug"); + log_debug("monitor", "call sendCertNotificationByTargetDays"); await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 21, notificationList); await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 14, notificationList); await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 7, notificationList); @@ -688,7 +688,7 @@ class Monitor extends BeanModel { async sendCertNotificationByTargetDays(daysRemaining, targetDays, notificationList) { if (daysRemaining > targetDays) { - log("monitor", `No need to send cert notification. ${daysRemaining} > ${targetDays}`, "debug"); + log_debug("monitor", `No need to send cert notification. ${daysRemaining} > ${targetDays}`); return; } @@ -702,21 +702,21 @@ class Monitor extends BeanModel { // Sent already, no need to send again if (row) { - log("monitor", "Sent already, no need to send again", "debug"); + log_debug("monitor", "Sent already, no need to send again"); return; } let sent = false; - log("monitor", "Send certificate notification", "debug"); + log_debug("monitor", "Send certificate notification"); for (let notification of notificationList) { try { - log("monitor", "Sending to " + notification.name, "debug"); + log_debug("monitor", "Sending to " + notification.name); await Notification.send(JSON.parse(notification.config), `[${this.name}][${this.url}] Certificate will be expired in ${daysRemaining} days`); sent = true; } catch (e) { - log("monitor", "Cannot send cert notification to " + notification.name, "error"); - log("monitor", e, "error"); + log_error("monitor", "Cannot send cert notification to " + notification.name); + log_error("monitor", e); } } @@ -728,7 +728,7 @@ class Monitor extends BeanModel { ]); } } else { - log("monitor", "No notification, no need to send cert notification", "debug"); + log_debug("monitor", "No notification, no need to send cert notification"); } } } diff --git a/server/notification-providers/matrix.js b/server/notification-providers/matrix.js index 1aaf56924..c074e8677 100644 --- a/server/notification-providers/matrix.js +++ b/server/notification-providers/matrix.js @@ -1,7 +1,7 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); const Crypto = require("crypto"); -const { log } = require("../../src/util"); +const { log_debug } = require("../../src/util"); class Matrix extends NotificationProvider { name = "matrix"; @@ -17,11 +17,11 @@ class Matrix extends NotificationProvider { .slice(0, size) ); - log("notification", "Random String: " + randomString, "debug"); + log_debug("notification", "Random String: " + randomString); const roomId = encodeURIComponent(notification.internalRoomId); - log("notification", "Matrix Room ID: " + roomId, "debug"); + log_debug("notification", "Matrix Room ID: " + roomId); try { let config = { diff --git a/server/notification.js b/server/notification.js index e0325759f..b138a21a2 100644 --- a/server/notification.js +++ b/server/notification.js @@ -23,14 +23,14 @@ const Feishu = require("./notification-providers/feishu"); const AliyunSms = require("./notification-providers/aliyun-sms"); const DingDing = require("./notification-providers/dingding"); const Bark = require("./notification-providers/bark"); -const { log } = require("../src/util"); +const { log_info } = require("../src/util"); class Notification { providerList = {}; static init() { - log("notification", "Prepare Notification Providers"); + log_info("notification", "Prepare Notification Providers"); this.providerList = {}; diff --git a/server/prometheus.js b/server/prometheus.js index e7e39881f..1a1cdd0f4 100644 --- a/server/prometheus.js +++ b/server/prometheus.js @@ -1,5 +1,5 @@ const PrometheusClient = require("prom-client"); -const { log } = require("../src/util"); +const { log_error } = require("../src/util"); const commonLabels = [ "monitor_name", @@ -57,23 +57,23 @@ class Prometheus { } monitor_cert_is_valid.set(this.monitorLabelValues, is_valid); } catch (e) { - log("prometheus", "Caught error", "error"); - log("prometheus", e, "error"); + log_error("prometheus", "Caught error"); + log_error("prometheus", e); } try { monitor_cert_days_remaining.set(this.monitorLabelValues, tlsInfo.certInfo.daysRemaining); } catch (e) { - log("prometheus", "Caught error", "error"); - log("prometheus", e, "error"); + log_error("prometheus", "Caught error"); + log_error("prometheus", e); } } try { monitor_status.set(this.monitorLabelValues, heartbeat.status); } catch (e) { - log("prometheus", "Caught error", "error"); - log("prometheus", e, "error"); + log_error("prometheus", "Caught error"); + log_error("prometheus", e); } try { @@ -84,8 +84,8 @@ class Prometheus { monitor_response_time.set(this.monitorLabelValues, -1); } } catch (e) { - log("prometheus", "Caught error", "error"); - log("prometheus", e, "error"); + log_error("prometheus", "Caught error"); + log_error("prometheus", e); } } diff --git a/server/rate-limiter.js b/server/rate-limiter.js index 10db259da..e792e4bcb 100644 --- a/server/rate-limiter.js +++ b/server/rate-limiter.js @@ -1,5 +1,5 @@ const { RateLimiter } = require("limiter"); -const { log } = require("../src/util"); +const { log_info } = require("../src/util"); class KumaRateLimiter { constructor(config) { @@ -9,7 +9,7 @@ class KumaRateLimiter { async pass(callback, num = 1) { const remainingRequests = await this.removeTokens(num); - log("rate-limit", "remaining requests: " + remainingRequests); + log_info("rate-limit", "remaining requests: " + remainingRequests); if (remainingRequests < 0) { if (callback) { callback({ diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 2991e5cad..b4875e990 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -5,7 +5,7 @@ const server = require("../server"); const apicache = require("../modules/apicache"); const Monitor = require("../model/monitor"); const dayjs = require("dayjs"); -const { UP, flipStatus, log } = require("../../src/util"); +const { UP, flipStatus, log_debug } = require("../../src/util"); let router = express.Router(); 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"); } - log("router", "PreviousStatus: " + previousStatus, "debug"); - log("router", "Current Status: " + status, "debug"); + log_debug("router", "PreviousStatus: " + previousStatus); + log_debug("router", "Current Status: " + status); bean.important = Monitor.isImportantBeat(isFirstBeat, previousStatus, status); bean.monitor_id = monitor.id; diff --git a/server/server.js b/server/server.js index e4cd56c1b..2891fdc5e 100644 --- a/server/server.js +++ b/server/server.js @@ -1,57 +1,57 @@ const args = require("args-parser")(process.argv); -const { sleep, log, getRandomInt, genSecret } = require("../src/util"); +const { sleep, log_info, log_debug, log_error, log_warn, getRandomInt, genSecret } = require("../src/util"); const config = require("./config"); -log("server", "Welcome to Uptime Kuma"); -log("server", "Arguments", "debug"); -log("server", args, "debug"); +log_info("server", "Welcome to Uptime Kuma"); +log_debug("server", "Arguments"); +log_debug("server", args); if (! process.env.NODE_ENV) { process.env.NODE_ENV = "production"; } -log("server", "Node Env: " + process.env.NODE_ENV); +log_info("server", "Node Env: " + process.env.NODE_ENV); -log("server", "Importing Node libraries"); +log_info("server", "Importing Node libraries"); const fs = require("fs"); const http = require("http"); const https = require("https"); -log("server", "Importing 3rd-party libraries"); -log("server", "Importing express", "debug"); +log_info("server", "Importing 3rd-party libraries"); +log_debug("server", "Importing express"); const express = require("express"); -log("server", "Importing socket.io", "debug"); +log_debug("server", "Importing socket.io"); const { Server } = require("socket.io"); -log("server", "Importing redbean-node", "debug"); +log_debug("server", "Importing redbean-node"); const { R } = require("redbean-node"); -log("server", "Importing jsonwebtoken", "debug"); +log_debug("server", "Importing jsonwebtoken"); const jwt = require("jsonwebtoken"); -log("server", "Importing http-graceful-shutdown", "debug"); +log_debug("server", "Importing http-graceful-shutdown"); const gracefulShutdown = require("http-graceful-shutdown"); -log("server", "Importing prometheus-api-metrics", "debug"); +log_debug("server", "Importing prometheus-api-metrics"); const prometheusAPIMetrics = require("prometheus-api-metrics"); -log("server", "Importing compare-versions", "debug"); +log_debug("server", "Importing compare-versions"); const compareVersions = require("compare-versions"); const { passwordStrength } = require("check-password-strength"); -log("server", "Importing 2FA Modules", "debug"); +log_debug("server", "Importing 2FA Modules"); const notp = require("notp"); const base32 = require("thirty-two"); -log("server", "Importing this project modules"); -log("server", "Importing Monitor", "debug"); +log_info("server", "Importing this project modules"); +log_debug("server", "Importing Monitor"); const Monitor = require("./model/monitor"); -log("server", "Importing Settings", "debug"); +log_debug("server", "Importing Settings"); const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, errorLog } = require("./util-server"); -log("server", "Importing Notification", "debug"); +log_debug("server", "Importing Notification"); const { Notification } = require("./notification"); Notification.init(); -log("server", "Importing Database", "debug"); +log_debug("server", "Importing Database"); const Database = require("./database"); -log("server", "Importing Background Jobs", "debug"); +log_debug("server", "Importing Background Jobs"); const { initBackgroundJobs } = require("./jobs"); const { loginRateLimiter } = require("./rate-limiter"); @@ -60,7 +60,7 @@ const { login } = require("./auth"); const passwordHash = require("./password-hash"); const checkVersion = require("./check-version"); -log("server", "Version: " + checkVersion.version); +log_info("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. // Dual-stack support for (::) @@ -72,7 +72,7 @@ if (!hostname && !FBSD) { } if (hostname) { - log("server", "Custom hostname: " + hostname); + log_info("server", "Custom hostname: " + hostname); } const port = parseInt(process.env.UPTIME_KUMA_PORT || process.env.PORT || args.port || 3001); @@ -95,22 +95,22 @@ const twofa_verification_opts = { const testMode = !!args["test"] || false; if (config.demoMode) { - log("server", "==== Demo Mode ===="); + log_info("server", "==== Demo Mode ===="); } -log("server", "Creating express and socket.io instance"); +log_info("server", "Creating express and socket.io instance"); const app = express(); let server; if (sslKey && sslCert) { - log("server", "Server Type: HTTPS"); + log_info("server", "Server Type: HTTPS"); server = https.createServer({ key: fs.readFileSync(sslKey), cert: fs.readFileSync(sslCert) }, app); } else { - log("server", "Server Type: HTTP"); + log_info("server", "Server Type: HTTP"); server = http.createServer(app); } @@ -168,7 +168,7 @@ try { } catch (e) { // "dist/index.html" is not necessary for development if (process.env.NODE_ENV !== "development") { - log("server", "Error: Cannot find 'dist/index.html', did you install correctly?", "error"); + log_error("server", "Error: Cannot find 'dist/index.html', did you install correctly?"); process.exit(1); } } @@ -181,7 +181,7 @@ exports.entryPage = "dashboard"; exports.entryPage = await setting("entryPage"); - log("server", "Adding route"); + log_info("server", "Adding route"); // *************************** // Normal Router here @@ -234,7 +234,7 @@ exports.entryPage = "dashboard"; } }); - log("server", "Adding socket handler"); + log_info("server", "Adding socket handler"); io.on("connection", async (socket) => { sendInfo(socket); @@ -242,7 +242,7 @@ exports.entryPage = "dashboard"; totalClient++; if (needSetup) { - log("server", "Redirect to setup page"); + log_info("server", "Redirect to setup page"); socket.emit("setup"); } @@ -255,30 +255,30 @@ exports.entryPage = "dashboard"; // *************************** socket.on("loginByToken", async (token, callback) => { - log("auth", `Login by token. IP=${getClientIp(socket)}`); + log_info("auth", `Login by token. IP=${getClientIp(socket)}`); try { let decoded = jwt.verify(token, jwtSecret); - log("auth", "Username from JWT: " + decoded.username); + log_info("auth", "Username from JWT: " + decoded.username); let user = await R.findOne("user", " username = ? AND active = 1 ", [ decoded.username, ]); if (user) { - log("auth", "afterLogin", "debug"); + log_debug("auth", "afterLogin"); afterLogin(socket, user); - log("auth", "afterLogin ok", "debug"); + log_debug("auth", "afterLogin ok"); - log("auth", `Successfully logged in user ${decoded.username}. IP=${getClientIp(socket)}`); + log_info("auth", `Successfully logged in user ${decoded.username}. IP=${getClientIp(socket)}`); callback({ ok: true, }); } else { - log("auth", `Inactive or deleted user ${decoded.username}. IP=${getClientIp(socket)}`); + log_info("auth", `Inactive or deleted user ${decoded.username}. IP=${getClientIp(socket)}`); callback({ ok: false, @@ -287,7 +287,7 @@ exports.entryPage = "dashboard"; } } catch (error) { - log("auth", `Invalid token for user ${decoded.username}. IP=${getClientIp(socket)}`, "error"); + log_error("auth", `Invalid token for user ${decoded.username}. IP=${getClientIp(socket)}`); callback({ ok: false, @@ -298,11 +298,11 @@ exports.entryPage = "dashboard"; }); socket.on("login", async (data, callback) => { - log("auth", `Login by username + password. IP=${getClientIp(socket)}`); + log_info("auth", `Login by username + password. IP=${getClientIp(socket)}`); // Login Rate Limit if (! await loginRateLimiter.pass(callback)) { - log("auth", `Too many failed requests for user ${data.username}. IP=${getClientIp(socket)}`); + log_info("auth", `Too many failed requests for user ${data.username}. IP=${getClientIp(socket)}`); return; } @@ -312,7 +312,7 @@ exports.entryPage = "dashboard"; if (user.twofa_status == 0) { afterLogin(socket, user); - log("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); + log_info("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); callback({ ok: true, @@ -324,7 +324,7 @@ exports.entryPage = "dashboard"; if (user.twofa_status == 1 && !data.token) { - log("auth", `2FA token required for user ${data.username}. IP=${getClientIp(socket)}`); + log_info("auth", `2FA token required for user ${data.username}. IP=${getClientIp(socket)}`); callback({ tokenRequired: true, @@ -342,7 +342,7 @@ exports.entryPage = "dashboard"; socket.userID, ]); - log("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); + log_info("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); callback({ ok: true, @@ -352,7 +352,7 @@ exports.entryPage = "dashboard"; }); } else { - log("auth", `Invalid token provided for user ${data.username}. IP=${getClientIp(socket)}`, "warn"); + log_warn("auth", `Invalid token provided for user ${data.username}. IP=${getClientIp(socket)}`); callback({ ok: false, @@ -362,7 +362,7 @@ exports.entryPage = "dashboard"; } } else { - log("auth", `Incorrect username or password for user ${data.username}. IP=${getClientIp(socket)}`, "warn"); + log_warn("auth", `Incorrect username or password for user ${data.username}. IP=${getClientIp(socket)}`); callback({ ok: false, @@ -428,7 +428,7 @@ exports.entryPage = "dashboard"; socket.userID, ]); - log("auth", `Saved 2FA token for user ${data.username}. IP=${getClientIp(socket)}`); + log_info("auth", `Saved 2FA token for user ${data.username}. IP=${getClientIp(socket)}`); callback({ ok: true, @@ -436,7 +436,7 @@ exports.entryPage = "dashboard"; }); } catch (error) { - log("auth", `Error changing 2FA token for user ${data.username}. IP=${getClientIp(socket)}`, "error"); + log_error("auth", `Error changing 2FA token for user ${data.username}. IP=${getClientIp(socket)}`); callback({ ok: false, @@ -453,7 +453,7 @@ exports.entryPage = "dashboard"; socket.userID, ]); - log("auth", `Disabled 2FA token for user ${data.username}. IP=${getClientIp(socket)}`); + log_info("auth", `Disabled 2FA token for user ${data.username}. IP=${getClientIp(socket)}`); callback({ ok: true, @@ -461,7 +461,7 @@ exports.entryPage = "dashboard"; }); } catch (error) { - log("auth", `Error disabling 2FA token for user ${data.username}. IP=${getClientIp(socket)}`, "error"); + log_error("auth", `Error disabling 2FA token for user ${data.username}. IP=${getClientIp(socket)}`); callback({ ok: false, @@ -577,7 +577,7 @@ exports.entryPage = "dashboard"; await startMonitor(socket.userID, bean.id); await sendMonitorList(socket); - log("monitor", `Added Monitor: ${monitorID} User ID: ${socket.userID}`); + log_info("monitor", `Added Monitor: ${monitorID} User ID: ${socket.userID}`); callback({ ok: true, @@ -587,7 +587,7 @@ exports.entryPage = "dashboard"; } catch (e) { - log("monitor", `Error adding Monitor: ${monitorID} User ID: ${socket.userID}`, "error"); + log_error("monitor", `Error adding Monitor: ${monitorID} User ID: ${socket.userID}`); callback({ ok: false, @@ -644,7 +644,7 @@ exports.entryPage = "dashboard"; }); } catch (e) { - console.error(e); + log_error("monitor", e); callback({ ok: false, msg: e.message, @@ -660,7 +660,7 @@ exports.entryPage = "dashboard"; ok: true, }); } catch (e) { - console.error(e); + log_error("monitor", e); callback({ ok: false, msg: e.message, @@ -672,7 +672,7 @@ exports.entryPage = "dashboard"; try { checkLogin(socket); - log("monitor", `Get Monitor: ${monitorID} User ID: ${socket.userID}`); + log_info("monitor", `Get Monitor: ${monitorID} User ID: ${socket.userID}`); let bean = await R.findOne("monitor", " id = ? AND user_id = ? ", [ monitorID, @@ -696,7 +696,7 @@ exports.entryPage = "dashboard"; try { checkLogin(socket); - log("monitor", `Get Monitor Beats: ${monitorID} User ID: ${socket.userID}`); + log_info("monitor", `Get Monitor Beats: ${monitorID} User ID: ${socket.userID}`); if (period == null) { throw new Error("Invalid period."); @@ -767,7 +767,7 @@ exports.entryPage = "dashboard"; try { checkLogin(socket); - log("manage", `Delete Monitor: ${monitorID} User ID: ${socket.userID}`); + log_info("manage", `Delete Monitor: ${monitorID} User ID: ${socket.userID}`); if (monitorID in monitorList) { monitorList[monitorID].stop(); @@ -1103,7 +1103,7 @@ exports.entryPage = "dashboard"; let backupData = JSON.parse(uploadedJSON); - log("manage", `Importing Backup, User ID: ${socket.userID}, Version: ${backupData.version}`); + log_info("manage", `Importing Backup, User ID: ${socket.userID}, Version: ${backupData.version}`); let notificationListData = backupData.notificationList; let monitorListData = backupData.monitorList; @@ -1275,7 +1275,7 @@ exports.entryPage = "dashboard"; try { checkLogin(socket); - log("manage", `Clear Events Monitor: ${monitorID} User ID: ${socket.userID}`); + log_info("manage", `Clear Events Monitor: ${monitorID} User ID: ${socket.userID}`); await R.exec("UPDATE heartbeat SET msg = ?, important = ? WHERE monitor_id = ? ", [ "", @@ -1301,7 +1301,7 @@ exports.entryPage = "dashboard"; try { checkLogin(socket); - log("manage", `Clear Heartbeats Monitor: ${monitorID} User ID: ${socket.userID}`); + log_info("manage", `Clear Heartbeats Monitor: ${monitorID} User ID: ${socket.userID}`); await R.exec("DELETE FROM heartbeat WHERE monitor_id = ?", [ monitorID @@ -1325,7 +1325,7 @@ exports.entryPage = "dashboard"; try { checkLogin(socket); - log("manage", `Clear Statistics User ID: ${socket.userID}`); + log_info("manage", `Clear Statistics User ID: ${socket.userID}`); await R.exec("DELETE FROM heartbeat"); @@ -1345,24 +1345,24 @@ exports.entryPage = "dashboard"; statusPageSocketHandler(socket); databaseSocketHandler(socket); - log("server", "added all socket handlers", "debug"); + log_debug("server", "added all socket handlers"); // *************************** // Better do anything after added all socket handlers here // *************************** - log("auth", "check auto login", "debug"); + log_debug("auth", "check auto login"); if (await setting("disableAuth")) { - log("auth", "Disabled Auth: auto login to admin"); + log_info("auth", "Disabled Auth: auto login to admin"); afterLogin(socket, await R.findOne("user")); socket.emit("autoLogin"); } else { - log("auth", "need auth", "debug"); + log_debug("auth", "need auth"); } }); - log("server", "Init the server"); + log_info("server", "Init the server"); server.once("error", async (err) => { console.error("Cannot listen: " + err.message); @@ -1371,9 +1371,9 @@ exports.entryPage = "dashboard"; server.listen(port, hostname, () => { if (hostname) { - log("server", `Listening on ${hostname}:${port}`); + log_info("server", `Listening on ${hostname}:${port}`); } else { - log("server", `Listening on ${port}`); + log_info("server", `Listening on ${port}`); } startMonitors(); checkVersion.startInterval(); @@ -1457,13 +1457,13 @@ async function getMonitorJSONList(userID) { async function initDatabase() { if (! fs.existsSync(Database.path)) { - log("server", "Copying Database"); + log_info("server", "Copying Database"); fs.copyFileSync(Database.templatePath, Database.path); } - log("server", "Connecting to the Database"); + log_info("server", "Connecting to the Database"); await Database.connect(); - log("server", "Connected"); + log_info("server", "Connected"); // Patch the database await Database.patch(); @@ -1473,16 +1473,16 @@ async function initDatabase() { ]); if (! jwtSecretBean) { - log("server", "JWT secret is not found, generate one."); + log_info("server", "JWT secret is not found, generate one."); jwtSecretBean = await initJWTSecret(); - log("server", "Stored JWT secret into database"); + log_info("server", "Stored JWT secret into database"); } else { - log("server", "Load JWT secret from database."); + log_info("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 ((await R.count("user")) === 0) { - log("server", "No user, need setup"); + log_info("server", "No user, need setup"); needSetup = true; } @@ -1492,7 +1492,7 @@ async function initDatabase() { async function startMonitor(userID, monitorID) { await checkOwner(userID, monitorID); - log("manage", `Resume Monitor: ${monitorID} User ID: ${userID}`); + log_info("manage", `Resume Monitor: ${monitorID} User ID: ${userID}`); await R.exec("UPDATE monitor SET active = 1 WHERE id = ? AND user_id = ? ", [ monitorID, @@ -1518,7 +1518,7 @@ async function restartMonitor(userID, monitorID) { async function pauseMonitor(userID, monitorID) { await checkOwner(userID, monitorID); - log("manage", `Pause Monitor: ${monitorID} User ID: ${userID}`); + log_info("manage", `Pause Monitor: ${monitorID} User ID: ${userID}`); await R.exec("UPDATE monitor SET active = 0 WHERE id = ? AND user_id = ? ", [ monitorID, @@ -1548,10 +1548,10 @@ async function startMonitors() { } async function shutdownFunction(signal) { - log("server", "Shutdown requested"); - log("server", "Called signal: " + signal); + log_info("server", "Shutdown requested"); + log_info("server", "Called signal: " + signal); - log("server", "Stopping all monitors"); + log_info("server", "Stopping all monitors"); for (let id in monitorList) { let monitor = monitorList[id]; monitor.stop(); @@ -1565,7 +1565,7 @@ function getClientIp(socket) { } function finalFunction() { - log("server", "Graceful shutdown successful!"); + log_info("server", "Graceful shutdown successful!"); } gracefulShutdown(server, { diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js index a05b311d3..96737cac1 100644 --- a/server/socket-handlers/status-page-socket-handler.js +++ b/server/socket-handlers/status-page-socket-handler.js @@ -1,7 +1,7 @@ const { R } = require("redbean-node"); const { checkLogin, setSettings } = require("../util-server"); const dayjs = require("dayjs"); -const { log } = require("../../src/util"); +const { log, log_info, log_debug, log_error } = require("../../src/util"); const ImageDataURI = require("../image-data-uri"); const Database = require("../database"); const apicache = require("../modules/apicache"); @@ -124,7 +124,7 @@ module.exports.statusPageSocketHandler = (socket) => { ]); let monitorOrder = 1; - console.log(group.monitorList); + log_info("socket", group.monitorList); for (let monitor of group.monitorList) { let relationBean = R.dispense("monitor_group"); @@ -139,7 +139,7 @@ module.exports.statusPageSocketHandler = (socket) => { } // Delete groups that are not in the list - log("socket", "Delete groups that are not in the list", "debug"); + log_debug("socket", "Delete groups that are not in the list"); const slots = groupIDList.map(() => "?").join(","); await R.exec(`DELETE FROM \`group\` WHERE id NOT IN (${slots})`, groupIDList); @@ -149,7 +149,7 @@ module.exports.statusPageSocketHandler = (socket) => { }); } catch (error) { - console.log(error); + log_error("socket", error); callback({ ok: false, diff --git a/server/util-server.js b/server/util-server.js index 6b1fc522e..672c368c3 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -1,7 +1,7 @@ const tcpp = require("tcp-ping"); const Ping = require("./ping-lite"); const { R } = require("redbean-node"); -const { log } = require("../src/util"); +const { log_debug } = require("../src/util"); const passwordHash = require("./password-hash"); const dayjs = require("dayjs"); const { Resolver } = require("dns"); @@ -119,7 +119,7 @@ exports.setting = async function (key) { try { const v = JSON.parse(value); - log("util", `Get Setting: ${key}: ${v}`, "debug"); + log_debug("util", `Get Setting: ${key}: ${v}`); return v; } catch (e) { return value; @@ -206,7 +206,7 @@ const parseCertificateInfo = function (info) { const existingList = {}; while (link) { - log("util", `[${i}] ${link.fingerprint}`, "debug"); + log_debug("util", `[${i}] ${link.fingerprint}`); if (!link.valid_from || !link.valid_to) { break; @@ -221,7 +221,7 @@ const parseCertificateInfo = function (info) { if (link.issuerCertificate == null) { break; } else if (link.issuerCertificate.fingerprint in existingList) { - log("util", `[Last] ${link.issuerCertificate.fingerprint}`, "debug"); + log_debug("util", `[Last] ${link.issuerCertificate.fingerprint}`); link.issuerCertificate = null; break; } else { @@ -242,7 +242,7 @@ exports.checkCertificate = function (res) { const info = res.request.res.socket.getPeerCertificate(true); const valid = res.request.res.socket.authorized || false; - log("util", "Parsing Certificate Info", "debug"); + log_debug("util", "Parsing Certificate Info"); const parsedInfo = parseCertificateInfo(info); return { @@ -345,7 +345,7 @@ exports.startUnitTest = async () => { */ exports.convertToUTF8 = (body) => { const guessEncoding = chardet.detect(body); - //log("util", "Guess Encoding: " + guessEncoding, "debug"); + //log_debug("util", "Guess Encoding: " + guessEncoding); const str = iconv.decode(body, guessEncoding); return str.toString(); }; diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index 3e013a08b..f10962ee6 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -435,7 +435,7 @@ dayjs.extend(timezone); import { timezoneList, setPageLocale } from "../util-frontend"; import { useToast } from "vue-toastification"; -import { log } from "../util.ts"; +import { log_debug } from "../util.ts"; const toast = useToast(); @@ -639,20 +639,20 @@ export default { this.loadDatabaseSize(); toast.success("Done"); } else { - log("settings", res, "debug"); + log_debug("settings", res); } }); }, loadDatabaseSize() { - log("settings", "load database size", "debug"); + log_debug("settings", "load database size"); this.$root.getSocket().emit("getDatabaseSize", (res) => { if (res.ok) { this.databaseSize = res.size; - log("settings", "database size: " + res.size, "debug"); + log_debug("settings", "database size: " + res.size); } else { - log("settings", res, "debug"); + log_debug("settings", res); } }); diff --git a/src/util.js b/src/util.js index 1b8020df7..6cb1d878c 100644 --- a/src/util.js +++ b/src/util.js @@ -7,7 +7,7 @@ // Backend uses the compiled file util.js // Frontend uses util.ts exports.__esModule = true; -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; +exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log_debug = exports.log_error = exports.log_warn = exports.log_info = 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; var _dayjs = require("dayjs"); var dayjs = _dayjs; exports.isDev = process.env.NODE_ENV === "development"; @@ -44,9 +44,7 @@ function ucfirst(str) { return firstLetter.toUpperCase() + str.substr(1); } exports.ucfirst = ucfirst; -// log levels = info / warn / error / debug function log(module, msg, level) { - if (level === void 0) { level = "info"; } module = module.toUpperCase(); level = level.toUpperCase(); var now = new Date().toISOString(); @@ -69,7 +67,22 @@ function log(module, msg, level) { console.log(formattedMessage); } } -exports.log = log; +function log_info(module, msg) { + log(module, msg, "info"); +} +exports.log_info = log_info; +function log_warn(module, msg) { + log(module, msg, "warn"); +} +exports.log_warn = log_warn; +function log_error(module, msg) { + log(module, msg, "error"); +} +exports.log_error = log_error; +function log_debug(module, msg) { + log(module, msg, "debug"); +} +exports.log_debug = log_debug; function polyfill() { /** * String.prototype.replaceAll() polyfill diff --git a/src/util.ts b/src/util.ts index 6fde8f3f3..d7666d886 100644 --- a/src/util.ts +++ b/src/util.ts @@ -49,8 +49,7 @@ export function ucfirst(str: string) { return firstLetter.toUpperCase() + str.substr(1); } -// log levels = info / warn / error / debug -export function log(module: string, msg: any, level:string = "info") { +function log(module: string, msg: any, level:string) { module = module.toUpperCase(); level = level.toUpperCase(); @@ -72,6 +71,21 @@ export function log(module: string, msg: any, level:string = "info") { } } +export function log_info(module: string, msg: any) { + log(module, msg, "info"); +} + +export function log_warn(module: string, msg: any) { + log(module, msg, "warn"); +} + +export function log_error(module: string, msg: any) { + log(module, msg, "error"); +} + +export function log_debug(module: string, msg: any) { + log(module, msg, "debug"); +} declare global { interface String { replaceAll(str: string, newStr: string): string; } } From df36a4bb3c818f0672bb6d137a3327910a7ebbec Mon Sep 17 00:00:00 2001 From: Andreas Brett Date: Mon, 15 Nov 2021 18:02:14 +0100 Subject: [PATCH 05/40] console.info for level "info" --- src/util.js | 2 +- src/util.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util.js b/src/util.js index 6cb1d878c..6a51c4c7a 100644 --- a/src/util.js +++ b/src/util.js @@ -50,7 +50,7 @@ function log(module, msg, level) { var now = new Date().toISOString(); var formattedMessage = (typeof msg === "string") ? now + " [" + module + "] " + level + ": " + msg : msg; if (level === "INFO") { - console.log(formattedMessage); + console.info(formattedMessage); } else if (level === "WARN") { console.warn(formattedMessage); diff --git a/src/util.ts b/src/util.ts index d7666d886..7bd920332 100644 --- a/src/util.ts +++ b/src/util.ts @@ -57,7 +57,7 @@ function log(module: string, msg: any, level:string) { const formattedMessage = (typeof msg === "string") ? `${now} [${module}] ${level}: ${msg}` : msg; if (level === "INFO") { - console.log(formattedMessage); + console.info(formattedMessage); } else if (level === "WARN") { console.warn(formattedMessage); } else if (level === "ERROR") { From 6f2dcc6dd76f1d718a5a17ed21045b4f4da99df4 Mon Sep 17 00:00:00 2001 From: Andreas Brett Date: Mon, 15 Nov 2021 18:07:18 +0100 Subject: [PATCH 06/40] using provided tsc config --- src/util.js | 60 ++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/src/util.js b/src/util.js index 6a51c4c7a..cb465f809 100644 --- a/src/util.js +++ b/src/util.js @@ -6,10 +6,10 @@ // // Backend uses the compiled file util.js // Frontend uses util.ts -exports.__esModule = true; +Object.defineProperty(exports, "__esModule", { value: true }); exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log_debug = exports.log_error = exports.log_warn = exports.log_info = 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; -var _dayjs = require("dayjs"); -var dayjs = _dayjs; +const _dayjs = require("dayjs"); +const dayjs = _dayjs; exports.isDev = process.env.NODE_ENV === "development"; exports.appName = "Uptime Kuma"; exports.DOWN = 0; @@ -29,7 +29,7 @@ function flipStatus(s) { } exports.flipStatus = flipStatus; function sleep(ms) { - return new Promise(function (resolve) { return setTimeout(resolve, ms); }); + return new Promise(resolve => setTimeout(resolve, ms)); } exports.sleep = sleep; /** @@ -40,15 +40,15 @@ function ucfirst(str) { if (!str) { return str; } - var firstLetter = str.substr(0, 1); + const firstLetter = str.substr(0, 1); return firstLetter.toUpperCase() + str.substr(1); } exports.ucfirst = ucfirst; function log(module, msg, level) { module = module.toUpperCase(); level = level.toUpperCase(); - var now = new Date().toISOString(); - var formattedMessage = (typeof msg === "string") ? now + " [" + module + "] " + level + ": " + msg : msg; + const now = new Date().toISOString(); + const formattedMessage = (typeof msg === "string") ? `${now} [${module}] ${level}: ${msg}` : msg; if (level === "INFO") { console.info(formattedMessage); } @@ -102,17 +102,16 @@ function polyfill() { } } exports.polyfill = polyfill; -var TimeLogger = /** @class */ (function () { - function TimeLogger() { +class TimeLogger { + constructor() { this.startTime = dayjs().valueOf(); } - TimeLogger.prototype.print = function (name) { + print(name) { if (exports.isDev && process.env.TIMELOGGER === "1") { console.log(name + ": " + (dayjs().valueOf() - this.startTime) + "ms"); } - }; - return TimeLogger; -}()); + } +} exports.TimeLogger = TimeLogger; /** * Returns a random number between min (inclusive) and max (exclusive) @@ -140,12 +139,12 @@ exports.getRandomInt = getRandomInt; * Returns either the NodeJS crypto.randomBytes() function or its * browser equivalent implemented via window.crypto.getRandomValues() */ -var getRandomBytes = ((typeof window !== 'undefined' && window.crypto) +let getRandomBytes = ((typeof window !== 'undefined' && window.crypto) // Browsers ? function () { - return function (numBytes) { - var randomBytes = new Uint8Array(numBytes); - for (var i = 0; i < numBytes; i += 65536) { + return (numBytes) => { + let randomBytes = new Uint8Array(numBytes); + for (let i = 0; i < numBytes; i += 65536) { window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536))); } return randomBytes; @@ -157,13 +156,13 @@ var getRandomBytes = ((typeof window !== 'undefined' && window.crypto) })(); function getCryptoRandomInt(min, max) { // synchronous version of: https://github.com/joepie91/node-random-number-csprng - var range = max - min; + const range = max - min; if (range >= Math.pow(2, 32)) console.log("Warning! Range is too large."); - var tmpRange = range; - var bitsNeeded = 0; - var bytesNeeded = 0; - var mask = 1; + let tmpRange = range; + let bitsNeeded = 0; + let bytesNeeded = 0; + let mask = 1; while (tmpRange > 0) { if (bitsNeeded % 8 === 0) bytesNeeded += 1; @@ -171,9 +170,9 @@ function getCryptoRandomInt(min, max) { mask = mask << 1 | 1; tmpRange = tmpRange >>> 1; } - var randomBytes = getRandomBytes(bytesNeeded); - var randomValue = 0; - for (var i = 0; i < bytesNeeded; i++) { + const randomBytes = getRandomBytes(bytesNeeded); + let randomValue = 0; + for (let i = 0; i < bytesNeeded; i++) { randomValue |= randomBytes[i] << 8 * i; } randomValue = randomValue & mask; @@ -185,12 +184,11 @@ function getCryptoRandomInt(min, max) { } } exports.getCryptoRandomInt = getCryptoRandomInt; -function genSecret(length) { - if (length === void 0) { length = 64; } - var secret = ""; - var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - var charsLength = chars.length; - for (var i = 0; i < length; i++) { +function genSecret(length = 64) { + let secret = ""; + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + const charsLength = chars.length; + for (let i = 0; i < length; i++) { secret += chars.charAt(getCryptoRandomInt(0, charsLength - 1)); } return secret; From a2de9e4e361a141f2fd6b1271218a6b1bbd55095 Mon Sep 17 00:00:00 2001 From: Fluency <93673101+fluencydoc@users.noreply.github.com> Date: Wed, 17 Nov 2021 16:02:31 -0800 Subject: [PATCH 07/40] Fixed export-function signature being scrambled. --- src/util-frontend.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/util-frontend.js b/src/util-frontend.js index dff6d679b..87cde3c43 100644 --- a/src/util-frontend.js +++ b/src/util-frontend.js @@ -24,14 +24,14 @@ function getTimezoneOffset(timeZone) { return -offset; } -export /** - * Returns a list of timezones sorted by their offset from UTC. - * @param {Array} timezones - An array of timezone objects. - * @returns {Array} A list of the given timezones sorted by their offset from UTC. - * - * Generated by Trelent - */ -function timezoneList() { +/** +* Returns a list of timezones sorted by their offset from UTC. +* @param {Array} timezones - An array of timezone objects. +* @returns {Array} A list of the given timezones sorted by their offset from UTC. +* +* Generated by Trelent +*/ +export function timezoneList() { let result = []; for (let timezone of timezones) { From 7179c6cc4c4a8c33177e4d3210e5bf8542806627 Mon Sep 17 00:00:00 2001 From: Fluency <93673101+fluencydoc@users.noreply.github.com> Date: Fri, 19 Nov 2021 10:30:31 -0800 Subject: [PATCH 08/40] Fix punctuation in extra/update-version.js Co-authored-by: Adam Stachowicz --- extra/update-version.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/update-version.js b/extra/update-version.js index 34b46281f..34404f4ef 100644 --- a/extra/update-version.js +++ b/extra/update-version.js @@ -38,7 +38,7 @@ if (! exists) { } /** - * Updates the version number in package.json and commits it to git + * Updates the version number in package.json and commits it to git. * @param {string} version - The new version number * * Generated by Trelent From 2f97f44086b53faf170a56d3e8de8a0ac238d7be Mon Sep 17 00:00:00 2001 From: Andreas Brett Date: Mon, 29 Nov 2021 20:37:44 +0100 Subject: [PATCH 09/40] Update MonitorHistory.vue --- src/components/settings/MonitorHistory.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/settings/MonitorHistory.vue b/src/components/settings/MonitorHistory.vue index 9b5b8bd78..e332bfd6e 100644 --- a/src/components/settings/MonitorHistory.vue +++ b/src/components/settings/MonitorHistory.vue @@ -52,7 +52,7 @@ diff --git a/src/components/Confirm.vue b/src/components/Confirm.vue index 391155f43..994075830 100644 --- a/src/components/Confirm.vue +++ b/src/components/Confirm.vue @@ -25,7 +25,7 @@ diff --git a/src/components/CountUp.vue b/src/components/CountUp.vue index b321fde19..5a0deb745 100644 --- a/src/components/CountUp.vue +++ b/src/components/CountUp.vue @@ -5,7 +5,7 @@ diff --git a/src/components/Datetime.vue b/src/components/Datetime.vue index 1df982cb1..8662e6d8a 100644 --- a/src/components/Datetime.vue +++ b/src/components/Datetime.vue @@ -4,12 +4,12 @@ diff --git a/src/components/HeartbeatBar.vue b/src/components/HeartbeatBar.vue index be0b122ed..245a8512c 100644 --- a/src/components/HeartbeatBar.vue +++ b/src/components/HeartbeatBar.vue @@ -38,7 +38,7 @@ export default { beatMargin: 4, move: false, maxBeat: -1, - } + }; }, computed: { @@ -69,12 +69,12 @@ export default { if (start < 0) { // Add empty placeholder for (let i = start; i < 0; i++) { - placeholders.push(0) + placeholders.push(0); } start = 0; } - return placeholders.concat(this.beatList.slice(start)) + return placeholders.concat(this.beatList.slice(start)); }, wrapStyle() { @@ -84,7 +84,7 @@ export default { return { padding: `${topBottom}px ${leftRight}px`, width: "100%", - } + }; }, barStyle() { @@ -94,12 +94,12 @@ export default { return { transition: "all ease-in-out 0.25s", transform: `translateX(${width}px)`, - } + }; } return { transform: "translateX(0)", - } + }; }, @@ -109,7 +109,7 @@ export default { height: this.beatHeight + "px", margin: this.beatMargin + "px", "--hover-scale": this.hoverScale, - } + }; }, }, @@ -120,7 +120,7 @@ export default { setTimeout(() => { this.move = false; - }, 300) + }, 300); }, deep: true, }, @@ -162,15 +162,15 @@ export default { methods: { resize() { if (this.$refs.wrap) { - this.maxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatMargin * 2)) + this.maxBeat = Math.floor(this.$refs.wrap.clientWidth / (this.beatWidth + this.beatMargin * 2)); } }, getBeatTitle(beat) { - return `${this.$root.datetime(beat.time)}` + ((beat.msg) ? ` - ${beat.msg}` : ``); + return `${this.$root.datetime(beat.time)}` + ((beat.msg) ? ` - ${beat.msg}` : ""); } }, -} +}; diff --git a/src/components/settings/MonitorHistory.vue b/src/components/settings/MonitorHistory.vue index 8fff60545..0092727f4 100644 --- a/src/components/settings/MonitorHistory.vue +++ b/src/components/settings/MonitorHistory.vue @@ -129,5 +129,3 @@ export default { }, }; - - diff --git a/src/components/settings/Security.vue b/src/components/settings/Security.vue index 1459519f5..e59600046 100644 --- a/src/components/settings/Security.vue +++ b/src/components/settings/Security.vue @@ -355,7 +355,7 @@ export default {