Merge branch 'master' into snmp-monitor

pull/4717/head
Frank Elsinga 7 months ago committed by GitHub
commit b4bd003626
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -43,11 +43,18 @@ It is a temporary live demo, all data will be deleted after 10 minutes. Sponsore
docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1 docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1
``` ```
Uptime Kuma is now running on http://localhost:3001 Uptime Kuma is now running on <http://0.0.0.0:3001>.
> [!WARNING] > [!WARNING]
> File Systems like **NFS** (Network File System) are **NOT** supported. Please map to a local directory or volume. > File Systems like **NFS** (Network File System) are **NOT** supported. Please map to a local directory or volume.
> [!NOTE]
> If you want to limit exppoure to localhost (without exposing port for other users or to use a [reverse proxyx](https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy)), you can expose the port like this:
>
> ```bash
> docker run -d --restart=always -p 127.0.0.1:3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1
> ```
### 💪🏻 Non-Docker ### 💪🏻 Non-Docker
Requirements: Requirements:

@ -0,0 +1,18 @@
BEGIN TRANSACTION;
PRAGMA writable_schema = TRUE;
UPDATE
SQLITE_MASTER
SET
sql = replace(sql,
'monitor_id INTEGER NOT NULL',
'monitor_id INTEGER NOT NULL REFERENCES [monitor] ([id]) ON DELETE CASCADE ON UPDATE CASCADE'
)
WHERE
name = 'monitor_tls_info'
AND type = 'table';
PRAGMA writable_schema = RESET;
COMMIT;

246
package-lock.json generated

@ -14,7 +14,7 @@
"@louislam/sqlite3": "15.1.6", "@louislam/sqlite3": "15.1.6",
"@vvo/tzdb": "^6.125.0", "@vvo/tzdb": "^6.125.0",
"args-parser": "~1.3.0", "args-parser": "~1.3.0",
"axios": "~0.28.0", "axios": "~0.28.1",
"axios-ntlm": "1.3.0", "axios-ntlm": "1.3.0",
"badge-maker": "~3.3.1", "badge-maker": "~3.3.1",
"bcryptjs": "~2.4.3", "bcryptjs": "~2.4.3",
@ -52,7 +52,7 @@
"mongodb": "~4.17.1", "mongodb": "~4.17.1",
"mqtt": "~4.3.7", "mqtt": "~4.3.7",
"mssql": "~8.1.4", "mssql": "~8.1.4",
"mysql2": "~3.6.2", "mysql2": "~3.9.6",
"nanoid": "~3.3.4", "nanoid": "~3.3.4",
"net-snmp": "^3.11.2", "net-snmp": "^3.11.2",
"node-cloudflared-tunnel": "~1.0.9", "node-cloudflared-tunnel": "~1.0.9",
@ -76,14 +76,14 @@
"socket.io": "~4.6.1", "socket.io": "~4.6.1",
"socket.io-client": "~4.6.1", "socket.io-client": "~4.6.1",
"socks-proxy-agent": "6.1.1", "socks-proxy-agent": "6.1.1",
"tar": "~6.1.11", "tar": "~6.2.1",
"tcp-ping": "~0.1.1", "tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2", "thirty-two": "~1.0.2",
"tough-cookie": "~4.1.3", "tough-cookie": "~4.1.3",
"ws": "^8.13.0" "ws": "^8.13.0"
}, },
"devDependencies": { "devDependencies": {
"@actions/github": "~5.0.1", "@actions/github": "~5.1.1",
"@fortawesome/fontawesome-svg-core": "~1.2.36", "@fortawesome/fontawesome-svg-core": "~1.2.36",
"@fortawesome/free-regular-svg-icons": "~5.15.4", "@fortawesome/free-regular-svg-icons": "~5.15.4",
"@fortawesome/free-solid-svg-icons": "~5.15.4", "@fortawesome/free-solid-svg-icons": "~5.15.4",
@ -107,7 +107,7 @@
"cross-env": "~7.0.3", "cross-env": "~7.0.3",
"delay": "^5.0.0", "delay": "^5.0.0",
"dns2": "~2.0.1", "dns2": "~2.0.1",
"dompurify": "~2.4.3", "dompurify": "~3.0.11",
"eslint": "~8.14.0", "eslint": "~8.14.0",
"eslint-plugin-jsdoc": "~46.4.6", "eslint-plugin-jsdoc": "~46.4.6",
"eslint-plugin-vue": "~8.7.1", "eslint-plugin-vue": "~8.7.1",
@ -128,7 +128,7 @@
"test": "~3.3.0", "test": "~3.3.0",
"typescript": "~4.4.4", "typescript": "~4.4.4",
"v-pagination-3": "~0.1.7", "v-pagination-3": "~0.1.7",
"vite": "~5.0.10", "vite": "~5.2.8",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-vue-devtools": "^7.0.15", "vite-plugin-vue-devtools": "^7.0.15",
"vue": "~3.4.2", "vue": "~3.4.2",
@ -147,7 +147,7 @@
"whatwg-url": "~12.0.1" "whatwg-url": "~12.0.1"
}, },
"engines": { "engines": {
"node": "14 || 16 || 18 || >= 20.4.0" "node": "18 || >= 20.4.0"
} }
}, },
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
@ -160,9 +160,9 @@
} }
}, },
"node_modules/@actions/github": { "node_modules/@actions/github": {
"version": "5.0.3", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.3.tgz", "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz",
"integrity": "sha512-myjA/pdLQfhUGLtRZC/J4L1RXOG4o6aYdiEq+zr5wVVKljzbFld+xv10k1FX6IkIJtNxbAq44BdwSNpQ015P0A==", "integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^2.0.1",
@ -1963,9 +1963,9 @@
} }
}, },
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
"integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -1979,9 +1979,9 @@
} }
}, },
"node_modules/@esbuild/android-arm": { "node_modules/@esbuild/android-arm": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
"integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -1995,9 +1995,9 @@
} }
}, },
"node_modules/@esbuild/android-arm64": { "node_modules/@esbuild/android-arm64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
"integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -2011,9 +2011,9 @@
} }
}, },
"node_modules/@esbuild/android-x64": { "node_modules/@esbuild/android-x64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
"integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2027,9 +2027,9 @@
} }
}, },
"node_modules/@esbuild/darwin-arm64": { "node_modules/@esbuild/darwin-arm64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
"integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -2043,9 +2043,9 @@
} }
}, },
"node_modules/@esbuild/darwin-x64": { "node_modules/@esbuild/darwin-x64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
"integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2059,9 +2059,9 @@
} }
}, },
"node_modules/@esbuild/freebsd-arm64": { "node_modules/@esbuild/freebsd-arm64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
"integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -2075,9 +2075,9 @@
} }
}, },
"node_modules/@esbuild/freebsd-x64": { "node_modules/@esbuild/freebsd-x64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
"integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2091,9 +2091,9 @@
} }
}, },
"node_modules/@esbuild/linux-arm": { "node_modules/@esbuild/linux-arm": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
"integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -2107,9 +2107,9 @@
} }
}, },
"node_modules/@esbuild/linux-arm64": { "node_modules/@esbuild/linux-arm64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
"integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -2123,9 +2123,9 @@
} }
}, },
"node_modules/@esbuild/linux-ia32": { "node_modules/@esbuild/linux-ia32": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
"integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -2139,9 +2139,9 @@
} }
}, },
"node_modules/@esbuild/linux-loong64": { "node_modules/@esbuild/linux-loong64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
"integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@ -2155,9 +2155,9 @@
} }
}, },
"node_modules/@esbuild/linux-mips64el": { "node_modules/@esbuild/linux-mips64el": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
"integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
"cpu": [ "cpu": [
"mips64el" "mips64el"
], ],
@ -2171,9 +2171,9 @@
} }
}, },
"node_modules/@esbuild/linux-ppc64": { "node_modules/@esbuild/linux-ppc64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
"integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -2187,9 +2187,9 @@
} }
}, },
"node_modules/@esbuild/linux-riscv64": { "node_modules/@esbuild/linux-riscv64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
"integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@ -2203,9 +2203,9 @@
} }
}, },
"node_modules/@esbuild/linux-s390x": { "node_modules/@esbuild/linux-s390x": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
"integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@ -2219,9 +2219,9 @@
} }
}, },
"node_modules/@esbuild/linux-x64": { "node_modules/@esbuild/linux-x64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
"integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2235,9 +2235,9 @@
} }
}, },
"node_modules/@esbuild/netbsd-x64": { "node_modules/@esbuild/netbsd-x64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
"integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2251,9 +2251,9 @@
} }
}, },
"node_modules/@esbuild/openbsd-x64": { "node_modules/@esbuild/openbsd-x64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
"integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2267,9 +2267,9 @@
} }
}, },
"node_modules/@esbuild/sunos-x64": { "node_modules/@esbuild/sunos-x64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
"integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2283,9 +2283,9 @@
} }
}, },
"node_modules/@esbuild/win32-arm64": { "node_modules/@esbuild/win32-arm64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
"integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -2299,9 +2299,9 @@
} }
}, },
"node_modules/@esbuild/win32-ia32": { "node_modules/@esbuild/win32-ia32": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
"integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -2315,9 +2315,9 @@
} }
}, },
"node_modules/@esbuild/win32-x64": { "node_modules/@esbuild/win32-x64": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
"integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -5079,9 +5079,9 @@
"integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==" "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw=="
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "0.28.0", "version": "0.28.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.28.0.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-0.28.1.tgz",
"integrity": "sha512-Tu7NYoGY4Yoc7I+Npf9HhUMtEEpV7ZiLH9yndTCoNhcpBH0kwcvFbzYN9/u5QKI5A6uefjsNNWaz5olJVYS62Q==", "integrity": "sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ==",
"dependencies": { "dependencies": {
"follow-redirects": "^1.15.0", "follow-redirects": "^1.15.0",
"form-data": "^4.0.0", "form-data": "^4.0.0",
@ -6672,9 +6672,9 @@
} }
}, },
"node_modules/dompurify": { "node_modules/dompurify": {
"version": "2.4.9", "version": "3.0.11",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.9.tgz", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.11.tgz",
"integrity": "sha512-iHtnxYMotKgOTvxIqq677JsKHvCOkAFqj9x8Mek2zdeHW1XjuFKwjpmZeMaXQRQ8AbJZDbcRz/+r1QhwvFtmQg==", "integrity": "sha512-Fan4uMuyB26gFV3ovPoEoQbxRRPfTu3CvImyZnhGq5fsIEO+gEFLp45ISFt+kQBWsK5ulDdT0oV28jS1UrwQLg==",
"dev": true "dev": true
}, },
"node_modules/domutils": { "node_modules/domutils": {
@ -7033,9 +7033,9 @@
} }
}, },
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.19.12", "version": "0.20.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
"integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"bin": { "bin": {
@ -7045,29 +7045,29 @@
"node": ">=12" "node": ">=12"
}, },
"optionalDependencies": { "optionalDependencies": {
"@esbuild/aix-ppc64": "0.19.12", "@esbuild/aix-ppc64": "0.20.2",
"@esbuild/android-arm": "0.19.12", "@esbuild/android-arm": "0.20.2",
"@esbuild/android-arm64": "0.19.12", "@esbuild/android-arm64": "0.20.2",
"@esbuild/android-x64": "0.19.12", "@esbuild/android-x64": "0.20.2",
"@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-arm64": "0.20.2",
"@esbuild/darwin-x64": "0.19.12", "@esbuild/darwin-x64": "0.20.2",
"@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-arm64": "0.20.2",
"@esbuild/freebsd-x64": "0.19.12", "@esbuild/freebsd-x64": "0.20.2",
"@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm": "0.20.2",
"@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-arm64": "0.20.2",
"@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-ia32": "0.20.2",
"@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-loong64": "0.20.2",
"@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-mips64el": "0.20.2",
"@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-ppc64": "0.20.2",
"@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-riscv64": "0.20.2",
"@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-s390x": "0.20.2",
"@esbuild/linux-x64": "0.19.12", "@esbuild/linux-x64": "0.20.2",
"@esbuild/netbsd-x64": "0.19.12", "@esbuild/netbsd-x64": "0.20.2",
"@esbuild/openbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.20.2",
"@esbuild/sunos-x64": "0.19.12", "@esbuild/sunos-x64": "0.20.2",
"@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-arm64": "0.20.2",
"@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-ia32": "0.20.2",
"@esbuild/win32-x64": "0.19.12" "@esbuild/win32-x64": "0.20.2"
} }
}, },
"node_modules/escalade": { "node_modules/escalade": {
@ -10250,9 +10250,9 @@
} }
}, },
"node_modules/mysql2": { "node_modules/mysql2": {
"version": "3.6.5", "version": "3.9.7",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.6.5.tgz", "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.7.tgz",
"integrity": "sha512-pS/KqIb0xlXmtmqEuTvBXTmLoQ5LmAz5NW/r8UyQ1ldvnprNEj3P9GbmuQQ2J0A4LO+ynotGi6TbscPa8OUb+w==", "integrity": "sha512-KnJT8vYRcNAZv73uf9zpXqNbvBG7DJrs+1nACsjZP1HMJ1TgXEy8wnNilXAn/5i57JizXKtrUtwDB7HxT9DDpw==",
"dependencies": { "dependencies": {
"denque": "^2.1.0", "denque": "^2.1.0",
"generate-function": "^2.3.1", "generate-function": "^2.3.1",
@ -13333,9 +13333,9 @@
"dev": true "dev": true
}, },
"node_modules/tar": { "node_modules/tar": {
"version": "6.1.15", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
"integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
"dependencies": { "dependencies": {
"chownr": "^2.0.0", "chownr": "^2.0.0",
"fs-minipass": "^2.0.0", "fs-minipass": "^2.0.0",
@ -13977,14 +13977,14 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.0.13", "version": "5.2.10",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.0.13.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz",
"integrity": "sha512-/9ovhv2M2dGTuA+dY93B9trfyWMDRQw2jdVBhHNP6wr0oF34wG2i/N55801iZIpgUpnHDm4F/FabGQLyc+eOgg==", "integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"esbuild": "^0.19.3", "esbuild": "^0.20.1",
"postcss": "^8.4.32", "postcss": "^8.4.38",
"rollup": "^4.2.0" "rollup": "^4.13.0"
}, },
"bin": { "bin": {
"vite": "bin/vite.js" "vite": "bin/vite.js"

@ -49,7 +49,7 @@
"build-docker-nightly-local": "npm run build && docker build -f docker/dockerfile -t louislam/uptime-kuma:nightly2 --target nightly .", "build-docker-nightly-local": "npm run build && docker build -f docker/dockerfile -t louislam/uptime-kuma:nightly2 --target nightly .",
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test2 --target pr-test2 . --push", "build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test2 --target pr-test2 . --push",
"upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain", "upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
"setup": "git checkout 1.23.11 && npm ci --production && npm run download-dist", "setup": "git checkout 1.23.13 && npm ci --production && npm run download-dist",
"download-dist": "node extra/download-dist.js", "download-dist": "node extra/download-dist.js",
"mark-as-nightly": "node extra/mark-as-nightly.js", "mark-as-nightly": "node extra/mark-as-nightly.js",
"reset-password": "node extra/reset-password.js", "reset-password": "node extra/reset-password.js",
@ -79,7 +79,7 @@
"@louislam/sqlite3": "15.1.6", "@louislam/sqlite3": "15.1.6",
"@vvo/tzdb": "^6.125.0", "@vvo/tzdb": "^6.125.0",
"args-parser": "~1.3.0", "args-parser": "~1.3.0",
"axios": "~0.28.0", "axios": "~0.28.1",
"axios-ntlm": "1.3.0", "axios-ntlm": "1.3.0",
"badge-maker": "~3.3.1", "badge-maker": "~3.3.1",
"bcryptjs": "~2.4.3", "bcryptjs": "~2.4.3",
@ -117,7 +117,7 @@
"mongodb": "~4.17.1", "mongodb": "~4.17.1",
"mqtt": "~4.3.7", "mqtt": "~4.3.7",
"mssql": "~8.1.4", "mssql": "~8.1.4",
"mysql2": "~3.6.2", "mysql2": "~3.9.6",
"nanoid": "~3.3.4", "nanoid": "~3.3.4",
"net-snmp": "^3.11.2", "net-snmp": "^3.11.2",
"node-cloudflared-tunnel": "~1.0.9", "node-cloudflared-tunnel": "~1.0.9",
@ -141,14 +141,14 @@
"socket.io": "~4.6.1", "socket.io": "~4.6.1",
"socket.io-client": "~4.6.1", "socket.io-client": "~4.6.1",
"socks-proxy-agent": "6.1.1", "socks-proxy-agent": "6.1.1",
"tar": "~6.1.11", "tar": "~6.2.1",
"tcp-ping": "~0.1.1", "tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2", "thirty-two": "~1.0.2",
"tough-cookie": "~4.1.3", "tough-cookie": "~4.1.3",
"ws": "^8.13.0" "ws": "^8.13.0"
}, },
"devDependencies": { "devDependencies": {
"@actions/github": "~5.0.1", "@actions/github": "~5.1.1",
"@fortawesome/fontawesome-svg-core": "~1.2.36", "@fortawesome/fontawesome-svg-core": "~1.2.36",
"@fortawesome/free-regular-svg-icons": "~5.15.4", "@fortawesome/free-regular-svg-icons": "~5.15.4",
"@fortawesome/free-solid-svg-icons": "~5.15.4", "@fortawesome/free-solid-svg-icons": "~5.15.4",
@ -172,7 +172,7 @@
"cross-env": "~7.0.3", "cross-env": "~7.0.3",
"delay": "^5.0.0", "delay": "^5.0.0",
"dns2": "~2.0.1", "dns2": "~2.0.1",
"dompurify": "~2.4.3", "dompurify": "~3.0.11",
"eslint": "~8.14.0", "eslint": "~8.14.0",
"eslint-plugin-jsdoc": "~46.4.6", "eslint-plugin-jsdoc": "~46.4.6",
"eslint-plugin-vue": "~8.7.1", "eslint-plugin-vue": "~8.7.1",
@ -193,7 +193,7 @@
"test": "~3.3.0", "test": "~3.3.0",
"typescript": "~4.4.4", "typescript": "~4.4.4",
"v-pagination-3": "~0.1.7", "v-pagination-3": "~0.1.7",
"vite": "~5.0.10", "vite": "~5.2.8",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-vue-devtools": "^7.0.15", "vite-plugin-vue-devtools": "^7.0.15",
"vue": "~3.4.2", "vue": "~3.4.2",

@ -250,12 +250,12 @@ class Monitor extends BeanModel {
/** /**
* Encode user and password to Base64 encoding * Encode user and password to Base64 encoding
* for HTTP "basic" auth, as per RFC-7617 * for HTTP "basic" auth, as per RFC-7617
* @param {string} user Username to encode * @param {string|null} user - The username (nullable if not changed by a user)
* @param {string} pass Password to encode * @param {string|null} pass - The password (nullable if not changed by a user)
* @returns {string} Encoded username:password * @returns {string} Encoded Base64 string
*/ */
encodeBase64(user, pass) { encodeBase64(user, pass) {
return Buffer.from(user + ":" + pass).toString("base64"); return Buffer.from(`${user || ""}:${pass || ""}`).toString("base64");
} }
/** /**
@ -538,6 +538,18 @@ class Monitor extends BeanModel {
} }
} }
let tlsInfo = {};
// Store tlsInfo when secureConnect event is emitted
// The keylog event listener is a workaround to access the tlsSocket
options.httpsAgent.once("keylog", async (line, tlsSocket) => {
tlsSocket.once("secureConnect", async () => {
tlsInfo = checkCertificate(tlsSocket);
tlsInfo.valid = tlsSocket.authorized || false;
await this.handleTlsInfo(tlsInfo);
});
});
log.debug("monitor", `[${this.name}] Axios Options: ${JSON.stringify(options)}`); log.debug("monitor", `[${this.name}] Axios Options: ${JSON.stringify(options)}`);
log.debug("monitor", `[${this.name}] Axios Request`); log.debug("monitor", `[${this.name}] Axios Request`);
@ -547,31 +559,19 @@ class Monitor extends BeanModel {
bean.msg = `${res.status} - ${res.statusText}`; bean.msg = `${res.status} - ${res.statusText}`;
bean.ping = dayjs().valueOf() - startTime; bean.ping = dayjs().valueOf() - startTime;
// Check certificate if https is used // fallback for if kelog event is not emitted, but we may still have tlsInfo,
let certInfoStartTime = dayjs().valueOf(); // e.g. if the connection is made through a proxy
if (this.getUrl()?.protocol === "https:") { if (this.getUrl()?.protocol === "https:" && tlsInfo.valid === undefined) {
log.debug("monitor", `[${this.name}] Check cert`); const tlsSocket = res.request.res.socket;
try {
let tlsInfoObject = checkCertificate(res);
tlsInfo = await this.updateTlsInfo(tlsInfoObject);
if (!this.getIgnoreTls() && this.isEnabledExpiryNotification()) { if (tlsSocket) {
log.debug("monitor", `[${this.name}] call checkCertExpiryNotifications`); tlsInfo = checkCertificate(tlsSocket);
await this.checkCertExpiryNotifications(tlsInfoObject); tlsInfo.valid = tlsSocket.authorized || false;
}
} catch (e) { await this.handleTlsInfo(tlsInfo);
if (e.message !== "No TLS certificate in response") {
log.error("monitor", "Caught error");
log.error("monitor", e.message);
}
} }
} }
if (process.env.TIMELOGGER === "1") {
log.debug("monitor", "Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms");
}
if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID === this.id) { if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID === this.id) {
log.info("monitor", res.data); log.info("monitor", res.data);
} }
@ -604,8 +604,12 @@ class Monitor extends BeanModel {
let data = res.data; let data = res.data;
// convert data to object // convert data to object
if (typeof data === "string") { if (typeof data === "string" && res.headers["content-type"] !== "application/json") {
data = JSON.parse(data); try {
data = JSON.parse(data);
} catch (_) {
// Failed to parse as JSON, just process it as a string
}
} }
let expression = jsonata(this.jsonPath); let expression = jsonata(this.jsonPath);
@ -1620,6 +1624,20 @@ class Monitor extends BeanModel {
return oAuthAccessToken; return oAuthAccessToken;
} }
/**
* Store TLS certificate information and check for expiry
* @param {object} tlsInfo Information about the TLS connection
* @returns {Promise<void>}
*/
async handleTlsInfo(tlsInfo) {
await this.updateTlsInfo(tlsInfo);
this.prometheus?.update(null, tlsInfo);
if (!this.getIgnoreTls() && this.isEnabledExpiryNotification()) {
log.debug("monitor", `[${this.name}] call checkCertExpiryNotifications`);
await this.checkCertExpiryNotifications(tlsInfo);
}
}
} }
module.exports = Monitor; module.exports = Monitor;

@ -10,6 +10,10 @@ const jwt = require("jsonwebtoken");
const config = require("../config"); const config = require("../config");
const { RemoteBrowser } = require("../remote-browser"); const { RemoteBrowser } = require("../remote-browser");
/**
* Cached instance of a browser
* @type {import ("playwright-core").Browser}
*/
let browser = null; let browser = null;
let allowedList = []; let allowedList = [];
@ -71,10 +75,12 @@ async function isAllowedChromeExecutable(executablePath) {
/** /**
* Get the current instance of the browser. If there isn't one, create * Get the current instance of the browser. If there isn't one, create
* it. * it.
* @returns {Promise<Browser>} The browser * @returns {Promise<import ("playwright-core").Browser>} The browser
*/ */
async function getBrowser() { async function getBrowser() {
if (!browser) { if (browser && browser.isConnected()) {
return browser;
} else {
let executablePath = await Settings.get("chromeExecutable"); let executablePath = await Settings.get("chromeExecutable");
executablePath = await prepareChromeExecutable(executablePath); executablePath = await prepareChromeExecutable(executablePath);
@ -83,8 +89,9 @@ async function getBrowser() {
//headless: false, //headless: false,
executablePath, executablePath,
}); });
return browser;
} }
return browser;
} }
/** /**

@ -19,6 +19,9 @@ class DingDing extends NotificationProvider {
markdown: { markdown: {
title: `[${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]}`, title: `[${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]}`,
text: `## [${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]} \n> ${heartbeatJSON["msg"]}\n> Time (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`, text: `## [${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]} \n> ${heartbeatJSON["msg"]}\n> Time (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`,
},
"at": {
"isAtAll": notification.mentioning === "everyone"
} }
}; };
if (await this.sendToDingDing(notification, params)) { if (await this.sendToDingDing(notification, params)) {
@ -62,7 +65,7 @@ class DingDing extends NotificationProvider {
if (result.data.errmsg === "ok") { if (result.data.errmsg === "ok") {
return true; return true;
} }
return false; throw new Error(result.data.errmsg);
} }
/** /**

@ -0,0 +1,42 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Keep extends NotificationProvider {
name = "Keep";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
try {
let data = {
heartbeat: heartbeatJSON,
monitor: monitorJSON,
msg,
};
let config = {
headers: {
"x-api-key": notification.webhookAPIKey,
"content-type": "application/json",
},
};
let url = notification.webhookURL;
if (url.endsWith("/")) {
url = url.slice(0, -1);
}
let webhookURL = url + "/alerts/event/uptimekuma";
await axios.post(webhookURL, data, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = Keep;

@ -0,0 +1,78 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class SevenIO extends NotificationProvider {
name = "SevenIO";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
const data = {
to: notification.sevenioTo,
from: notification.sevenioSender || "Uptime Kuma",
text: msg,
};
const config = {
baseURL: "https://gateway.seven.io/api/",
headers: {
"Content-Type": "application/json",
"X-API-Key": notification.sevenioApiKey,
},
};
try {
// testing or certificate expiry notification
if (heartbeatJSON == null) {
await axios.post("sms", data, config);
return okMsg;
}
let address = "";
switch (monitorJSON["type"]) {
case "ping":
address = monitorJSON["hostname"];
break;
case "port":
case "dns":
case "gamedig":
case "steam":
address = monitorJSON["hostname"];
if (monitorJSON["port"]) {
address += ":" + monitorJSON["port"];
}
break;
default:
if (![ "https://", "http://", "" ].includes(monitorJSON["url"])) {
address = monitorJSON["url"];
}
break;
}
if (address !== "") {
address = `(${address}) `;
}
// If heartbeatJSON is not null, we go into the normal alerting loop.
if (heartbeatJSON["status"] === DOWN) {
data.text = `Your service ${monitorJSON["name"]} ${address}went down at ${heartbeatJSON["localDateTime"]} ` +
`(${heartbeatJSON["timezone"]}). Error: ${heartbeatJSON["msg"]}`;
} else if (heartbeatJSON["status"] === UP) {
data.text = `Your service ${monitorJSON["name"]} ${address}went back up at ${heartbeatJSON["localDateTime"]} ` +
`(${heartbeatJSON["timezone"]}).`;
}
await axios.post("sms", data, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = SevenIO;

@ -18,6 +18,7 @@ const Gotify = require("./notification-providers/gotify");
const GrafanaOncall = require("./notification-providers/grafana-oncall"); const GrafanaOncall = require("./notification-providers/grafana-oncall");
const HomeAssistant = require("./notification-providers/home-assistant"); const HomeAssistant = require("./notification-providers/home-assistant");
const HeiiOnCall = require("./notification-providers/heii-oncall"); const HeiiOnCall = require("./notification-providers/heii-oncall");
const Keep = require("./notification-providers/keep");
const Kook = require("./notification-providers/kook"); const Kook = require("./notification-providers/kook");
const Line = require("./notification-providers/line"); const Line = require("./notification-providers/line");
const LineNotify = require("./notification-providers/linenotify"); const LineNotify = require("./notification-providers/linenotify");
@ -56,6 +57,7 @@ const GoAlert = require("./notification-providers/goalert");
const SMSManager = require("./notification-providers/smsmanager"); const SMSManager = require("./notification-providers/smsmanager");
const ServerChan = require("./notification-providers/serverchan"); const ServerChan = require("./notification-providers/serverchan");
const ZohoCliq = require("./notification-providers/zoho-cliq"); const ZohoCliq = require("./notification-providers/zoho-cliq");
const SevenIO = require("./notification-providers/sevenio");
const Whapi = require("./notification-providers/whapi"); const Whapi = require("./notification-providers/whapi");
const GtxMessaging = require("./notification-providers/gtx-messaging"); const GtxMessaging = require("./notification-providers/gtx-messaging");
const Cellsynt = require("./notification-providers/cellsynt"); const Cellsynt = require("./notification-providers/cellsynt");
@ -94,6 +96,7 @@ class Notification {
new GrafanaOncall(), new GrafanaOncall(),
new HomeAssistant(), new HomeAssistant(),
new HeiiOnCall(), new HeiiOnCall(),
new Keep(),
new Kook(), new Kook(),
new Line(), new Line(),
new LineNotify(), new LineNotify(),
@ -132,6 +135,7 @@ class Notification {
new WeCom(), new WeCom(),
new GoAlert(), new GoAlert(),
new ZohoCliq(), new ZohoCliq(),
new SevenIO(),
new Whapi(), new Whapi(),
new GtxMessaging(), new GtxMessaging(),
new Cellsynt(), new Cellsynt(),

@ -80,23 +80,25 @@ class Prometheus {
} }
} }
try { if (heartbeat) {
monitorStatus.set(this.monitorLabelValues, heartbeat.status); try {
} catch (e) { monitorStatus.set(this.monitorLabelValues, heartbeat.status);
log.error("prometheus", "Caught error"); } catch (e) {
log.error("prometheus", e); log.error("prometheus", "Caught error");
} log.error("prometheus", e);
}
try { try {
if (typeof heartbeat.ping === "number") { if (typeof heartbeat.ping === "number") {
monitorResponseTime.set(this.monitorLabelValues, heartbeat.ping); monitorResponseTime.set(this.monitorLabelValues, heartbeat.ping);
} else { } else {
// Is it good? // Is it good?
monitorResponseTime.set(this.monitorLabelValues, -1); monitorResponseTime.set(this.monitorLabelValues, -1);
}
} catch (e) {
log.error("prometheus", "Caught error");
log.error("prometheus", e);
} }
} catch (e) {
log.error("prometheus", "Caught error");
log.error("prometheus", e);
} }
} }

@ -1324,6 +1324,12 @@ let needSetup = false;
await doubleCheckPassword(socket, currentPassword); await doubleCheckPassword(socket, currentPassword);
} }
// Log out all clients if enabling auth
// GHSA-23q2-5gf8-gjpp
if (currentDisabledAuth && !data.disableAuth) {
server.disconnectAllSocketClients(socket.userID, socket.id);
}
const previousChromeExecutable = await Settings.get("chromeExecutable"); const previousChromeExecutable = await Settings.get("chromeExecutable");
const previousNSCDStatus = await Settings.get("nscd"); const previousNSCDStatus = await Settings.get("nscd");

@ -653,21 +653,27 @@ const parseCertificateInfo = function (info) {
/** /**
* Check if certificate is valid * Check if certificate is valid
* @param {object} res Response object from axios * @param {tls.TLSSocket} socket TLSSocket, which may or may not be connected
* @returns {object} Object containing certificate information * @returns {object} Object containing certificate information
* @throws No socket was found to check certificate for
*/ */
exports.checkCertificate = function (res) { exports.checkCertificate = function (socket) {
if (!res.request.res.socket) { let certInfoStartTime = dayjs().valueOf();
throw new Error("No socket found");
// Return null if there is no socket
if (socket === undefined || socket == null) {
return null;
} }
const info = res.request.res.socket.getPeerCertificate(true); const info = socket.getPeerCertificate(true);
const valid = res.request.res.socket.authorized || false; const valid = socket.authorized || false;
log.debug("cert", "Parsing Certificate Info"); log.debug("cert", "Parsing Certificate Info");
const parsedInfo = parseCertificateInfo(info); const parsedInfo = parseCertificateInfo(info);
if (process.env.TIMELOGGER === "1") {
log.debug("monitor", "Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms");
}
return { return {
valid: valid, valid: valid,
certInfo: parsedInfo certInfo: parsedInfo

@ -123,6 +123,7 @@ export default {
"GrafanaOncall": "Grafana Oncall", "GrafanaOncall": "Grafana Oncall",
"HeiiOnCall": "Heii On-Call", "HeiiOnCall": "Heii On-Call",
"HomeAssistant": "Home Assistant", "HomeAssistant": "Home Assistant",
"Keep": "Keep",
"Kook": "Kook", "Kook": "Kook",
"line": "LINE Messenger", "line": "LINE Messenger",
"LineNotify": "LINE Notify", "LineNotify": "LINE Notify",
@ -154,6 +155,7 @@ export default {
"webhook": "Webhook", "webhook": "Webhook",
"GoAlert": "GoAlert", "GoAlert": "GoAlert",
"ZohoCliq": "ZohoCliq", "ZohoCliq": "ZohoCliq",
"SevenIO": "SevenIO",
"whapi": "WhatsApp (Whapi)", "whapi": "WhatsApp (Whapi)",
"gtxmessaging": "GtxMessaging", "gtxmessaging": "GtxMessaging",
"Cellsynt": "Cellsynt", "Cellsynt": "Cellsynt",

@ -2,9 +2,10 @@
<div class="mb-3"> <div class="mb-3">
<label for="WebHookUrl" class="form-label">{{ $t("WebHookUrl") }}<span style="color: red;"><sup>*</sup></span></label> <label for="WebHookUrl" class="form-label">{{ $t("WebHookUrl") }}<span style="color: red;"><sup>*</sup></span></label>
<input id="WebHookUrl" v-model="$parent.notification.webHookUrl" type="text" class="form-control" required> <input id="WebHookUrl" v-model="$parent.notification.webHookUrl" type="text" class="form-control" required>
</div>
<div class="mb-3">
<label for="secretKey" class="form-label">{{ $t("SecretKey") }}<span style="color: red;"><sup>*</sup></span></label> <label for="secretKey" class="form-label">{{ $t("SecretKey") }}<span style="color: red;"><sup>*</sup></span></label>
<input id="secretKey" v-model="$parent.notification.secretKey" type="text" class="form-control" required> <HiddenInput id="secretKey" v-model="$parent.notification.secretKey" :required="true" autocomplete="new-password"></HiddenInput>
<div class="form-text"> <div class="form-text">
<p>{{ $t("For safety, must use secret key") }}</p> <p>{{ $t("For safety, must use secret key") }}</p>
@ -13,4 +14,24 @@
</i18n-t> </i18n-t>
</div> </div>
</div> </div>
<div class="mb-3">
<label for="mentioning" class="form-label">{{ $t("Mentioning") }}<span style="color: red;"><sup>*</sup></span></label>
<select id="mentioning" v-model="$parent.notification.mentioning" class="form-select" required>
<option value="nobody">{{ $t("Don't mention people") }}</option>
<option value="everyone">{{ $t("Mention group", { group: "@everyone" }) }}</option>
</select>
</div>
</template> </template>
<script lang="ts">
import HiddenInput from "../HiddenInput.vue";
export default {
components: { HiddenInput },
mounted() {
if (typeof this.$parent.notification.mentioning === "undefined") {
this.$parent.notification.mentioning = "nobody";
}
}
};
</script>

@ -0,0 +1,42 @@
<template>
<div class="mb-3">
<label for="webhook-url" class="form-label">{{ $t("Host URL") }}</label>
<input
id="webhook-url"
v-model="$parent.notification.webhookURL"
type="url"
pattern="https?://.+"
class="form-control"
required
/>
<div class="form-text">
<i18n-t tag="p" keypath="Read more:">
<a href="https://docs.keephq.dev/providers/documentation/uptimekuma-provider" target="_blank">https://docs.keephq.dev/providers/documentation/uptimekuma-provider</a>
</i18n-t>
</div>
</div>
<div class="mb-3">
<label for="webhook-apikey" class="form-label">{{
$t("API Key")
}}</label>
<HiddenInput
id="webhook-apikey"
v-model="$parent.notification.webhookAPIKey"
:required="true"
></HiddenInput>
</div>
</template>
<script>
import HiddenInput from "../HiddenInput.vue";
export default {
components: {
HiddenInput,
},
mounted() {
this.$parent.notification.webhookURL ||= "";
},
};
</script>

@ -5,6 +5,14 @@
<input id="hostname" v-model="$parent.notification.smtpHost" type="text" class="form-control" required> <input id="hostname" v-model="$parent.notification.smtpHost" type="text" class="form-control" required>
</div> </div>
<i18n-t tag="div" keypath="Either enter the hostname of the server you want to connect to or localhost if you intend to use a locally configured mail transfer agent" class="form-text">
<template #localhost>
<code>localhost</code>
</template>
<template #local_mta>
<a href="https://wikipedia.org/wiki/Mail_Transfer_Agent" target="_blank">{{ $t("locally configured mail transfer agent") }}</a>
</template>
</i18n-t>
<div class="mb-3"> <div class="mb-3">
<label for="port" class="form-label">{{ $t("Port") }}</label> <label for="port" class="form-label">{{ $t("Port") }}</label>
<input id="port" v-model="$parent.notification.smtpPort" type="number" class="form-control" required min="0" max="65535" step="1"> <input id="port" v-model="$parent.notification.smtpPort" type="number" class="form-control" required min="0" max="65535" step="1">

@ -0,0 +1,31 @@
<template>
<div class="mb-3">
<label for="sevenio-api-key" class="form-label">{{ $t("apiKeySevenIO") }}</label>
<HiddenInput id="sevenio-api-key" v-model="$parent.notification.sevenioApiKey" :required="true" autocomplete="new-password"></HiddenInput>
<div class="form-text">
{{ $t("wayToGetSevenIOApiKey") }}
</div>
</div>
<div class="mb-3">
<label for="sevenio-sender" class="form-label">{{ $t("senderSevenIO") }}</label>
<input id="sevenio-sender" v-model="$parent.notification.sevenioSender" type="text" class="form-control" autocomplete="false" placeholder="Uptime Kuma">
</div>
<div class="mb-3">
<label for="sevenio-receiver" class="form-label">{{ $t("receiverSevenIO") }}</label>
<input id="sevenio-receiver" v-model="$parent.notification.sevenioReceiver" type="number" class="form-control" required autocomplete="false" placeholder="0123456789">
<div class="form-text">
{{ $t("receiverInfoSevenIO") }}
</div>
</div>
</template>
<script>
import HiddenInput from "../HiddenInput.vue";
export default {
components: {
HiddenInput,
},
};
</script>

@ -17,6 +17,7 @@ import GrafanaOncall from "./GrafanaOncall.vue";
import GtxMessaging from "./GtxMessaging.vue"; import GtxMessaging from "./GtxMessaging.vue";
import HomeAssistant from "./HomeAssistant.vue"; import HomeAssistant from "./HomeAssistant.vue";
import HeiiOnCall from "./HeiiOnCall.vue"; import HeiiOnCall from "./HeiiOnCall.vue";
import Keep from "./Keep.vue";
import Kook from "./Kook.vue"; import Kook from "./Kook.vue";
import Line from "./Line.vue"; import Line from "./Line.vue";
import LineNotify from "./LineNotify.vue"; import LineNotify from "./LineNotify.vue";
@ -55,6 +56,7 @@ import WeCom from "./WeCom.vue";
import GoAlert from "./GoAlert.vue"; import GoAlert from "./GoAlert.vue";
import ZohoCliq from "./ZohoCliq.vue"; import ZohoCliq from "./ZohoCliq.vue";
import Splunk from "./Splunk.vue"; import Splunk from "./Splunk.vue";
import SevenIO from "./SevenIO.vue";
import Whapi from "./Whapi.vue"; import Whapi from "./Whapi.vue";
import Cellsynt from "./Cellsynt.vue"; import Cellsynt from "./Cellsynt.vue";
@ -81,6 +83,7 @@ const NotificationFormList = {
"GrafanaOncall": GrafanaOncall, "GrafanaOncall": GrafanaOncall,
"HomeAssistant": HomeAssistant, "HomeAssistant": HomeAssistant,
"HeiiOnCall": HeiiOnCall, "HeiiOnCall": HeiiOnCall,
"Keep": Keep,
"Kook": Kook, "Kook": Kook,
"line": Line, "line": Line,
"LineNotify": LineNotify, "LineNotify": LineNotify,
@ -119,6 +122,7 @@ const NotificationFormList = {
"GoAlert": GoAlert, "GoAlert": GoAlert,
"ServerChan": ServerChan, "ServerChan": ServerChan,
"ZohoCliq": ZohoCliq, "ZohoCliq": ZohoCliq,
"SevenIO": SevenIO,
"whapi": Whapi, "whapi": Whapi,
"gtxmessaging": GtxMessaging, "gtxmessaging": GtxMessaging,
"Cellsynt": Cellsynt, "Cellsynt": Cellsynt,

@ -59,10 +59,29 @@ for (let lang in languageList) {
const rtlLangs = [ "he-IL", "fa", "ar-SY", "ur" ]; const rtlLangs = [ "he-IL", "fa", "ar-SY", "ur" ];
export const currentLocale = () => localStorage.locale /**
|| languageList[navigator.language] && navigator.language * Find the best matching locale to display
|| languageList[navigator.language.substring(0, 2)] && navigator.language.substring(0, 2) * If no locale can be matched, the default is "en"
|| "en"; * @returns {string} the locale that should be displayed
*/
export function currentLocale() {
for (const locale of [ localStorage.locale, navigator.language, ...navigator.languages ]) {
// localstorage might not have a value or there might not be a language in `navigator.language`
if (!locale) {
continue;
}
if (locale in messages) {
return locale;
}
// some locales are further specified such as "en-US".
// If we only have a generic locale for this, we can use it too
const genericLocale = locale.split("-")[0];
if (genericLocale in messages) {
return genericLocale;
}
}
return "en";
}
export const localeDirection = () => { export const localeDirection = () => {
return rtlLangs.includes(currentLocale()) ? "rtl" : "ltr"; return rtlLangs.includes(currentLocale()) ? "rtl" : "ltr";

@ -63,6 +63,9 @@
"Friendly Name": "Friendly Name", "Friendly Name": "Friendly Name",
"URL": "URL", "URL": "URL",
"Hostname": "Hostname", "Hostname": "Hostname",
"Host URL": "Host URL",
"locally configured mail transfer agent": "locally configured mail transfer agent",
"Either enter the hostname of the server you want to connect to or localhost if you intend to use a locally configured mail transfer agent": "Either enter the hostname of the server you want to connect to or {localhost} if you intend to use a {local_mta}",
"Port": "Port", "Port": "Port",
"Heartbeat Interval": "Heartbeat Interval", "Heartbeat Interval": "Heartbeat Interval",
"Request Timeout": "Request Timeout", "Request Timeout": "Request Timeout",
@ -665,6 +668,9 @@
"WebHookUrl": "WebHookUrl", "WebHookUrl": "WebHookUrl",
"SecretKey": "SecretKey", "SecretKey": "SecretKey",
"For safety, must use secret key": "For safety, must use secret key", "For safety, must use secret key": "For safety, must use secret key",
"Mentioning": "Mentioning",
"Don't mention people": "Don't mention people",
"Mention group": "Mention {group}",
"Device Token": "Device Token", "Device Token": "Device Token",
"Platform": "Platform", "Platform": "Platform",
"Huawei": "Huawei", "Huawei": "Huawei",
@ -885,6 +891,11 @@
"deleteRemoteBrowserMessage": "Are you sure want to delete this Remote Browser for all monitors?", "deleteRemoteBrowserMessage": "Are you sure want to delete this Remote Browser for all monitors?",
"GrafanaOncallUrl": "Grafana Oncall URL", "GrafanaOncallUrl": "Grafana Oncall URL",
"Browser Screenshot": "Browser Screenshot", "Browser Screenshot": "Browser Screenshot",
"wayToGetSevenIOApiKey": "Visit the dashboard under app.seven.io > developer > api key > the green add button",
"senderSevenIO": "Sending number or name",
"receiverSevenIO": "Receiving number",
"receiverInfoSevenIO": "If the receiving number is not located in Germany, you have to add the country code in front of the number (e.g. for the country code 1 from the US use 117612121212 instead of 017612121212)",
"apiKeySevenIO": "SevenIO API Key",
"wayToWriteWhapiRecipient": "The phone number with the international prefix, but without the plus sign at the start ({0}), the Contact ID ({1}) or the Group ID ({2}).", "wayToWriteWhapiRecipient": "The phone number with the international prefix, but without the plus sign at the start ({0}), the Contact ID ({1}) or the Group ID ({2}).",
"wayToGetWhapiUrlAndToken": "You can get the API URL and the token by going into your desired channel from {0}", "wayToGetWhapiUrlAndToken": "You can get the API URL and the token by going into your desired channel from {0}",
"whapiRecipient": "Phone Number / Contact ID / Group ID", "whapiRecipient": "Phone Number / Contact ID / Group ID",

Loading…
Cancel
Save