From cfb53c4a3f41f30ebcf53db4390df86847b9af55 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 11 Apr 2025 13:28:55 +0200 Subject: [PATCH 01/17] Update url for Matrix Login to match Matrix Spec v1.13 (#5729) Co-authored-by: Frank Elsinga --- src/components/notifications/Matrix.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/notifications/Matrix.vue b/src/components/notifications/Matrix.vue index a9fd63403..60d43cf17 100644 --- a/src/components/notifications/Matrix.vue +++ b/src/components/notifications/Matrix.vue @@ -18,7 +18,7 @@ {{ $t("matrixDesc1") }}

- curl -XPOST -d '{"type": "m.login.password", "identifier": {"user": "botusername", "type": "m.id.user"}, "password": "passwordforuser"}' "https://home.server/_matrix/client/r0/login". + curl -XPOST -d '{"type": "m.login.password", "identifier": {"user": "botusername", "type": "m.id.user"}, "password": "passwordforuser"}' "https://home.server/_matrix/client/v3/login". From bdf37c5a482b9fad1ef97589dd3d30a38fa6c965 Mon Sep 17 00:00:00 2001 From: lbriceno-tz <141683647+lbriceno-tz@users.noreply.github.com> Date: Sat, 12 Apr 2025 05:15:28 -0500 Subject: [PATCH 02/17] fix: flat txt records before conditions check (#5768) --- server/monitor-types/dns.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/monitor-types/dns.js b/server/monitor-types/dns.js index 8b87932fe..5a47e4591 100644 --- a/server/monitor-types/dns.js +++ b/server/monitor-types/dns.js @@ -34,12 +34,16 @@ class DnsMonitorType extends MonitorType { switch (monitor.dns_resolve_type) { case "A": case "AAAA": - case "TXT": case "PTR": dnsMessage = `Records: ${dnsRes.join(" | ")}`; conditionsResult = dnsRes.some(record => handleConditions({ record })); break; + case "TXT": + dnsMessage = `Records: ${dnsRes.join(" | ")}`; + conditionsResult = dnsRes.flat().some(record => handleConditions({ record })); + break; + case "CNAME": dnsMessage = dnsRes[0]; conditionsResult = handleConditions({ record: dnsRes[0] }); From f1baa02d7a339ca33c05e1ec4a44d766a69298be Mon Sep 17 00:00:00 2001 From: Mohit Nagaraj Date: Sat, 12 Apr 2025 15:56:17 +0530 Subject: [PATCH 03/17] fix: remove modal when navigating back (#5165) Co-authored-by: deepsource-io[bot] <42547082+deepsource-io[bot]@users.noreply.github.com> Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com> Co-authored-by: Frank Elsinga --- src/components/CreateGroupDialog.vue | 16 ++++++++++++++++ src/components/NotificationDialog.vue | 17 +++++++++++++++++ src/components/ProxyDialog.vue | 19 +++++++++++++++++-- src/components/TagsManager.vue | 16 ++++++++++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/components/CreateGroupDialog.vue b/src/components/CreateGroupDialog.vue index ba7fe6eb7..8bac1ccd0 100644 --- a/src/components/CreateGroupDialog.vue +++ b/src/components/CreateGroupDialog.vue @@ -42,6 +42,9 @@ export default { mounted() { this.modal = new Modal(this.$refs.modal); }, + beforeUnmount() { + this.cleanupModal(); + }, methods: { /** * Show the confirm dialog @@ -58,6 +61,19 @@ export default { this.$emit("added", this.groupName); this.modal.hide(); }, + /** + * Clean up modal and restore scroll behavior + * @returns {void} + */ + cleanupModal() { + if (this.modal) { + try { + this.modal.hide(); + } catch (e) { + console.warn("Modal hide failed:", e); + } + } + } }, }; diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue index bed841fa5..56cae66c8 100644 --- a/src/components/NotificationDialog.vue +++ b/src/components/NotificationDialog.vue @@ -235,6 +235,9 @@ export default { mounted() { this.modal = new Modal(this.$refs.modal); }, + beforeUnmount() { + this.cleanupModal(); + }, methods: { /** @@ -339,6 +342,20 @@ export default { }); } while (this.$root.notificationList.find(it => it.name === name)); return name; + }, + + /** + * Clean up modal and restore scroll behavior + * @returns {void} + */ + cleanupModal() { + if (this.modal) { + try { + this.modal.hide(); + } catch (e) { + console.warn("Modal hide failed:", e); + } + } } }, }; diff --git a/src/components/ProxyDialog.vue b/src/components/ProxyDialog.vue index fc92359b9..2f7ed7b61 100644 --- a/src/components/ProxyDialog.vue +++ b/src/components/ProxyDialog.vue @@ -125,11 +125,12 @@ export default { } }; }, - mounted() { this.modal = new Modal(this.$refs.modal); }, - + beforeUnmount() { + this.cleanupModal(); + }, methods: { /** * Show dialog to confirm deletion @@ -209,6 +210,20 @@ export default { } }); }, + + /** + * Clean up modal and restore scroll behavior + * @returns {void} + */ + cleanupModal() { + if (this.modal) { + try { + this.modal.hide(); + } catch (e) { + console.warn("Modal hide failed:", e); + } + } + } }, }; diff --git a/src/components/TagsManager.vue b/src/components/TagsManager.vue index a8a96ccbb..aa8f93a83 100644 --- a/src/components/TagsManager.vue +++ b/src/components/TagsManager.vue @@ -248,6 +248,9 @@ export default { this.modal = new Modal(this.$refs.modal); this.getExistingTags(); }, + beforeUnmount() { + this.cleanupModal(); + }, methods: { /** * Show the add tag dialog @@ -459,6 +462,19 @@ export default { this.newTags = []; this.deleteTags = []; this.processing = false; + }, + /** + * Clean up modal and restore scroll behavior + * @returns {void} + */ + cleanupModal() { + if (this.modal) { + try { + this.modal.hide(); + } catch (e) { + console.warn("Modal hide failed:", e); + } + } } }, }; From 13a85b82005da06c82720d3b7459c3bb1bfe7bd4 Mon Sep 17 00:00:00 2001 From: II-EMC <61621465+II-EMC@users.noreply.github.com> Date: Sat, 12 Apr 2025 12:53:36 +0200 Subject: [PATCH 04/17] fix: Mattermost notification provider not sending service name (#5760) Co-authored-by: Frank Elsinga --- server/notification-providers/mattermost.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/notification-providers/mattermost.js b/server/notification-providers/mattermost.js index 9946d02b2..32d890981 100644 --- a/server/notification-providers/mattermost.js +++ b/server/notification-providers/mattermost.js @@ -79,11 +79,13 @@ class Mattermost extends NotificationProvider { fallback: "Your " + monitorJSON.pathName + + monitorJSON.name + " service went " + statusText, color: color, title: monitorJSON.pathName + + monitorJSON.name + " service went " + statusText, title_link: monitorJSON.url, From 510056fbbcfd5fea271dd412e139520b4c62ec3b Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Fri, 18 Apr 2025 07:35:09 +0800 Subject: [PATCH 05/17] Fix #5745: Some labels without value still show a 'null' value (#5771) --- src/components/Tag.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Tag.vue b/src/components/Tag.vue index 6c2ff8c9b..5b8b96fc2 100644 --- a/src/components/Tag.vue +++ b/src/components/Tag.vue @@ -48,7 +48,7 @@ export default { }, computed: { displayText() { - if (this.item.value === "" || this.item.value === undefined) { + if (this.item.value === "" || this.item.value === undefined || this.item.value === null) { return this.item.name; } else { return `${this.item.name}: ${this.item.value}`; From ceb9c7e742bd3fc2c8ba5114a71cac88762851b5 Mon Sep 17 00:00:00 2001 From: Alan Escarcha Date: Fri, 18 Apr 2025 20:09:10 -0300 Subject: [PATCH 06/17] feat: Support for country flags emojis (#5782) Co-authored-by: Frank Elsinga --- package-lock.json | 7 +++++++ package.json | 1 + src/App.vue | 2 ++ src/assets/app.scss | 2 +- src/components/settings/About.vue | 3 +++ src/lang/en.json | 3 ++- 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7ab51157b..c5269c088 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "command-exists": "~1.2.9", "compare-versions": "~3.6.0", "compression": "~1.7.4", + "country-flag-emoji-polyfill": "^0.1.8", "croner": "~8.1.0", "dayjs": "~1.11.5", "dev-null": "^0.1.1", @@ -7204,6 +7205,12 @@ } } }, + "node_modules/country-flag-emoji-polyfill": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/country-flag-emoji-polyfill/-/country-flag-emoji-polyfill-0.1.8.tgz", + "integrity": "sha512-Mbah52sADS3gshUYhK5142gtUuJpHYOXlXtLFI3Ly4RqgkmPMvhX9kMZSTqDM8P7UqtSW99eHKFphhQSGXA3Cg==", + "license": "MIT" + }, "node_modules/cpu-features": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz", diff --git a/package.json b/package.json index 4284d5b5e..4a5aefd0d 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "command-exists": "~1.2.9", "compare-versions": "~3.6.0", "compression": "~1.7.4", + "country-flag-emoji-polyfill": "^0.1.8", "croner": "~8.1.0", "dayjs": "~1.11.5", "dev-null": "^0.1.1", diff --git a/src/App.vue b/src/App.vue index f102360c1..a7bb69b42 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,9 +4,11 @@ diff --git a/src/assets/app.scss b/src/assets/app.scss index 6ddc99dec..fd43a7bee 100644 --- a/src/assets/app.scss +++ b/src/assets/app.scss @@ -3,7 +3,7 @@ @import "node_modules/bootstrap/scss/bootstrap"; #app { - font-family: BlinkMacSystemFont, segoe ui, Roboto, helvetica neue, Arial, noto sans, sans-serif, apple color emoji, segoe ui emoji, segoe ui symbol, noto color emoji; + font-family: "Twemoji Country Flags", BlinkMacSystemFont, segoe ui, Roboto, helvetica neue, Arial, noto sans, sans-serif, apple color emoji, segoe ui emoji, segoe ui symbol, noto color emoji; } h1 { diff --git a/src/components/settings/About.vue b/src/components/settings/About.vue index 3ef9e6d78..b8049d8bd 100644 --- a/src/components/settings/About.vue +++ b/src/components/settings/About.vue @@ -21,6 +21,9 @@ +
+

{{ $t("Font Twemoji by Twitter licensed under") }} CC-BY 4.0

+
diff --git a/src/lang/en.json b/src/lang/en.json index cb704b0fe..c32bebaae 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -1067,5 +1067,6 @@ "YZJ Robot Token": "YZJ Robot token", "Plain Text": "Plain Text", "Message Template": "Message Template", - "Template Format": "Template Format" + "Template Format": "Template Format", + "Font Twemoji by Twitter licensed under": "Font Twemoji by Twitter licensed under" } From 8d8e3e5a8e78030b8ffbe258dc872b8bea234390 Mon Sep 17 00:00:00 2001 From: Jonathan Starck <29304143+Psycho0verload@users.noreply.github.com> Date: Sat, 19 Apr 2025 01:34:16 +0200 Subject: [PATCH 07/17] fix(dashboard): prevent y-overlapping of tags by adding a gap #5773 (#5774) Co-authored-by: Frank Elsinga --- src/components/MonitorListItem.vue | 2 +- src/components/Tag.vue | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/MonitorListItem.vue b/src/components/MonitorListItem.vue index 74ba4835c..93c1deab4 100644 --- a/src/components/MonitorListItem.vue +++ b/src/components/MonitorListItem.vue @@ -22,7 +22,7 @@ {{ monitor.name }} -
+
diff --git a/src/components/Tag.vue b/src/components/Tag.vue index 5b8b96fc2..ceccce8a6 100644 --- a/src/components/Tag.vue +++ b/src/components/Tag.vue @@ -6,7 +6,6 @@ 'm-2': size == 'normal', 'px-2': size == 'sm', 'py-0': size == 'sm', - 'mx-1': size == 'sm', }" :style="{ backgroundColor: item.color, fontSize: size == 'sm' ? '0.7em' : '1em' }" > From 999132aca883d7f720a14b37ae61eac7a3999d53 Mon Sep 17 00:00:00 2001 From: happy-game Date: Tue, 22 Apr 2025 01:57:28 +0800 Subject: [PATCH 08/17] fix: Check password strength when resetting the password in CLI (#5788) --- extra/reset-password.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/extra/reset-password.js b/extra/reset-password.js index b87d90f16..e66173af1 100644 --- a/extra/reset-password.js +++ b/extra/reset-password.js @@ -3,6 +3,7 @@ console.log("== Uptime Kuma Reset Password Tool =="); const Database = require("../server/database"); const { R } = require("redbean-node"); const readline = require("readline"); +const { passwordStrength } = require("check-password-strength"); const { initJWTSecret } = require("../server/util-server"); const User = require("../server/model/user"); const { io } = require("socket.io-client"); @@ -42,8 +43,15 @@ const main = async () => { console.log("Using password from argument"); console.warn("\x1b[31m%s\x1b[0m", "Warning: the password might be stored, in plain text, in your shell's history"); password = confirmPassword = args["new-password"] + ""; + if (passwordStrength(password).value === "Too weak") { + throw new Error("Password is too weak, please use a stronger password."); + } } else { password = await question("New Password: "); + if (passwordStrength(password).value === "Too weak") { + console.log("Password is too weak, please try again."); + continue; + } confirmPassword = await question("Confirm New Password: "); } From 0876b1cbf5bc2beea8f28e7f93190a6f7e57f807 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Tue, 22 Apr 2025 13:14:12 +0200 Subject: [PATCH 09/17] chore:extracted the group monitor to a different monitoring type (#4395) --- server/model/monitor.js | 35 +------------------------ server/monitor-types/group.js | 49 +++++++++++++++++++++++++++++++++++ server/uptime-kuma-server.js | 2 ++ 3 files changed, 52 insertions(+), 34 deletions(-) create mode 100644 server/monitor-types/group.js diff --git a/server/model/monitor.js b/server/model/monitor.js index 5999d93e7..a07f2595a 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -380,39 +380,6 @@ class Monitor extends BeanModel { if (await Monitor.isUnderMaintenance(this.id)) { bean.msg = "Monitor under maintenance"; bean.status = MAINTENANCE; - } else if (this.type === "group") { - const children = await Monitor.getChildren(this.id); - - if (children.length > 0) { - bean.status = UP; - bean.msg = "All children up and running"; - for (const child of children) { - if (!child.active) { - // Ignore inactive childs - continue; - } - const lastBeat = await Monitor.getPreviousHeartbeat(child.id); - - // Only change state if the monitor is in worse conditions then the ones before - // lastBeat.status could be null - if (!lastBeat) { - bean.status = PENDING; - } else if (bean.status === UP && (lastBeat.status === PENDING || lastBeat.status === DOWN)) { - bean.status = lastBeat.status; - } else if (bean.status === PENDING && lastBeat.status === DOWN) { - bean.status = lastBeat.status; - } - } - - if (bean.status !== UP) { - bean.msg = "Child inaccessible"; - } - } else { - // Set status pending if group is empty - bean.status = PENDING; - bean.msg = "Group empty"; - } - } else if (this.type === "http" || this.type === "keyword" || this.type === "json-query") { // Do not do any queries/high loading things before the "bean.ping" let startTime = dayjs().valueOf(); @@ -1625,7 +1592,7 @@ class Monitor extends BeanModel { /** * Gets all Children of the monitor * @param {number} monitorID ID of monitor to get - * @returns {Promise>} Children + * @returns {Promise[]>} Children */ static async getChildren(monitorID) { return await R.getAll(` diff --git a/server/monitor-types/group.js b/server/monitor-types/group.js new file mode 100644 index 000000000..28d0443d4 --- /dev/null +++ b/server/monitor-types/group.js @@ -0,0 +1,49 @@ +const { UP, PENDING, DOWN } = require("../../src/util"); +const { MonitorType } = require("./monitor-type"); +const Monitor = require("../model/monitor"); + +class GroupMonitorType extends MonitorType { + name = "group"; + + /** + * @inheritdoc + */ + async check(monitor, heartbeat, _server) { + const children = await Monitor.getChildren(monitor.id); + + if (children.length > 0) { + heartbeat.status = UP; + heartbeat.msg = "All children up and running"; + for (const child of children) { + if (!child.active) { + // Ignore inactive childs + continue; + } + const lastBeat = await Monitor.getPreviousHeartbeat(child.id); + + // Only change state if the monitor is in worse conditions then the ones before + // lastBeat.status could be null + if (!lastBeat) { + heartbeat.status = PENDING; + } else if (heartbeat.status === UP && (lastBeat.status === PENDING || lastBeat.status === DOWN)) { + heartbeat.status = lastBeat.status; + } else if (heartbeat.status === PENDING && lastBeat.status === DOWN) { + heartbeat.status = lastBeat.status; + } + } + + if (heartbeat.status !== UP) { + heartbeat.msg = "Child inaccessible"; + } + } else { + // Set status pending if group is empty + heartbeat.status = PENDING; + heartbeat.msg = "Group empty"; + } + } +} + +module.exports = { + GroupMonitorType, +}; + diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 062f098d7..cdaa83dfc 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -113,6 +113,7 @@ class UptimeKumaServer { UptimeKumaServer.monitorTypeList["tailscale-ping"] = new TailscalePing(); UptimeKumaServer.monitorTypeList["dns"] = new DnsMonitorType(); UptimeKumaServer.monitorTypeList["mqtt"] = new MqttMonitorType(); + UptimeKumaServer.monitorTypeList["group"] = new GroupMonitorType(); UptimeKumaServer.monitorTypeList["snmp"] = new SNMPMonitorType(); UptimeKumaServer.monitorTypeList["mongodb"] = new MongodbMonitorType(); UptimeKumaServer.monitorTypeList["rabbitmq"] = new RabbitMqMonitorType(); @@ -551,6 +552,7 @@ const { RealBrowserMonitorType } = require("./monitor-types/real-browser-monitor const { TailscalePing } = require("./monitor-types/tailscale-ping"); const { DnsMonitorType } = require("./monitor-types/dns"); const { MqttMonitorType } = require("./monitor-types/mqtt"); +const { GroupMonitorType } = require("./monitor-types/group"); const { SNMPMonitorType } = require("./monitor-types/snmp"); const { MongodbMonitorType } = require("./monitor-types/mongodb"); const { RabbitMqMonitorType } = require("./monitor-types/rabbitmq"); From 3b58ac3fd3712df192741b6b7bfd759d4624fd2c Mon Sep 17 00:00:00 2001 From: Ryo Hanafusa Date: Fri, 25 Apr 2025 20:47:18 +0900 Subject: [PATCH 10/17] feat: Extend the length of status bar and feed sufficient data (#5241) Co-authored-by: Frank Elsinga --- server/routers/status-page-router.js | 2 +- src/components/MonitorListItem.vue | 4 ++-- src/components/PublicGroupList.vue | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server/routers/status-page-router.js b/server/routers/status-page-router.js index 893f57564..6e57451f1 100644 --- a/server/routers/status-page-router.js +++ b/server/routers/status-page-router.js @@ -89,7 +89,7 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques SELECT * FROM heartbeat WHERE monitor_id = ? ORDER BY time DESC - LIMIT 50 + LIMIT 100 `, [ monitorID, ]); diff --git a/src/components/MonitorListItem.vue b/src/components/MonitorListItem.vue index 93c1deab4..ce38086b9 100644 --- a/src/components/MonitorListItem.vue +++ b/src/components/MonitorListItem.vue @@ -14,7 +14,7 @@
-
+
@@ -26,7 +26,7 @@
-
+
diff --git a/src/components/PublicGroupList.vue b/src/components/PublicGroupList.vue index bacddbf13..38aca2957 100644 --- a/src/components/PublicGroupList.vue +++ b/src/components/PublicGroupList.vue @@ -33,7 +33,7 @@