From 1c13a759707f4d43bfa6bbc352f2bb8fa23ef98d Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Fri, 13 Oct 2023 02:50:10 +0800 Subject: [PATCH 01/17] Fix #3868 postgres monitor could possibly crash Uptime Kuma (#3880) * Bump pg * Handle uncaughtException * Fix parsing issue of postgres connection and fix the query example --- package-lock.json | 36 +++++++++++++++++++++++++----------- package.json | 5 +++-- server/server.js | 6 ++++-- server/util-server.js | 21 +++++++++++++++++---- src/pages/EditMonitor.vue | 2 +- 5 files changed, 50 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 973e95835..6ba2b32ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,8 +57,8 @@ "notp": "~2.0.3", "openid-client": "^5.4.2", "password-hash": "~1.2.2", - "pg": "~8.8.0", - "pg-connection-string": "~2.5.0", + "pg": "~8.11.3", + "pg-connection-string": "~2.6.2", "playwright-core": "~1.35.1", "prom-client": "~13.2.0", "prometheus-api-metrics": "~3.2.1", @@ -13392,6 +13392,11 @@ "node": "^12.20.0 || >=14" } }, + "node_modules/knex/node_modules/pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, "node_modules/knex/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -15221,21 +15226,24 @@ "dev": true }, "node_modules/pg": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", - "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", "dependencies": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", - "pg-connection-string": "^2.5.0", - "pg-pool": "^3.5.2", - "pg-protocol": "^1.5.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", "pg-types": "^2.1.0", "pgpass": "1.x" }, "engines": { "node": ">= 8.0.0" }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, "peerDependencies": { "pg-native": ">=3.0.1" }, @@ -15245,10 +15253,16 @@ } } }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, "node_modules/pg-connection-string": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", - "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" }, "node_modules/pg-int8": { "version": "1.0.1", diff --git a/package.json b/package.json index bc95de954..21f01fe39 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "simple-dns-server": "node extra/simple-dns-server.js", "simple-mqtt-server": "node extra/simple-mqtt-server.js", "simple-mongo": "docker run --rm -p 27017:27017 mongo", + "simple-postgres": "docker run --rm -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres", "update-language-files": "cd extra/update-language-files && node index.js && cross-env-shell eslint ../../src/languages/$npm_config_language.js --fix", "ncu-patch": "npm-check-updates -u -t patch", "release-final": "node ./extra/test-docker.js && node extra/update-version.js && npm run build-docker && node ./extra/press-any-key.js && npm run upload-artifacts && node ./extra/update-wiki-version.js", @@ -121,8 +122,8 @@ "notp": "~2.0.3", "openid-client": "^5.4.2", "password-hash": "~1.2.2", - "pg": "~8.8.0", - "pg-connection-string": "~2.5.0", + "pg": "~8.11.3", + "pg-connection-string": "~2.6.2", "playwright-core": "~1.35.1", "prom-client": "~13.2.0", "prometheus-api-metrics": "~3.2.1", diff --git a/server/server.js b/server/server.js index c8f826b02..e8132cb90 100644 --- a/server/server.js +++ b/server/server.js @@ -1887,8 +1887,10 @@ gracefulShutdown(server.httpServer, { }); // Catch unexpected errors here -process.addListener("unhandledRejection", (error, promise) => { +let unexpectedErrorHandler = (error, promise) => { console.trace(error); UptimeKumaServer.errorLog(error, false); console.error("If you keep encountering errors, please report to https://github.com/louislam/uptime-kuma/issues"); -}); +}; +process.addListener("unhandledRejection", unexpectedErrorHandler); +process.addListener("uncaughtException", unexpectedErrorHandler); diff --git a/server/util-server.js b/server/util-server.js index 0cb63ad00..9e4946e60 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -395,6 +395,9 @@ exports.mssqlQuery = async function (connectionString, query) { try { pool = new mssql.ConnectionPool(connectionString); await pool.connect(); + if (!query) { + query = "SELECT 1"; + } await pool.request().query(query); pool.close(); } catch (e) { @@ -415,12 +418,22 @@ exports.postgresQuery = function (connectionString, query) { return new Promise((resolve, reject) => { const config = postgresConParse(connectionString); - if (config.password === "") { - // See https://github.com/brianc/node-postgres/issues/1927 - return reject(new Error("Password is undefined.")); + // Fix #3868, which true/false is not parsed to boolean + if (typeof config.ssl === "string") { + config.ssl = config.ssl === "true"; } - const client = new Client({ connectionString }); + if (config.password === "") { + // See https://github.com/brianc/node-postgres/issues/1927 + reject(new Error("Password is undefined.")); + return; + } + const client = new Client(config); + + client.on("error", (error) => { + log.debug("postgres", "Error caught in the error event handler."); + reject(error); + }); client.connect((err) => { if (err) { diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 7a90b5752..1f64172d9 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -374,7 +374,7 @@ From 4ccf263481fbf74289d3c105a23103eededb79ae Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Mon, 16 Oct 2023 00:27:47 +0800 Subject: [PATCH 02/17] Update docker image base from Node.js 16 to Node.js 18 for Uptime Kuma v1 (#3901) --- docker/debian-base.dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/debian-base.dockerfile b/docker/debian-base.dockerfile index 244e6c5fb..bd609830a 100644 --- a/docker/debian-base.dockerfile +++ b/docker/debian-base.dockerfile @@ -1,6 +1,6 @@ -# DON'T UPDATE TO node:14-bullseye-slim, see #372. -# If the image changed, the second stage image should be changed too -FROM node:16-buster-slim +# DON'T UPDATE TO bullseye-slim, see #372. +# There is no 20-buster-slim for armv7 unfortunately, 18-buster-slim is the last one for Uptime Kuma v1. +FROM node:18-buster-slim ARG TARGETPLATFORM WORKDIR /app From 18169c59a190dab5c65e3b8643534d61b4a62cf4 Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Mon, 16 Oct 2023 00:38:56 +0800 Subject: [PATCH 03/17] [MySQL monitor] Split password into a standalone field (#3899) --- package-lock.json | 37 ++++++++++++------------------------- package.json | 3 ++- server/model/monitor.js | 10 +++++++--- server/util-server.js | 8 ++++++-- src/pages/EditMonitor.vue | 11 +++++++++++ 5 files changed, 38 insertions(+), 31 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6ba2b32ab..3d389ac5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ "mongodb": "~4.17.1", "mqtt": "~4.3.7", "mssql": "~8.1.4", - "mysql2": "~2.3.3", + "mysql2": "~3.6.2", "nanoid": "~3.3.4", "node-cloudflared-tunnel": "~1.0.9", "node-radius-client": "~1.0.0", @@ -14418,16 +14418,16 @@ } }, "node_modules/mysql2": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz", - "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.6.2.tgz", + "integrity": "sha512-m5erE6bMoWfPXW1D5UrVwlT8PowAoSX69KcZzPuARQ3wY1RJ52NW9PdvdPo076XiSIkQ5IBTis7hxdlrQTlyug==", "dependencies": { - "denque": "^2.0.1", + "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", + "long": "^5.2.1", + "lru-cache": "^8.0.0", + "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" }, @@ -14435,27 +14435,14 @@ "node": ">= 8.0" } }, - "node_modules/mysql2/node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, "node_modules/mysql2/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", + "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==", "engines": { - "node": ">=10" + "node": ">=16.14" } }, - "node_modules/mysql2/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/named-placeholders": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", diff --git a/package.json b/package.json index 21f01fe39..141283f5a 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "simple-mqtt-server": "node extra/simple-mqtt-server.js", "simple-mongo": "docker run --rm -p 27017:27017 mongo", "simple-postgres": "docker run --rm -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres", + "simple-mariadb": "docker run --rm -p 3306:3306 -e MYSQL_ROOT_PASSWORD=mariadb# mariadb", "update-language-files": "cd extra/update-language-files && node index.js && cross-env-shell eslint ../../src/languages/$npm_config_language.js --fix", "ncu-patch": "npm-check-updates -u -t patch", "release-final": "node ./extra/test-docker.js && node extra/update-version.js && npm run build-docker && node ./extra/press-any-key.js && npm run upload-artifacts && node ./extra/update-wiki-version.js", @@ -113,7 +114,7 @@ "mongodb": "~4.17.1", "mqtt": "~4.3.7", "mssql": "~8.1.4", - "mysql2": "~2.3.3", + "mysql2": "~3.6.2", "nanoid": "~3.3.4", "node-cloudflared-tunnel": "~1.0.9", "node-radius-client": "~1.0.0", diff --git a/server/model/monitor.js b/server/model/monitor.js index c83ece49e..7fffe630c 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -756,7 +756,7 @@ class Monitor extends BeanModel { } else if (this.type === "sqlserver") { let startTime = dayjs().valueOf(); - await mssqlQuery(this.databaseConnectionString, this.databaseQuery); + await mssqlQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1"); bean.msg = ""; bean.status = UP; @@ -795,7 +795,7 @@ class Monitor extends BeanModel { } else if (this.type === "postgres") { let startTime = dayjs().valueOf(); - await postgresQuery(this.databaseConnectionString, this.databaseQuery); + await postgresQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1"); bean.msg = ""; bean.status = UP; @@ -803,7 +803,11 @@ class Monitor extends BeanModel { } else if (this.type === "mysql") { let startTime = dayjs().valueOf(); - bean.msg = await mysqlQuery(this.databaseConnectionString, this.databaseQuery); + // Use `radius_password` as `password` field, since there are too many unnecessary fields + // TODO: rename `radius_password` to `password` later for general use + let mysqlPassword = this.radiusPassword; + + bean.msg = await mysqlQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1", mysqlPassword); bean.status = UP; bean.ping = dayjs().valueOf() - startTime; } else if (this.type === "mongodb") { diff --git a/server/util-server.js b/server/util-server.js index 9e4946e60..bab804053 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -468,11 +468,15 @@ exports.postgresQuery = function (connectionString, query) { * Run a query on MySQL/MariaDB * @param {string} connectionString The database connection string * @param {string} query The query to validate the database with + * @param {?string} password The password to use * @returns {Promise<(string)>} */ -exports.mysqlQuery = function (connectionString, query) { +exports.mysqlQuery = function (connectionString, query, password = undefined) { return new Promise((resolve, reject) => { - const connection = mysql.createConnection(connectionString); + const connection = mysql.createConnection({ + uri: connectionString, + password + }); connection.on("error", (err) => { reject(err); diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 1f64172d9..1a02832c1 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -370,6 +370,15 @@ + + + - +