From b0259b559249c979698b9f59891399920bf81070 Mon Sep 17 00:00:00 2001 From: c0derMo <jaydeveloper@outlook.de> Date: Thu, 13 Jan 2022 16:17:07 +0000 Subject: [PATCH 01/99] Added docker container monitor --- db/patch-add-docker-columns.sql | 10 ++++++++++ server/database.js | 1 + server/model/monitor.js | 23 +++++++++++++++++++++++ src/pages/EditMonitor.vue | 19 +++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 db/patch-add-docker-columns.sql diff --git a/db/patch-add-docker-columns.sql b/db/patch-add-docker-columns.sql new file mode 100644 index 00000000..fdde4170 --- /dev/null +++ b/db/patch-add-docker-columns.sql @@ -0,0 +1,10 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD docker_daemon VARCHAR(255); + +ALTER TABLE monitor + ADD docker_container VARCHAR(255); + +COMMIT; diff --git a/server/database.js b/server/database.js index afcace70..536acd19 100644 --- a/server/database.js +++ b/server/database.js @@ -53,6 +53,7 @@ class Database { "patch-2fa-invalidate-used-token.sql": true, "patch-notification_sent_history.sql": true, "patch-monitor-basic-auth.sql": true, + "patch-add-docker-columns.sql": true } /** diff --git a/server/model/monitor.js b/server/model/monitor.js index c4441d63..5683352f 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -77,6 +77,8 @@ class Monitor extends BeanModel { dns_resolve_server: this.dns_resolve_server, dns_last_result: this.dns_last_result, pushToken: this.pushToken, + docker_container: this.docker_container, + docker_daemon: this.docker_daemon, notificationIDList, tags: tags, }; @@ -347,6 +349,27 @@ class Monitor extends BeanModel { throw new Error("Server not found on Steam"); } + } else if (this.type === "docker") { + debug(`[${this.name}] Prepare Options for axios`); + + const options = { + url: `/containers/${this.docker_container}/json`, + headers: { + "Accept": "*/*", + "User-Agent": "Uptime-Kuma/" + version, + }, + socketPath: this.docker_daemon, + httpsAgent: new https.Agent({ + maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940) + rejectUnauthorized: ! this.getIgnoreTls(), + }), + }; + + debug(`[${this.name}] Axios Request`); + let res = await axios.request(options); + if (res.data.State.Running) { + bean.status = UP; + } } else { bean.msg = "Unknown Monitor Type"; bean.status = PENDING; diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 4b6a920c..8b02a75f 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -32,6 +32,9 @@ <option value="steam"> Steam Game Server </option> + <option value="docker"> + Docker Container + </option> </select> </div> @@ -115,6 +118,20 @@ </div> </template> + <!-- Docker Container Name / ID --> + <!-- For Docker Type --> + <div v-if="monitor.type === 'docker'" class="my-3"> + <label for="docker_container" class="form-label">{{ $t("Container Name / ID") }}</label> + <input id="docker_container" v-model="monitor.docker_container" type="text" class="form-control" required> + </div> + + <!-- Docker Daemon --> + <!-- For Docker Type --> + <div v-if="monitor.type === 'docker'" class="my-3"> + <label for="docker_daemon" class="form-label">{{ $t("Docker Daemon") }}</label> + <input id="docker_daemon" v-model="monitor.docker_daemon" type="text" class="form-control" required> + </div> + <!-- Interval --> <div class="my-3"> <label for="interval" class="form-label">{{ $t("Heartbeat Interval") }} ({{ $t("checkEverySecond", [ monitor.interval ]) }})</label> @@ -439,6 +456,8 @@ export default { accepted_statuscodes: ["200-299"], dns_resolve_type: "A", dns_resolve_server: "1.1.1.1", + docker_container: "", + docker_daemon: "/var/run/docker.sock" }; for (let i = 0; i < this.$root.notificationList.length; i++) { From c5cc42272f0a72dbbf7c971173ad54fe6a524bf5 Mon Sep 17 00:00:00 2001 From: c0derMo <jaydeveloper@outlook.de> Date: Thu, 13 Jan 2022 18:28:45 +0000 Subject: [PATCH 02/99] Fixing the editing of docker container & adding english translation --- server/model/monitor.js | 1 + server/server.js | 2 ++ src/languages/en.js | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 5683352f..5e32a89d 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -369,6 +369,7 @@ class Monitor extends BeanModel { let res = await axios.request(options); if (res.data.State.Running) { bean.status = UP; + bean.msg = ""; } } else { bean.msg = "Unknown Monitor Type"; diff --git a/server/server.js b/server/server.js index 868bbd5e..7495cfb8 100644 --- a/server/server.js +++ b/server/server.js @@ -588,6 +588,8 @@ exports.entryPage = "dashboard"; bean.dns_resolve_type = monitor.dns_resolve_type; bean.dns_resolve_server = monitor.dns_resolve_server; bean.pushToken = monitor.pushToken; + bean.docker_container = monitor.docker_container; + bean.docker_daemon = monitor.docker_daemon; await R.store(bean); diff --git a/src/languages/en.js b/src/languages/en.js index 47513466..1d56e139 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -351,7 +351,7 @@ export default { serwersmsAPIPassword: "API Password", serwersmsPhoneNumber: "Phone number", serwersmsSenderName: "SMS Sender Name (registered via customer portal)", - "stackfield": "Stackfield", + stackfield: "Stackfield", smtpDkimSettings: "DKIM Settings", smtpDkimDesc: "Please refer to the Nodemailer DKIM {0} for usage.", documentation: "documentation", @@ -361,4 +361,6 @@ export default { smtpDkimHashAlgo: "Hash Algorithm (Optional)", smtpDkimheaderFieldNames: "Header Keys to sign (Optional)", smtpDkimskipFields: "Header Keys not to sign (Optional)", + "Container Name / ID": "Container Name / ID", + "Docker Daemon": "Docker Daemon", }; From 9619d31a05752d878de80d84679d0fec7fa2e117 Mon Sep 17 00:00:00 2001 From: c0derMo <jaydeveloper@outlook.de> Date: Thu, 13 Jan 2022 18:33:01 +0000 Subject: [PATCH 03/99] Adding docker container ability to readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f88db5f..f2434b2d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ VPS is sponsored by Uptime Kuma sponsors on [Open Collective](https://opencollec ## ⭐ Features -* Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / Ping / DNS Record / Push / Steam Game Server. +* Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / Ping / DNS Record / Push / Steam Game Server / Docker Containers. * Fancy, Reactive, Fast UI/UX. * Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [70+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications). * 20 second intervals. From 4818bb67d60075b67435922bc3d00236e0bc23ac Mon Sep 17 00:00:00 2001 From: c0derMo <jaydeveloper@outlook.de> Date: Fri, 14 Jan 2022 09:09:37 +0000 Subject: [PATCH 04/99] Added trailing comma, fixed spelling & translation --- server/database.js | 2 +- server/model/monitor.js | 2 +- src/languages/en.js | 1 + src/pages/EditMonitor.vue | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/server/database.js b/server/database.js index 536acd19..69551bac 100644 --- a/server/database.js +++ b/server/database.js @@ -53,7 +53,7 @@ class Database { "patch-2fa-invalidate-used-token.sql": true, "patch-notification_sent_history.sql": true, "patch-monitor-basic-auth.sql": true, - "patch-add-docker-columns.sql": true + "patch-add-docker-columns.sql": true, } /** diff --git a/server/model/monitor.js b/server/model/monitor.js index 5e32a89d..b75500ec 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -350,7 +350,7 @@ class Monitor extends BeanModel { } } else if (this.type === "docker") { - debug(`[${this.name}] Prepare Options for axios`); + debug(`[${this.name}] Prepare Options for Axios`); const options = { url: `/containers/${this.docker_container}/json`, diff --git a/src/languages/en.js b/src/languages/en.js index 1d56e139..ae9fa526 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -363,4 +363,5 @@ export default { smtpDkimskipFields: "Header Keys not to sign (Optional)", "Container Name / ID": "Container Name / ID", "Docker Daemon": "Docker Daemon", + "Docker Container": "Docker Container", }; diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 8b02a75f..86c35ef0 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -33,7 +33,7 @@ Steam Game Server </option> <option value="docker"> - Docker Container + {{ $t("Docker Container") }} </option> </select> </div> @@ -457,7 +457,7 @@ export default { dns_resolve_type: "A", dns_resolve_server: "1.1.1.1", docker_container: "", - docker_daemon: "/var/run/docker.sock" + docker_daemon: "/var/run/docker.sock", }; for (let i = 0; i < this.$root.notificationList.length; i++) { From 29df70949d453dc4675eda05d7f107669e1fb3e1 Mon Sep 17 00:00:00 2001 From: c0derMo <jaydeveloper@outlook.de> Date: Sat, 22 Jan 2022 01:57:37 +0000 Subject: [PATCH 05/99] Add ability to connect to daemon via http / tcp for windows compatibility --- db/patch-add-docker-columns.sql | 3 +++ server/model/monitor.js | 8 +++++++- server/server.js | 1 + src/languages/en.js | 3 +++ src/pages/EditMonitor.vue | 15 +++++++++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/db/patch-add-docker-columns.sql b/db/patch-add-docker-columns.sql index fdde4170..56475667 100644 --- a/db/patch-add-docker-columns.sql +++ b/db/patch-add-docker-columns.sql @@ -7,4 +7,7 @@ ALTER TABLE monitor ALTER TABLE monitor ADD docker_container VARCHAR(255); +ALTER TABLE monitor + ADD docker_type VARCHAR(255); + COMMIT; diff --git a/server/model/monitor.js b/server/model/monitor.js index b75500ec..d8a4be23 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -79,6 +79,7 @@ class Monitor extends BeanModel { pushToken: this.pushToken, docker_container: this.docker_container, docker_daemon: this.docker_daemon, + docker_type: this.docker_type, notificationIDList, tags: tags, }; @@ -358,13 +359,18 @@ class Monitor extends BeanModel { "Accept": "*/*", "User-Agent": "Uptime-Kuma/" + version, }, - socketPath: this.docker_daemon, httpsAgent: new https.Agent({ maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940) rejectUnauthorized: ! this.getIgnoreTls(), }), }; + if (this.docker_type === "socket") { + options.socketPath = this.docker_daemon; + } else if (this.docker_type === "tcp") { + options.baseURL = this.docker_daemon; + } + debug(`[${this.name}] Axios Request`); let res = await axios.request(options); if (res.data.State.Running) { diff --git a/server/server.js b/server/server.js index 7495cfb8..ac68769d 100644 --- a/server/server.js +++ b/server/server.js @@ -590,6 +590,7 @@ exports.entryPage = "dashboard"; bean.pushToken = monitor.pushToken; bean.docker_container = monitor.docker_container; bean.docker_daemon = monitor.docker_daemon; + bean.docker_type = monitor.docker_type; await R.store(bean); diff --git a/src/languages/en.js b/src/languages/en.js index ae9fa526..ade50373 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -364,4 +364,7 @@ export default { "Container Name / ID": "Container Name / ID", "Docker Daemon": "Docker Daemon", "Docker Container": "Docker Container", + "Docker Type": "Connection Type", + docker_socket: "Socket", + docker_tcp: "TCP / HTTP", }; diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 86c35ef0..b80b9a26 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -125,6 +125,20 @@ <input id="docker_container" v-model="monitor.docker_container" type="text" class="form-control" required> </div> + <!-- Docker Connection Type --> + <!-- For Docker Type --> + <div v-if="monitor.type === 'docker'" class="my-3"> + <label for="docker_type" class="form-label">{{ $t("Docker Type") }}</label> + <select id="docker_type" v-model="monitor.docker_type" class="form-select"> + <option value="socket"> + {{ $t("docker_socket") }} + </option> + <option value="tcp"> + {{ $t("docker_tcp") }} + </option> + </select> + </div> + <!-- Docker Daemon --> <!-- For Docker Type --> <div v-if="monitor.type === 'docker'" class="my-3"> @@ -458,6 +472,7 @@ export default { dns_resolve_server: "1.1.1.1", docker_container: "", docker_daemon: "/var/run/docker.sock", + docker_type: "socket", }; for (let i = 0; i < this.$root.notificationList.length; i++) { From 1ac904d6d6260a34d08a29249fb7cc15236ee787 Mon Sep 17 00:00:00 2001 From: OidaTiftla <chm.stephan@outlook.com> Date: Sun, 23 Jan 2022 15:22:57 +0100 Subject: [PATCH 06/99] Introduce resend interval if down --- package-lock.json | 4 ++-- package.json | 8 ++++---- server/model/monitor.js | 17 +++++++++++++++++ server/server.js | 7 +++++++ src/pages/EditMonitor.vue | 8 ++++++++ 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index fc21a63f..5253c3af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "uptime-kuma", - "version": "1.11.3", + "version": "1.11.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "uptime-kuma", - "version": "1.11.3", + "version": "1.11.4", "license": "MIT", "dependencies": { "@fortawesome/fontawesome-svg-core": "~1.2.36", diff --git a/package.json b/package.json index 048a5e0a..cd522a31 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uptime-kuma", - "version": "1.11.3", + "version": "1.11.4", "license": "MIT", "repository": { "type": "git", @@ -30,13 +30,13 @@ "build-docker": "npm run build && npm run build-docker-debian && npm run build-docker-alpine", "build-docker-alpine-base": "docker buildx build -f docker/alpine-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-alpine . --push", "build-docker-debian-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-debian . --push", - "build-docker-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:alpine -t louislam/uptime-kuma:1-alpine -t louislam/uptime-kuma:1.11.3-alpine --target release . --push", - "build-docker-debian": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.11.3 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.11.3-debian --target release . --push", + "build-docker-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:alpine -t louislam/uptime-kuma:1-alpine -t louislam/uptime-kuma:1.11.4-alpine --target release . --push", + "build-docker-debian": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.11.4 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.11.4-debian --target release . --push", "build-docker-nightly": "npm run build && docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push", "build-docker-nightly-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly-alpine --target nightly . --push", "build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --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.11.3 && npm ci --production && npm run download-dist", + "setup": "git checkout 1.11.4 && npm ci --production && npm run download-dist", "download-dist": "node extra/download-dist.js", "update-version": "node extra/update-version.js", "mark-as-nightly": "node extra/mark-as-nightly.js", diff --git a/server/model/monitor.js b/server/model/monitor.js index c4441d63..eaba61ad 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -68,6 +68,7 @@ class Monitor extends BeanModel { type: this.type, interval: this.interval, retryInterval: this.retryInterval, + resendInterval: this.resendInterval, keyword: this.keyword, ignoreTls: this.getIgnoreTls(), upsideDown: this.isUpsideDown(), @@ -135,6 +136,7 @@ class Monitor extends BeanModel { bean.monitor_id = this.id; bean.time = R.isoDateTime(dayjs.utc()); bean.status = DOWN; + bean.lastNotifiedTime = previousBeat?.lastNotifiedTime || null; // after first update lastNotifiedTime will be undefined if (this.isUpsideDown()) { bean.status = flipStatus(bean.status); @@ -390,12 +392,27 @@ class Monitor extends BeanModel { debug(`[${this.name}] sendNotification`); await Monitor.sendNotification(isFirstBeat, this, bean); + // Set last notified time to now + bean.lastNotifiedTime = dayjs().valueOf(); + // Clear Status Page Cache debug(`[${this.name}] apicache clear`); apicache.clear(); } else { bean.important = false; + + if (bean.status === DOWN && this.resendInterval > 0) { + timeSinceLastNotified = dayjs().valueOf() - (bean.lastNotifiedTime || 0); + if (timeSinceLastNotified >= this.resendInterval) { + // Send notification again, because we are still DOWN + debug(`[${this.name}] sendNotification`); + await Monitor.sendNotification(isFirstBeat, this, bean); + + // Set last notified time to now + bean.lastNotifiedTime = dayjs().valueOf(); + } + } } if (bean.status === UP) { diff --git a/server/server.js b/server/server.js index 153cac4f..5a9cf944 100644 --- a/server/server.js +++ b/server/server.js @@ -588,6 +588,7 @@ exports.entryPage = "dashboard"; bean.basic_auth_pass = monitor.basic_auth_pass; bean.interval = monitor.interval; bean.retryInterval = monitor.retryInterval; + bean.resendInterval = monitor.resendInterval; bean.hostname = monitor.hostname; bean.maxretries = monitor.maxretries; bean.port = monitor.port; @@ -1082,6 +1083,7 @@ exports.entryPage = "dashboard"; let monitorListData = backupData.monitorList; let version17x = compareVersions.compare(backupData.version, "1.7.0", ">="); + let version1114 = compareVersions.compare(backupData.version, "1.11.4", ">="); // If the import option is "overwrite" it'll clear most of the tables, except "settings" and "user" if (importHandle == "overwrite") { @@ -1131,6 +1133,7 @@ exports.entryPage = "dashboard"; // Define default values let retryInterval = 0; + let resendInterval = 0; /* Only replace the default value with the backup file data for the specific version, where it appears the first time @@ -1139,6 +1142,9 @@ exports.entryPage = "dashboard"; if (version17x) { retryInterval = monitorListData[i].retryInterval; } + if (version1114) { + resendInterval = monitorListData[i].resendInterval; + } // --- End --- @@ -1154,6 +1160,7 @@ exports.entryPage = "dashboard"; basic_auth_pass: monitorListData[i].basic_auth_pass, interval: monitorListData[i].interval, retryInterval: retryInterval, + resendInterval: resendInterval, hostname: monitorListData[i].hostname, maxretries: monitorListData[i].maxretries, port: monitorListData[i].port, diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 4b6a920c..b95c1098 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -137,6 +137,14 @@ <input id="retry-interval" v-model="monitor.retryInterval" type="number" class="form-control" required min="20" step="1"> </div> + <div class="my-3"> + <label for="resend-interval" class="form-label"> + {{ $t("Notification resend Interval if Down") }} + <span>({{ $t("resendEverySecond", [ monitor.resendInterval ]) }})</span> + </label> + <input id="resend-interval" v-model="monitor.resendInterval" type="number" class="form-control" required min="20" step="1"> + </div> + <h2 v-if="monitor.type !== 'push'" class="mt-5 mb-2">{{ $t("Advanced") }}</h2> <div v-if="monitor.type === 'http' || monitor.type === 'keyword' " class="my-3 form-check"> From b69a8b8493e095842bcf7daceaea21110106146a Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Sun, 23 Jan 2022 17:35:53 +0100 Subject: [PATCH 07/99] Fix formatting Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com> --- server/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/server.js b/server/server.js index 5a9cf944..0ad361ad 100644 --- a/server/server.js +++ b/server/server.js @@ -1142,6 +1142,7 @@ exports.entryPage = "dashboard"; if (version17x) { retryInterval = monitorListData[i].retryInterval; } + if (version1114) { resendInterval = monitorListData[i].resendInterval; } From 65fc71e4858ae61b7e1fb639ca335b8ad4f22ca4 Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Sun, 23 Jan 2022 17:34:39 +0100 Subject: [PATCH 08/99] Revert version change --- package-lock.json | 4 ++-- package.json | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5253c3af..fc21a63f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "uptime-kuma", - "version": "1.11.4", + "version": "1.11.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "uptime-kuma", - "version": "1.11.4", + "version": "1.11.3", "license": "MIT", "dependencies": { "@fortawesome/fontawesome-svg-core": "~1.2.36", diff --git a/package.json b/package.json index cd522a31..048a5e0a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uptime-kuma", - "version": "1.11.4", + "version": "1.11.3", "license": "MIT", "repository": { "type": "git", @@ -30,13 +30,13 @@ "build-docker": "npm run build && npm run build-docker-debian && npm run build-docker-alpine", "build-docker-alpine-base": "docker buildx build -f docker/alpine-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-alpine . --push", "build-docker-debian-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-debian . --push", - "build-docker-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:alpine -t louislam/uptime-kuma:1-alpine -t louislam/uptime-kuma:1.11.4-alpine --target release . --push", - "build-docker-debian": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.11.4 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.11.4-debian --target release . --push", + "build-docker-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:alpine -t louislam/uptime-kuma:1-alpine -t louislam/uptime-kuma:1.11.3-alpine --target release . --push", + "build-docker-debian": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.11.3 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.11.3-debian --target release . --push", "build-docker-nightly": "npm run build && docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push", "build-docker-nightly-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly-alpine --target nightly . --push", "build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --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.11.4 && npm ci --production && npm run download-dist", + "setup": "git checkout 1.11.3 && npm ci --production && npm run download-dist", "download-dist": "node extra/download-dist.js", "update-version": "node extra/update-version.js", "mark-as-nightly": "node extra/mark-as-nightly.js", From 11e9eee09d45996d476168d8c646962eb6104bd1 Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Sun, 23 Jan 2022 17:48:09 +0100 Subject: [PATCH 09/99] Change seconds to minutes --- server/model/monitor.js | 2 +- src/languages/en.js | 1 + src/pages/EditMonitor.vue | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index eaba61ad..f4803355 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -403,7 +403,7 @@ class Monitor extends BeanModel { bean.important = false; if (bean.status === DOWN && this.resendInterval > 0) { - timeSinceLastNotified = dayjs().valueOf() - (bean.lastNotifiedTime || 0); + timeSinceLastNotified = (dayjs().valueOf() - (bean.lastNotifiedTime || 0)) / 60; // divide by 60 to convert from seconds to minutes if (timeSinceLastNotified >= this.resendInterval) { // Send notification again, because we are still DOWN debug(`[${this.name}] sendNotification`); diff --git a/src/languages/en.js b/src/languages/en.js index 47513466..21e215f7 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -2,6 +2,7 @@ export default { languageName: "English", checkEverySecond: "Check every {0} seconds", retryCheckEverySecond: "Retry every {0} seconds", + resendEveryMinute: "Resend every {0} minutes if DOWN", retriesDescription: "Maximum retries before the service is marked as down and a notification is sent", ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites", upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.", diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index b95c1098..3b4cbcf1 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -140,7 +140,7 @@ <div class="my-3"> <label for="resend-interval" class="form-label"> {{ $t("Notification resend Interval if Down") }} - <span>({{ $t("resendEverySecond", [ monitor.resendInterval ]) }})</span> + <span>({{ $t("resendEveryMinute", [ monitor.resendInterval ]) }})</span> </label> <input id="resend-interval" v-model="monitor.resendInterval" type="number" class="form-control" required min="20" step="1"> </div> @@ -439,6 +439,7 @@ export default { method: "GET", interval: 60, retryInterval: this.interval, + resendInterval: 0, maxretries: 0, notificationIDList: {}, ignoreTls: false, From f931e709e638f0720309d1c59cbf17fe34b622a1 Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Mon, 24 Jan 2022 09:18:12 +0100 Subject: [PATCH 10/99] Add database patch --- db/patch-monitor-add-resend-interval.sql | 7 +++++++ server/database.js | 1 + 2 files changed, 8 insertions(+) create mode 100644 db/patch-monitor-add-resend-interval.sql diff --git a/db/patch-monitor-add-resend-interval.sql b/db/patch-monitor-add-resend-interval.sql new file mode 100644 index 00000000..e8bb08b8 --- /dev/null +++ b/db/patch-monitor-add-resend-interval.sql @@ -0,0 +1,7 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD resend_interval INTEGER default 0 not null; + +COMMIT; diff --git a/server/database.js b/server/database.js index afcace70..ce4d5089 100644 --- a/server/database.js +++ b/server/database.js @@ -53,6 +53,7 @@ class Database { "patch-2fa-invalidate-used-token.sql": true, "patch-notification_sent_history.sql": true, "patch-monitor-basic-auth.sql": true, + "patch-monitor-add-resend-interval.sql": true, } /** From 8c4ab9d652d931c44ffbc434c4d8599ee2aa5cd3 Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Mon, 24 Jan 2022 09:18:22 +0100 Subject: [PATCH 11/99] Simplify --- src/languages/en.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/en.js b/src/languages/en.js index 21e215f7..33ad0a42 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -2,7 +2,7 @@ export default { languageName: "English", checkEverySecond: "Check every {0} seconds", retryCheckEverySecond: "Retry every {0} seconds", - resendEveryMinute: "Resend every {0} minutes if DOWN", + resendEveryMinute: "Resend every {0} minutes", retriesDescription: "Maximum retries before the service is marked as down and a notification is sent", ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites", upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.", From 30ce53f57c3ada92b700c14cba6be822f687ee55 Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Mon, 24 Jan 2022 09:18:38 +0100 Subject: [PATCH 12/99] Fix min value of resend interval --- src/pages/EditMonitor.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 3b4cbcf1..a297c54b 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -142,7 +142,7 @@ {{ $t("Notification resend Interval if Down") }} <span>({{ $t("resendEveryMinute", [ monitor.resendInterval ]) }})</span> </label> - <input id="resend-interval" v-model="monitor.resendInterval" type="number" class="form-control" required min="20" step="1"> + <input id="resend-interval" v-model="monitor.resendInterval" type="number" class="form-control" required min="0" step="1"> </div> <h2 v-if="monitor.type !== 'push'" class="mt-5 mb-2">{{ $t("Advanced") }}</h2> From f390a8caf1fea00348a3245b4c79d4315c125f3a Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Mon, 24 Jan 2022 21:59:25 +0100 Subject: [PATCH 13/99] Fix missing DB patch and use DATETIME as column format --- db/patch-heartbeat-add-last-notified-time.sql | 7 +++++++ server/database.js | 1 + server/model/monitor.js | 10 +++++----- 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 db/patch-heartbeat-add-last-notified-time.sql diff --git a/db/patch-heartbeat-add-last-notified-time.sql b/db/patch-heartbeat-add-last-notified-time.sql new file mode 100644 index 00000000..af9c21c0 --- /dev/null +++ b/db/patch-heartbeat-add-last-notified-time.sql @@ -0,0 +1,7 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +ALTER TABLE heartbeat + ADD last_notified_time DATETIME default null; + +COMMIT; diff --git a/server/database.js b/server/database.js index ce4d5089..0aae8ffc 100644 --- a/server/database.js +++ b/server/database.js @@ -54,6 +54,7 @@ class Database { "patch-notification_sent_history.sql": true, "patch-monitor-basic-auth.sql": true, "patch-monitor-add-resend-interval.sql": true, + "patch-heartbeat-add-last-notified-time.sql": true, } /** diff --git a/server/model/monitor.js b/server/model/monitor.js index f4803355..85a0e944 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -136,7 +136,7 @@ class Monitor extends BeanModel { bean.monitor_id = this.id; bean.time = R.isoDateTime(dayjs.utc()); bean.status = DOWN; - bean.lastNotifiedTime = previousBeat?.lastNotifiedTime || null; // after first update lastNotifiedTime will be undefined + bean.lastNotifiedTime = previousBeat?.lastNotifiedTime; if (this.isUpsideDown()) { bean.status = flipStatus(bean.status); @@ -393,7 +393,7 @@ class Monitor extends BeanModel { await Monitor.sendNotification(isFirstBeat, this, bean); // Set last notified time to now - bean.lastNotifiedTime = dayjs().valueOf(); + bean.lastNotifiedTime = R.isoDateTime(dayjs.utc()); // Clear Status Page Cache debug(`[${this.name}] apicache clear`); @@ -403,14 +403,14 @@ class Monitor extends BeanModel { bean.important = false; if (bean.status === DOWN && this.resendInterval > 0) { - timeSinceLastNotified = (dayjs().valueOf() - (bean.lastNotifiedTime || 0)) / 60; // divide by 60 to convert from seconds to minutes + let timeSinceLastNotified = (dayjs.utc().valueOf() - (bean.lastNotifiedTime == null ? 0 : dayjs.utc(bean.lastNotifiedTime).valueOf())) / 1000 / 60; // divide by 1000 to convert from milliseconds to seconds and divide by 60 to convert from seconds to minutes if (timeSinceLastNotified >= this.resendInterval) { // Send notification again, because we are still DOWN - debug(`[${this.name}] sendNotification`); + debug(`[${this.name}] sendNotification again: lastNotifiedTime: ${bean.lastNotifiedTime} | current time: ${R.isoDateTime(dayjs.utc())}`); await Monitor.sendNotification(isFirstBeat, this, bean); // Set last notified time to now - bean.lastNotifiedTime = dayjs().valueOf(); + bean.lastNotifiedTime = R.isoDateTime(dayjs.utc()); } } } From 855b12f435ca87059c2797b8695418947fc9b73e Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Mon, 24 Jan 2022 22:20:38 +0100 Subject: [PATCH 14/99] Add text for resend disabled --- src/languages/en.js | 1 + src/pages/EditMonitor.vue | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/languages/en.js b/src/languages/en.js index 33ad0a42..17a58543 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -3,6 +3,7 @@ export default { checkEverySecond: "Check every {0} seconds", retryCheckEverySecond: "Retry every {0} seconds", resendEveryMinute: "Resend every {0} minutes", + resendDisabled: "Resend disabled", retriesDescription: "Maximum retries before the service is marked as down and a notification is sent", ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites", upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.", diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index a297c54b..a7bc4f78 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -140,7 +140,8 @@ <div class="my-3"> <label for="resend-interval" class="form-label"> {{ $t("Notification resend Interval if Down") }} - <span>({{ $t("resendEveryMinute", [ monitor.resendInterval ]) }})</span> + <span v-if="monitor.resendInterval > 0">({{ $t("resendEveryMinute", [ monitor.resendInterval ]) }})</span> + <span v-else>({{ $t("resendDisabled") }})</span> </label> <input id="resend-interval" v-model="monitor.resendInterval" type="number" class="form-control" required min="0" step="1"> </div> From d446a57d42613490c6bd5a6bec075b289ff3caef Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Mon, 24 Jan 2022 22:20:48 +0100 Subject: [PATCH 15/99] Add german translation --- src/languages/de-DE.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index 48cdd2e3..9286a09b 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -164,6 +164,8 @@ export default { "Search...": "Suchen...", "Heartbeat Retry Interval": "Heartbeat-Wiederholungsintervall", retryCheckEverySecond: "Versuche alle {0} Sekunden", + resendEveryMinute: "Erneut versenden alle {0} Minuten", + resendDisabled: "Erneut versenden deaktiviert", "Import Backup": "Backup importieren", "Export Backup": "Backup exportieren", "Avg. Ping": "Durchschn. Ping", From d8013f31e8906aeb0188725353392581621cd121 Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Sun, 27 Mar 2022 21:24:41 +0200 Subject: [PATCH 16/99] Update version after merging new master branch --- server/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/server.js b/server/server.js index e10df8cc..36b8590f 100644 --- a/server/server.js +++ b/server/server.js @@ -1087,7 +1087,7 @@ exports.entryPage = "dashboard"; let monitorListData = backupData.monitorList; let version17x = compareVersions.compare(backupData.version, "1.7.0", ">="); - let version1114 = compareVersions.compare(backupData.version, "1.11.4", ">="); + let version1132 = compareVersions.compare(backupData.version, "1.13.2", ">="); // If the import option is "overwrite" it'll clear most of the tables, except "settings" and "user" if (importHandle == "overwrite") { @@ -1147,7 +1147,7 @@ exports.entryPage = "dashboard"; retryInterval = monitorListData[i].retryInterval; } - if (version1114) { + if (version1132) { resendInterval = monitorListData[i].resendInterval; } From 84a0b24448fc06f791bf4555fb2db8cd384c815b Mon Sep 17 00:00:00 2001 From: Moritz R <c0derMo@users.noreply.github.com> Date: Sun, 3 Apr 2022 17:15:21 +0200 Subject: [PATCH 17/99] Update server/model/monitor.js As per recommendation of @Computroniks Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com> --- server/model/monitor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/model/monitor.js b/server/model/monitor.js index d8a4be23..c9b697d0 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -377,6 +377,7 @@ class Monitor extends BeanModel { bean.status = UP; bean.msg = ""; } + } else { bean.msg = "Unknown Monitor Type"; bean.status = PENDING; From 60f8ab7285fc0b3c1dfca5c8857807ba270e9956 Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Thu, 21 Apr 2022 12:09:59 +0200 Subject: [PATCH 18/99] Use new logging mechanism --- server/model/monitor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index a7e0b82f..0ac2e33e 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -473,7 +473,7 @@ class Monitor extends BeanModel { let timeSinceLastNotified = (dayjs.utc().valueOf() - (bean.lastNotifiedTime == null ? 0 : dayjs.utc(bean.lastNotifiedTime).valueOf())) / 1000 / 60; // divide by 1000 to convert from milliseconds to seconds and divide by 60 to convert from seconds to minutes if (timeSinceLastNotified >= this.resendInterval) { // Send notification again, because we are still DOWN - debug(`[${this.name}] sendNotification again: lastNotifiedTime: ${bean.lastNotifiedTime} | current time: ${R.isoDateTime(dayjs.utc())}`); + log.debug("monitor", `[${this.name}] sendNotification again: lastNotifiedTime: ${bean.lastNotifiedTime} | current time: ${R.isoDateTime(dayjs.utc())}`); await Monitor.sendNotification(isFirstBeat, this, bean); // Set last notified time to now From 19933bbd99d7e11dba97e61183051dc876b9581e Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Thu, 21 Apr 2022 12:18:15 +0200 Subject: [PATCH 19/99] Improve backwards compatibility --- server/server.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/server/server.js b/server/server.js index d53fe696..58c08f9d 100644 --- a/server/server.js +++ b/server/server.js @@ -1168,7 +1168,6 @@ try { let monitorListData = backupData.monitorList; let version17x = compareVersions.compare(backupData.version, "1.7.0", ">="); - let version1132 = compareVersions.compare(backupData.version, "1.13.2", ">="); // If the import option is "overwrite" it'll clear most of the tables, except "settings" and "user" if (importHandle == "overwrite") { @@ -1237,7 +1236,6 @@ try { // Define default values let retryInterval = 0; - let resendInterval = 0; /* Only replace the default value with the backup file data for the specific version, where it appears the first time @@ -1247,10 +1245,6 @@ try { retryInterval = monitorListData[i].retryInterval; } - if (version1132) { - resendInterval = monitorListData[i].resendInterval; - } - // --- End --- let monitor = { @@ -1265,7 +1259,7 @@ try { basic_auth_pass: monitorListData[i].basic_auth_pass, interval: monitorListData[i].interval, retryInterval: retryInterval, - resendInterval: resendInterval, + resendInterval: monitorListData[i].resendInterval || 0, hostname: monitorListData[i].hostname, maxretries: monitorListData[i].maxretries, port: monitorListData[i].port, From d6b591a513cb928c9173dab0b9042922a4b3df49 Mon Sep 17 00:00:00 2001 From: OidaTiftla <chm.stephan@outlook.com> Date: Thu, 21 Apr 2022 17:45:58 +0200 Subject: [PATCH 20/99] Make comment more readable Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com> --- server/model/monitor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 0ac2e33e..1383153e 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -470,7 +470,8 @@ class Monitor extends BeanModel { bean.important = false; if (bean.status === DOWN && this.resendInterval > 0) { - let timeSinceLastNotified = (dayjs.utc().valueOf() - (bean.lastNotifiedTime == null ? 0 : dayjs.utc(bean.lastNotifiedTime).valueOf())) / 1000 / 60; // divide by 1000 to convert from milliseconds to seconds and divide by 60 to convert from seconds to minutes + // divide by 1000 to convert from milliseconds to seconds and divide by 60 to convert from seconds to minutes + let timeSinceLastNotified = (dayjs.utc().valueOf() - (bean.lastNotifiedTime == null ? 0 : dayjs.utc(bean.lastNotifiedTime).valueOf())) / 1000 / 60; if (timeSinceLastNotified >= this.resendInterval) { // Send notification again, because we are still DOWN log.debug("monitor", `[${this.name}] sendNotification again: lastNotifiedTime: ${bean.lastNotifiedTime} | current time: ${R.isoDateTime(dayjs.utc())}`); From 052fde5a24daa70855082c4ed9ba362c3785e463 Mon Sep 17 00:00:00 2001 From: OidaTiftla <chm.stephan@outlook.com> Date: Thu, 21 Apr 2022 17:56:38 +0200 Subject: [PATCH 21/99] Fix casing of text label Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com> --- src/pages/EditMonitor.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 4338b4ea..661a89c4 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -172,7 +172,7 @@ <div class="my-3"> <label for="resend-interval" class="form-label"> - {{ $t("Notification resend Interval if Down") }} + {{ $t("Notification resend interval if down") }} <span v-if="monitor.resendInterval > 0">({{ $t("resendEveryMinute", [ monitor.resendInterval ]) }})</span> <span v-else>({{ $t("resendDisabled") }})</span> </label> From c7ec9a07e248a730095e725c870f8396dfaa2296 Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Thu, 21 Apr 2022 17:59:38 +0200 Subject: [PATCH 22/99] Add translation for text label --- src/languages/de-DE.js | 1 + src/languages/en.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index ae28bf5b..5af4c8a1 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -163,6 +163,7 @@ export default { Pink: "Pink", "Search...": "Suchen...", "Heartbeat Retry Interval": "Überprüfungsintervall", + "Notification resend interval if down": "Benachrichtigung erneut versenden wenn Inaktiv", retryCheckEverySecond: "Alle {0} Sekunden neu versuchen", resendEveryMinute: "Erneut versenden alle {0} Minuten", resendDisabled: "Erneut versenden deaktiviert", diff --git a/src/languages/en.js b/src/languages/en.js index 7726d12f..a3a375f3 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -74,6 +74,7 @@ export default { "Heartbeat Interval": "Heartbeat Interval", Retries: "Retries", "Heartbeat Retry Interval": "Heartbeat Retry Interval", + "Notification resend interval if down": "Notification resend interval if down", Advanced: "Advanced", "Upside Down Mode": "Upside Down Mode", "Max. Redirects": "Max. Redirects", From 7ed8ae9f7cc35e24c29bab087c5324d764bf67dc Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Thu, 21 Apr 2022 18:23:32 +0200 Subject: [PATCH 23/99] Fix trailing space warning --- server/model/monitor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 1383153e..84b211b8 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -471,7 +471,7 @@ class Monitor extends BeanModel { if (bean.status === DOWN && this.resendInterval > 0) { // divide by 1000 to convert from milliseconds to seconds and divide by 60 to convert from seconds to minutes - let timeSinceLastNotified = (dayjs.utc().valueOf() - (bean.lastNotifiedTime == null ? 0 : dayjs.utc(bean.lastNotifiedTime).valueOf())) / 1000 / 60; + let timeSinceLastNotified = (dayjs.utc().valueOf() - (bean.lastNotifiedTime == null ? 0 : dayjs.utc(bean.lastNotifiedTime).valueOf())) / 1000 / 60; if (timeSinceLastNotified >= this.resendInterval) { // Send notification again, because we are still DOWN log.debug("monitor", `[${this.name}] sendNotification again: lastNotifiedTime: ${bean.lastNotifiedTime} | current time: ${R.isoDateTime(dayjs.utc())}`); From 98ee9caf2cdc54a2f5edb864906d620e84196317 Mon Sep 17 00:00:00 2001 From: OidaTiftla <chm.stephan@outlook.com> Date: Thu, 5 May 2022 15:55:33 +0200 Subject: [PATCH 24/99] Add variable for currentTime Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com> --- server/model/monitor.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 15181af6..f29f6de5 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -492,11 +492,12 @@ class Monitor extends BeanModel { let timeSinceLastNotified = (dayjs.utc().valueOf() - (bean.lastNotifiedTime == null ? 0 : dayjs.utc(bean.lastNotifiedTime).valueOf())) / 1000 / 60; if (timeSinceLastNotified >= this.resendInterval) { // Send notification again, because we are still DOWN - log.debug("monitor", `[${this.name}] sendNotification again: lastNotifiedTime: ${bean.lastNotifiedTime} | current time: ${R.isoDateTime(dayjs.utc())}`); + const currentTime = R.isoDateTime(dayjs.utc()); + log.debug("monitor", `[${this.name}] sendNotification again: lastNotifiedTime: ${bean.lastNotifiedTime} | current time: ${currentTime}`); await Monitor.sendNotification(isFirstBeat, this, bean); // Set last notified time to now - bean.lastNotifiedTime = R.isoDateTime(dayjs.utc()); + bean.lastNotifiedTime = currentTime; } } } From 93050208bbe9eb1c5678bf609c18e47953fb8485 Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Thu, 5 May 2022 16:01:10 +0200 Subject: [PATCH 25/99] Merge database changes into single patch file --- db/patch-heartbeat-add-last-notified-time.sql | 7 ------- db/patch-monitor-add-resend-interval.sql | 3 +++ server/database.js | 1 - 3 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 db/patch-heartbeat-add-last-notified-time.sql diff --git a/db/patch-heartbeat-add-last-notified-time.sql b/db/patch-heartbeat-add-last-notified-time.sql deleted file mode 100644 index af9c21c0..00000000 --- a/db/patch-heartbeat-add-last-notified-time.sql +++ /dev/null @@ -1,7 +0,0 @@ --- You should not modify if this have pushed to Github, unless it does serious wrong with the db. -BEGIN TRANSACTION; - -ALTER TABLE heartbeat - ADD last_notified_time DATETIME default null; - -COMMIT; diff --git a/db/patch-monitor-add-resend-interval.sql b/db/patch-monitor-add-resend-interval.sql index e8bb08b8..c31dd7a2 100644 --- a/db/patch-monitor-add-resend-interval.sql +++ b/db/patch-monitor-add-resend-interval.sql @@ -4,4 +4,7 @@ BEGIN TRANSACTION; ALTER TABLE monitor ADD resend_interval INTEGER default 0 not null; +ALTER TABLE heartbeat + ADD last_notified_time DATETIME default null; + COMMIT; diff --git a/server/database.js b/server/database.js index 8e3b188b..5dbfd676 100644 --- a/server/database.js +++ b/server/database.js @@ -59,7 +59,6 @@ class Database { "patch-status-page-footer-css.sql": true, "patch-added-mqtt-monitor.sql": true, "patch-monitor-add-resend-interval.sql": true, - "patch-heartbeat-add-last-notified-time.sql": true, }; /** From 398ecb76667710731bc065f35b78706125fc8077 Mon Sep 17 00:00:00 2001 From: Sascha Kruse <sascha.kruse@frederix-hotspot.de> Date: Thu, 12 May 2022 11:48:38 +0200 Subject: [PATCH 26/99] add radius check --- db/patch-add-radius-monitor.sql | 18 ++++++++++++++++ package.json | 1 + server/database.js | 1 + server/model/monitor.js | 33 +++++++++++++++++++++++++++-- server/server.js | 5 +++++ server/util-server.js | 30 ++++++++++++++++++++++++++ src/languages/en.js | 6 ++++++ src/pages/EditMonitor.vue | 37 +++++++++++++++++++++++++++++++-- 8 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 db/patch-add-radius-monitor.sql diff --git a/db/patch-add-radius-monitor.sql b/db/patch-add-radius-monitor.sql new file mode 100644 index 00000000..1fd5b44f --- /dev/null +++ b/db/patch-add-radius-monitor.sql @@ -0,0 +1,18 @@ +BEGIN TRANSACTION; + +ALTER TABLE monitor + ADD radius_username VARCHAR(255); + +ALTER TABLE monitor + ADD radius_password VARCHAR(255); + +ALTER TABLE monitor + ADD radius_calling_station_id VARCHAR(50); + +ALTER TABLE monitor + ADD radius_called_station_id VARCHAR(50); + +ALTER TABLE monitor + ADD radius_secret VARCHAR(255); + +COMMIT diff --git a/package.json b/package.json index e9b7003b..304a466e 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "limiter": "^2.1.0", "mqtt": "^4.2.8", "node-cloudflared-tunnel": "~1.0.9", + "node-radius-client": "^1.0.0", "nodemailer": "~6.6.5", "notp": "~2.0.3", "password-hash": "~1.2.2", diff --git a/server/database.js b/server/database.js index b17e7f4e..4ce509f3 100644 --- a/server/database.js +++ b/server/database.js @@ -58,6 +58,7 @@ class Database { "patch-monitor-expiry-notification.sql": true, "patch-status-page-footer-css.sql": true, "patch-added-mqtt-monitor.sql": true, + "patch-add-radius-monitor.sql": true, }; /** diff --git a/server/model/monitor.js b/server/model/monitor.js index f2d16524..0b8fade4 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -7,7 +7,7 @@ dayjs.extend(timezone); const axios = require("axios"); const { Prometheus } = require("../prometheus"); const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); -const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mqttAsync } = require("../util-server"); +const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, radius, setting, mqttAsync } = require("../util-server"); const { R } = require("redbean-node"); const { BeanModel } = require("redbean-node/dist/bean-model"); const { Notification } = require("../notification"); @@ -87,7 +87,12 @@ class Monitor extends BeanModel { mqttUsername: this.mqttUsername, mqttPassword: this.mqttPassword, mqttTopic: this.mqttTopic, - mqttSuccessMessage: this.mqttSuccessMessage + mqttSuccessMessage: this.mqttSuccessMessage, + radiusUsername: this.radiusUsername, + radiusPassword: this.radiusPassword, + radiusCalledStationId: this.radiusCalledStationId, + radiusCallingStationId: this.radiusCallingStationId, + radiusSecret: this.radiusSecret }; if (includeSensitiveData) { @@ -435,6 +440,30 @@ class Monitor extends BeanModel { interval: this.interval, }); bean.status = UP; + } else if (this.type === "radius") { + let startTime = dayjs().valueOf(); + try { + const resp = await radius( + this.hostname, + this.radiusUsername, + this.radiusPassword, + this.radiusCalledStationId, + this.radiusCallingStationId, + this.radiusSecret + ); + if (resp.code) { + bean.msg = resp.code; + } + bean.status = UP; + } catch (error) { + bean.status = DOWN; + if (error.response?.code) { + bean.msg = error.response.code; + } else { + bean.msg = error.message; + } + } + bean.ping = dayjs().valueOf() - startTime; } else { bean.msg = "Unknown Monitor Type"; bean.status = PENDING; diff --git a/server/server.js b/server/server.js index 79cb2102..55b10816 100644 --- a/server/server.js +++ b/server/server.js @@ -674,6 +674,11 @@ try { bean.mqttPassword = monitor.mqttPassword; bean.mqttTopic = monitor.mqttTopic; bean.mqttSuccessMessage = monitor.mqttSuccessMessage; + bean.radiusUsername = monitor.radiusUsername; + bean.radiusPassword = monitor.radiusPassword; + bean.radiusCalledStationId = monitor.radiusCalledStationId; + bean.radiusCallingStationId = monitor.radiusCallingStationId; + bean.radiusSecret = monitor.radiusSecret; await R.store(bean); diff --git a/server/util-server.js b/server/util-server.js index 54974e14..5dd81e00 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -10,6 +10,12 @@ const chardet = require("chardet"); const mqtt = require("mqtt"); const chroma = require("chroma-js"); const { badgeConstants } = require("./config"); +const radiusClient = require("node-radius-client"); +const { + dictionaries: { + rfc2865: { file, attributes }, + }, +} = require("node-radius-utils"); // From ping-lite exports.WIN = /^win/.test(process.platform); @@ -203,6 +209,30 @@ exports.dnsResolve = function (hostname, resolverServer, rrtype) { }); }; +exports.radius = function ( + hostname, + username, + password, + calledStationId, + callingStationId, + secret, +) { + const client = new radiusClient({ + host: hostname, + dictionaries: [ file ], + }); + + return client.accessRequest({ + secret: secret, + attributes: [ + [ attributes.USER_NAME, username ], + [ attributes.USER_PASSWORD, password ], + [ attributes.CALLING_STATION_ID, callingStationId ], + [ attributes.CALLED_STATION_ID, calledStationId ], + ], + }); +}; + /** * Retrieve value of setting based on key * @param {string} key Key of setting to retrieve diff --git a/src/languages/en.js b/src/languages/en.js index ab73ce35..13826453 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -464,4 +464,10 @@ export default { "Domain Names": "Domain Names", signedInDisp: "Signed in as {0}", signedInDispDisabled: "Auth Disabled.", + RadiusSecret: "Radius Secret", + RadiusSecretDescription: "Shared Secret between client and server", + RadiusCalledStationId: "Called Station Id", + RadiusCalledStationIdDescription: "Identifier of the called device", + RadiusCallingStationId: "Calling Station Id", + RadiusCallingStationIdDescription: "Identifier of the calling device", }; diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 43f34527..e2beaca1 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -35,6 +35,9 @@ <option value="mqtt"> MQTT </option> + <option value="radius"> + Radius + </option> </select> </div> @@ -70,8 +73,8 @@ </div> <!-- Hostname --> - <!-- TCP Port / Ping / DNS / Steam / MQTT only --> - <div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'mqtt'" class="my-3"> + <!-- TCP Port / Ping / DNS / Steam / MQTT / Radius only --> + <div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'mqtt' || monitor.type === 'radius'" class="my-3"> <label for="hostname" class="form-label">{{ $t("Hostname") }}</label> <input id="hostname" v-model="monitor.hostname" type="text" class="form-control" :pattern="`${ipRegexPattern}|${hostnameRegexPattern}`" required> </div> @@ -148,6 +151,36 @@ </div> </template> + <template v-if="monitor.type === 'radius'"> + <div class="my-3"> + <label for="radius_username" class="form-label">Radius {{ $t("Username") }}</label> + <input id="radius_username" v-model="monitor.radiusUsername" type="text" class="form-control" required /> + </div> + + <div class="my-3"> + <label for="radius_password" class="form-label">Radius {{ $t("Password") }}</label> + <input id="radius_password" v-model="monitor.radiusPassword" type="password" class="form-control" required /> + </div> + + <div class="my-3"> + <label for="radius_secret" class="form-label">{{ $t("RadiusSecret") }}</label> + <input id="radius_secret" v-model="monitor.radiusSecret" type="password" class="form-control" required /> + <div class="form-text"> {{ $t( "RadiusSecretDescription") }} </div> + </div> + + <div class="my-3"> + <label for="radius_called_station_id" class="form-label">{{ $t("RadiusCalledStationId") }}</label> + <input id="radius_called_station_id" v-model="monitor.radiusCalledStationId" type="text" class="form-control" required /> + <div class="form-text"> {{ $t( "RadiusCalledStationIdDescription") }} </div> + </div> + + <div class="my-3"> + <label for="radius_calling_station_id" class="form-label">{{ $t("RadiusCallingStationId") }}</label> + <input id="radius_calling_station_id" v-model="monitor.radiusCallingStationId" type="text" class="form-control" required /> + <div class="form-text"> {{ $t( "RadiusCallingStationIdDescription") }} </div> + </div> + </template> + <!-- Interval --> <div class="my-3"> <label for="interval" class="form-label">{{ $t("Heartbeat Interval") }} ({{ $t("checkEverySecond", [ monitor.interval ]) }})</label> From 42d68edab07881e4d9ffe88349c8de2a0db85b1f Mon Sep 17 00:00:00 2001 From: Sascha Kruse <knopwob@knopwob.de> Date: Wed, 18 May 2022 15:55:36 +0200 Subject: [PATCH 27/99] (style) add trailing comma Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com> --- server/model/monitor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 0b8fade4..71b4255c 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -92,7 +92,7 @@ class Monitor extends BeanModel { radiusPassword: this.radiusPassword, radiusCalledStationId: this.radiusCalledStationId, radiusCallingStationId: this.radiusCallingStationId, - radiusSecret: this.radiusSecret + radiusSecret: this.radiusSecret, }; if (includeSensitiveData) { From 32cfd411f87ed98bd3247a7751b2f4791fbd388e Mon Sep 17 00:00:00 2001 From: c0derMo <jaydeveloper@outlook.de> Date: Thu, 19 May 2022 12:35:55 +0000 Subject: [PATCH 28/99] Fixed style & code errors --- server/model/monitor.js | 4 ++-- src/pages/EditMonitor.vue | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index c7e2cd31..2bc40b5f 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -429,7 +429,7 @@ class Monitor extends BeanModel { throw new Error("Server not found on Steam"); } } else if (this.type === "docker") { - debug(`[${this.name}] Prepare Options for Axios`); + log.debug(`[${this.name}] Prepare Options for Axios`); const options = { url: `/containers/${this.docker_container}/json`, @@ -449,7 +449,7 @@ class Monitor extends BeanModel { options.baseURL = this.docker_daemon; } - debug(`[${this.name}] Axios Request`); + log.debug(`[${this.name}] Axios Request`); let res = await axios.request(options); if (res.data.State.Running) { bean.status = UP; diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 56c9ac92..1d156883 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -120,7 +120,7 @@ </div> </div> </template> - + <!-- Docker Container Name / ID --> <!-- For Docker Type --> <div v-if="monitor.type === 'docker'" class="my-3"> From 5f6347d277695f8af5a68b186b373809f7a03272 Mon Sep 17 00:00:00 2001 From: Daeho Ro <lamanus@outlook.kr> Date: Sun, 12 Jun 2022 04:02:44 +0900 Subject: [PATCH 29/99] pull request for adding alertnow notification --- server/notification-providers/alertnow.js | 50 ++++++++++ server/notification.js | 68 ++++++------- src/components/notifications/AlertNow.vue | 13 +++ src/components/notifications/index.js | 112 +++++++++++----------- 4 files changed, 155 insertions(+), 88 deletions(-) create mode 100644 server/notification-providers/alertnow.js create mode 100644 src/components/notifications/AlertNow.vue diff --git a/server/notification-providers/alertnow.js b/server/notification-providers/alertnow.js new file mode 100644 index 00000000..d778b01d --- /dev/null +++ b/server/notification-providers/alertnow.js @@ -0,0 +1,50 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); +const { setting } = require("../util-server"); +const { getMonitorRelativeURL, UP, DOWN } = require("../../src/util"); + +class AlertNow extends NotificationProvider { + + name = "AlertNow"; + + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + let okMsg = "Sent Successfully."; + try { + let textMsg = ""; + let status = "open"; + let eventType = "ERROR"; + let eventId = new Date().toISOString().slice(0, 10).replace(/-/g, ""); + + if (heartbeatJSON && heartbeatJSON.status === UP) { + textMsg = `[${heartbeatJSON.name}] ✅ Application is back online`; + status = "close"; + eventType = "INFO"; + eventId += `_${heartbeatJSON.name.replace(/\s/g, "")}`; + } else if (heartbeatJSON && heartbeatJSON.status === DOWN) { + textMsg = `[${heartbeatJSON.name}] 🔴 Application went down`; + } + + textMsg += ` - ${msg}`; + + const baseURL = await setting("primaryBaseURL"); + if (baseURL && monitorJSON) { + textMsg += ` >> ${baseURL + getMonitorRelativeURL(monitorJSON.id)}`; + } + + const data = { + "summary": textMsg, + "status": status, + "event_type": eventType, + "event_id": eventId, + }; + + await axios.post(notification.alertNowWebhookURL, data); + return okMsg; + } catch (error) { + this.throwGeneralAxiosError(error); + } + + } +} + +module.exports = AlertNow; diff --git a/server/notification.js b/server/notification.js index c457ed14..a3b3a70b 100644 --- a/server/notification.js +++ b/server/notification.js @@ -1,40 +1,41 @@ const { R } = require("redbean-node"); +const { log } = require("../src/util"); +const Alerta = require("./notification-providers/alerta"); +const AlertNow = require("./notification-providers/alertnow"); +const AliyunSms = require("./notification-providers/aliyun-sms"); const Apprise = require("./notification-providers/apprise"); +const Bark = require("./notification-providers/bark"); +const ClickSendSMS = require("./notification-providers/clicksendsms"); +const DingDing = require("./notification-providers/dingding"); const Discord = require("./notification-providers/discord"); +const Feishu = require("./notification-providers/feishu"); +const GoogleChat = require("./notification-providers/google-chat"); +const Gorush = require("./notification-providers/gorush"); const Gotify = require("./notification-providers/gotify"); -const Ntfy = require("./notification-providers/ntfy"); const Line = require("./notification-providers/line"); const LunaSea = require("./notification-providers/lunasea"); -const Mattermost = require("./notification-providers/mattermost"); const Matrix = require("./notification-providers/matrix"); +const Mattermost = require("./notification-providers/mattermost"); +const Ntfy = require("./notification-providers/ntfy"); const Octopush = require("./notification-providers/octopush"); +const OneBot = require("./notification-providers/onebot"); +const PagerDuty = require("./notification-providers/pagerduty"); const PromoSMS = require("./notification-providers/promosms"); -const ClickSendSMS = require("./notification-providers/clicksendsms"); const Pushbullet = require("./notification-providers/pushbullet"); +const PushDeer = require("./notification-providers/pushdeer"); const Pushover = require("./notification-providers/pushover"); const Pushy = require("./notification-providers/pushy"); -const TechulusPush = require("./notification-providers/techulus-push"); const RocketChat = require("./notification-providers/rocket-chat"); +const SerwerSMS = require("./notification-providers/serwersms"); const Signal = require("./notification-providers/signal"); const Slack = require("./notification-providers/slack"); const SMTP = require("./notification-providers/smtp"); +const Stackfield = require("./notification-providers/stackfield"); const Teams = require("./notification-providers/teams"); +const TechulusPush = require("./notification-providers/techulus-push"); const Telegram = require("./notification-providers/telegram"); const Webhook = require("./notification-providers/webhook"); -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 SerwerSMS = require("./notification-providers/serwersms"); -const Stackfield = require("./notification-providers/stackfield"); const WeCom = require("./notification-providers/wecom"); -const GoogleChat = require("./notification-providers/google-chat"); -const PagerDuty = require("./notification-providers/pagerduty"); -const Gorush = require("./notification-providers/gorush"); -const Alerta = require("./notification-providers/alerta"); -const OneBot = require("./notification-providers/onebot"); -const PushDeer = require("./notification-providers/pushdeer"); class Notification { @@ -47,41 +48,42 @@ class Notification { this.providerList = {}; const list = [ - new Apprise(), + new Alerta(), + new AlertNow(), new AliyunSms(), + new Apprise(), + new Bark(), + new ClickSendSMS(), new DingDing(), new Discord(), - new Teams(), + new Feishu(), + new GoogleChat(), + new Gorush(), new Gotify(), - new Ntfy(), new Line(), new LunaSea(), - new Feishu(), - new Mattermost(), new Matrix(), + new Mattermost(), + new Ntfy(), new Octopush(), + new OneBot(), + new PagerDuty(), new PromoSMS(), - new ClickSendSMS(), new Pushbullet(), + new PushDeer(), new Pushover(), new Pushy(), - new TechulusPush(), new RocketChat(), + new SerwerSMS(), new Signal(), new Slack(), new SMTP(), + new Stackfield(), + new Teams(), + new TechulusPush(), new Telegram(), new Webhook(), - new Bark(), - new SerwerSMS(), - new Stackfield(), new WeCom(), - new GoogleChat(), - new PagerDuty(), - new Gorush(), - new Alerta(), - new OneBot(), - new PushDeer(), ]; for (let item of list) { diff --git a/src/components/notifications/AlertNow.vue b/src/components/notifications/AlertNow.vue new file mode 100644 index 00000000..93acc959 --- /dev/null +++ b/src/components/notifications/AlertNow.vue @@ -0,0 +1,13 @@ +<template> + <div class="mb-3"> + <label for="alertnow-webhook-url" class="form-label">{{ $t("Webhook URL") }}<span style="color: red;"><sup>*</sup></span></label> + <input id="alertnow-webhook-url" v-model="$parent.notification.alertNowWebhookURL" type="text" class="form-control" required> + + <div class="form-text"> + <span style="color: red;"><sup>*</sup></span>{{ $t("Required") }} + <i18n-t tag="p" keypath="aboutWebhooks" style="margin-top: 8px;"> + <a href="https://service.opsnow.com/docs/alertnow/en/user-guide-alertnow-en.html#standard" target="_blank">{{ $t("here") }}</a> + </i18n-t> + </div> + </div> +</template> diff --git a/src/components/notifications/index.js b/src/components/notifications/index.js index 18c316a5..e5cbe8ce 100644 --- a/src/components/notifications/index.js +++ b/src/components/notifications/index.js @@ -1,38 +1,39 @@ -import STMP from "./SMTP.vue"; -import Telegram from "./Telegram.vue"; +import Alerta from "./Alerta.vue"; +import AlertNow from "./AlertNow.vue"; +import AliyunSMS from "./AliyunSms.vue"; +import Apprise from "./Apprise.vue"; +import Bark from "./Bark.vue"; +import ClickSendSMS from "./ClickSendSMS.vue"; +import DingDing from "./DingDing.vue"; import Discord from "./Discord.vue"; -import Webhook from "./Webhook.vue"; -import Signal from "./Signal.vue"; +import Feishu from "./Feishu.vue"; +import GoogleChat from "./GoogleChat.vue"; +import Gorush from "./Gorush.vue"; import Gotify from "./Gotify.vue"; +import Line from "./Line.vue"; +import LunaSea from "./LunaSea.vue"; +import Matrix from "./Matrix.vue"; +import Mattermost from "./Mattermost.vue"; import Ntfy from "./Ntfy.vue"; -import Slack from "./Slack.vue"; -import RocketChat from "./RocketChat.vue"; -import Teams from "./Teams.vue"; +import Octopush from "./Octopush.vue"; +import OneBot from "./OneBot.vue"; +import PagerDuty from "./PagerDuty.vue"; +import PromoSMS from "./PromoSMS.vue"; +import Pushbullet from "./Pushbullet.vue"; +import PushDeer from "./PushDeer.vue"; import Pushover from "./Pushover.vue"; import Pushy from "./Pushy.vue"; -import TechulusPush from "./TechulusPush.vue"; -import Octopush from "./Octopush.vue"; -import PromoSMS from "./PromoSMS.vue"; -import ClickSendSMS from "./ClickSendSMS.vue"; -import LunaSea from "./LunaSea.vue"; -import Feishu from "./Feishu.vue"; -import Apprise from "./Apprise.vue"; -import Pushbullet from "./Pushbullet.vue"; -import Line from "./Line.vue"; -import Mattermost from "./Mattermost.vue"; -import Matrix from "./Matrix.vue"; -import AliyunSMS from "./AliyunSms.vue"; -import DingDing from "./DingDing.vue"; -import Bark from "./Bark.vue"; +import RocketChat from "./RocketChat.vue"; import SerwerSMS from "./SerwerSMS.vue"; +import Signal from "./Signal.vue"; +import Slack from "./Slack.vue"; import Stackfield from "./Stackfield.vue"; +import STMP from "./SMTP.vue"; +import Teams from "./Teams.vue"; +import TechulusPush from "./TechulusPush.vue"; +import Telegram from "./Telegram.vue"; +import Webhook from "./Webhook.vue"; import WeCom from "./WeCom.vue"; -import GoogleChat from "./GoogleChat.vue"; -import PagerDuty from "./PagerDuty.vue"; -import Gorush from "./Gorush.vue"; -import Alerta from "./Alerta.vue"; -import OneBot from "./OneBot.vue"; -import PushDeer from "./PushDeer.vue"; /** * Manage all notification form. @@ -40,41 +41,42 @@ import PushDeer from "./PushDeer.vue"; * @type { Record<string, any> } */ const NotificationFormList = { - "telegram": Telegram, - "webhook": Webhook, - "smtp": STMP, - "discord": Discord, - "teams": Teams, - "signal": Signal, - "gotify": Gotify, - "ntfy": Ntfy, - "slack": Slack, - "rocket.chat": RocketChat, - "pushover": Pushover, - "pushy": Pushy, - "PushByTechulus": TechulusPush, - "octopush": Octopush, - "promosms": PromoSMS, - "clicksendsms": ClickSendSMS, - "lunasea": LunaSea, - "Feishu": Feishu, + "alerta": Alerta, + "AlertNow": AlertNow, "AliyunSMS": AliyunSMS, "apprise": Apprise, - "pushbullet": Pushbullet, - "line": Line, - "mattermost": Mattermost, - "matrix": Matrix, - "DingDing": DingDing, "Bark": Bark, - "serwersms": SerwerSMS, - "stackfield": Stackfield, - "WeCom": WeCom, + "clicksendsms": ClickSendSMS, + "DingDing": DingDing, + "discord": Discord, + "Feishu": Feishu, "GoogleChat": GoogleChat, - "PagerDuty": PagerDuty, "gorush": Gorush, - "alerta": Alerta, + "gotify": Gotify, + "line": Line, + "lunasea": LunaSea, + "matrix": Matrix, + "mattermost": Mattermost, + "ntfy": Ntfy, + "octopush": Octopush, "OneBot": OneBot, + "PagerDuty": PagerDuty, + "promosms": PromoSMS, + "pushbullet": Pushbullet, + "PushByTechulus": TechulusPush, "PushDeer": PushDeer, + "pushover": Pushover, + "pushy": Pushy, + "rocket.chat": RocketChat, + "serwersms": SerwerSMS, + "signal": Signal, + "slack": Slack, + "smtp": STMP, + "stackfield": Stackfield, + "teams": Teams, + "telegram": Telegram, + "webhook": Webhook, + "WeCom": WeCom, }; export default NotificationFormList; From 817c941489efabe35ac08ed6a6e9158e424617fe Mon Sep 17 00:00:00 2001 From: Super Manito <68613938+SuperManito@users.noreply.github.com> Date: Sun, 12 Jun 2022 22:30:42 +0800 Subject: [PATCH 30/99] Add Bark Notification Parameters --- server/notification-providers/bark.js | 15 +++- src/components/notifications/Bark.vue | 106 ++++++++++++++++++++++++++ src/languages/bg-BG.js | 2 + src/languages/de-DE.js | 2 + src/languages/en.js | 2 + src/languages/ko-KR.js | 2 + src/languages/nl-NL.js | 2 + src/languages/pl.js | 2 + src/languages/th-TH.js | 2 + src/languages/tr-TR.js | 2 + src/languages/vi-VN.js | 2 + src/languages/zh-CN.js | 2 + src/languages/zh-TW.js | 2 + 13 files changed, 140 insertions(+), 3 deletions(-) diff --git a/server/notification-providers/bark.js b/server/notification-providers/bark.js index 092511d8..a2c4966a 100644 --- a/server/notification-providers/bark.js +++ b/server/notification-providers/bark.js @@ -12,9 +12,7 @@ const { default: axios } = require("axios"); // bark is an APN bridge that sends notifications to Apple devices. -const barkNotificationGroup = "UptimeKuma"; const barkNotificationAvatar = "https://github.com/louislam/uptime-kuma/raw/master/public/icon.png"; -const barkNotificationSound = "telegraph"; const successMessage = "Successes!"; class Bark extends NotificationProvider { @@ -53,10 +51,21 @@ class Bark extends NotificationProvider { appendAdditionalParameters(postUrl) { // grouping all our notifications postUrl += "?group=" + barkNotificationGroup; + if (notification.barkGroup != null) { + postUrl += "&group=" + notification.barkGroup; + } else { + postUrl += "&group=" + "UptimeKuma"; + // default group + } // set icon to uptime kuma icon, 11kb should be fine postUrl += "&icon=" + barkNotificationAvatar; // picked a sound, this should follow system's mute status when arrival - postUrl += "&sound=" + barkNotificationSound; + if (notification.barkSound != null) { + postUrl += "&sound=" + notification.barkSound; + } else { + postUrl += "&sound=" + "telegraph"; + // default sound + } return postUrl; } diff --git a/src/components/notifications/Bark.vue b/src/components/notifications/Bark.vue index 014450de..70e4322d 100644 --- a/src/components/notifications/Bark.vue +++ b/src/components/notifications/Bark.vue @@ -12,4 +12,110 @@ >{{ $t("here") }}</a> </i18n-t> </div> + <div class="mb-3"> + <label for="Bark Group" class="form-label">{{ $t("Bark Group") }}</label> + <input id="Bark Group" v-model="$parent.notification.barkGroup" type="text" class="form-control" required> + </div> + <div class="mb-3"> + <label for="Bark Sound" class="form-label">{{ $t("Bark Sound") }}</label> + + <select id="Bark Sound" v-model="$parent.notification.barkSound" class="form-select" required> + <option value="alarm"> + alarm + </option> + <option value="anticipate"> + anticipate + </option> + <option value="bell"> + bell + </option> + <option value="birdsong"> + birdsong + </option> + <option value="bloom"> + bloom + </option> + <option value="calypso"> + calypso + </option> + <option value="chime"> + chime + </option> + <option value="choo"> + choo + </option> + <option value="descent"> + descent + </option> + <option value="electronic"> + electronic + </option> + <option value="fanfare"> + fanfare + </option> + <option value="glass"> + glass + </option> + <option value="gotosleep"> + gotosleep + </option> + <option value="healthnotification"> + healthnotification + </option> + <option value="horn"> + horn + </option> + <option value="ladder"> + ladder + </option> + <option value="mailsent"> + mailsent + </option> + <option value="minuet"> + minuet + </option> + <option value="multiwayinvitation"> + multiwayinvitation + </option> + <option value="newmail"> + newmail + </option> + <option value="newsflash"> + newsflash + </option> + <option value="noir"> + noir + </option> + <option value="paymentsuccess"> + paymentsuccess + </option> + <option value="shake"> + shake + </option> + <option value="sherwoodforest"> + sherwoodforest + </option> + <option value="silence"> + silence + </option> + <option value="spell"> + spell + </option> + <option value="suspense"> + suspense + </option> + <option value="telegraph"> + telegraph + </option> + <option value="tiptoes"> + tiptoes + </option> + <option value="typewriters"> + typewriters + </option> + <option value="update"> + update + </option> + </select> + </div> </template> diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js index 6297062a..23b1b726 100644 --- a/src/languages/bg-BG.js +++ b/src/languages/bg-BG.js @@ -389,6 +389,8 @@ export default { SignName: "Знак име", "Sms template must contain parameters: ": "SMS шаблонът трябва да съдържа следните параметри: ", "Bark Endpoint": "Bark крайна точка", + "Bark Group": "Bark група", + "Bark Sound": "Bark Звънене", WebHookUrl: "URL адрес на уеб кука", SecretKey: "Таен ключ", "For safety, must use secret key": "За сигурност, трябва да се използва таен ключ", diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index e679937c..aeba230f 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -389,6 +389,8 @@ export default { SignName: "Signaturname", "Sms template must contain parameters: ": "SMS Vorlage muss folgende Parameter enthalten: ", "Bark Endpoint": "Bark Endpunkt", + "Bark Group": "Bark Gruppe", + "Bark Sound": "Bark Klingelton", WebHookUrl: "Webhook URL", SecretKey: "Geheimer Schlüssel", "For safety, must use secret key": "Zur Sicherheit muss ein geheimer Schlüssel verwendet werden", diff --git a/src/languages/en.js b/src/languages/en.js index aa6737dd..4b8f782f 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -406,6 +406,8 @@ export default { SignName: "SignName", "Sms template must contain parameters: ": "Sms template must contain parameters: ", "Bark Endpoint": "Bark Endpoint", + "Bark Group": "Bark Group", + "Bark Sound": "Bark Sound", WebHookUrl: "WebHookUrl", SecretKey: "SecretKey", "For safety, must use secret key": "For safety, must use secret key", diff --git a/src/languages/ko-KR.js b/src/languages/ko-KR.js index da034167..0ed7a6f2 100644 --- a/src/languages/ko-KR.js +++ b/src/languages/ko-KR.js @@ -406,6 +406,8 @@ export default { SignName: "SignName", "Sms template must contain parameters: ": "Sms 템플릿은 다음과 같은 파라미터가 포함되어야 해요:", "Bark Endpoint": "Bark Endpoint", + "Bark Group": "Bark Group", + "Bark Sound": "Bark Sound", WebHookUrl: "웹훅 URL", SecretKey: "Secret Key", "For safety, must use secret key": "안전을 위해 꼭 Secret Key를 사용하세요.", diff --git a/src/languages/nl-NL.js b/src/languages/nl-NL.js index 96424a5f..93bae56d 100644 --- a/src/languages/nl-NL.js +++ b/src/languages/nl-NL.js @@ -397,6 +397,8 @@ export default { SignName: "SignName", "Sms template must contain parameters: ": "Sms sjabloon moet de volgende parameters bevatten: ", "Bark Endpoint": "Bark Endpoint", + "Bark Group": "Bark Group", + "Bark Sound": "Bark Sound", WebHookUrl: "WebHookUrl", SecretKey: "SecretKey", "For safety, must use secret key": "Voor de veiligheid moet je de secret key gebruiken", diff --git a/src/languages/pl.js b/src/languages/pl.js index ab2480d3..57a5cbe6 100644 --- a/src/languages/pl.js +++ b/src/languages/pl.js @@ -396,6 +396,8 @@ export default { SignName: "Podpis", "Sms template must contain parameters: ": "Szablon sms musi posiadać parametry: ", "Bark Endpoint": "Punkt końcowy Bark", + "Bark Group": "grupa Bark", + "Bark Sound": "Dzwonek Bark", WebHookUrl: "WebHookUrl", SecretKey: "Tajny klucz", "For safety, must use secret key": "Ze względów bezpieczeństwa musisz użyć tajnego klucza", diff --git a/src/languages/th-TH.js b/src/languages/th-TH.js index 70138ff4..1773de7a 100644 --- a/src/languages/th-TH.js +++ b/src/languages/th-TH.js @@ -396,6 +396,8 @@ export default { SignName: "ป้ายชื่อ", "Sms template must contain parameters: ": "เทมเพลต SMS ต้องมีพารามิเตอร์ : ", "Bark Endpoint": "Bark Endpoint", + "Bark Group": "Bark Group", + "Bark Sound": "Bark Sound", WebHookUrl: "WebHookUrl", SecretKey: "SecretKey", "For safety, must use secret key": "เพื่อความปลอดภัย จำเป็นต้องตั้งค่ากุญแจการเข้าถึง", diff --git a/src/languages/tr-TR.js b/src/languages/tr-TR.js index 4904bdb7..bce1f0fd 100644 --- a/src/languages/tr-TR.js +++ b/src/languages/tr-TR.js @@ -397,6 +397,8 @@ export default { SignName: "SignName", "Sms template must contain parameters: ": "Sms şablonu parametreleri içermelidir:", "Bark Endpoint": "Bark Endpoint", + "Bark Group": "Bark Group", + "Bark Sound": "Bark Sound", WebHookUrl: "WebHookUrl", SecretKey: "SecretKey", "For safety, must use secret key": "Güvenlik için gizli anahtar kullanılmalıdır", diff --git a/src/languages/vi-VN.js b/src/languages/vi-VN.js index 9005c393..9d8da69a 100644 --- a/src/languages/vi-VN.js +++ b/src/languages/vi-VN.js @@ -396,6 +396,8 @@ export default { SignName: "SignName", "Sms template must contain parameters: ": "Sms template must contain parameters: ", "Bark Endpoint": "Bark Endpoint", + "Bark Group": "Bark Group", + "Bark Sound": "Bark Sound", WebHookUrl: "WebHookUrl", SecretKey: "SecretKey", "For safety, must use secret key": "Để an toàn, hãy dùng secret key", diff --git a/src/languages/zh-CN.js b/src/languages/zh-CN.js index 428d56bb..003fdd7a 100644 --- a/src/languages/zh-CN.js +++ b/src/languages/zh-CN.js @@ -402,6 +402,8 @@ export default { TemplateCode: "TemplateCode", SignName: "SignName", "Bark Endpoint": "Bark 接入点", + "Bark Group": "Bark 群组", + "Bark Sound": "Bark 铃声", "Device Token": "Apple Device Token", Platform: "平台", iOS: "iOS", diff --git a/src/languages/zh-TW.js b/src/languages/zh-TW.js index ff849adb..1118d100 100644 --- a/src/languages/zh-TW.js +++ b/src/languages/zh-TW.js @@ -396,6 +396,8 @@ export default { SignName: "SignName", "Sms template must contain parameters: ": "Sms 範本必須包含參數:", "Bark Endpoint": "Bark 端點", + "Bark Group": "Bark 群組", + "Bark Sound": "Bark 鈴聲", WebHookUrl: "WebHookUrl", SecretKey: "SecretKey", "For safety, must use secret key": "為了安全起見,必須使用秘密金鑰", From a41023ca2a05f1015021d30352b9e4f752778320 Mon Sep 17 00:00:00 2001 From: Super Manito <68613938+SuperManito@users.noreply.github.com> Date: Sun, 12 Jun 2022 22:41:24 +0800 Subject: [PATCH 31/99] Update --- server/notification-providers/bark.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server/notification-providers/bark.js b/server/notification-providers/bark.js index a2c4966a..b9113a74 100644 --- a/server/notification-providers/bark.js +++ b/server/notification-providers/bark.js @@ -50,7 +50,6 @@ class Bark extends NotificationProvider { */ appendAdditionalParameters(postUrl) { // grouping all our notifications - postUrl += "?group=" + barkNotificationGroup; if (notification.barkGroup != null) { postUrl += "&group=" + notification.barkGroup; } else { From 404923b7c82cdc633c637f364f0f2ccbb878d346 Mon Sep 17 00:00:00 2001 From: Super Manito <68613938+SuperManito@users.noreply.github.com> Date: Sun, 12 Jun 2022 22:49:04 +0800 Subject: [PATCH 32/99] bugfix --- server/notification-providers/bark.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/notification-providers/bark.js b/server/notification-providers/bark.js index b9113a74..f9215c8a 100644 --- a/server/notification-providers/bark.js +++ b/server/notification-providers/bark.js @@ -48,7 +48,7 @@ class Bark extends NotificationProvider { * @param {string} postUrl URL to append parameters to * @returns {string} */ - appendAdditionalParameters(postUrl) { + appendAdditionalParameters(notification, postUrl) { // grouping all our notifications if (notification.barkGroup != null) { postUrl += "&group=" + notification.barkGroup; From a23ab9d1de03e0825f6c1206c141fcec98a41a8d Mon Sep 17 00:00:00 2001 From: Super Manito <68613938+SuperManito@users.noreply.github.com> Date: Sun, 12 Jun 2022 23:18:32 +0800 Subject: [PATCH 33/99] Update --- src/components/notifications/Bark.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/notifications/Bark.vue b/src/components/notifications/Bark.vue index 70e4322d..34d35db1 100644 --- a/src/components/notifications/Bark.vue +++ b/src/components/notifications/Bark.vue @@ -18,7 +18,6 @@ </div> <div class="mb-3"> <label for="Bark Sound" class="form-label">{{ $t("Bark Sound") }}</label> - <select id="Bark Sound" v-model="$parent.notification.barkSound" class="form-select" required> <option value="alarm"> alarm From f442507cab4e4c9c3a8d03c83810d36183ed41f4 Mon Sep 17 00:00:00 2001 From: Super Manito <68613938+SuperManito@users.noreply.github.com> Date: Mon, 13 Jun 2022 00:16:34 +0800 Subject: [PATCH 34/99] Update --- src/components/notifications/Bark.vue | 128 +++++++------------------- 1 file changed, 32 insertions(+), 96 deletions(-) diff --git a/src/components/notifications/Bark.vue b/src/components/notifications/Bark.vue index 34d35db1..5ff01b1a 100644 --- a/src/components/notifications/Bark.vue +++ b/src/components/notifications/Bark.vue @@ -19,102 +19,38 @@ <div class="mb-3"> <label for="Bark Sound" class="form-label">{{ $t("Bark Sound") }}</label> <select id="Bark Sound" v-model="$parent.notification.barkSound" class="form-select" required> - <option value="alarm"> - alarm - </option> - <option value="anticipate"> - anticipate - </option> - <option value="bell"> - bell - </option> - <option value="birdsong"> - birdsong - </option> - <option value="bloom"> - bloom - </option> - <option value="calypso"> - calypso - </option> - <option value="chime"> - chime - </option> - <option value="choo"> - choo - </option> - <option value="descent"> - descent - </option> - <option value="electronic"> - electronic - </option> - <option value="fanfare"> - fanfare - </option> - <option value="glass"> - glass - </option> - <option value="gotosleep"> - gotosleep - </option> - <option value="healthnotification"> - healthnotification - </option> - <option value="horn"> - horn - </option> - <option value="ladder"> - ladder - </option> - <option value="mailsent"> - mailsent - </option> - <option value="minuet"> - minuet - </option> - <option value="multiwayinvitation"> - multiwayinvitation - </option> - <option value="newmail"> - newmail - </option> - <option value="newsflash"> - newsflash - </option> - <option value="noir"> - noir - </option> - <option value="paymentsuccess"> - paymentsuccess - </option> - <option value="shake"> - shake - </option> - <option value="sherwoodforest"> - sherwoodforest - </option> - <option value="silence"> - silence - </option> - <option value="spell"> - spell - </option> - <option value="suspense"> - suspense - </option> - <option value="telegraph"> - telegraph - </option> - <option value="tiptoes"> - tiptoes - </option> - <option value="typewriters"> - typewriters - </option> - <option value="update"> - update - </option> + <option value="alarm">alarm</option> + <option value="anticipate">anticipate</option> + <option value="bell">bell</option> + <option value="birdsong">birdsong</option> + <option value="bloom">bloom</option> + <option value="calypso">calypso</option> + <option value="chime">chime</option> + <option value="choo">choo</option> + <option value="descent">descent</option> + <option value="electronic">electronic</option> + <option value="fanfare">fanfare</option> + <option value="glass">glass</option> + <option value="gotosleep">gotosleep</option> + <option value="healthnotification">healthnotification</option> + <option value="horn">horn</option> + <option value="ladder">ladder</option> + <option value="mailsent">mailsent</option> + <option value="minuet">minuet</option> + <option value="multiwayinvitation">multiwayinvitation</option> + <option value="newmail">newmail</option> + <option value="newsflash">newsflash</option> + <option value="noir">noir</option> + <option value="paymentsuccess">paymentsuccess</option> + <option value="shake">shake</option> + <option value="sherwoodforest">sherwoodforest</option> + <option value="silence">silence</option> + <option value="spell">spell</option> + <option value="suspense">suspense</option> + <option value="telegraph">telegraph</option> + <option value="tiptoes">tiptoes</option> + <option value="typewriters">typewriters</option> + <option value="update">update</option> </select> </div> </template> From 5f347b10ba88114a5c15757e4f86c96a3672e479 Mon Sep 17 00:00:00 2001 From: Super Manito <68613938+SuperManito@users.noreply.github.com> Date: Mon, 13 Jun 2022 01:15:38 +0800 Subject: [PATCH 35/99] Update --- src/components/notifications/Bark.vue | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/notifications/Bark.vue b/src/components/notifications/Bark.vue index 5ff01b1a..6cac73d3 100644 --- a/src/components/notifications/Bark.vue +++ b/src/components/notifications/Bark.vue @@ -2,9 +2,6 @@ <div class="mb-3"> <label for="Bark Endpoint" class="form-label">{{ $t("Bark Endpoint") }}<span style="color: red;"><sup>*</sup></span></label> <input id="Bark Endpoint" v-model="$parent.notification.barkEndpoint" type="text" class="form-control" required> - <div class="form-text"> - <p><span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}</p> - </div> <i18n-t tag="div" keypath="wayToGetTeamsURL" class="form-text"> <a href="https://github.com/Finb/Bark" From 774fe58ddca362a7d5c6fdfed8e39b0d8fdbc983 Mon Sep 17 00:00:00 2001 From: Super Manito <68613938+SuperManito@users.noreply.github.com> Date: Mon, 13 Jun 2022 01:30:27 +0800 Subject: [PATCH 36/99] Update --- src/languages/bg-BG.js | 2 -- src/languages/de-DE.js | 2 -- src/languages/ko-KR.js | 2 -- src/languages/nl-NL.js | 2 -- src/languages/pl.js | 2 -- src/languages/th-TH.js | 2 -- src/languages/tr-TR.js | 2 -- src/languages/vi-VN.js | 2 -- 8 files changed, 16 deletions(-) diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js index 23b1b726..6297062a 100644 --- a/src/languages/bg-BG.js +++ b/src/languages/bg-BG.js @@ -389,8 +389,6 @@ export default { SignName: "Знак име", "Sms template must contain parameters: ": "SMS шаблонът трябва да съдържа следните параметри: ", "Bark Endpoint": "Bark крайна точка", - "Bark Group": "Bark група", - "Bark Sound": "Bark Звънене", WebHookUrl: "URL адрес на уеб кука", SecretKey: "Таен ключ", "For safety, must use secret key": "За сигурност, трябва да се използва таен ключ", diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index aeba230f..e679937c 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -389,8 +389,6 @@ export default { SignName: "Signaturname", "Sms template must contain parameters: ": "SMS Vorlage muss folgende Parameter enthalten: ", "Bark Endpoint": "Bark Endpunkt", - "Bark Group": "Bark Gruppe", - "Bark Sound": "Bark Klingelton", WebHookUrl: "Webhook URL", SecretKey: "Geheimer Schlüssel", "For safety, must use secret key": "Zur Sicherheit muss ein geheimer Schlüssel verwendet werden", diff --git a/src/languages/ko-KR.js b/src/languages/ko-KR.js index 0ed7a6f2..da034167 100644 --- a/src/languages/ko-KR.js +++ b/src/languages/ko-KR.js @@ -406,8 +406,6 @@ export default { SignName: "SignName", "Sms template must contain parameters: ": "Sms 템플릿은 다음과 같은 파라미터가 포함되어야 해요:", "Bark Endpoint": "Bark Endpoint", - "Bark Group": "Bark Group", - "Bark Sound": "Bark Sound", WebHookUrl: "웹훅 URL", SecretKey: "Secret Key", "For safety, must use secret key": "안전을 위해 꼭 Secret Key를 사용하세요.", diff --git a/src/languages/nl-NL.js b/src/languages/nl-NL.js index 93bae56d..96424a5f 100644 --- a/src/languages/nl-NL.js +++ b/src/languages/nl-NL.js @@ -397,8 +397,6 @@ export default { SignName: "SignName", "Sms template must contain parameters: ": "Sms sjabloon moet de volgende parameters bevatten: ", "Bark Endpoint": "Bark Endpoint", - "Bark Group": "Bark Group", - "Bark Sound": "Bark Sound", WebHookUrl: "WebHookUrl", SecretKey: "SecretKey", "For safety, must use secret key": "Voor de veiligheid moet je de secret key gebruiken", diff --git a/src/languages/pl.js b/src/languages/pl.js index 57a5cbe6..ab2480d3 100644 --- a/src/languages/pl.js +++ b/src/languages/pl.js @@ -396,8 +396,6 @@ export default { SignName: "Podpis", "Sms template must contain parameters: ": "Szablon sms musi posiadać parametry: ", "Bark Endpoint": "Punkt końcowy Bark", - "Bark Group": "grupa Bark", - "Bark Sound": "Dzwonek Bark", WebHookUrl: "WebHookUrl", SecretKey: "Tajny klucz", "For safety, must use secret key": "Ze względów bezpieczeństwa musisz użyć tajnego klucza", diff --git a/src/languages/th-TH.js b/src/languages/th-TH.js index 1773de7a..70138ff4 100644 --- a/src/languages/th-TH.js +++ b/src/languages/th-TH.js @@ -396,8 +396,6 @@ export default { SignName: "ป้ายชื่อ", "Sms template must contain parameters: ": "เทมเพลต SMS ต้องมีพารามิเตอร์ : ", "Bark Endpoint": "Bark Endpoint", - "Bark Group": "Bark Group", - "Bark Sound": "Bark Sound", WebHookUrl: "WebHookUrl", SecretKey: "SecretKey", "For safety, must use secret key": "เพื่อความปลอดภัย จำเป็นต้องตั้งค่ากุญแจการเข้าถึง", diff --git a/src/languages/tr-TR.js b/src/languages/tr-TR.js index bce1f0fd..4904bdb7 100644 --- a/src/languages/tr-TR.js +++ b/src/languages/tr-TR.js @@ -397,8 +397,6 @@ export default { SignName: "SignName", "Sms template must contain parameters: ": "Sms şablonu parametreleri içermelidir:", "Bark Endpoint": "Bark Endpoint", - "Bark Group": "Bark Group", - "Bark Sound": "Bark Sound", WebHookUrl: "WebHookUrl", SecretKey: "SecretKey", "For safety, must use secret key": "Güvenlik için gizli anahtar kullanılmalıdır", diff --git a/src/languages/vi-VN.js b/src/languages/vi-VN.js index 9d8da69a..9005c393 100644 --- a/src/languages/vi-VN.js +++ b/src/languages/vi-VN.js @@ -396,8 +396,6 @@ export default { SignName: "SignName", "Sms template must contain parameters: ": "Sms template must contain parameters: ", "Bark Endpoint": "Bark Endpoint", - "Bark Group": "Bark Group", - "Bark Sound": "Bark Sound", WebHookUrl: "WebHookUrl", SecretKey: "SecretKey", "For safety, must use secret key": "Để an toàn, hãy dùng secret key", From 252709ff494d6e16f5689d05a069e19dcb4a9aeb Mon Sep 17 00:00:00 2001 From: Super Manito <68613938+SuperManito@users.noreply.github.com> Date: Mon, 13 Jun 2022 17:06:05 +0800 Subject: [PATCH 37/99] Update server/notification-providers/bark.js Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com> --- server/notification-providers/bark.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/notification-providers/bark.js b/server/notification-providers/bark.js index f9215c8a..8d579724 100644 --- a/server/notification-providers/bark.js +++ b/server/notification-providers/bark.js @@ -53,8 +53,8 @@ class Bark extends NotificationProvider { if (notification.barkGroup != null) { postUrl += "&group=" + notification.barkGroup; } else { - postUrl += "&group=" + "UptimeKuma"; // default group + postUrl += "&group=" + "UptimeKuma"; } // set icon to uptime kuma icon, 11kb should be fine postUrl += "&icon=" + barkNotificationAvatar; From 55a6e5af425a1be2df58680aeaed4d726614050a Mon Sep 17 00:00:00 2001 From: Super Manito <68613938+SuperManito@users.noreply.github.com> Date: Mon, 13 Jun 2022 17:06:12 +0800 Subject: [PATCH 38/99] Update server/notification-providers/bark.js Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com> --- server/notification-providers/bark.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/notification-providers/bark.js b/server/notification-providers/bark.js index 8d579724..21ee9b13 100644 --- a/server/notification-providers/bark.js +++ b/server/notification-providers/bark.js @@ -62,8 +62,8 @@ class Bark extends NotificationProvider { if (notification.barkSound != null) { postUrl += "&sound=" + notification.barkSound; } else { - postUrl += "&sound=" + "telegraph"; // default sound + postUrl += "&sound=" + "telegraph"; } return postUrl; } From 1c4ddaeddf2c7d2f78ce881c73ae575a3cbfdb3a Mon Sep 17 00:00:00 2001 From: Super Manito <68613938+SuperManito@users.noreply.github.com> Date: Mon, 13 Jun 2022 18:17:47 +0800 Subject: [PATCH 39/99] Update --- server/notification-providers/bark.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/notification-providers/bark.js b/server/notification-providers/bark.js index 21ee9b13..6b22ae49 100644 --- a/server/notification-providers/bark.js +++ b/server/notification-providers/bark.js @@ -53,7 +53,7 @@ class Bark extends NotificationProvider { if (notification.barkGroup != null) { postUrl += "&group=" + notification.barkGroup; } else { - // default group + // default group name postUrl += "&group=" + "UptimeKuma"; } // set icon to uptime kuma icon, 11kb should be fine @@ -62,7 +62,7 @@ class Bark extends NotificationProvider { if (notification.barkSound != null) { postUrl += "&sound=" + notification.barkSound; } else { - // default sound + // default app sound postUrl += "&sound=" + "telegraph"; } return postUrl; From 54b9698a05e21649ec78f64ec5187b41d885f9d9 Mon Sep 17 00:00:00 2001 From: Super Manito <68613938+SuperManito@users.noreply.github.com> Date: Mon, 13 Jun 2022 21:44:10 +0800 Subject: [PATCH 40/99] Update --- server/notification-providers/bark.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/notification-providers/bark.js b/server/notification-providers/bark.js index 6b22ae49..3258e7c5 100644 --- a/server/notification-providers/bark.js +++ b/server/notification-providers/bark.js @@ -49,20 +49,20 @@ class Bark extends NotificationProvider { * @returns {string} */ appendAdditionalParameters(notification, postUrl) { + // set icon to uptime kuma icon, 11kb should be fine + postUrl += "&icon=" + barkNotificationAvatar; // grouping all our notifications if (notification.barkGroup != null) { postUrl += "&group=" + notification.barkGroup; } else { - // default group name + // default name postUrl += "&group=" + "UptimeKuma"; } - // set icon to uptime kuma icon, 11kb should be fine - postUrl += "&icon=" + barkNotificationAvatar; // picked a sound, this should follow system's mute status when arrival if (notification.barkSound != null) { postUrl += "&sound=" + notification.barkSound; } else { - // default app sound + // default sound postUrl += "&sound=" + "telegraph"; } return postUrl; From ac27e6e2af5dd8140b20c6f36a51a4af608b5a69 Mon Sep 17 00:00:00 2001 From: OidaTiftla <oidatiftla@oidatiftla.de> Date: Wed, 15 Jun 2022 16:56:26 +0200 Subject: [PATCH 41/99] Rename feature to: Resend Notification if Down X times consequently Co-authored-by: Louis Lam <louislam@users.noreply.github.com> --- db/patch-monitor-add-resend-interval.sql | 2 +- server/model/monitor.js | 20 +++++++++----------- src/languages/de-DE.js | 4 ++-- src/languages/en.js | 4 ++-- src/pages/EditMonitor.vue | 4 ++-- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/db/patch-monitor-add-resend-interval.sql b/db/patch-monitor-add-resend-interval.sql index c31dd7a2..8e28bf69 100644 --- a/db/patch-monitor-add-resend-interval.sql +++ b/db/patch-monitor-add-resend-interval.sql @@ -5,6 +5,6 @@ ALTER TABLE monitor ADD resend_interval INTEGER default 0 not null; ALTER TABLE heartbeat - ADD last_notified_time DATETIME default null; + ADD down_count INTEGER default 0 not null; COMMIT; diff --git a/server/model/monitor.js b/server/model/monitor.js index e1d02766..b3435f24 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -206,7 +206,7 @@ class Monitor extends BeanModel { bean.monitor_id = this.id; bean.time = R.isoDateTimeMillis(dayjs.utc()); bean.status = DOWN; - bean.lastNotifiedTime = previousBeat?.lastNotifiedTime; + bean.downCount = previousBeat?.downCount || 0; if (this.isUpsideDown()) { bean.status = flipStatus(bean.status); @@ -523,8 +523,8 @@ class Monitor extends BeanModel { log.debug("monitor", `[${this.name}] sendNotification`); await Monitor.sendNotification(isFirstBeat, this, bean); - // Set last notified time to now - bean.lastNotifiedTime = R.isoDateTime(dayjs.utc()); + // Reset down count + bean.downCount = 0; // Clear Status Page Cache log.debug("monitor", `[${this.name}] apicache clear`); @@ -534,16 +534,14 @@ class Monitor extends BeanModel { bean.important = false; if (bean.status === DOWN && this.resendInterval > 0) { - // divide by 1000 to convert from milliseconds to seconds and divide by 60 to convert from seconds to minutes - let timeSinceLastNotified = (dayjs.utc().valueOf() - (bean.lastNotifiedTime == null ? 0 : dayjs.utc(bean.lastNotifiedTime).valueOf())) / 1000 / 60; - if (timeSinceLastNotified >= this.resendInterval) { + ++bean.downCount; + if (bean.downCount >= this.resendInterval) { // Send notification again, because we are still DOWN - const currentTime = R.isoDateTime(dayjs.utc()); - log.debug("monitor", `[${this.name}] sendNotification again: lastNotifiedTime: ${bean.lastNotifiedTime} | current time: ${currentTime}`); + log.debug("monitor", `[${this.name}] sendNotification again: Down Count: ${bean.downCount} | Resend Interval: ${this.resendInterval}`); await Monitor.sendNotification(isFirstBeat, this, bean); - // Set last notified time to now - bean.lastNotifiedTime = currentTime; + // Reset down count + bean.downCount = 0; } } } @@ -556,7 +554,7 @@ class Monitor extends BeanModel { } 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.warn("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`); + log.warn("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type} | Down Count: ${bean.downCount} | Resend Interval: ${this.resendInterval}`); } log.debug("monitor", `[${this.name}] Send to socket`); diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index f9f1e301..c4ef0b26 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -162,9 +162,9 @@ export default { Pink: "Pink", "Search...": "Suchen...", "Heartbeat Retry Interval": "Überprüfungsintervall", - "Notification resend interval if down": "Benachrichtigung erneut versenden wenn Inaktiv", + "Resend Notification if Down X times consequently": "Benachrichtigung erneut senden, wenn Inaktiv X mal hintereinander", retryCheckEverySecond: "Alle {0} Sekunden neu versuchen", - resendEveryMinute: "Erneut versenden alle {0} Minuten", + resendEveryXTimes: "Erneut versenden alle {0} mal", resendDisabled: "Erneut versenden deaktiviert", "Import Backup": "Backup importieren", "Export Backup": "Backup exportieren", diff --git a/src/languages/en.js b/src/languages/en.js index c3c3b740..49354a26 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -2,7 +2,7 @@ export default { languageName: "English", checkEverySecond: "Check every {0} seconds", retryCheckEverySecond: "Retry every {0} seconds", - resendEveryMinute: "Resend every {0} minutes", + resendEveryXTimes: "Resend every {0} times", resendDisabled: "Resend disabled", retriesDescription: "Maximum retries before the service is marked as down and a notification is sent", ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites", @@ -74,7 +74,7 @@ export default { "Heartbeat Interval": "Heartbeat Interval", Retries: "Retries", "Heartbeat Retry Interval": "Heartbeat Retry Interval", - "Notification resend interval if down": "Notification resend interval if down", + "Resend Notification if Down X times consequently": "Resend Notification if Down X times consequently", Advanced: "Advanced", "Upside Down Mode": "Upside Down Mode", "Max. Redirects": "Max. Redirects", diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 55924952..87bf1996 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -204,8 +204,8 @@ <div class="my-3"> <label for="resend-interval" class="form-label"> - {{ $t("Notification resend interval if down") }} - <span v-if="monitor.resendInterval > 0">({{ $t("resendEveryMinute", [ monitor.resendInterval ]) }})</span> + {{ $t("Resend Notification if Down X times consequently") }} + <span v-if="monitor.resendInterval > 0">({{ $t("resendEveryXTimes", [ monitor.resendInterval ]) }})</span> <span v-else>({{ $t("resendDisabled") }})</span> </label> <input id="resend-interval" v-model="monitor.resendInterval" type="number" class="form-control" required min="0" step="1"> From 945288f0c01c45b771d81da711768d8987754baa Mon Sep 17 00:00:00 2001 From: Christopher Pickering <christopher.pickering@keemail.me> Date: Wed, 15 Jun 2022 12:12:47 -0500 Subject: [PATCH 42/99] Added postgres monitor --- package-lock.json | 215 ++++++++++++++++++++++++++++++++++++++ package.json | 1 + server/model/monitor.js | 10 +- server/util-server.js | 28 +++++ src/pages/EditMonitor.vue | 22 ++-- 5 files changed, 268 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 87342813..d213b883 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,7 @@ "nodemailer": "~6.6.5", "notp": "~2.0.3", "password-hash": "~1.2.2", + "pg": "^8.7.3", "postcss-rtlcss": "~3.4.1", "postcss-scss": "~4.0.3", "prismjs": "^1.27.0", @@ -5335,6 +5336,14 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, "node_modules/builtins": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.0.tgz", @@ -14437,6 +14446,11 @@ "node": ">=8" } }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "node_modules/pacote": { "version": "13.0.5", "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.0.5.tgz", @@ -14689,11 +14703,88 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "optional": true }, + "node_modules/pg": { + "version": "8.7.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz", + "integrity": "sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.5.1", + "pg-protocol": "^1.5.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "pg-native": ">=2.0.0" + }, + "peerDependenciesMeta": { + "pg-native": { + "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==" }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.1.tgz", + "integrity": "sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/pgpass/node_modules/split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -14927,6 +15018,41 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -22865,6 +22991,11 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, "builtins": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.0.tgz", @@ -29671,6 +29802,11 @@ "semver": "^6.2.0" } }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "pacote": { "version": "13.0.5", "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.0.5.tgz", @@ -29867,11 +30003,67 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "optional": true }, + "pg": { + "version": "8.7.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz", + "integrity": "sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.5.1", + "pg-protocol": "^1.5.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, "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==" }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.1.tgz", + "integrity": "sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==" + }, + "pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "requires": { + "split2": "^4.1.0" + }, + "dependencies": { + "split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==" + } + } + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -30035,6 +30227,29 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", diff --git a/package.json b/package.json index efb3e7c1..781e07b1 100644 --- a/package.json +++ b/package.json @@ -104,6 +104,7 @@ "nodemailer": "~6.6.5", "notp": "~2.0.3", "password-hash": "~1.2.2", + "pg": "^8.7.3", "postcss-rtlcss": "~3.4.1", "postcss-scss": "~4.0.3", "prismjs": "^1.27.0", diff --git a/server/model/monitor.js b/server/model/monitor.js index 3e026fb6..9f1bbea5 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -7,7 +7,7 @@ dayjs.extend(timezone); const axios = require("axios"); const { Prometheus } = require("../prometheus"); const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); -const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, mqttAsync, setSetting, httpNtlm } = require("../util-server"); +const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mqttAsync, setSetting, httpNtlm } = require("../util-server"); const { R } = require("redbean-node"); const { BeanModel } = require("redbean-node/dist/bean-model"); const { Notification } = require("../notification"); @@ -477,6 +477,14 @@ class Monitor extends BeanModel { await mssqlQuery(this.databaseConnectionString, this.databaseQuery); + bean.msg = ""; + bean.status = UP; + bean.ping = dayjs().valueOf() - startTime; + } else if (this.type === "postgres") { + let startTime = dayjs().valueOf(); + + await postgresQuery(this.databaseConnectionString, this.databaseQuery); + bean.msg = ""; bean.status = UP; bean.ping = dayjs().valueOf() - startTime; diff --git a/server/util-server.js b/server/util-server.js index 87f9151d..34139383 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -11,6 +11,7 @@ const mqtt = require("mqtt"); const chroma = require("chroma-js"); const { badgeConstants } = require("./config"); const mssql = require("mssql"); +const { Client } = require("pg"); const { NtlmClient } = require("axios-ntlm"); // From ping-lite @@ -254,6 +255,33 @@ exports.mssqlQuery = function (connectionString, query) { }); }; +/** + * Run a query on Postgres + * @param {string} connectionString The database connection string + * @param {string} query The query to validate the database with + * @returns {Promise<(string[]|Object[]|Object)>} + */ +exports.postgresQuery = function (connectionString, query) { + + return new Promise((resolve, reject) => { + + const client = new Client({ connectionString }); + + client.connect(); + + client.query(query) + .then(res => { + resolve(res); + }) + .catch(err => { + reject(err); + }) + .finally(() => { + client.end(); + }); + }); +}; + /** * Retrieve value of setting based on key * @param {string} key Key of setting to retrieve diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 83ffcfd8..cc100bac 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -45,6 +45,9 @@ <option value="sqlserver"> SQL Server </option> + <option value="postgres"> + PostgreSQL + </option> </optgroup> </select> </div> @@ -168,15 +171,21 @@ </div> </template> - <!-- SQL Server --> - <template v-if="monitor.type === 'sqlserver'"> + <!-- SQL Server and PostgreSQL --> + <template v-if="monitor.type === 'sqlserver' || monitor.type === 'postgres'"> <div class="my-3"> - <label for="sqlserverConnectionString" class="form-label">SQL Server {{ $t("Connection String") }}</label> - <input id="sqlserverConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control"> + <label for="sqlConnectionString" class="form-label">{{ $t("Connection String") }}</label> + + <template v-if="monitor.type === 'sqlserver'"> + <input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>"> + </template> + <template v-if="monitor.type === 'postgres'"> + <input id="sqlConnectionString" v-model="monitor.databaseConnectionString" placeholder="postgres://username:password@host:port/database" type="text" class="form-control"> + </template> </div> <div class="my-3"> - <label for="sqlserverQuery" class="form-label">SQL Server {{ $t("Query") }}</label> - <textarea id="sqlserverQuery" v-model="monitor.databaseQuery" class="form-control" placeholder="Example: select getdate()"></textarea> + <label for="sqlQuery" class="form-label">{{ $t("Query") }}</label> + <textarea id="sqlQuery" v-model="monitor.databaseQuery" class="form-control" placeholder="Example: select getdate()"></textarea> </div> </template> @@ -584,7 +593,6 @@ export default { method: "GET", interval: 60, retryInterval: this.interval, - databaseConnectionString: "Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>", maxretries: 0, notificationIDList: {}, ignoreTls: false, From edcdedcaae098add2ed7b58d89e247e0207c1e8e Mon Sep 17 00:00:00 2001 From: Christopher Pickering <christopher.pickering@keemail.me> Date: Wed, 15 Jun 2022 13:00:14 -0500 Subject: [PATCH 43/99] Added check for blank password. --- package-lock.json | 1 + package.json | 1 + server/util-server.js | 10 +++++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index d213b883..b26f6008 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,6 +53,7 @@ "notp": "~2.0.3", "password-hash": "~1.2.2", "pg": "^8.7.3", + "pg-connection-string": "^2.5.0", "postcss-rtlcss": "~3.4.1", "postcss-scss": "~4.0.3", "prismjs": "^1.27.0", diff --git a/package.json b/package.json index 781e07b1..17c73689 100644 --- a/package.json +++ b/package.json @@ -105,6 +105,7 @@ "notp": "~2.0.3", "password-hash": "~1.2.2", "pg": "^8.7.3", + "pg-connection-string": "^2.5.0", "postcss-rtlcss": "~3.4.1", "postcss-scss": "~4.0.3", "prismjs": "^1.27.0", diff --git a/server/util-server.js b/server/util-server.js index 34139383..dc403cbd 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -12,6 +12,7 @@ const chroma = require("chroma-js"); const { badgeConstants } = require("./config"); const mssql = require("mssql"); const { Client } = require("pg"); +const postgresConParse = require("pg-connection-string").parse; const { NtlmClient } = require("axios-ntlm"); // From ping-lite @@ -265,11 +266,18 @@ 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.")); + } + const client = new Client({ connectionString }); client.connect(); - client.query(query) + return client.query(query) .then(res => { resolve(res); }) From 4b2a465c94e2671fcaf1b354257b3f0927b1d252 Mon Sep 17 00:00:00 2001 From: "sur.la.route" <christopher.pickering@keemail.me> Date: Wed, 15 Jun 2022 20:14:06 -0500 Subject: [PATCH 44/99] Fix order of type and placeholder Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com> --- src/pages/EditMonitor.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index cc100bac..f8784055 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -180,7 +180,7 @@ <input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>"> </template> <template v-if="monitor.type === 'postgres'"> - <input id="sqlConnectionString" v-model="monitor.databaseConnectionString" placeholder="postgres://username:password@host:port/database" type="text" class="form-control"> + <input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="postgres://username:password@host:port/database"> </template> </div> <div class="my-3"> From e1f766756f067f043bfc6a43c3f24e2c9c19f76a Mon Sep 17 00:00:00 2001 From: "sur.la.route" <christopher.pickering@keemail.me> Date: Wed, 15 Jun 2022 20:14:26 -0500 Subject: [PATCH 45/99] Removed blank line Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com> --- server/util-server.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server/util-server.js b/server/util-server.js index dc403cbd..89777bce 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -263,7 +263,6 @@ exports.mssqlQuery = function (connectionString, query) { * @returns {Promise<(string[]|Object[]|Object)>} */ exports.postgresQuery = function (connectionString, query) { - return new Promise((resolve, reject) => { const config = postgresConParse(connectionString); From 47e82ed83ad980b16374ecd1010ccf4b4f9ae9bd Mon Sep 17 00:00:00 2001 From: "sur.la.route" <christopher.pickering@keemail.me> Date: Wed, 15 Jun 2022 20:14:36 -0500 Subject: [PATCH 46/99] Removed blank line Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com> --- server/util-server.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server/util-server.js b/server/util-server.js index 89777bce..0ac13c68 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -264,7 +264,6 @@ exports.mssqlQuery = function (connectionString, query) { */ exports.postgresQuery = function (connectionString, query) { return new Promise((resolve, reject) => { - const config = postgresConParse(connectionString); if (config.password === "") { From c4e2d67d17319cc438be7174aaea3f7f6f560077 Mon Sep 17 00:00:00 2001 From: Robert <treboryx@gmail.com> Date: Fri, 17 Jun 2022 10:11:53 +0300 Subject: [PATCH 47/99] fix: hide mobile header when not logged in --- src/layouts/Layout.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/Layout.vue b/src/layouts/Layout.vue index aea58bf1..57519f55 100644 --- a/src/layouts/Layout.vue +++ b/src/layouts/Layout.vue @@ -77,7 +77,7 @@ <!-- Mobile Only --> <div v-if="$root.isMobile" style="width: 100%; height: 60px;" /> - <nav v-if="$root.isMobile" class="bottom-nav"> + <nav v-if="$root.isMobile && $root.loggedIn" class="bottom-nav"> <router-link to="/dashboard" class="nav-link"> <div><font-awesome-icon icon="tachometer-alt" /></div> {{ $t("Dashboard") }} From 6f01a448ad295685d457c7394bd660c0a566ce44 Mon Sep 17 00:00:00 2001 From: theS1LV3R <s1lv3r@corax.team> Date: Thu, 23 Jun 2022 23:08:04 +0200 Subject: [PATCH 48/99] feat: get client ip from x-forwarded-for header if available Useful for use-cases where Uptime Kuma is running behind a reverse proxy --- server/server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/server.js b/server/server.js index 2d3f37ee..e74abaff 100644 --- a/server/server.js +++ b/server/server.js @@ -1677,7 +1677,8 @@ async function shutdownFunction(signal) { } function getClientIp(socket) { - return socket.client.conn.remoteAddress.replace(/^.*:/, ""); + return socket.client.conn.request.headers["x-forwarded-for"] + || socket.client.conn.remoteAddress.replace(/^.*:/, ""); } /** Final function called before application exits */ From f84ae82983744ab50e7e2b9ac5d4a277b40b60e8 Mon Sep 17 00:00:00 2001 From: rmt/src <144435+rmtsrc@users.noreply.github.com> Date: Sat, 25 Jun 2022 17:22:53 +0100 Subject: [PATCH 49/99] feat: added Home Assistant notification integration --- .../notification-providers/home-assistant.js | 38 ++++++++++++++++++ server/notification.js | 2 + .../notifications/HomeAssistant.vue | 40 +++++++++++++++++++ src/components/notifications/index.js | 2 + src/languages/bg-BG.js | 1 + src/languages/cs-CZ.js | 1 + src/languages/da-DK.js | 1 + src/languages/de-DE.js | 1 + src/languages/en.js | 1 + src/languages/es-ES.js | 1 + src/languages/et-EE.js | 1 + src/languages/eu.js | 1 + src/languages/fa.js | 1 + src/languages/fr-FR.js | 1 + src/languages/hr-HR.js | 1 + src/languages/hu.js | 1 + src/languages/id-ID.js | 1 + src/languages/it-IT.js | 1 + src/languages/ja.js | 1 + src/languages/ko-KR.js | 1 + src/languages/nb-NO.js | 1 + src/languages/nl-NL.js | 1 + src/languages/pl.js | 1 + src/languages/pt-BR.js | 1 + src/languages/ru-RU.js | 1 + src/languages/sl-SI.js | 1 + src/languages/sr-latn.js | 1 + src/languages/sr.js | 1 + src/languages/sv-SE.js | 1 + src/languages/th-TH.js | 1 + src/languages/tr-TR.js | 1 + src/languages/uk-UA.js | 1 + src/languages/vi-VN.js | 1 + src/languages/zh-CN.js | 1 + src/languages/zh-HK.js | 1 + src/languages/zh-TW.js | 1 + 36 files changed, 114 insertions(+) create mode 100644 server/notification-providers/home-assistant.js create mode 100644 src/components/notifications/HomeAssistant.vue diff --git a/server/notification-providers/home-assistant.js b/server/notification-providers/home-assistant.js new file mode 100644 index 00000000..285989ee --- /dev/null +++ b/server/notification-providers/home-assistant.js @@ -0,0 +1,38 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); + +const defaultNotificationService = "notify"; + +class HomeAssistant extends NotificationProvider { + name = "HomeAssistant"; + + async send(notification, message, monitor = null, heartbeat = null) { + const notificationService = notification?.notificationService || defaultNotificationService; + + try { + await axios.post( + `${notification.homeAssistantUrl}/api/services/notify/${notificationService}`, + { + title: "Uptime Kuma", + message, + ...(notificationService !== "persistent_notification" && { data: { + name: monitor?.name, + status: heartbeat?.status, + } }), + }, + { + headers: { + Authorization: `Bearer ${notification.longLivedAccessToken}`, + "Content-Type": "application/json", + }, + } + ); + + return "Sent Successfully."; + } catch (error) { + this.throwGeneralAxiosError(error); + } + } +} + +module.exports = HomeAssistant; diff --git a/server/notification.js b/server/notification.js index c457ed14..c86983fa 100644 --- a/server/notification.js +++ b/server/notification.js @@ -35,6 +35,7 @@ const Gorush = require("./notification-providers/gorush"); const Alerta = require("./notification-providers/alerta"); const OneBot = require("./notification-providers/onebot"); const PushDeer = require("./notification-providers/pushdeer"); +const HomeAssistant = require("./notification-providers/home-assistant"); class Notification { @@ -82,6 +83,7 @@ class Notification { new Alerta(), new OneBot(), new PushDeer(), + new HomeAssistant(), ]; for (let item of list) { diff --git a/src/components/notifications/HomeAssistant.vue b/src/components/notifications/HomeAssistant.vue new file mode 100644 index 00000000..67e370a1 --- /dev/null +++ b/src/components/notifications/HomeAssistant.vue @@ -0,0 +1,40 @@ +<template> + <div class="mb-3"> + <label for="homeAssistantUrl" class="form-label">{{ $t("Home Assistant URL") }}<span style="color: red;"><sup>*</sup></span></label> + <input id="homeAssistantUrl" v-model="$parent.notification.homeAssistantUrl" type="url" class="form-control" required> + </div> + + <div class="mb-3"> + <label for="longLivedAccessToken" class="form-label">{{ $t("Long-Lived Access Token") }}<span style="color: red;"><sup>*</sup></span></label> + <input id="longLivedAccessToken" v-model="$parent.notification.longLivedAccessToken" type="text" class="form-control" required> + + <div class="form-text"> + <p>{{ $t("Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ") }}</p> + </div> + </div> + + <div class="mb-3"> + <label for="notificationService" class="form-label">{{ $t("Notification Service") }}</label> + <input id="notificationService" v-model="$parent.notification.notificationService" type="text" :placeholder="$t('default: notify all devices')" class="form-control"> + + <div class="form-text"> + <p>{{ $t("A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.") }}</p> + <p>{{ $t("Automations can optionally be triggered in Home Assistant:") }}</p> + <p> + {{ $t("Trigger type:") }} <code>Event</code><br /> + {{ $t("Event type:") }} <code>call_service</code><br /> + {{ $t("Event data:") }} + </p> + <pre>domain: notify +service: mobile_app_my_phone # change to your device name +service_data: + title: Uptime Kuma + data: + status: 0 # 0=down 1=up + # name: Optional Uptime Kuma Monitor Name to filter by</pre> + <p> + {{ $t("Then choose an action, for example switch the scene to where an RGB light is red.") }} + </p> + </div> + </div> +</template> diff --git a/src/components/notifications/index.js b/src/components/notifications/index.js index 18c316a5..cd0acabb 100644 --- a/src/components/notifications/index.js +++ b/src/components/notifications/index.js @@ -33,6 +33,7 @@ import Gorush from "./Gorush.vue"; import Alerta from "./Alerta.vue"; import OneBot from "./OneBot.vue"; import PushDeer from "./PushDeer.vue"; +import HomeAssistant from "./HomeAssistant.vue"; /** * Manage all notification form. @@ -75,6 +76,7 @@ const NotificationFormList = { "alerta": Alerta, "OneBot": OneBot, "PushDeer": PushDeer, + "HomeAssistant": HomeAssistant, }; export default NotificationFormList; diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js index b2c185d9..1a6d351a 100644 --- a/src/languages/bg-BG.js +++ b/src/languages/bg-BG.js @@ -536,4 +536,5 @@ export default { Domain: "Домейн", Workstation: "Работна станция", disableCloudflaredNoAuthMsg: "Тъй като сте в режим \"No Auth mode\", парола не се изисква.", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/cs-CZ.js b/src/languages/cs-CZ.js index 1ad47fd3..135c0d4c 100644 --- a/src/languages/cs-CZ.js +++ b/src/languages/cs-CZ.js @@ -364,4 +364,5 @@ export default { smtpDkimHashAlgo: "Hashovací algoritmus (volitelné)", smtpDkimheaderFieldNames: "Podepisovat tyto hlavičky (volitelné)", smtpDkimskipFields: "Nepodepisovat tyto hlavičky (volitelné)", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/da-DK.js b/src/languages/da-DK.js index 83cd97ba..4b0f04d9 100644 --- a/src/languages/da-DK.js +++ b/src/languages/da-DK.js @@ -352,4 +352,5 @@ export default { serwersmsPhoneNumber: "Telefonnummer", serwersmsSenderName: "SMS Afsender Navn (registreret via kundeportal)", stackfield: "Stackfield", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index 3df13b94..107adca4 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -455,4 +455,5 @@ export default { "Domain Names": "Domainnamen", signedInDisp: "Angemeldet als {0}", signedInDispDisabled: "Authentifizierung deaktiviert.", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/en.js b/src/languages/en.js index 9aeedd9d..d80c3c8d 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -536,4 +536,5 @@ export default { "Domain": "Domain", "Workstation": "Workstation", disableCloudflaredNoAuthMsg: "You are in No Auth mode, password is not require.", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/es-ES.js b/src/languages/es-ES.js index 31538295..7b3af365 100644 --- a/src/languages/es-ES.js +++ b/src/languages/es-ES.js @@ -206,4 +206,5 @@ export default { records: "registros", "One record": "Un registro", steamApiKeyDescription: "Para monitorear un servidor de juegos de Steam, necesita una clave Steam Web-API. Puede registrar su clave API aquí: ", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/et-EE.js b/src/languages/et-EE.js index f581a699..448577a7 100644 --- a/src/languages/et-EE.js +++ b/src/languages/et-EE.js @@ -206,4 +206,5 @@ export default { alertaApiKey: "API võti", alertaAlertState: "Häireseisund", alertaRecoverState: "Taasta algolek", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/eu.js b/src/languages/eu.js index c99f1eb7..00a7a5f6 100644 --- a/src/languages/eu.js +++ b/src/languages/eu.js @@ -536,4 +536,5 @@ export default { Domain: "Domeinua", Workstation: "Lan gunea", disableCloudflaredNoAuthMsg: "Ez Auth moduan zaude, pasahitza ez da beharrezkoa.", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/fa.js b/src/languages/fa.js index 52845192..fc7eec9e 100644 --- a/src/languages/fa.js +++ b/src/languages/fa.js @@ -205,4 +205,5 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/fr-FR.js b/src/languages/fr-FR.js index 00abe8d3..d6e74635 100644 --- a/src/languages/fr-FR.js +++ b/src/languages/fr-FR.js @@ -309,4 +309,5 @@ export default { alertaApiKey: "Clé de l'API", alertaAlertState: "État de l'Alerte", alertaRecoverState: "État de récupération", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/hr-HR.js b/src/languages/hr-HR.js index bebd2c56..5bdc6983 100644 --- a/src/languages/hr-HR.js +++ b/src/languages/hr-HR.js @@ -375,4 +375,5 @@ export default { alertaAlertState: "Stanje upozorenja", alertaRecoverState: "Stanje oporavka", deleteStatusPageMsg: "Sigurno želite obrisati ovu statusnu stranicu?", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/hu.js b/src/languages/hu.js index e6118c9e..cb53ca8b 100644 --- a/src/languages/hu.js +++ b/src/languages/hu.js @@ -373,4 +373,5 @@ export default { alertaAlertState: "Figyelmeztetési állapot", alertaRecoverState: "Visszaállási állapot", deleteStatusPageMsg: "Biztos, hogy törölni akarja a státusz oldalt?", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/id-ID.js b/src/languages/id-ID.js index 0a065308..1e8499fd 100644 --- a/src/languages/id-ID.js +++ b/src/languages/id-ID.js @@ -283,4 +283,5 @@ export default { promosmsPhoneNumber: "Nomor telepon (untuk penerima Polandia Anda dapat melewati kode area)", promosmsSMSSender: "Nama Pengirim SMS : Nama pra-registrasi atau salah satu bawaan: InfoSMS, Info SMS, MaxSMS, INFO, SMS", "Feishu WebHookUrl": "Feishu WebHookUrl", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/it-IT.js b/src/languages/it-IT.js index f5276183..5b593c0b 100644 --- a/src/languages/it-IT.js +++ b/src/languages/it-IT.js @@ -364,4 +364,5 @@ export default { smtpDkimheaderFieldNames: "Campi Intestazione da firmare (opzionale)", smtpDkimskipFields: "Campi Intestazione da non firmare (opzionale)", GoogleChat: "Google Chat (solo per Google Workspace)", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/ja.js b/src/languages/ja.js index 187ade0c..c53a6334 100644 --- a/src/languages/ja.js +++ b/src/languages/ja.js @@ -198,4 +198,5 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/ko-KR.js b/src/languages/ko-KR.js index dbb02e65..50f6222a 100644 --- a/src/languages/ko-KR.js +++ b/src/languages/ko-KR.js @@ -528,4 +528,5 @@ export default { "Go back to the previous page.": "이전 페이지로 돌아가기", "Coming Soon": "Coming Soon", wayToGetClickSendSMSToken: "{0}에서 API 사용자 이름과 키를 얻을 수 있어요.", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/nb-NO.js b/src/languages/nb-NO.js index 96f71d97..6d54ec82 100644 --- a/src/languages/nb-NO.js +++ b/src/languages/nb-NO.js @@ -282,4 +282,5 @@ export default { promosmsTypeSpeed: "SMS SPEED - Høyest prioritet i systemet.Veldig rask på pålitelig, men dyrt (omtrent det dobbeltet av SMS FULL pris).", promosmsPhoneNumber: "Telefonnummber (for polske mottakere. Du trenger ikke områdekode.)", promosmsSMSSender: "SMS Avsendernavn : Forhåndsregistert navn eller en av standardnavnene: InfoSMS, SMS Info, MaxSMS, INFO, SMS", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/nl-NL.js b/src/languages/nl-NL.js index 3b6ebd83..f3f95267 100644 --- a/src/languages/nl-NL.js +++ b/src/languages/nl-NL.js @@ -462,4 +462,5 @@ export default { "Footer Text": "Footer Tekst", "Show Powered By": "Laat 'Mogeljik gemaakt door' zien", "Domain Names": "Domein Namen", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/pl.js b/src/languages/pl.js index 3e962746..fe533bba 100644 --- a/src/languages/pl.js +++ b/src/languages/pl.js @@ -467,4 +467,5 @@ export default { "Domain Names": "Domeny", signedInDisp: "Zalogowany jako {0}", signedInDispDisabled: "Autoryzacja wyłączona.", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/pt-BR.js b/src/languages/pt-BR.js index 7bc8d0fd..4c03c4a6 100644 --- a/src/languages/pt-BR.js +++ b/src/languages/pt-BR.js @@ -200,4 +200,5 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/ru-RU.js b/src/languages/ru-RU.js index 0aaf0968..cb7b70ee 100644 --- a/src/languages/ru-RU.js +++ b/src/languages/ru-RU.js @@ -400,4 +400,5 @@ export default { proxyDescription: "Прокси должны быть привязаны к монитору, чтобы работать.", enableProxyDescription: "Этот прокси не будет влиять на запросы монитора, пока не будет активирован. Вы можете контролировать временное отключение прокси для всех мониторов через статус активации.", setAsDefaultProxyDescription: "Этот прокси будет по умолчанию включен для новых мониторов. Вы всё ещё можете отдельно отключать прокси в каждом мониторе.", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/sl-SI.js b/src/languages/sl-SI.js index 3c8497f0..1ad70828 100644 --- a/src/languages/sl-SI.js +++ b/src/languages/sl-SI.js @@ -354,4 +354,5 @@ export default { serwersmsPhoneNumber: "Telefonska številka", serwersmsSenderName: "Ime SMS pošiljatelja (registrirani prek portala za stranke)", "stackfield": "Stackfield", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/sr-latn.js b/src/languages/sr-latn.js index 32e074ee..1bc2bb63 100644 --- a/src/languages/sr-latn.js +++ b/src/languages/sr-latn.js @@ -201,4 +201,5 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/sr.js b/src/languages/sr.js index bd8e4dd3..d811ec55 100644 --- a/src/languages/sr.js +++ b/src/languages/sr.js @@ -201,4 +201,5 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/sv-SE.js b/src/languages/sv-SE.js index 1fc35be1..35c8d4b3 100644 --- a/src/languages/sv-SE.js +++ b/src/languages/sv-SE.js @@ -107,4 +107,5 @@ export default { "Repeat Password": "Upprepa Lösenord", respTime: "Svarstid (ms)", notAvailableShort: "Ej Tillg.", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/th-TH.js b/src/languages/th-TH.js index a573206b..1893e442 100644 --- a/src/languages/th-TH.js +++ b/src/languages/th-TH.js @@ -518,4 +518,5 @@ export default { "Go back to the previous page.": "กลับไปที่หน้าก่อนหน้า", "Coming Soon": "เร็ว ๆ นี้", wayToGetClickSendSMSToken: "คุณสามารถรับ API Username และ API Key ได้จาก {0}", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/tr-TR.js b/src/languages/tr-TR.js index 215b5381..7ae7e647 100644 --- a/src/languages/tr-TR.js +++ b/src/languages/tr-TR.js @@ -527,4 +527,5 @@ export default { "do nothing": "hiçbir şey yapma", "auto acknowledged": "otomatik onaylama", "auto resolve": "otomatik çözümleme", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/uk-UA.js b/src/languages/uk-UA.js index 51802a39..fe3da3e3 100644 --- a/src/languages/uk-UA.js +++ b/src/languages/uk-UA.js @@ -392,4 +392,5 @@ export default { alertaAlertState: "Стан алерту", alertaRecoverState: "Стан відновлення", deleteStatusPageMsg: "Дійсно хочете видалити цю сторінку статусів?", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/vi-VN.js b/src/languages/vi-VN.js index 505776f0..38d3d970 100644 --- a/src/languages/vi-VN.js +++ b/src/languages/vi-VN.js @@ -466,4 +466,5 @@ export default { "Domain Names": "Domain Names", signedInDisp: "Signed in as {0}", signedInDispDisabled: "Auth Disabled.", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/zh-CN.js b/src/languages/zh-CN.js index 67077f38..8ae84b3e 100644 --- a/src/languages/zh-CN.js +++ b/src/languages/zh-CN.js @@ -540,4 +540,5 @@ export default { "ntfy Topic": "ntfy 主题", "Domain": "域名", "Workstation": "工作站", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/zh-HK.js b/src/languages/zh-HK.js index a55f4fb6..ac9069be 100644 --- a/src/languages/zh-HK.js +++ b/src/languages/zh-HK.js @@ -380,4 +380,5 @@ export default { proxyDescription: "必須將代理伺服器指派給監測器才能運作。", enableProxyDescription: "此代理伺服器在啟用前不會在監測器上生效,您可以藉由控制啟用狀態來暫時對所有的監測器停用代理伺服器。", setAsDefaultProxyDescription: "預設情況下,新監測器將啟用此代理伺服器。您仍可分別停用各監測器的代理伺服器。", + HomeAssistant: "Home Assistant", }; diff --git a/src/languages/zh-TW.js b/src/languages/zh-TW.js index ace32e17..f3ceefd5 100644 --- a/src/languages/zh-TW.js +++ b/src/languages/zh-TW.js @@ -465,4 +465,5 @@ export default { "Footer Text": "頁尾文字", "Show Powered By": "顯示技術支援文字", "Domain Names": "網域名稱", + HomeAssistant: "Home Assistant", }; From 5dd197374dff744cb765175b0e4eb65271d4dbd1 Mon Sep 17 00:00:00 2001 From: rmt/src <144435+rmtsrc@users.noreply.github.com> Date: Sun, 26 Jun 2022 10:56:46 +0100 Subject: [PATCH 50/99] fix: only add en translation --- src/languages/bg-BG.js | 1 - src/languages/cs-CZ.js | 1 - src/languages/da-DK.js | 1 - src/languages/de-DE.js | 1 - src/languages/es-ES.js | 1 - src/languages/et-EE.js | 1 - src/languages/eu.js | 1 - src/languages/fa.js | 1 - src/languages/fr-FR.js | 1 - src/languages/hr-HR.js | 1 - src/languages/hu.js | 1 - src/languages/id-ID.js | 1 - src/languages/it-IT.js | 1 - src/languages/ja.js | 1 - src/languages/ko-KR.js | 1 - src/languages/nb-NO.js | 1 - src/languages/nl-NL.js | 1 - src/languages/pl.js | 1 - src/languages/pt-BR.js | 1 - src/languages/ru-RU.js | 1 - src/languages/sl-SI.js | 1 - src/languages/sr-latn.js | 1 - src/languages/sr.js | 1 - src/languages/sv-SE.js | 1 - src/languages/th-TH.js | 1 - src/languages/tr-TR.js | 1 - src/languages/uk-UA.js | 1 - src/languages/vi-VN.js | 1 - src/languages/zh-CN.js | 1 - src/languages/zh-HK.js | 1 - src/languages/zh-TW.js | 1 - 31 files changed, 31 deletions(-) diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js index 1a6d351a..b2c185d9 100644 --- a/src/languages/bg-BG.js +++ b/src/languages/bg-BG.js @@ -536,5 +536,4 @@ export default { Domain: "Домейн", Workstation: "Работна станция", disableCloudflaredNoAuthMsg: "Тъй като сте в режим \"No Auth mode\", парола не се изисква.", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/cs-CZ.js b/src/languages/cs-CZ.js index 135c0d4c..1ad47fd3 100644 --- a/src/languages/cs-CZ.js +++ b/src/languages/cs-CZ.js @@ -364,5 +364,4 @@ export default { smtpDkimHashAlgo: "Hashovací algoritmus (volitelné)", smtpDkimheaderFieldNames: "Podepisovat tyto hlavičky (volitelné)", smtpDkimskipFields: "Nepodepisovat tyto hlavičky (volitelné)", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/da-DK.js b/src/languages/da-DK.js index 4b0f04d9..83cd97ba 100644 --- a/src/languages/da-DK.js +++ b/src/languages/da-DK.js @@ -352,5 +352,4 @@ export default { serwersmsPhoneNumber: "Telefonnummer", serwersmsSenderName: "SMS Afsender Navn (registreret via kundeportal)", stackfield: "Stackfield", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index 107adca4..3df13b94 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -455,5 +455,4 @@ export default { "Domain Names": "Domainnamen", signedInDisp: "Angemeldet als {0}", signedInDispDisabled: "Authentifizierung deaktiviert.", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/es-ES.js b/src/languages/es-ES.js index 7b3af365..31538295 100644 --- a/src/languages/es-ES.js +++ b/src/languages/es-ES.js @@ -206,5 +206,4 @@ export default { records: "registros", "One record": "Un registro", steamApiKeyDescription: "Para monitorear un servidor de juegos de Steam, necesita una clave Steam Web-API. Puede registrar su clave API aquí: ", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/et-EE.js b/src/languages/et-EE.js index 448577a7..f581a699 100644 --- a/src/languages/et-EE.js +++ b/src/languages/et-EE.js @@ -206,5 +206,4 @@ export default { alertaApiKey: "API võti", alertaAlertState: "Häireseisund", alertaRecoverState: "Taasta algolek", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/eu.js b/src/languages/eu.js index 00a7a5f6..c99f1eb7 100644 --- a/src/languages/eu.js +++ b/src/languages/eu.js @@ -536,5 +536,4 @@ export default { Domain: "Domeinua", Workstation: "Lan gunea", disableCloudflaredNoAuthMsg: "Ez Auth moduan zaude, pasahitza ez da beharrezkoa.", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/fa.js b/src/languages/fa.js index fc7eec9e..52845192 100644 --- a/src/languages/fa.js +++ b/src/languages/fa.js @@ -205,5 +205,4 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/fr-FR.js b/src/languages/fr-FR.js index d6e74635..00abe8d3 100644 --- a/src/languages/fr-FR.js +++ b/src/languages/fr-FR.js @@ -309,5 +309,4 @@ export default { alertaApiKey: "Clé de l'API", alertaAlertState: "État de l'Alerte", alertaRecoverState: "État de récupération", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/hr-HR.js b/src/languages/hr-HR.js index 5bdc6983..bebd2c56 100644 --- a/src/languages/hr-HR.js +++ b/src/languages/hr-HR.js @@ -375,5 +375,4 @@ export default { alertaAlertState: "Stanje upozorenja", alertaRecoverState: "Stanje oporavka", deleteStatusPageMsg: "Sigurno želite obrisati ovu statusnu stranicu?", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/hu.js b/src/languages/hu.js index cb53ca8b..e6118c9e 100644 --- a/src/languages/hu.js +++ b/src/languages/hu.js @@ -373,5 +373,4 @@ export default { alertaAlertState: "Figyelmeztetési állapot", alertaRecoverState: "Visszaállási állapot", deleteStatusPageMsg: "Biztos, hogy törölni akarja a státusz oldalt?", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/id-ID.js b/src/languages/id-ID.js index 1e8499fd..0a065308 100644 --- a/src/languages/id-ID.js +++ b/src/languages/id-ID.js @@ -283,5 +283,4 @@ export default { promosmsPhoneNumber: "Nomor telepon (untuk penerima Polandia Anda dapat melewati kode area)", promosmsSMSSender: "Nama Pengirim SMS : Nama pra-registrasi atau salah satu bawaan: InfoSMS, Info SMS, MaxSMS, INFO, SMS", "Feishu WebHookUrl": "Feishu WebHookUrl", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/it-IT.js b/src/languages/it-IT.js index 5b593c0b..f5276183 100644 --- a/src/languages/it-IT.js +++ b/src/languages/it-IT.js @@ -364,5 +364,4 @@ export default { smtpDkimheaderFieldNames: "Campi Intestazione da firmare (opzionale)", smtpDkimskipFields: "Campi Intestazione da non firmare (opzionale)", GoogleChat: "Google Chat (solo per Google Workspace)", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/ja.js b/src/languages/ja.js index c53a6334..187ade0c 100644 --- a/src/languages/ja.js +++ b/src/languages/ja.js @@ -198,5 +198,4 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/ko-KR.js b/src/languages/ko-KR.js index 50f6222a..dbb02e65 100644 --- a/src/languages/ko-KR.js +++ b/src/languages/ko-KR.js @@ -528,5 +528,4 @@ export default { "Go back to the previous page.": "이전 페이지로 돌아가기", "Coming Soon": "Coming Soon", wayToGetClickSendSMSToken: "{0}에서 API 사용자 이름과 키를 얻을 수 있어요.", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/nb-NO.js b/src/languages/nb-NO.js index 6d54ec82..96f71d97 100644 --- a/src/languages/nb-NO.js +++ b/src/languages/nb-NO.js @@ -282,5 +282,4 @@ export default { promosmsTypeSpeed: "SMS SPEED - Høyest prioritet i systemet.Veldig rask på pålitelig, men dyrt (omtrent det dobbeltet av SMS FULL pris).", promosmsPhoneNumber: "Telefonnummber (for polske mottakere. Du trenger ikke områdekode.)", promosmsSMSSender: "SMS Avsendernavn : Forhåndsregistert navn eller en av standardnavnene: InfoSMS, SMS Info, MaxSMS, INFO, SMS", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/nl-NL.js b/src/languages/nl-NL.js index f3f95267..3b6ebd83 100644 --- a/src/languages/nl-NL.js +++ b/src/languages/nl-NL.js @@ -462,5 +462,4 @@ export default { "Footer Text": "Footer Tekst", "Show Powered By": "Laat 'Mogeljik gemaakt door' zien", "Domain Names": "Domein Namen", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/pl.js b/src/languages/pl.js index fe533bba..3e962746 100644 --- a/src/languages/pl.js +++ b/src/languages/pl.js @@ -467,5 +467,4 @@ export default { "Domain Names": "Domeny", signedInDisp: "Zalogowany jako {0}", signedInDispDisabled: "Autoryzacja wyłączona.", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/pt-BR.js b/src/languages/pt-BR.js index 4c03c4a6..7bc8d0fd 100644 --- a/src/languages/pt-BR.js +++ b/src/languages/pt-BR.js @@ -200,5 +200,4 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/ru-RU.js b/src/languages/ru-RU.js index cb7b70ee..0aaf0968 100644 --- a/src/languages/ru-RU.js +++ b/src/languages/ru-RU.js @@ -400,5 +400,4 @@ export default { proxyDescription: "Прокси должны быть привязаны к монитору, чтобы работать.", enableProxyDescription: "Этот прокси не будет влиять на запросы монитора, пока не будет активирован. Вы можете контролировать временное отключение прокси для всех мониторов через статус активации.", setAsDefaultProxyDescription: "Этот прокси будет по умолчанию включен для новых мониторов. Вы всё ещё можете отдельно отключать прокси в каждом мониторе.", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/sl-SI.js b/src/languages/sl-SI.js index 1ad70828..3c8497f0 100644 --- a/src/languages/sl-SI.js +++ b/src/languages/sl-SI.js @@ -354,5 +354,4 @@ export default { serwersmsPhoneNumber: "Telefonska številka", serwersmsSenderName: "Ime SMS pošiljatelja (registrirani prek portala za stranke)", "stackfield": "Stackfield", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/sr-latn.js b/src/languages/sr-latn.js index 1bc2bb63..32e074ee 100644 --- a/src/languages/sr-latn.js +++ b/src/languages/sr-latn.js @@ -201,5 +201,4 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/sr.js b/src/languages/sr.js index d811ec55..bd8e4dd3 100644 --- a/src/languages/sr.js +++ b/src/languages/sr.js @@ -201,5 +201,4 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/sv-SE.js b/src/languages/sv-SE.js index 35c8d4b3..1fc35be1 100644 --- a/src/languages/sv-SE.js +++ b/src/languages/sv-SE.js @@ -107,5 +107,4 @@ export default { "Repeat Password": "Upprepa Lösenord", respTime: "Svarstid (ms)", notAvailableShort: "Ej Tillg.", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/th-TH.js b/src/languages/th-TH.js index 1893e442..a573206b 100644 --- a/src/languages/th-TH.js +++ b/src/languages/th-TH.js @@ -518,5 +518,4 @@ export default { "Go back to the previous page.": "กลับไปที่หน้าก่อนหน้า", "Coming Soon": "เร็ว ๆ นี้", wayToGetClickSendSMSToken: "คุณสามารถรับ API Username และ API Key ได้จาก {0}", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/tr-TR.js b/src/languages/tr-TR.js index 7ae7e647..215b5381 100644 --- a/src/languages/tr-TR.js +++ b/src/languages/tr-TR.js @@ -527,5 +527,4 @@ export default { "do nothing": "hiçbir şey yapma", "auto acknowledged": "otomatik onaylama", "auto resolve": "otomatik çözümleme", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/uk-UA.js b/src/languages/uk-UA.js index fe3da3e3..51802a39 100644 --- a/src/languages/uk-UA.js +++ b/src/languages/uk-UA.js @@ -392,5 +392,4 @@ export default { alertaAlertState: "Стан алерту", alertaRecoverState: "Стан відновлення", deleteStatusPageMsg: "Дійсно хочете видалити цю сторінку статусів?", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/vi-VN.js b/src/languages/vi-VN.js index 38d3d970..505776f0 100644 --- a/src/languages/vi-VN.js +++ b/src/languages/vi-VN.js @@ -466,5 +466,4 @@ export default { "Domain Names": "Domain Names", signedInDisp: "Signed in as {0}", signedInDispDisabled: "Auth Disabled.", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/zh-CN.js b/src/languages/zh-CN.js index 8ae84b3e..67077f38 100644 --- a/src/languages/zh-CN.js +++ b/src/languages/zh-CN.js @@ -540,5 +540,4 @@ export default { "ntfy Topic": "ntfy 主题", "Domain": "域名", "Workstation": "工作站", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/zh-HK.js b/src/languages/zh-HK.js index ac9069be..a55f4fb6 100644 --- a/src/languages/zh-HK.js +++ b/src/languages/zh-HK.js @@ -380,5 +380,4 @@ export default { proxyDescription: "必須將代理伺服器指派給監測器才能運作。", enableProxyDescription: "此代理伺服器在啟用前不會在監測器上生效,您可以藉由控制啟用狀態來暫時對所有的監測器停用代理伺服器。", setAsDefaultProxyDescription: "預設情況下,新監測器將啟用此代理伺服器。您仍可分別停用各監測器的代理伺服器。", - HomeAssistant: "Home Assistant", }; diff --git a/src/languages/zh-TW.js b/src/languages/zh-TW.js index f3ceefd5..ace32e17 100644 --- a/src/languages/zh-TW.js +++ b/src/languages/zh-TW.js @@ -465,5 +465,4 @@ export default { "Footer Text": "頁尾文字", "Show Powered By": "顯示技術支援文字", "Domain Names": "網域名稱", - HomeAssistant: "Home Assistant", }; From e5e8db6c38aa76f4585f0c81b804435aeb427ca8 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Wed, 29 Jun 2022 22:17:47 +0800 Subject: [PATCH 51/99] Add cacheable-lookup --- package-lock.json | 14 ++++++++++++++ package.json | 1 + server/uptime-kuma-server.js | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/package-lock.json b/package-lock.json index 9d64290b..2ac4a758 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "bcryptjs": "~2.4.3", "bootstrap": "5.1.3", "bree": "~7.1.5", + "cacheable-lookup": "^6.0.4", "chardet": "^1.3.0", "chart.js": "~3.6.2", "chartjs-adapter-dayjs": "~1.0.0", @@ -4770,6 +4771,14 @@ "node": ">= 0.8" } }, + "node_modules/cacheable-lookup": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.0.4.tgz", + "integrity": "sha512-mbcDEZCkv2CZF4G01kr8eBd/5agkt9oCqz75tJMSIsquvRZ2sL6Hi5zGVKi/0OSC9oO1GHfJ2AV0ZIOY9vye0A==", + "engines": { + "node": ">=10.6.0" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -19882,6 +19891,11 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" }, + "cacheable-lookup": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.0.4.tgz", + "integrity": "sha512-mbcDEZCkv2CZF4G01kr8eBd/5agkt9oCqz75tJMSIsquvRZ2sL6Hi5zGVKi/0OSC9oO1GHfJ2AV0ZIOY9vye0A==" + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", diff --git a/package.json b/package.json index 08eed263..022e7d8d 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "bcryptjs": "~2.4.3", "bootstrap": "5.1.3", "bree": "~7.1.5", + "cacheable-lookup": "^6.0.4", "chardet": "^1.3.0", "chart.js": "~3.6.2", "chartjs-adapter-dayjs": "~1.0.0", diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 605ba533..6f7be7ba 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -7,6 +7,7 @@ const { R } = require("redbean-node"); const { log } = require("../src/util"); const Database = require("./database"); const util = require("util"); +const CacheableLookup = require("cacheable-lookup"); /** * `module.exports` (alias: `server`) should be inside this class, in order to avoid circular dependency issue. @@ -71,6 +72,10 @@ class UptimeKumaServer { } } + const cacheable = new CacheableLookup(); + cacheable.install(http.globalAgent); + cacheable.install(https.globalAgent); + this.io = new Server(this.httpServer); } From 0a368ff55316f2cfbf2f2d3d5292937b42946564 Mon Sep 17 00:00:00 2001 From: Zoe <s1lv3r@corax.team> Date: Mon, 4 Jul 2022 20:36:03 +0200 Subject: [PATCH 52/99] feat: add x-real-ip as a secondary header for client ip Now allows both x-forwarded-for as well as x-real-ip to be used for the client ip, preferring x-forwarded-for --- server/server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/server.js b/server/server.js index e74abaff..476f8664 100644 --- a/server/server.js +++ b/server/server.js @@ -1677,7 +1677,8 @@ async function shutdownFunction(signal) { } function getClientIp(socket) { - return socket.client.conn.request.headers["x-forwarded-for"] + return socket.client.conn.request.headers["x-forwarded-for"] + || socket.client.conn.request.headers["x-real-ip"] || socket.client.conn.remoteAddress.replace(/^.*:/, ""); } From c4125a8334d0fb4c7737a96d928f745fa9360b0a Mon Sep 17 00:00:00 2001 From: theS1LV3R <s1lv3r@corax.team> Date: Mon, 4 Jul 2022 20:38:44 +0200 Subject: [PATCH 53/99] style: fix linter error --- server/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/server.js b/server/server.js index 476f8664..d3ae075d 100644 --- a/server/server.js +++ b/server/server.js @@ -1677,7 +1677,7 @@ async function shutdownFunction(signal) { } function getClientIp(socket) { - return socket.client.conn.request.headers["x-forwarded-for"] + return socket.client.conn.request.headers["x-forwarded-for"] || socket.client.conn.request.headers["x-real-ip"] || socket.client.conn.remoteAddress.replace(/^.*:/, ""); } From f33b6de157423ba9ce5778167e8e8a31e2d06b19 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng <harry@harryzheng.com> Date: Thu, 30 Jun 2022 20:49:48 -0400 Subject: [PATCH 54/99] Support X-Forwarded-Host header --- server/uptime-kuma-server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 605ba533..991c7ba2 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -49,6 +49,7 @@ class UptimeKumaServer { log.info("server", "Creating express and socket.io instance"); this.app = express(); + this.app.enable("trust proxy"); if (sslKey && sslCert) { log.info("server", "Server Type: HTTPS"); From 6ce012c9a141213044522e5d1826c90bcd741adb Mon Sep 17 00:00:00 2001 From: Chongyi Zheng <harry@harryzheng.com> Date: Tue, 12 Jul 2022 22:45:54 -0400 Subject: [PATCH 55/99] Add trust proxy checkbox in Settings page --- src/components/settings/ReverseProxy.vue | 47 ++++++++++++++++++++++++ src/languages/en.js | 4 ++ src/pages/Settings.vue | 4 ++ 3 files changed, 55 insertions(+) diff --git a/src/components/settings/ReverseProxy.vue b/src/components/settings/ReverseProxy.vue index 616b0996..85046cc2 100644 --- a/src/components/settings/ReverseProxy.vue +++ b/src/components/settings/ReverseProxy.vue @@ -91,6 +91,47 @@ {{ $t("For example: nginx, Apache and Traefik.") }} <br /> {{ $t("Please read") }} <a href="https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy" target="_blank">https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy</a>. </div> + + <h4 class="my-4">{{ $t("HTTP Headers") }}</h4> + <div class="my-3"> + <label class="form-label"> + {{ $t("Trust Proxy") }} + </label> + <div class="form-check"> + <input + id="trustProxyYes" + v-model="settings.trustProxy" + class="form-check-input" + type="radio" + name="flexRadioDefault" + :value="true" + required + /> + <label class="form-check-label" for="trustProxyYes"> + {{ $t("Trust 'X-Forwarded-*' headers") }} + </label> + </div> + <div class="form-check"> + <input + id="trustProxyNo" + v-model="settings.trustProxy" + class="form-check-input" + type="radio" + name="flexRadioDefault" + :value="false" + required + /> + <label class="form-check-label" for="trustProxyYes"> + {{ $t("Don't trust 'X-Forwarded-*' headers") }} + </label> + </div> + </div> + + <div> + <button class="btn btn-primary" type="submit" @click="saveSettings()"> + {{ $t("Save") }} + </button> + </div> </div> </template> @@ -113,6 +154,12 @@ export default { settings() { return this.$parent.$parent.$parent.settings; }, + saveSettings() { + return this.$parent.$parent.$parent.saveSettings; + }, + settingsLoaded() { + return this.$parent.$parent.$parent.settingsLoaded; + }, }, watch: { diff --git a/src/languages/en.js b/src/languages/en.js index 9aeedd9d..3c3cdff4 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -453,6 +453,10 @@ export default { "Message:": "Message:", "Don't know how to get the token? Please read the guide:": "Don't know how to get the token? Please read the guide:", "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.", + "HTTP Headers": "HTTP Headers", + "Trust Proxy": "Trust Proxy", + "Trust 'X-Forwarded-*' headers": "Trust 'X-Forwarded-*' headers", + "Don't trust 'X-Forwarded-*' headers": "Don't trust 'X-Forwarded-*' headers", "Other Software": "Other Software", "For example: nginx, Apache and Traefik.": "For example: nginx, Apache and Traefik.", "Please read": "Please read", diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index 03eb09e9..e1013789 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -153,6 +153,10 @@ export default { this.settings.tlsExpiryNotifyDays = [ 7, 14, 21 ]; } + if (this.settings.trustProxy === undefined) { + this.settings.trustProxy = false; + } + this.settingsLoaded = true; }); }, From 3fa5dfc87340ffec34d830a4e906f399845e33d6 Mon Sep 17 00:00:00 2001 From: Chongyi Zheng <harry@harryzheng.com> Date: Tue, 12 Jul 2022 22:59:23 -0400 Subject: [PATCH 56/99] Use x-forwarded-host only when trustProxy is true --- server/server.js | 14 +++++++++++--- server/uptime-kuma-server.js | 2 -- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/server/server.js b/server/server.js index 2d3f37ee..0c08da07 100644 --- a/server/server.js +++ b/server/server.js @@ -164,12 +164,20 @@ let needSetup = false; // Entry Page app.get("/", async (request, response) => { - log.debug("entry", `Request Domain: ${request.hostname}`); + let hostname = request.hostname; + if (await setting("trustProxy")) { + const proxy = request.headers["x-forwarded-host"]; + if (proxy) { + hostname = proxy; + } + } - if (request.hostname in StatusPage.domainMappingList) { + log.debug("entry", `Request Domain: ${hostname}`); + + if (hostname in StatusPage.domainMappingList) { log.debug("entry", "This is a status page domain"); - let slug = StatusPage.domainMappingList[request.hostname]; + let slug = StatusPage.domainMappingList[hostname]; await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug); } else if (exports.entryPage && exports.entryPage.startsWith("statusPage-")) { diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 991c7ba2..34031b23 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -49,8 +49,6 @@ class UptimeKumaServer { log.info("server", "Creating express and socket.io instance"); this.app = express(); - this.app.enable("trust proxy"); - if (sslKey && sslCert) { log.info("server", "Server Type: HTTPS"); this.httpServer = https.createServer({ From d44d984a46e70910cb823c7f15cc6cf3c627b835 Mon Sep 17 00:00:00 2001 From: SiderealArt <nelson22768384@gmail.com> Date: Thu, 14 Jul 2022 22:25:39 +0800 Subject: [PATCH 57/99] update zh-TW --- src/languages/zh-TW.js | 71 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/languages/zh-TW.js b/src/languages/zh-TW.js index ace32e17..be87c540 100644 --- a/src/languages/zh-TW.js +++ b/src/languages/zh-TW.js @@ -13,6 +13,7 @@ export default { pauseDashboardHome: "暫停", deleteMonitorMsg: "您確定要刪除此監測器嗎?", deleteNotificationMsg: "您確定要為所有監測器刪除此通知嗎?", + dnsPortDescription: "DNS 伺服器連接埠。預設為 53。您可以隨時變更連接埠。", resolverserverDescription: "Cloudflare 為預設伺服器。您可以隨時更換解析伺服器。", rrtypeDescription: "選擇您想要監測的資源記錄類型", pauseMonitorMsg: "您確定要暫停嗎?", @@ -332,6 +333,8 @@ export default { info: "資訊", warning: "警告", danger: "危險", + error: "錯誤", + critical: "嚴重", primary: "主要", light: "淺色", dark: "暗色", @@ -372,6 +375,13 @@ export default { smtpDkimHashAlgo: "雜湊演算法 (選填)", smtpDkimheaderFieldNames: "要簽署的郵件標頭 (選填)", smtpDkimskipFields: "不簽署的郵件標頭 (選填)", + wayToGetPagerDutyKey: "您可以前往服務 -> 服務目錄 -> (選取服務) -> 整合 -> 新增整合以取得。您可以搜尋 \"Events API V2\"。詳細資訊 {0}", + "Integration Key": "整合金鑰", + "Integration URL": "整合網址", + "Auto resolve or acknowledged": "自動解決或認可", + "do nothing": "不進行任何操作", + "auto acknowledged": "自動認可", + "auto resolve": "自動解決", gorush: "Gorush", alerta: "Alerta", alertaApiEndpoint: "API 端點", @@ -465,4 +475,65 @@ export default { "Footer Text": "頁尾文字", "Show Powered By": "顯示技術支援文字", "Domain Names": "網域名稱", + signedInDisp: "以 {0} 身分登入", + signedInDispDisabled: "驗證已停用。", + "Certificate Expiry Notification": "憑證到期通知", + "API Username": "API 使用者名稱", + "API Key": "API 金鑰", + "Recipient Number": "收件者號碼", + "From Name/Number": "來自名字/號碼", + "Leave blank to use a shared sender number.": "留空以使用共享寄件人號碼。", + "Octopush API Version": "Octopush API 版本", + "Legacy Octopush-DM": "舊版 Octopush-DM", + "endpoint": "端", + octopushAPIKey: "\"API key\" from HTTP API credentials in control panel", + octopushLogin: "\"Login\" from HTTP API credentials in control panel", + promosmsLogin: "API 登入名稱", + promosmsPassword: "API 密碼", + "pushoversounds pushover": "Pushover (預設)", + "pushoversounds bike": "車鈴", + "pushoversounds bugle": "號角", + "pushoversounds cashregister": "收銀機", + "pushoversounds classical": "古典", + "pushoversounds cosmic": "宇宙", + "pushoversounds falling": "下落", + "pushoversounds gamelan": "甘美朗", + "pushoversounds incoming": "來電", + "pushoversounds intermission": "中場休息", + "pushoversounds magic": "魔法", + "pushoversounds mechanical": "機械", + "pushoversounds pianobar": "Piano Bar", + "pushoversounds siren": "Siren", + "pushoversounds spacealarm": "Space Alarm", + "pushoversounds tugboat": "汽笛", + "pushoversounds alien": "外星鬧鐘 (長)", + "pushoversounds climb": "爬升 (長)", + "pushoversounds persistent": "持續 (長)", + "pushoversounds echo": "Pushover 回音 (長)", + "pushoversounds updown": "上下 (長)", + "pushoversounds vibrate": "僅震動", + "pushoversounds none": "無 (靜音)", + pushyAPIKey: "API 密鑰", + pushyToken: "裝置權杖", + "Show update if available": "顯示可用更新", + "Also check beta release": "檢查 Beta 版", + "Using a Reverse Proxy?": "正在使用反向代理?", + "Check how to config it for WebSocket": "查看如何為 WebSocket 設定", + "Steam Game Server": "Steam 遊戲伺服器", + "Most likely causes:": "可能原因:", + "The resource is no longer available.": "資源已不可用。", + "There might be a typing error in the address.": "網址可能有誤。", + "What you can try:": "您可以嘗試:", + "Retype the address.": "重新輸入網址。", + "Go back to the previous page.": "返回上一頁。", + "Coming Soon": "即將推出", + wayToGetClickSendSMSToken: "您可以從 {0} 取得 API 使用者名稱和金鑰。", + "Connection String": "連線字串", + "Query": "查詢", + settingsCertificateExpiry: "TLS 憑證到期", + certificationExpiryDescription: "TLS 將於 X 天後到期時觸發 HTTPS 監測器通知:", + "ntfy Topic": "ntfy 主題", + "Domain": "網域", + "Workstation": "工作站", + disableCloudflaredNoAuthMsg: "您處於無驗證模式。無須輸入密碼。", }; From 525607f49e6b9c7837c476471df488706c92092c Mon Sep 17 00:00:00 2001 From: Denis Stepanov <denis@stryi.com.ua> Date: Mon, 18 Jul 2022 09:00:44 +0300 Subject: [PATCH 58/99] Update ukrainian language --- src/languages/uk-UA.js | 157 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 146 insertions(+), 11 deletions(-) diff --git a/src/languages/uk-UA.js b/src/languages/uk-UA.js index 51802a39..cc01793c 100644 --- a/src/languages/uk-UA.js +++ b/src/languages/uk-UA.js @@ -1,5 +1,5 @@ export default { - languageName: "Український", + languageName: "Українська", checkEverySecond: "Перевірка кожні {0} секунд", retriesDescription: "Максимальна кількість спроб перед позначенням сервісу як недоступного та надсиланням повідомлення", ignoreTLSError: "Ігнорувати помилку TLS/SSL для сайтів HTTPS", @@ -7,11 +7,11 @@ export default { maxRedirectDescription: "Максимальна кількість перенаправлень. Поставте 0, щоб вимкнути перенаправлення.", acceptedStatusCodesDescription: "Виберіть коди статусів для визначення доступності сервісу.", passwordNotMatchMsg: "Повторення паролю не збігається.", - notificationDescription: "Прив'яжіть повідомлення до моніторів.", + notificationDescription: "Прив'яжіть сповіщення до моніторів.", keywordDescription: "Пошук слова в чистому HTML або JSON-відповіді (чутливо до регістру)", pauseDashboardHome: "Пауза", deleteMonitorMsg: "Ви дійсно хочете видалити цей монітор?", - deleteNotificationMsg: "Ви дійсно хочете видалити це повідомлення для всіх моніторів?", + deleteNotificationMsg: "Ви дійсно хочете видалити це сповіщення для всіх моніторів?", resolverserverDescription: "Cloudflare є сервером за замовчуванням. Ви завжди можете змінити цей сервер.", rrtypeDescription: "Виберіть тип ресурсного запису, який ви хочете відстежувати", pauseMonitorMsg: "Ви дійсно хочете поставити на паузу?", @@ -54,7 +54,7 @@ export default { Keyword: "Ключове слово", "Friendly Name": "Ім'я", URL: "URL", - Hostname: "Ім'я хоста", + Hostname: "Адреса хоста", Port: "Порт", "Heartbeat Interval": "Частота опитування", Retries: "Спроб", @@ -63,7 +63,7 @@ export default { "Max. Redirects": "Макс. кількість перенаправлень", "Accepted Status Codes": "Припустимі коди статусу", Save: "Зберегти", - Notifications: "Повідомлення", + Notifications: "Сповіщення", "Not available, please setup.": "Доступних сповіщень немає, необхідно створити.", "Setup Notification": "Створити сповіщення", Light: "Світла", @@ -100,7 +100,7 @@ export default { "No Monitors, please": "Моніторів немає, будь ласка", "No Monitors": "Монітори відсутні", "add one": "створіть новий", - "Notification Type": "Тип повідомлення", + "Notification Type": "Тип сповіщення", Email: "Пошта", Test: "Перевірка", "Certificate Info": "Інформація про сертифікат", @@ -119,7 +119,7 @@ export default { Events: "Події", Heartbeats: "Опитування", "Auto Get": "Авто-отримання", - enableDefaultNotificationDescription: "Для кожного нового монітора це повідомлення буде включено за замовчуванням. Ви все ще можете відключити повідомлення в кожному моніторі окремо.", + enableDefaultNotificationDescription: "Для кожного нового монітора це сповіщення буде включено за замовчуванням. Ви все ще можете відключити сповіщення в кожному моніторі окремо.", "Default enabled": "Використовувати за промовчанням", "Also apply to existing monitors": "Застосувати до існуючих моніторів", Export: "Експорт", @@ -170,7 +170,7 @@ export default { Purple: "Пурпурний", Pink: "Рожевий", "Search...": "Пошук...", - "Avg. Ping": "Середнє значення пінгу", + "Avg. Ping": "Середній пінг", "Avg. Response": "Середній час відповіді", "Entry Page": "Головна сторінка", statusPageNothing: "Тут порожньо. Додайте групу або монітор.", @@ -210,7 +210,7 @@ export default { "Push URL": "URL пуша", needPushEvery: "До цієї URL необхідно звертатися кожні {0} секунд", pushOptionalParams: "Опціональні параметри: {0}", - defaultNotificationName: "Моє повідомлення {notification} ({number})", + defaultNotificationName: "Моє сповіщення {notification} ({number})", here: "тут", Required: "Потрібно", "Bot Token": "Токен бота", @@ -257,7 +257,7 @@ export default { "User Key": "Ключ користувача", Device: "Пристрій", "Message Title": "Заголовок повідомлення", - "Notification Sound": "Звук повідомлення", + "Notification Sound": "Звук сповіщення", "More info on:": "Більше інформації: {0}", pushoverDesc1: "Екстренний пріоритет (2) має таймуут повтору за замовчуванням 30 секунд і закінчується через 1 годину.", pushoverDesc2: "Якщо ви бажаєте надсилати повідомлення різним пристроям, необхідно заповнити поле Пристрій.", @@ -354,7 +354,7 @@ export default { "No consecutive dashes --": "Заборонено використовувати тире --", "HTTP Options": "HTTP Опції", Authentication: "Аутентифікація", - "HTTP Basic Auth": "HTTP Авторизація", + "HTTP Basic Auth": "Базова HTTP", PushByTechulus: "Push by Techulus", clicksendsms: "ClickSend SMS", GoogleChat: "Google Chat (тільки Google Workspace)", @@ -392,4 +392,139 @@ export default { alertaAlertState: "Стан алерту", alertaRecoverState: "Стан відновлення", deleteStatusPageMsg: "Дійсно хочете видалити цю сторінку статусів?", + Proxies: "Проксі", + default: "За замовчуванням", + enabled: "Активно", + setAsDefault: "Встановити за замовчуванням", + deleteProxyMsg: "Ви впевнені, що хочете видалити цей проксі для всіх моніторів?", + proxyDescription: "Щоб функціонувати, монітору потрібно призначити проксі.", + enableProxyDescription: "Цей проксі не впливатиме на запити моніторингу, доки його не буде активовано. Ви можете контролювати тимчасове відключення проксі з усіх моніторів за статусом активації.", + setAsDefaultProxyDescription: "Цей проксі буде ввімкнено за умовчанням для нових моніторів. Ви все одно можете вимкнути проксі окремо для кожного монітора.", + Invalid: "Недійсний", + AccessKeyId: "AccessKey ID", + SecretAccessKey: "AccessKey Secret", + PhoneNumbers: "PhoneNumbers", + TemplateCode: "TemplateCode", + SignName: "SignName", + "Sms template must contain parameters: ": "Шаблон смс повинен містити параметри: ", + "Bark Endpoint": "Bark Endpoint", + WebHookUrl: "WebHookUrl", + SecretKey: "SecretKey", + "For safety, must use secret key": "Для безпеки необхідно використовувати секретний ключ", + "Device Token": "Токен пристрою", + Platform: "Платформа", + iOS: "iOS", + Android: "Android", + Huawei: "Huawei", + High: "Високий", + Retry: "Повтор", + Topic: "Тема", + "WeCom Bot Key": "WeCom Bot ключ", + "Setup Proxy": "Налаштувати проксі", + "Proxy Protocol": "Протокол проксі", + "Proxy Server": "Проксі-сервер", + "Proxy server has authentication": "Проксі-сервер має аутентифікацію", + User: "Користувач", + Installed: "Встановлено", + "Not installed": "Не встановлено", + Running: "Запущено", + "Not running": "Не запущено", + "Remove Token": "Видалити токен", + Start: "Запустити", + Stop: "Зупинити", + "Uptime Kuma": "Uptime Kuma", + Slug: "Slug", + "Accept characters:": "Прийняти символи:", + startOrEndWithOnly: "Починається або закінчується лише {0}", + "No consecutive dashes": "Немає послідовних тире", + "The slug is already taken. Please choose another slug.": "The slug is already taken. Please choose another slug.", + "No Proxy": "Без проксі", + "Page Not Found": "Сторінку не знайдено", + "Reverse Proxy": "Реверсивний проксі", + wayToGetCloudflaredURL: "(Завантажити Cloudflare з {0})", + cloudflareWebsite: "Веб-сайт Cloudflare", + "Message:": "Повідомлення:", + "Don't know how to get the token? Please read the guide:": "Не знаєте, як отримати токен? Прочитайте посібник:", + "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Поточне з’єднання може бути втрачено, якщо ви зараз під’єднуєтеся через Cloudflare Tunnel. Ви дійсно хочете зробити це? Для підтвердження введіть поточний пароль.", + "Other Software": "Інше програмне забезпечення", + "For example: nginx, Apache and Traefik.": "Наприклад: nginx, Apache and Traefik.", + "Please read": "Будь ласка, прочитайте", + "Subject:": "Тема:", + "Valid To:": "Дійсний до:", + "Days Remaining:": "Залишилось днів:", + "Issuer:": "Емітент:", + "Fingerprint:": "Відбиток:", + "No status pages": "Немає сторінок статусу", + "Domain Name Expiry Notification": "Сповіщення про закінчення терміну дії доменного імені", + Proxy: "Проксі", + "Date Created": "Дата створення", + onebotHttpAddress: "OneBot адреса HTTP", + onebotMessageType: "OneBot тип повідомлення", + onebotGroupMessage: "Група", + onebotPrivateMessage: "Приватне", + onebotUserOrGroupId: "Група/Користувач ID", + onebotSafetyTips: "Для безпеки необхідно встановити маркер доступу", + "PushDeer Key": "PushDeer ключ", + "Footer Text": "Текст нижнього колонтитула", + "Show Powered By": "Показувати платформу", + "Domain Names": "Доменні імена", + signedInDisp: "Ви ввійшли як {0}", + signedInDispDisabled: "Авторизація вимкнена.", + "Certificate Expiry Notification": "Сповіщення про закінчення терміну дії сертифіката", + "API Username": "Користувач API", + "API Key": "Ключ API", + "Recipient Number": "Номер одержувача", + "From Name/Number": "Від Ім'я/Номер", + "Leave blank to use a shared sender number.": "Залиште поле порожнім, щоб використовувати спільний номер відправника.", + "Octopush API Version": "Octopush API версія", + "Legacy Octopush-DM": "Legacy Octopush-DM", + "endpoint": "кінцева точка", + octopushAPIKey: "\"Ключ API\" з облікових даних HTTP API в панелі керування", + octopushLogin: "\"Ім'я користувача\" з облікових даних HTTP API на панелі керування", + promosmsLogin: "API Логін", + promosmsPassword: "API Пароль", + "pushoversounds pushover": "Pushover (по замовчуванню)", + "pushoversounds bike": "Bike", + "pushoversounds bugle": "Bugle", + "pushoversounds cashregister": "Cash Register", + "pushoversounds classical": "Classical", + "pushoversounds cosmic": "Cosmic", + "pushoversounds falling": "Falling", + "pushoversounds gamelan": "Gamelan", + "pushoversounds incoming": "Incoming", + "pushoversounds intermission": "Intermission", + "pushoversounds magic": "Magic", + "pushoversounds mechanical": "Mechanical", + "pushoversounds pianobar": "Piano Bar", + "pushoversounds siren": "Siren", + "pushoversounds spacealarm": "Space Alarm", + "pushoversounds tugboat": "Tug Boat", + "pushoversounds alien": "Alien Alarm (long)", + "pushoversounds climb": "Climb (long)", + "pushoversounds persistent": "Persistent (long)", + "pushoversounds echo": "Pushover Echo (long)", + "pushoversounds updown": "Up Down (long)", + "pushoversounds vibrate": "Vibrate Only", + "pushoversounds none": "None (silent)", + pushyAPIKey: "Секретний ключ API", + pushyToken: "Токен пристрою", + "Using a Reverse Proxy?": "Використовувати зворотній проксі?", + "Check how to config it for WebSocket": "Перевірте, як налаштувати його для WebSocket", + "Steam Game Server": "Ігровий сервер Steam", + "Most likely causes:": "Найімовірніші причини:", + "The resource is no longer available.": "Ресурс більше не доступний.", + "There might be a typing error in the address.": "Можливо, в адресі є помилка.", + "What you can try:": "Що ви можете спробувати:", + "Retype the address.": "Повторно введіть адресу.", + "Go back to the previous page.": "Повернутися на попередню сторінку.", + "Coming Soon": "Незабаром", + wayToGetClickSendSMSToken: "Ви можете отримати ім’я користувача API та ключ API з {0} .", + "Connection String": "Рядок підключення", + "Query": "Запит", + settingsCertificateExpiry: "Закінчення терміну дії сертифіката TLS", + certificationExpiryDescription: "Запуск сповіщення для HTTPS моніторів коли до закінчення терміну дії TLS сертифіката:", + "ntfy Topic": "ntfy Тема", + "Domain": "Домен", + "Workstation": "Робоча станція", + disableCloudflaredNoAuthMsg: "Ви перебуваєте в режимі без авторизації, пароль не потрібен.", }; From 25d711e6834d88c10d21099e53ab333f758b8fc0 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Mon, 18 Jul 2022 22:06:25 +0800 Subject: [PATCH 59/99] Fix jsdoc data type --- server/util-server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/util-server.js b/server/util-server.js index f6a0e396..deacb3a9 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -384,7 +384,7 @@ exports.checkCertificate = function (res) { /** * Check if the provided status code is within the accepted ranges - * @param {string} status The status code to check + * @param {number} status The status code to check * @param {string[]} acceptedCodes An array of accepted status codes * @returns {boolean} True if status code within range, false otherwise * @throws {Error} Will throw an error if the provided status code is not a valid range string or code string From 2073f0c28476bb46fb953ecefb9622273e8819d9 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Mon, 18 Jul 2022 22:33:35 +0800 Subject: [PATCH 60/99] Bind cacheable-lookup to custom http agent --- server/cacheable-dns-http-agent.js | 50 ++++++++++++++++++++++++++++++ server/model/monitor.js | 6 +++- server/uptime-kuma-server.js | 6 ++-- 3 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 server/cacheable-dns-http-agent.js diff --git a/server/cacheable-dns-http-agent.js b/server/cacheable-dns-http-agent.js new file mode 100644 index 00000000..0eb7a6ee --- /dev/null +++ b/server/cacheable-dns-http-agent.js @@ -0,0 +1,50 @@ +const https = require("https"); +const http = require("http"); +const CacheableLookup = require("cacheable-lookup"); + +class CacheableDnsHttpAgent { + + static cacheable = new CacheableLookup(); + + static httpAgentList = {}; + static httpsAgentList = {}; + + /** + * Register cacheable to global agents + */ + static registerGlobalAgent() { + this.cacheable.install(http.globalAgent); + this.cacheable.install(https.globalAgent); + } + + /** + * @var {https.AgentOptions} agentOptions + * @return {https.Agent} + */ + static getHttpsAgent(agentOptions) { + let key = JSON.stringify(agentOptions); + if (!(key in this.httpsAgentList)) { + this.httpsAgentList[key] = new https.Agent(agentOptions); + this.cacheable.install(this.httpsAgentList[key]); + } + return this.httpsAgentList[key]; + } + + /** + * @var {http.AgentOptions} agentOptions + * @return {https.Agents} + */ + static getHttpAgent(agentOptions) { + let key = JSON.stringify(agentOptions); + if (!(key in this.httpAgentList)) { + this.httpAgentList[key] = new http.Agent(agentOptions); + this.cacheable.install(this.httpAgentList[key]); + } + return this.httpAgentList[key]; + } + +} + +module.exports = { + CacheableDnsHttpAgent, +}; diff --git a/server/model/monitor.js b/server/model/monitor.js index 5c97785f..bcb5a8b7 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -16,6 +16,7 @@ const { demoMode } = require("../config"); const version = require("../../package.json").version; const apicache = require("../modules/apicache"); const { UptimeKumaServer } = require("../uptime-kuma-server"); +const { CacheableDnsHttpAgent } = require("../cacheable-dns-http-agent"); /** * status: @@ -434,10 +435,13 @@ class Monitor extends BeanModel { "Accept": "*/*", "User-Agent": "Uptime-Kuma/" + version, }, - httpsAgent: new https.Agent({ + httpsAgent: CacheableDnsHttpAgent.getHttpsAgent({ maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940) rejectUnauthorized: !this.getIgnoreTls(), }), + httpAgent: CacheableDnsHttpAgent.getHttpAgent({ + maxCachedSessions: 0, + }), maxRedirects: this.maxredirects, validateStatus: (status) => { return checkStatusCode(status, this.getAcceptedStatuscodes()); diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 6f7be7ba..e93e2b78 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -7,7 +7,7 @@ const { R } = require("redbean-node"); const { log } = require("../src/util"); const Database = require("./database"); const util = require("util"); -const CacheableLookup = require("cacheable-lookup"); +const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent"); /** * `module.exports` (alias: `server`) should be inside this class, in order to avoid circular dependency issue. @@ -72,9 +72,7 @@ class UptimeKumaServer { } } - const cacheable = new CacheableLookup(); - cacheable.install(http.globalAgent); - cacheable.install(https.globalAgent); + CacheableDnsHttpAgent.registerGlobalAgent(); this.io = new Server(this.httpServer); } From 65d71e5db0653361c55e191313e491269f6b61af Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Mon, 18 Jul 2022 23:14:16 +0800 Subject: [PATCH 61/99] Fix mssqlQuery keep adding error listener, which causes memory leak. Also it is not necessary since the error catched in the promise .catch(..). --- server/util-server.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/server/util-server.js b/server/util-server.js index deacb3a9..ec68c2f3 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -238,10 +238,6 @@ exports.dnsResolve = function (hostname, resolverServer, resolverPort, rrtype) { */ exports.mssqlQuery = function (connectionString, query) { return new Promise((resolve, reject) => { - mssql.on("error", err => { - reject(err); - }); - mssql.connect(connectionString).then(pool => { return pool.request() .query(query); From 9cd060c6c3fba9912bced3643a268d84b24f42f1 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Mon, 18 Jul 2022 23:27:05 +0800 Subject: [PATCH 62/99] socks-proxy-agent 6.2.X is a breaking change, freeze to 6.1.1. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8693135a..93c249f4 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "redbean-node": "0.1.4", "socket.io": "~4.4.1", "socket.io-client": "~4.4.1", - "socks-proxy-agent": "^6.1.1", + "socks-proxy-agent": "6.1.1", "tar": "^6.1.11", "tcp-ping": "~0.1.1", "thirty-two": "~1.0.2" From 8f7b7e74c955eea2d4107d1658f94530101aede9 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Mon, 18 Jul 2022 23:28:19 +0800 Subject: [PATCH 63/99] socks-proxy-agent 6.2.X is a breaking change, freeze to 6.1.1. --- package-lock.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index b0e55246..e64f9fa7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "redbean-node": "0.1.4", "socket.io": "~4.4.1", "socket.io-client": "~4.4.1", - "socks-proxy-agent": "^6.1.1", + "socks-proxy-agent": "6.1.1", "tar": "^6.1.11", "tcp-ping": "~0.1.1", "thirty-two": "~1.0.2" @@ -14306,13 +14306,13 @@ } }, "node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", + "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", "dependencies": { "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" + "debug": "^4.3.1", + "socks": "^2.6.1" }, "engines": { "node": ">= 10" @@ -27095,13 +27095,13 @@ } }, "socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", + "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", "requires": { "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" + "debug": "^4.3.1", + "socks": "^2.6.1" } }, "sortablejs": { From 17ed051401f3889e8be041084301f05517a33526 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Mon, 18 Jul 2022 23:32:45 +0800 Subject: [PATCH 64/99] Add CacheableDnsHttpAgent.install() --- package.json | 2 +- server/cacheable-dns-http-agent.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 93c249f4..7a18dbdf 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "badge-maker": "^3.3.1", "bcryptjs": "~2.4.3", "bree": "~7.1.5", - "cacheable-lookup": "^6.0.4", + "cacheable-lookup": "~6.0.4", "chardet": "^1.3.0", "check-password-strength": "^2.0.5", "cheerio": "^1.0.0-rc.10", diff --git a/server/cacheable-dns-http-agent.js b/server/cacheable-dns-http-agent.js index 0eb7a6ee..56e8430e 100644 --- a/server/cacheable-dns-http-agent.js +++ b/server/cacheable-dns-http-agent.js @@ -17,6 +17,10 @@ class CacheableDnsHttpAgent { this.cacheable.install(https.globalAgent); } + static install(agent) { + this.cacheable.install(agent); + } + /** * @var {https.AgentOptions} agentOptions * @return {https.Agent} From c412c66aebb04fab95a075dc13e9114edc045025 Mon Sep 17 00:00:00 2001 From: Mario Garrido <mariogarrido@7graus.com> Date: Fri, 22 Jul 2022 06:29:41 +0100 Subject: [PATCH 65/99] Add pt-PT language file --- src/languages/pt-PT.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/languages/pt-PT.js diff --git a/src/languages/pt-PT.js b/src/languages/pt-PT.js new file mode 100644 index 00000000..e69de29b From 77340cf0d296456d770c0244b4ec27f5c18348b7 Mon Sep 17 00:00:00 2001 From: Mario Garrido <mariogarrido@7graus.com> Date: Fri, 22 Jul 2022 15:16:23 +0100 Subject: [PATCH 66/99] feat: adicionar pt-PT --- src/languages/pt-PT.js | 203 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) diff --git a/src/languages/pt-PT.js b/src/languages/pt-PT.js index e69de29b..ac452569 100644 --- a/src/languages/pt-PT.js +++ b/src/languages/pt-PT.js @@ -0,0 +1,203 @@ +export default { + languageName: "Português (Portugal)", + checkEverySecond: "Verificar a cada {0} segundos.", + retryCheckEverySecond: "Tentar novamente a cada {0} segundos.", + retriesDescription: "Máximo de tentativas antes que o serviço seja marcado como inativo e uma notificação seja enviada", + ignoreTLSError: "Ignorar erros TLS/SSL para sites HTTPS", + upsideDownModeDescription: "Inverte o status de cabeça para baixo. Se o serviço estiver acessível, ele está OFFLINE.", + maxRedirectDescription: "Número máximo de redirecionamentos a seguir. Define como 0 para desativar redirecionamentos.", + acceptedStatusCodesDescription: "Selecione os códigos de status que são considerados uma resposta bem-sucedida.", + passwordNotMatchMsg: "A senha repetida não corresponde.", + notificationDescription: "Atribuir uma notificação ao (s) monitor (es) para que funcione.", + keywordDescription: "Pesquisa a palavra-chave em html simples ou resposta JSON e diferencia maiúsculas de minúsculas", + pauseDashboardHome: "Pausa", + deleteMonitorMsg: "Tens a certeza de que queres excluir este monitor?", + deleteNotificationMsg: "Tems a certeza de que queres excluir esta notificação para todos os monitores?", + resolverserverDescription: "A Cloudflare é o servidor padrão, podes alterar o servidor resolvedor a qualquer momento.", + rrtypeDescription: "Seleciona o RR-Type que queres monitorar", + pauseMonitorMsg: "Tens a certeza que queres fazer uma pausa?", + enableDefaultNotificationDescription: "Para cada novo monitor, esta notificação estará activa por padrão. Podes também desativar a notificação separadamente para cada monitor.", + clearEventsMsg: "Tens a certeza que queres excluir todos os eventos deste monitor?", + clearHeartbeatsMsg: "Tens a certeza de que queres excluir todos os heartbeats deste monitor?", + confirmClearStatisticsMsg: "Tens a certeza que queres excluir TODAS as estatísticas?", + importHandleDescription: "Escolha 'Ignorar existente' se quiseres ignorar todos os monitores ou notificações com o mesmo nome. 'Substituir' excluirá todos os monitores e notificações existentes.", + confirmImportMsg: "Tens a certeza que queres importar o backup? Certifique-se que selecionou a opção de importação correta.", + twoFAVerifyLabel: "Insire o teu token para verificar se 2FA está a funcionar", + tokenValidSettingsMsg: "O token é válido! Agora podes salvar as configurações 2FA.", + confirmEnableTwoFAMsg: "Tens a certeza de que queres habilitar 2FA?", + confirmDisableTwoFAMsg: "Tens a certeza de que queres desativar 2FA?", + Settings: "Configurações", + Dashboard: "Dashboard", + "New Update": "Nova Atualização", + Language: "Linguagem", + Appearance: "Aparência", + Theme: "Tema", + General: "Geral", + Version: "Versão", + "Check Update On GitHub": "Verificar atualização no Github", + List: "Lista", + Add: "Adicionar", + "Add New Monitor": "Adicionar novo monitor", + "Quick Stats": "Estatísticas rápidas", + Up: "On", + Down: "Off", + Pending: "Pendente", + Unknown: "Desconhecido", + Pause: "Pausa", + Name: "Nome", + Status: "Status", + DateTime: "Data hora", + Message: "Mensagem", + "No important events": "Nenhum evento importante", + Resume: "Resumo", + Edit: "Editar", + Delete: "Apagar", + Current: "Atual", + Uptime: "Tempo de atividade", + "Cert Exp.": "Cert Exp.", + day: "dia | dias", + "-day": "-dia", + hour: "hora", + "-hour": "-hora", + Response: "Resposta", + Ping: "Ping", + "Monitor Type": "Tipo de Monitor", + Keyword: "Palavra-Chave", + "Friendly Name": "Nome Amigável", + URL: "URL", + Hostname: "Hostname", + Port: "Porta", + "Heartbeat Interval": "Intervalo de Heartbeat", + Retries: "Novas tentativas", + "Heartbeat Retry Interval": "Intervalo de repetição de Heartbeat", + Advanced: "Avançado", + "Upside Down Mode": "Modo de cabeça para baixo", + "Max. Redirects": "Redirecionamento Máx.", + "Accepted Status Codes": "Status Code Aceitáveis", + Save: "Guardar", + Notifications: "Notificações", + "Not available, please setup.": "Não disponível, por favor configure.", + "Setup Notification": "Configurar Notificação", + Light: "Claro", + Dark: "Escuro", + Auto: "Auto", + "Theme - Heartbeat Bar": "Tema - Barra de Heartbeat", + Normal: "Normal", + Bottom: "Inferior", + None: "Nenhum", + Timezone: "Fuso horário", + "Search Engine Visibility": "Visibilidade do mecanismo de pesquisa", + "Allow indexing": "Permitir Indexação", + "Discourage search engines from indexing site": "Desencorar que motores de busca indexem o site", + "Change Password": "Mudar senha", + "Current Password": "Senha atual", + "New Password": "Nova Senha", + "Repeat New Password": "Repetir Nova Senha", + "Update Password": "Atualizar Senha", + "Disable Auth": "Desativar Autenticação", + "Enable Auth": "Ativar Autenticação", + "disableauth.message1": "Tens a certeza que queres <strong>desativar a autenticação</strong>?", + "disableauth.message2": "Isso é para <strong>alguém que tem autenticação de terceiros</strong> em frente ao 'UpTime Kuma' como o Cloudflare Access.", + "Please use this option carefully!": "Por favor, utilize isso com cautela.", + Logout: "Deslogar", + Leave: "Sair", + "I understand, please disable": "Eu entendo, por favor desative.", + Confirm: "Confirmar", + Yes: "Sim", + No: "Não", + Username: "Usuário", + Password: "Senha", + "Remember me": "Lembre-me", + Login: "Autenticar", + "No Monitors, please": "Nenhum monitor, por favor", + "add one": "adicionar um", + "Notification Type": "Tipo de Notificação", + Email: "Email", + Test: "Testar", + "Certificate Info": "Info. do Certificado ", + "Resolver Server": "Resolver Servidor", + "Resource Record Type": "Tipo de registro de aplicação", + "Last Result": "Último resultado", + "Create your admin account": "Crie sua conta de admin", + "Repeat Password": "Repita a senha", + "Import Backup": "Importar Backup", + "Export Backup": "Exportar Backup", + Export: "Exportar", + Import: "Importar", + respTime: "Tempo de Resp. (ms)", + notAvailableShort: "N/A", + "Default enabled": "Padrão habilitado", + "Apply on all existing monitors": "Aplicar em todos os monitores existentes", + Create: "Criar", + "Clear Data": "Limpar Dados", + Events: "Eventos", + Heartbeats: "Heartbeats", + "Auto Get": "Obter Automático", + backupDescription: "Podes fazer backup de todos os monitores e todas as notificações em um arquivo JSON.", + backupDescription2: "OBS: Os dados do histórico e do evento não estão incluídos.", + backupDescription3: "Dados confidenciais, como tokens de notificação, estão incluídos no arquivo de exportação, mantenha-o com cuidado.", + alertNoFile: "Selecione um arquivo para importar.", + alertWrongFileType: "Selecione um arquivo JSON.", + "Clear all statistics": "Limpar todas as estatísticas", + "Skip existing": "Saltar existente", + Overwrite: "Sobrescrever", + Options: "Opções", + "Keep both": "Manter os dois", + "Verify Token": "Verificar Token", + "Setup 2FA": "Configurar 2FA", + "Enable 2FA": "Ativar 2FA", + "Disable 2FA": "Desativar 2FA", + "2FA Settings": "Configurações do 2FA ", + "Two Factor Authentication": "Autenticação e Dois Fatores", + Active: "Ativo", + Inactive: "Inativo", + Token: "Token", + "Show URI": "Mostrar URI", + Tags: "Tag", + "Add New below or Select...": "Adicionar Novo abaixo ou Selecionar ...", + "Tag with this name already exist.": "Já existe uma etiqueta com este nome.", + "Tag with this value already exist.": "Já existe uma etiqueta com este valor.", + color: "cor", + "value (optional)": "valor (opcional)", + Gray: "Cinza", + Red: "Vermelho", + Orange: "Laranja", + Green: "Verde", + Blue: "Azul", + Indigo: "Índigo", + Purple: "Roxo", + Pink: "Rosa", + "Search...": "Pesquisa...", + "Avg. Ping": "Ping Médio.", + "Avg. Response": "Resposta Média. ", + "Status Page": "Página de Status", + "Status Pages": "Página de Status", + "Entry Page": "Página de entrada", + statusPageNothing: "Nada aqui, por favor, adicione um grupo ou monitor.", + "No Services": "Nenhum Serviço", + "All Systems Operational": "Todos os Serviços Operacionais", + "Partially Degraded Service": "Serviço parcialmente degradados", + "Degraded Service": "Serviço Degradado", + "Add Group": "Adicionar Grupo", + "Add a monitor": "Adicionar um monitor", + "Edit Status Page": "Editar Página de Status", + "Go to Dashboard": "Ir para o dashboard", + telegram: "Telegram", + webhook: "Webhook", + smtp: "Email (SMTP)", + discord: "Discord", + teams: "Microsoft Teams", + signal: "Signal", + gotify: "Gotify", + slack: "Slack", + "rocket.chat": "Rocket.chat", + pushover: "Pushover", + pushy: "Pushy", + octopush: "Octopush", + promosms: "PromoSMS", + lunasea: "LunaSea", + apprise: "Apprise (Support 50+ Notification services)", + pushbullet: "Pushbullet", + line: "Line Messenger", + mattermost: "Mattermost", +}; From 2ccf1fe41b5fa4aa4235f626a6ce6673bfad7076 Mon Sep 17 00:00:00 2001 From: Mario Garrido <mariogarrido@7graus.com> Date: Fri, 22 Jul 2022 15:42:38 +0100 Subject: [PATCH 67/99] fix: small changes in semantics --- src/languages/pt-PT.js | 54 +++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/languages/pt-PT.js b/src/languages/pt-PT.js index ac452569..21e68d26 100644 --- a/src/languages/pt-PT.js +++ b/src/languages/pt-PT.js @@ -6,24 +6,24 @@ export default { ignoreTLSError: "Ignorar erros TLS/SSL para sites HTTPS", upsideDownModeDescription: "Inverte o status de cabeça para baixo. Se o serviço estiver acessível, ele está OFFLINE.", maxRedirectDescription: "Número máximo de redirecionamentos a seguir. Define como 0 para desativar redirecionamentos.", - acceptedStatusCodesDescription: "Selecione os códigos de status que são considerados uma resposta bem-sucedida.", + acceptedStatusCodesDescription: "Seleciona os códigos de status que são considerados uma resposta bem-sucedida.", passwordNotMatchMsg: "A senha repetida não corresponde.", notificationDescription: "Atribuir uma notificação ao (s) monitor (es) para que funcione.", - keywordDescription: "Pesquisa a palavra-chave em html simples ou resposta JSON e diferencia maiúsculas de minúsculas", + keywordDescription: "Pesquisa a palavra-chave em HTML simples ou resposta JSON e diferencia maiúsculas de minúsculas", pauseDashboardHome: "Pausa", deleteMonitorMsg: "Tens a certeza de que queres excluir este monitor?", - deleteNotificationMsg: "Tems a certeza de que queres excluir esta notificação para todos os monitores?", - resolverserverDescription: "A Cloudflare é o servidor padrão, podes alterar o servidor resolvedor a qualquer momento.", - rrtypeDescription: "Seleciona o RR-Type que queres monitorar", + deleteNotificationMsg: "Tens a certeza de que queres excluir esta notificação para todos os monitores?", + resolverserverDescription: "A Cloudflare é o servidor padrão, podes alterar o servidor 'resolvedor' a qualquer momento.", + rrtypeDescription: "Seleciona o RR-Type que queres monitorizar", pauseMonitorMsg: "Tens a certeza que queres fazer uma pausa?", - enableDefaultNotificationDescription: "Para cada novo monitor, esta notificação estará activa por padrão. Podes também desativar a notificação separadamente para cada monitor.", + enableDefaultNotificationDescription: "Para cada monitor novo esta notificação vai estar activa por padrão. Podes também desativar a notificação separadamente para cada monitor.", clearEventsMsg: "Tens a certeza que queres excluir todos os eventos deste monitor?", clearHeartbeatsMsg: "Tens a certeza de que queres excluir todos os heartbeats deste monitor?", confirmClearStatisticsMsg: "Tens a certeza que queres excluir TODAS as estatísticas?", - importHandleDescription: "Escolha 'Ignorar existente' se quiseres ignorar todos os monitores ou notificações com o mesmo nome. 'Substituir' excluirá todos os monitores e notificações existentes.", - confirmImportMsg: "Tens a certeza que queres importar o backup? Certifique-se que selecionou a opção de importação correta.", - twoFAVerifyLabel: "Insire o teu token para verificar se 2FA está a funcionar", - tokenValidSettingsMsg: "O token é válido! Agora podes salvar as configurações 2FA.", + importHandleDescription: "Escolhe 'Ignorar existente' se quiseres ignorar todos os monitores ou notificações com o mesmo nome. 'Substituir' excluirá todos os monitores e notificações existentes.", + confirmImportMsg: "Tens a certeza que queres importar o backup? Certifica-te que selecionaste a opção de importação correta.", + twoFAVerifyLabel: "Insire o teu token para verificares se o 2FA está a funcionar", + tokenValidSettingsMsg: "O token é válido! Agora podes salvar as configurações do 2FA.", confirmEnableTwoFAMsg: "Tens a certeza de que queres habilitar 2FA?", confirmDisableTwoFAMsg: "Tens a certeza de que queres desativar 2FA?", Settings: "Configurações", @@ -67,16 +67,16 @@ export default { URL: "URL", Hostname: "Hostname", Port: "Porta", - "Heartbeat Interval": "Intervalo de Heartbeat", + "Heartbeat Interval": "Intervalo de Heartbeats", Retries: "Novas tentativas", - "Heartbeat Retry Interval": "Intervalo de repetição de Heartbeat", + "Heartbeat Retry Interval": "Intervalo de repetição de Heartbeats", Advanced: "Avançado", "Upside Down Mode": "Modo de cabeça para baixo", "Max. Redirects": "Redirecionamento Máx.", "Accepted Status Codes": "Status Code Aceitáveis", Save: "Guardar", Notifications: "Notificações", - "Not available, please setup.": "Não disponível, por favor configure.", + "Not available, please setup.": "Não disponível, por favor configura.", "Setup Notification": "Configurar Notificação", Light: "Claro", Dark: "Escuro", @@ -88,7 +88,7 @@ export default { Timezone: "Fuso horário", "Search Engine Visibility": "Visibilidade do mecanismo de pesquisa", "Allow indexing": "Permitir Indexação", - "Discourage search engines from indexing site": "Desencorar que motores de busca indexem o site", + "Discourage search engines from indexing site": "Desencorajar que motores de busca indexem o site", "Change Password": "Mudar senha", "Current Password": "Senha atual", "New Password": "Nova Senha", @@ -98,16 +98,16 @@ export default { "Enable Auth": "Ativar Autenticação", "disableauth.message1": "Tens a certeza que queres <strong>desativar a autenticação</strong>?", "disableauth.message2": "Isso é para <strong>alguém que tem autenticação de terceiros</strong> em frente ao 'UpTime Kuma' como o Cloudflare Access.", - "Please use this option carefully!": "Por favor, utilize isso com cautela.", - Logout: "Deslogar", + "Please use this option carefully!": "Por favor, utiliza esta opção com cuidado.", + Logout: "Logout", Leave: "Sair", - "I understand, please disable": "Eu entendo, por favor desative.", + "I understand, please disable": "Eu entendo, por favor desativa.", Confirm: "Confirmar", Yes: "Sim", No: "Não", - Username: "Usuário", + Username: "Utilizador", Password: "Senha", - "Remember me": "Lembre-me", + "Remember me": "Lembra-me", Login: "Autenticar", "No Monitors, please": "Nenhum monitor, por favor", "add one": "adicionar um", @@ -118,8 +118,8 @@ export default { "Resolver Server": "Resolver Servidor", "Resource Record Type": "Tipo de registro de aplicação", "Last Result": "Último resultado", - "Create your admin account": "Crie sua conta de admin", - "Repeat Password": "Repita a senha", + "Create your admin account": "Cria a tua conta de admin", + "Repeat Password": "Repete a senha", "Import Backup": "Importar Backup", "Export Backup": "Exportar Backup", Export: "Exportar", @@ -133,11 +133,11 @@ export default { Events: "Eventos", Heartbeats: "Heartbeats", "Auto Get": "Obter Automático", - backupDescription: "Podes fazer backup de todos os monitores e todas as notificações em um arquivo JSON.", + backupDescription: "Podes fazer backup de todos os monitores e todas as notificações num arquivo JSON.", backupDescription2: "OBS: Os dados do histórico e do evento não estão incluídos.", - backupDescription3: "Dados confidenciais, como tokens de notificação, estão incluídos no arquivo de exportação, mantenha-o com cuidado.", - alertNoFile: "Selecione um arquivo para importar.", - alertWrongFileType: "Selecione um arquivo JSON.", + backupDescription3: "Dados confidenciais, como tokens de notificação, estão incluídos no arquivo de exportação, mantem-no com cuidado.", + alertNoFile: "Seleciona um arquivo para importar.", + alertWrongFileType: "Seleciona um arquivo JSON.", "Clear all statistics": "Limpar todas as estatísticas", "Skip existing": "Saltar existente", Overwrite: "Sobrescrever", @@ -148,7 +148,7 @@ export default { "Enable 2FA": "Ativar 2FA", "Disable 2FA": "Desativar 2FA", "2FA Settings": "Configurações do 2FA ", - "Two Factor Authentication": "Autenticação e Dois Fatores", + "Two Factor Authentication": "Autenticação de Dois Fatores", Active: "Ativo", Inactive: "Inativo", Token: "Token", @@ -173,7 +173,7 @@ export default { "Status Page": "Página de Status", "Status Pages": "Página de Status", "Entry Page": "Página de entrada", - statusPageNothing: "Nada aqui, por favor, adicione um grupo ou monitor.", + statusPageNothing: "Nada aqui, por favor, adiciona um grupo ou monitor.", "No Services": "Nenhum Serviço", "All Systems Operational": "Todos os Serviços Operacionais", "Partially Degraded Service": "Serviço parcialmente degradados", From 239611a016a85712305100818d4c7b88a14664a9 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Fri, 22 Jul 2022 23:27:02 +0800 Subject: [PATCH 68/99] Do not set sendUrl if sendUrl is undefined --- package-lock.json | 2 +- server/socket-handlers/status-page-socket-handler.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e64f9fa7..d76f5a94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "badge-maker": "^3.3.1", "bcryptjs": "~2.4.3", "bree": "~7.1.5", - "cacheable-lookup": "^6.0.4", + "cacheable-lookup": "~6.0.4", "chardet": "^1.3.0", "check-password-strength": "^2.0.5", "cheerio": "^1.0.0-rc.10", diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js index 80017e7d..16d6ee73 100644 --- a/server/socket-handlers/status-page-socket-handler.js +++ b/server/socket-handlers/status-page-socket-handler.js @@ -202,7 +202,11 @@ module.exports.statusPageSocketHandler = (socket) => { relationBean.weight = monitorOrder++; relationBean.group_id = groupBean.id; relationBean.monitor_id = monitor.id; - relationBean.send_url = monitor.sendUrl; + + if (monitor.sendUrl !== undefined) { + relationBean.send_url = monitor.sendUrl; + } + await R.store(relationBean); } From 0d098b0958048ccf9503049a4436b9a4f758e4d8 Mon Sep 17 00:00:00 2001 From: c0derMo <jaydeveloper@outlook.de> Date: Fri, 22 Jul 2022 15:47:04 +0000 Subject: [PATCH 69/99] Docker Hosts are now a table & have their own dialog --- db/patch-add-docker-columns.sql | 13 +- server/client.js | 20 +++ server/docker.js | 67 ++++++++ server/model/docker_host.js | 19 +++ server/model/monitor.js | 13 +- server/server.js | 8 +- .../socket-handlers/docker-socket-handler.js | 67 ++++++++ src/components/DockerHostDialog.vue | 160 ++++++++++++++++++ src/mixins/socket.js | 5 + src/pages/EditMonitor.vue | 44 +++-- 10 files changed, 385 insertions(+), 31 deletions(-) create mode 100644 server/docker.js create mode 100644 server/model/docker_host.js create mode 100644 server/socket-handlers/docker-socket-handler.js create mode 100644 src/components/DockerHostDialog.vue diff --git a/db/patch-add-docker-columns.sql b/db/patch-add-docker-columns.sql index 56475667..4cea448d 100644 --- a/db/patch-add-docker-columns.sql +++ b/db/patch-add-docker-columns.sql @@ -1,13 +1,18 @@ -- You should not modify if this have pushed to Github, unless it does serious wrong with the db. BEGIN TRANSACTION; +CREATE TABLE docker_host ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + user_id INT NOT NULL, + docker_daemon VARCHAR(255), + docker_type VARCHAR(255), + name VARCHAR(255) +); + ALTER TABLE monitor - ADD docker_daemon VARCHAR(255); + ADD docker_host INTEGER REFERENCES docker_host(id); ALTER TABLE monitor ADD docker_container VARCHAR(255); -ALTER TABLE monitor - ADD docker_type VARCHAR(255); - COMMIT; diff --git a/server/client.js b/server/client.js index f6f133d1..61403842 100644 --- a/server/client.js +++ b/server/client.js @@ -122,10 +122,30 @@ async function sendInfo(socket) { }); } +async function sendDockerHostList(socket) { + const timeLogger = new TimeLogger(); + + let result = []; + let list = await R.find("docker_host", " user_id = ? ", [ + socket.userID, + ]); + + for (let bean of list) { + result.push(bean.export()); + } + + io.to(socket.userID).emit("dockerHostList", result); + + timeLogger.print("Send Docker Host List"); + + return list; +} + module.exports = { sendNotificationList, sendImportantHeartbeatList, sendHeartbeatList, sendProxyList, sendInfo, + sendDockerHostList }; diff --git a/server/docker.js b/server/docker.js new file mode 100644 index 00000000..a13236aa --- /dev/null +++ b/server/docker.js @@ -0,0 +1,67 @@ +const axios = require("axios"); +const { R } = require("redbean-node"); +const version = require("../package.json").version; +const https = require("https"); + +class DockerHost { + static async save(dockerHost, dockerHostID, userID) { + let bean; + + if (dockerHostID) { + bean = await R.findOne("docker_host", " id = ? AND user_id = ? ", [ dockerHostID, userID ]); + + if (!bean) { + throw new Error("docker host not found"); + } + + } else { + bean = R.dispense("docker_host"); + } + + bean.user_id = userID; + bean.docker_daemon = dockerHost.docker_daemon; + bean.docker_type = dockerHost.docker_type; + bean.name = dockerHost.name; + + await R.store(bean); + + return bean; + } + + static async delete(dockerHostID, userID) { + let bean = await R.findOne("docker_host", " id = ? AND user_id = ? ", [ dockerHostID, userID ]); + + if (!bean) { + throw new Error("docker host not found"); + } + + await R.trash(bean); + } + + static async getAmountContainer(dockerHost) { + const options = { + url: "/containers/json?all=true", + headers: { + "Accept": "*/*", + "User-Agent": "Uptime-Kuma/" + version + }, + httpsAgent: new https.Agent({ + maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940) + rejectUnauthorized: false, + }), + }; + + if (dockerHost.docker_type === "socket") { + options.socketPath = dockerHost.docker_daemon; + } else if (dockerHost.docker_type === "tcp") { + options.baseURL = dockerHost.docker_daemon; + } + + let res = await axios.request(options); + return res.data.length; + } +} + +module.exports = { + DockerHost, +} \ No newline at end of file diff --git a/server/model/docker_host.js b/server/model/docker_host.js new file mode 100644 index 00000000..26f3035a --- /dev/null +++ b/server/model/docker_host.js @@ -0,0 +1,19 @@ +const { BeanModel } = require("redbean-node/dist/bean-model"); + +class DockerHost extends BeanModel { + /** + * Returns an object that ready to parse to JSON + * @returns {Object} + */ + toJSON() { + return { + id: this._id, + userId: this._user_id, + daemon: this._dockerDaemon, + type: this._dockerType, + name: this._name, + } + } +} + +module.exports = DockerHost; \ No newline at end of file diff --git a/server/model/monitor.js b/server/model/monitor.js index eff167c6..373796e9 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -89,8 +89,7 @@ class Monitor extends BeanModel { dns_last_result: this.dns_last_result, pushToken: this.pushToken, docker_container: this.docker_container, - docker_daemon: this.docker_daemon, - docker_type: this.docker_type, + docker_host: this.docker_host, proxyId: this.proxy_id, notificationIDList, tags: tags, @@ -471,6 +470,8 @@ class Monitor extends BeanModel { } else if (this.type === "docker") { log.debug(`[${this.name}] Prepare Options for Axios`); + const docker_host = await R.load("docker_host", this.docker_host); + const options = { url: `/containers/${this.docker_container}/json`, headers: { @@ -483,10 +484,10 @@ class Monitor extends BeanModel { }), }; - if (this.docker_type === "socket") { - options.socketPath = this.docker_daemon; - } else if (this.docker_type === "tcp") { - options.baseURL = this.docker_daemon; + if (docker_host._dockerType === "socket") { + options.socketPath = docker_host._dockerDaemon; + } else if (docker_host._dockerType === "tcp") { + options.baseURL = docker_host._dockerDaemon; } log.debug(`[${this.name}] Axios Request`); diff --git a/server/server.js b/server/server.js index 71a9a7b5..1e566148 100644 --- a/server/server.js +++ b/server/server.js @@ -118,13 +118,14 @@ if (config.demoMode) { } // Must be after io instantiation -const { sendNotificationList, sendHeartbeatList, sendImportantHeartbeatList, sendInfo, sendProxyList } = require("./client"); +const { sendNotificationList, sendHeartbeatList, sendImportantHeartbeatList, sendInfo, sendProxyList, sendDockerHostList } = require("./client"); const { statusPageSocketHandler } = require("./socket-handlers/status-page-socket-handler"); const databaseSocketHandler = require("./socket-handlers/database-socket-handler"); const TwoFA = require("./2fa"); const StatusPage = require("./model/status_page"); const { cloudflaredSocketHandler, autoStart: cloudflaredAutoStart, stop: cloudflaredStop } = require("./socket-handlers/cloudflared-socket-handler"); const { proxySocketHandler } = require("./socket-handlers/proxy-socket-handler"); +const { dockerSocketHandler } = require("./socket-handlers/docker-socket-handler"); app.use(express.json()); @@ -665,8 +666,7 @@ let needSetup = false; bean.dns_resolve_server = monitor.dns_resolve_server; bean.pushToken = monitor.pushToken; bean.docker_container = monitor.docker_container; - bean.docker_daemon = monitor.docker_daemon; - bean.docker_type = monitor.docker_type; + bean.docker_host = monitor.docker_host; bean.proxyId = Number.isInteger(monitor.proxyId) ? monitor.proxyId : null; bean.mqttUsername = monitor.mqttUsername; bean.mqttPassword = monitor.mqttPassword; @@ -1425,6 +1425,7 @@ let needSetup = false; cloudflaredSocketHandler(socket); databaseSocketHandler(socket); proxySocketHandler(socket); + dockerSocketHandler(socket); log.debug("server", "added all socket handlers"); @@ -1525,6 +1526,7 @@ async function afterLogin(socket, user) { let monitorList = await server.sendMonitorList(socket); sendNotificationList(socket); sendProxyList(socket); + sendDockerHostList(socket); await sleep(500); diff --git a/server/socket-handlers/docker-socket-handler.js b/server/socket-handlers/docker-socket-handler.js new file mode 100644 index 00000000..eddcd7b8 --- /dev/null +++ b/server/socket-handlers/docker-socket-handler.js @@ -0,0 +1,67 @@ +const { sendDockerHostList } = require("../client"); +const { checkLogin } = require("../util-server"); +const { DockerHost } = require("../docker"); + +module.exports.dockerSocketHandler = (socket) => { + socket.on("addDockerHost", async (dockerHost, dockerHostID, callback) => { + try { + checkLogin(socket); + + let dockerHostBean = await DockerHost.save(dockerHost, dockerHostID, socket.userID); + await sendDockerHostList(socket); + + callback({ + ok: true, + msg: "Saved", + id: dockerHostBean.id, + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }) + } + }); + + socket.on("deleteDockerHost", async (dockerHostID, callback) => { + try { + checkLogin(socket); + + await DockerHost.delete(dockerHostID, socket.userID); + await sendDockerHostList(socket); + + callback({ + ok: true, + msg: "Deleted", + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }) + } + }); + + socket.on("testDockerHost", async (dockerHost, callback) => { + try { + checkLogin(socket); + + let amount = await DockerHost.getAmountContainer(dockerHost); + + callback({ + ok: true, + msg: "Amount of containers: " + amount, + }); + + } catch (e) { + console.error(e); + + callback({ + ok: false, + msg: e.message, + }) + } + }) +} \ No newline at end of file diff --git a/src/components/DockerHostDialog.vue b/src/components/DockerHostDialog.vue new file mode 100644 index 00000000..e52c4ecf --- /dev/null +++ b/src/components/DockerHostDialog.vue @@ -0,0 +1,160 @@ +<template> + <form @submit.prevent="submit"> + <div ref="modal" class="modal fade" tabindex="-1" data-bs-backdrop="static"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h5 id="exampleModalLabel" class="modal-title"> + {{ $t("Setup Docker Host") }} + </h5> + <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" /> + </div> + <div class="modal-body"> + <div class="mb-3"> + <label for="docker-name" class="form-label">{{ $t("Friendly Name") }}</label> + <input id="docker-name" v-model="dockerHost.name" type="text" class="form-control" required> + </div> + + <div class="mb-3"> + <label for="docker-type" class="form-label">{{ $t("Connection Type") }}</label> + <select id="docker-type" v-model="dockerHost.dockerType" class="form-select"> + <option v-for="type in connectionTypes" :key="type" :value="type">{{ $t(type) }}</option> + </select> + </div> + + <div class="mb-3"> + <label for="docker-daemon" class="form-label">{{ $t("Docker Daemon") }}</label> + <input id="docker-daemon" v-model="dockerHost.dockerDaemon" type="text" class="form-control" required> + </div> + </div> + + <div class="modal-footer"> + <button v-if="id" type="button" class="btn btn-danger" :disabled="processing" @click="deleteConfirm"> + {{ $t("Delete") }} + </button> + <button type="button" class="btn btn-warning" :disabled="processing" @click="test"> + {{ $t("Test") }} + </button> + <button type="submit" class="btn btn-primary" :disabled="processing"> + <div v-if="processing" class="spinner-border spinner-border-sm me-1"></div> + {{ $t("Save") }} + </button> + </div> + </div> + </div> + </div> + </form> + + <Confirm ref="confirmDelete" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="deleteDockerHost"> + {{ $t("deleteDockerHostMsg") }} + </Confirm> +</template> + +<script lang="ts"> +import { Modal } from "bootstrap"; + +import Confirm from "./Confirm.vue"; + +export default { + components: { + Confirm, + }, + props: {}, + emits: [ "added" ], + data() { + return { + model: null, + processing: false, + id: null, + connectionTypes: ["socket", "tcp"], + dockerHost: { + name: "", + dockerDaemon: "", + dockerType: "", + // Do not set default value here, please scroll to show() + } + }; + }, + + mounted() { + this.modal = new Modal(this.$refs.modal); + }, + methods: { + + deleteConfirm() { + this.modal.hide(); + this.$refs.confirmDelete.show(); + }, + + show(dockerHostID) { + if (dockerHostID) { + this.id = dockerHostID; + + for (let n of this.$root.dockerHostList) { + if (n.id === dockerHostID) { + this.dockerHost = n; + break; + } + } + } else { + this.id = null; + this.dockerHost = { + name: "", + dockerType: "socket", + dockerDaemon: "/var/run/docker.sock", + }; + } + + this.modal.show(); + }, + + submit() { + this.processing = true; + this.$root.getSocket().emit("addDockerHost", this.dockerHost, this.id, (res) => { + this.$root.toastRes(res); + this.processing = false; + + if (res.ok) { + this.modal.hide(); + + // Emit added event, doesn't emit edit. + if (! this.id) { + this.$emit("added", res.id); + } + + } + }); + }, + + test() { + this.processing = true; + this.$root.getSocket().emit("testDockerHost", this.dockerHost, (res) => { + this.$root.toastRes(res); + this.processing = false; + }); + }, + + deleteDockerHost() { + this.processing = true; + this.$root.getSocket().emit("deleteDockerHost", this.id, (res) => { + this.$root.toastRes(res); + this.processing = false; + + if (res.ok) { + this.modal.hide(); + } + }); + }, + }, +}; +</script> + +<style lang="scss" scoped> +@import "../assets/vars.scss"; + +.dark { + .modal-dialog .form-text, .modal-dialog p { + color: $dark-font-color; + } +} +</style> diff --git a/src/mixins/socket.js b/src/mixins/socket.js index c54b573f..f6de82c2 100644 --- a/src/mixins/socket.js +++ b/src/mixins/socket.js @@ -39,6 +39,7 @@ export default { uptimeList: { }, tlsInfoList: {}, notificationList: [], + dockerHostList: [], statusPageListLoaded: false, statusPageList: [], proxyList: [], @@ -141,6 +142,10 @@ export default { }); }); + socket.on("dockerHostList", (data) => { + this.dockerHostList = data; + }) + socket.on("heartbeat", (data) => { if (! (data.monitorID in this.heartbeatList)) { this.heartbeatList[data.monitorID] = []; diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 60032459..5ff318bf 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -148,25 +148,25 @@ <input id="docker_container" v-model="monitor.docker_container" type="text" class="form-control" required> </div> - <!-- Docker Connection Type --> + <!-- Docker Host --> <!-- For Docker Type --> <div v-if="monitor.type === 'docker'" class="my-3"> - <label for="docker_type" class="form-label">{{ $t("Docker Type") }}</label> - <select id="docker_type" v-model="monitor.docker_type" class="form-select"> - <option value="socket"> - {{ $t("docker_socket") }} - </option> - <option value="tcp"> - {{ $t("docker_tcp") }} - </option> - </select> - </div> + <h2 class="mb-2">{{ $t("Docker Host") }}</h2> + <p v-if="$root.dockerHostList.length === 0"> + {{ $t("Not available, please setup.") }} + </p> - <!-- Docker Daemon --> - <!-- For Docker Type --> - <div v-if="monitor.type === 'docker'" class="my-3"> - <label for="docker_daemon" class="form-label">{{ $t("Docker Daemon") }}</label> - <input id="docker_daemon" v-model="monitor.docker_daemon" type="text" class="form-control" required> + <div class="mb-3"> + <label for="docker-host" class="form-label">{{ $t("Docker Host") }}</label> + <select id="docket-host" v-model="monitor.docker_host" class="form-select"> + <option v-for="host in $root.dockerHostList" :key="host.id" :value="host.id">{{ host.name }}</option> + </select> + <a href="#" @click="$refs.dockerHostDialog.show(monitor.docker_host)">{{ $t("Edit") }}</a> + </div> + + <button class="btn btn-primary me-2" type="button" @click="$refs.dockerHostDialog.show()"> + {{ $t("Setup Docker Host") }} + </button> </div> <!-- MQTT --> @@ -446,6 +446,7 @@ </form> <NotificationDialog ref="notificationDialog" @added="addedNotification" /> + <DockerHostDialog ref="dockerHostDialog" @added="addedDockerHost" /> <ProxyDialog ref="proxyDialog" @added="addedProxy" /> </div> </transition> @@ -456,6 +457,7 @@ import VueMultiselect from "vue-multiselect"; import { useToast } from "vue-toastification"; import CopyableInput from "../components/CopyableInput.vue"; import NotificationDialog from "../components/NotificationDialog.vue"; +import DockerHostDialog from "../components/DockerHostDialog.vue"; import ProxyDialog from "../components/ProxyDialog.vue"; import TagsManager from "../components/TagsManager.vue"; import { genSecret, isDev } from "../util.ts"; @@ -467,6 +469,7 @@ export default { ProxyDialog, CopyableInput, NotificationDialog, + DockerHostDialog, TagsManager, VueMultiselect, }, @@ -625,8 +628,7 @@ export default { dns_resolve_type: "A", dns_resolve_server: "1.1.1.1", docker_container: "", - docker_daemon: "/var/run/docker.sock", - docker_type: "socket", + docker_host: null, proxyId: null, mqttUsername: "", mqttPassword: "", @@ -740,6 +742,12 @@ export default { addedProxy(id) { this.monitor.proxyId = id; }, + + // Added a Docker Host Event + // Enable it if the Docker Host is added in EditMonitor.vue + addedDockerHost(id) { + this.monitor.docker_host = id; + } }, }; </script> From e356d5f62391fbcbaa523c291e2219372128ed7c Mon Sep 17 00:00:00 2001 From: c0derMo <jaydeveloper@outlook.de> Date: Fri, 22 Jul 2022 15:57:40 +0000 Subject: [PATCH 70/99] Fixing linting & adding documentation --- server/client.js | 5 +++++ server/docker.js | 20 ++++++++++++++++++- server/model/docker_host.js | 4 ++-- server/model/monitor.js | 10 +++++----- .../socket-handlers/docker-socket-handler.js | 14 ++++++++----- src/components/DockerHostDialog.vue | 2 +- src/mixins/socket.js | 2 +- 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/server/client.js b/server/client.js index 61403842..bda77642 100644 --- a/server/client.js +++ b/server/client.js @@ -122,6 +122,11 @@ async function sendInfo(socket) { }); } +/** + * Send list of docker hosts to client + * @param {Socket} socket Socket.io socket instance + * @returns {Promise<Bean[]>} + */ async function sendDockerHostList(socket) { const timeLogger = new TimeLogger(); diff --git a/server/docker.js b/server/docker.js index a13236aa..57e793ab 100644 --- a/server/docker.js +++ b/server/docker.js @@ -4,6 +4,13 @@ const version = require("../package.json").version; const https = require("https"); class DockerHost { + /** + * Save a docker host + * @param {Object} dockerHost Docker host to save + * @param {?number} dockerHostID ID of the docker host to update + * @param {number} userID ID of the user who adds the docker host + * @returns {Promise<Bean>} + */ static async save(dockerHost, dockerHostID, userID) { let bean; @@ -28,6 +35,12 @@ class DockerHost { return bean; } + /** + * Delete a Docker host + * @param {number} dockerHostID ID of the Docker host to delete + * @param {number} userID ID of the user who created the Docker host + * @returns {Promise<void>} + */ static async delete(dockerHostID, userID) { let bean = await R.findOne("docker_host", " id = ? AND user_id = ? ", [ dockerHostID, userID ]); @@ -38,6 +51,11 @@ class DockerHost { await R.trash(bean); } + /** + * Fetches the amount of containers on the Docker host + * @param {Object} dockerHost Docker host to check for + * @returns {number} Total amount of containers on the host + */ static async getAmountContainer(dockerHost) { const options = { url: "/containers/json?all=true", @@ -64,4 +82,4 @@ class DockerHost { module.exports = { DockerHost, -} \ No newline at end of file +}; diff --git a/server/model/docker_host.js b/server/model/docker_host.js index 26f3035a..229a9a52 100644 --- a/server/model/docker_host.js +++ b/server/model/docker_host.js @@ -12,8 +12,8 @@ class DockerHost extends BeanModel { daemon: this._dockerDaemon, type: this._dockerType, name: this._name, - } + }; } } -module.exports = DockerHost; \ No newline at end of file +module.exports = DockerHost; diff --git a/server/model/monitor.js b/server/model/monitor.js index 373796e9..babff876 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -470,7 +470,7 @@ class Monitor extends BeanModel { } else if (this.type === "docker") { log.debug(`[${this.name}] Prepare Options for Axios`); - const docker_host = await R.load("docker_host", this.docker_host); + const dockerHost = await R.load("docker_host", this.docker_host); const options = { url: `/containers/${this.docker_container}/json`, @@ -484,10 +484,10 @@ class Monitor extends BeanModel { }), }; - if (docker_host._dockerType === "socket") { - options.socketPath = docker_host._dockerDaemon; - } else if (docker_host._dockerType === "tcp") { - options.baseURL = docker_host._dockerDaemon; + if (dockerHost._dockerType === "socket") { + options.socketPath = dockerHost._dockerDaemon; + } else if (dockerHost._dockerType === "tcp") { + options.baseURL = dockerHost._dockerDaemon; } log.debug(`[${this.name}] Axios Request`); diff --git a/server/socket-handlers/docker-socket-handler.js b/server/socket-handlers/docker-socket-handler.js index eddcd7b8..7f3646bb 100644 --- a/server/socket-handlers/docker-socket-handler.js +++ b/server/socket-handlers/docker-socket-handler.js @@ -2,6 +2,10 @@ const { sendDockerHostList } = require("../client"); const { checkLogin } = require("../util-server"); const { DockerHost } = require("../docker"); +/** + * Handlers for docker hosts + * @param {Socket} socket Socket.io instance + */ module.exports.dockerSocketHandler = (socket) => { socket.on("addDockerHost", async (dockerHost, dockerHostID, callback) => { try { @@ -20,7 +24,7 @@ module.exports.dockerSocketHandler = (socket) => { callback({ ok: false, msg: e.message, - }) + }); } }); @@ -40,7 +44,7 @@ module.exports.dockerSocketHandler = (socket) => { callback({ ok: false, msg: e.message, - }) + }); } }); @@ -61,7 +65,7 @@ module.exports.dockerSocketHandler = (socket) => { callback({ ok: false, msg: e.message, - }) + }); } - }) -} \ No newline at end of file + }); +}; diff --git a/src/components/DockerHostDialog.vue b/src/components/DockerHostDialog.vue index e52c4ecf..d7cf2de0 100644 --- a/src/components/DockerHostDialog.vue +++ b/src/components/DockerHostDialog.vue @@ -66,7 +66,7 @@ export default { model: null, processing: false, id: null, - connectionTypes: ["socket", "tcp"], + connectionTypes: [ "socket", "tcp" ], dockerHost: { name: "", dockerDaemon: "", diff --git a/src/mixins/socket.js b/src/mixins/socket.js index f6de82c2..e2096b37 100644 --- a/src/mixins/socket.js +++ b/src/mixins/socket.js @@ -144,7 +144,7 @@ export default { socket.on("dockerHostList", (data) => { this.dockerHostList = data; - }) + }); socket.on("heartbeat", (data) => { if (! (data.monitorID in this.heartbeatList)) { From f1bcecb0c64c9197592f007faf8cdd755755d2c0 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Sun, 24 Jul 2022 14:08:03 +0800 Subject: [PATCH 71/99] Merge package-lock.json --- package-lock.json | 216 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) diff --git a/package-lock.json b/package-lock.json index d76f5a94..778e6bc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,6 +42,8 @@ "nodemailer": "~6.6.5", "notp": "~2.0.3", "password-hash": "~1.2.2", + "pg": "^8.7.3", + "pg-connection-string": "^2.5.0", "prom-client": "~13.2.0", "prometheus-api-metrics": "~3.2.1", "redbean-node": "0.1.4", @@ -4789,6 +4791,14 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, "node_modules/bulk-write-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/bulk-write-stream/-/bulk-write-stream-2.0.1.tgz", @@ -12488,6 +12498,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -12636,11 +12651,88 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "optional": true }, + "node_modules/pg": { + "version": "8.7.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz", + "integrity": "sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.5.1", + "pg-protocol": "^1.5.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "pg-native": ">=2.0.0" + }, + "peerDependenciesMeta": { + "pg-native": { + "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==" }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.1.tgz", + "integrity": "sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/pgpass/node_modules/split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -12896,6 +12988,41 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -20016,6 +20143,11 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, "bulk-write-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/bulk-write-stream/-/bulk-write-stream-2.0.1.tgz", @@ -25736,6 +25868,11 @@ "p-timeout": "^3.0.0" } }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -25845,11 +25982,67 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "optional": true }, + "pg": { + "version": "8.7.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz", + "integrity": "sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.5.1", + "pg-protocol": "^1.5.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, "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==" }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.1.tgz", + "integrity": "sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==" + }, + "pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "requires": { + "split2": "^4.1.0" + }, + "dependencies": { + "split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==" + } + } + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -26018,6 +26211,29 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", From fb3b407577b5b2c9e9b8e6a45d53a6b32caf8d7b Mon Sep 17 00:00:00 2001 From: c0derMo <jaydeveloper@outlook.de> Date: Sun, 24 Jul 2022 12:34:43 +0000 Subject: [PATCH 72/99] Added a settings page & localization --- server/docker.js | 3 ++ src/components/settings/Docker.vue | 50 ++++++++++++++++++++++++++++++ src/languages/en.js | 20 +++++++----- src/pages/EditMonitor.vue | 2 +- src/pages/Settings.vue | 3 ++ src/router.js | 5 +++ 6 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 src/components/settings/Docker.vue diff --git a/server/docker.js b/server/docker.js index 57e793ab..ed9e0854 100644 --- a/server/docker.js +++ b/server/docker.js @@ -48,6 +48,9 @@ class DockerHost { throw new Error("docker host not found"); } + // Delete removed proxy from monitors if exists + await R.exec("UPDATE monitor SET docker_host = null WHERE docker_host = ?", [ dockerHostID ]); + await R.trash(bean); } diff --git a/src/components/settings/Docker.vue b/src/components/settings/Docker.vue new file mode 100644 index 00000000..7b99bb8b --- /dev/null +++ b/src/components/settings/Docker.vue @@ -0,0 +1,50 @@ +<template> + <div> + <div class="dockerHost-list my-4"> + <p v-if="$root.dockerHostList.length === 0"> + {{ $t("Not available, please setup.") }} + </p> + + <ul class="list-group mb-3" style="border-radius: 1rem;"> + <li v-for="(dockerHost, index) in $root.dockerHostList" :key="index" class="list-group-item"> + {{ dockerHost.name }}<br> + <a href="#" @click="$refs.dockerHostDialog.show(dockerHost.id)">{{ $t("Edit") }}</a> + </li> + </ul> + + <button class="btn btn-primary me-2" type="button" @click="$refs.dockerHostDialog.show()"> + {{ $t("Setup Docker Host") }} + </button> + </div> + + <DockerHostDialog ref="dockerHostDialog" /> + </div> +</template> + +<script> +import DockerHostDialog from "../../components/DockerHostDialog.vue"; +import ActionInput from "../ActionInput.vue"; + +export default { + components: { + DockerHostDialog, + ActionInput, + }, + + data() { + return {}; + }, + + computed: { + settings() { + return this.$parent.$parent.$parent.settings; + }, + saveSettings() { + return this.$parent.$parent.$parent.saveSettings; + }, + settingsLoaded() { + return this.$parent.$parent.$parent.settingsLoaded; + }, + } +}; +</script> \ No newline at end of file diff --git a/src/languages/en.js b/src/languages/en.js index 37392a4f..c7e4b377 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -372,12 +372,6 @@ export default { smtpDkimHashAlgo: "Hash Algorithm (Optional)", smtpDkimheaderFieldNames: "Header Keys to sign (Optional)", smtpDkimskipFields: "Header Keys not to sign (Optional)", - "Container Name / ID": "Container Name / ID", - "Docker Daemon": "Docker Daemon", - "Docker Container": "Docker Container", - "Docker Type": "Connection Type", - docker_socket: "Socket", - docker_tcp: "TCP / HTTP", wayToGetPagerDutyKey: "You can get this by going to Service -> Service Directory -> (Select a service) -> Integrations -> Add integration. Here you can search for \"Events API V2\". More info {0}", "Integration Key": "Integration Key", "Integration URL": "Integration URL", @@ -487,7 +481,7 @@ export default { "Leave blank to use a shared sender number.": "Leave blank to use a shared sender number.", "Octopush API Version": "Octopush API Version", "Legacy Octopush-DM": "Legacy Octopush-DM", - "endpoint": "endpoint", + endpoint: "endpoint", octopushAPIKey: "\"API key\" from HTTP API credentials in control panel", octopushLogin: "\"Login\" from HTTP API credentials in control panel", promosmsLogin: "API Login Name", @@ -531,7 +525,17 @@ export default { "Coming Soon": "Coming Soon", wayToGetClickSendSMSToken: "You can get API Username and API Key from {0} .", "Connection String": "Connection String", - "Query": "Query", + Query: "Query", settingsCertificateExpiry: "TLS Certificate Expiry", certificationExpiryDescription: "HTTPS Monitors trigger notification when TLS certificate expires in:", + "Setup Docker Host": "Setup Docker Host", + "Connection Type": "Connection Type", + "Docker Daemon": "Docker Daemon", + deleteDockerHostMsg: "Are you sure want to delete this docker host for all monitors?", + socket: "Socket", + tcp: "TCP / HTTP", + "Docker Container": "Docker Container", + "Container Name / ID": "Container Name / ID", + "Docker Host": "Docker Host", + "Docker Hosts": "Docker Hosts" }; diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 5ff318bf..c93fa97d 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -156,7 +156,7 @@ {{ $t("Not available, please setup.") }} </p> - <div class="mb-3"> + <div class="mb-3" v-else> <label for="docker-host" class="form-label">{{ $t("Docker Host") }}</label> <select id="docket-host" v-model="monitor.docker_host" class="form-select"> <option v-for="host in $root.dockerHostList" :key="host.id" :value="host.id">{{ host.name }}</option> diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index 54d15009..d8ebc26e 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -89,6 +89,9 @@ export default { "monitor-history": { title: this.$t("Monitor History"), }, + "docker-hosts": { + title: this.$t("Docker Hosts"), + }, security: { title: this.$t("Security"), }, diff --git a/src/router.js b/src/router.js index 72619477..7d29a188 100644 --- a/src/router.js +++ b/src/router.js @@ -25,6 +25,7 @@ const Security = () => import("./components/settings/Security.vue"); import Proxies from "./components/settings/Proxies.vue"; import Backup from "./components/settings/Backup.vue"; import About from "./components/settings/About.vue"; +import DockerHosts from "./components/settings/Docker.vue"; const routes = [ { @@ -95,6 +96,10 @@ const routes = [ path: "monitor-history", component: MonitorHistory, }, + { + path: "docker-hosts", + component: DockerHosts, + }, { path: "security", component: Security, From 13f7db655b9d2b718a65a3902406c79066090f85 Mon Sep 17 00:00:00 2001 From: __filename <63600304+ankhgerel@users.noreply.github.com> Date: Sun, 24 Jul 2022 20:44:43 +0800 Subject: [PATCH 73/99] chore(locale): change some typo ko-KR --- src/languages/ko-KR.js | 52 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/languages/ko-KR.js b/src/languages/ko-KR.js index dbb02e65..4d1d6194 100644 --- a/src/languages/ko-KR.js +++ b/src/languages/ko-KR.js @@ -3,7 +3,7 @@ export default { checkEverySecond: "{0}초마다 확인해요.", retryCheckEverySecond: "{0}초마다 다시 확인해요.", retriesDescription: "서비스가 중단된 후 알림을 보내기 전 최대 재시도 횟수", - ignoreTLSError: "HTTPS 웹사이트에서 TLS/SSL 에러 무시하기", + ignoreTLSError: "HTTPS 웹사이트에서 TLS/SSL 오류 무시하기", upsideDownModeDescription: "서버 상태를 반대로 표시해요. 서버가 작동하면 오프라인으로 표시할 거예요.", maxRedirectDescription: "최대 리다이렉트 횟수예요. 0을 입력하면 리다이렉트를 꺼요.", acceptedStatusCodesDescription: "응답 성공으로 간주할 상태 코드를 정해요.", @@ -30,7 +30,7 @@ export default { Dashboard: "대시보드", "New Update": "새로운 업데이트", Language: "언어", - Appearance: "외형", + Appearance: "디스플레이", Theme: "테마", General: "일반", Version: "버전", @@ -78,7 +78,7 @@ export default { Notifications: "알림", "Not available, please setup.": "존재하지 않아요, 새로운 거 하나 만드는 건 어때요?", "Setup Notification": "알림 설정", - Light: "라이트", + Light: "화이트", Dark: "다크", Auto: "자동", "Theme - Heartbeat Bar": "테마 - 하트비트 바", @@ -91,7 +91,7 @@ export default { "Discourage search engines from indexing site": "검색 엔진 인덱싱 거부", "Change Password": "비밀번호 변경", "Current Password": "기존 비밀번호", - "New Password": "새로운 비밀번호", + "New Password": "새 비밀번호", "Repeat New Password": "새로운 비밀번호 재입력", "Update Password": "비밀번호 변경", "Disable Auth": "인증 비활성화", @@ -109,14 +109,14 @@ export default { Password: "비밀번호", "Remember me": "비밀번호 기억하기", Login: "로그인", - "No Monitors, please": "모니터링이 없어요,", - "add one": "하나 추가해봐요", + "No Monitors, please": "모니터링이 현재 없어요,", + "add one": "한번 추가해보실레요?", "Notification Type": "알림 종류", Email: "이메일", Test: "테스트", "Certificate Info": "인증서 정보", "Resolver Server": "Resolver 서버", - "Resource Record Type": "자원 레코드 유형", + "Resource Record Type": "리소스 레코드 유형", "Last Result": "최근 결과", "Create your admin account": "관리자 계정 만들기", "Repeat Password": "비밀번호 재입력", @@ -208,19 +208,19 @@ export default { smtpBCC: "숨은 참조", discord: "Discord", "Discord Webhook URL": "Discord Webhook URL", - wayToGetDiscordURL: "서버 설정 -> 연동 -> 웹후크 보기 -> 새 웹후크에서 얻을 수 있어요.", + wayToGetDiscordURL: "서버 설정 -> 연동 -> 웹후크 보기 -> 새 웹후크에서 얻을 수 있어요!", "Bot Display Name": "표시 이름", "Prefix Custom Message": "접두사 메시지", "Hello @everyone is...": "{'@'}everyone 서버 상태 알림이에요...", teams: "Microsoft Teams", "Webhook URL": "Webhook URL", - wayToGetTeamsURL: "{0}에서 Webhook을 어떻게 만드는지 알아봐요.", + wayToGetTeamsURL: "{0}에서 Webhook을 어떻게 만드는지 알아보세요!", signal: "Signal", Number: "숫자", Recipients: "받는 사람", needSignalAPI: "REST API를 사용하는 Signal 클라이언트가 있어야 해요.", wayToCheckSignalURL: "밑에 URL을 확인해 URL 설정 방법을 볼 수 있어요.", - signalImportant: "중요: 받는 사람의 그룹과 숫자는 섞을 수 없어요!", + signalImportant: "경고: 받는 사람의 그룹과 숫자는 섞을 수 없어요!", gotify: "Gotify", "Application Token": "애플리케이션 토큰", "Server URL": "서버 URL", @@ -230,8 +230,8 @@ export default { "Channel Name": "채널 이름", "Uptime Kuma URL": "Uptime Kuma URL", aboutWebhooks: "Webhook에 대한 설명: {0}", - aboutChannelName: "Webhook 채널을 우회하려면 {0} 채널 이름칸에 채널 이름을 입력해주세요. 예: #기타-채널", - aboutKumaURL: "Uptime Kuma URL칸을 공백으로 두면 기본적으로 Project Github 페이지로 설정해요.", + aboutChannelName: "Webhook 채널을 무시하려면 {0} 채널 이름칸에 채널 이름을 입력해주세요. 예: #기타-채널", + aboutKumaURL: "Uptime Kuma URL칸을 공백으로 두면 기본적으로 Github Project 페이지로 설정해요.", emojiCheatSheet: "이모지 목록 시트: {0}", "rocket.chat": "Rocket.chat", pushover: "Pushover", @@ -243,8 +243,8 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", - "User Key": "사용자 키", - Device: "장치", + "User Key": "유저 키", + Device: "디바이스", "Message Title": "메시지 제목", "Notification Sound": "알림음", "More info on:": "자세한 정보: {0}", @@ -254,7 +254,7 @@ export default { octopushTypePremium: "프리미엄 (빠름) - 알림 기능에 적합해요)", octopushTypeLowCost: "저렴한 요금 (느림) - 가끔 차단될 수 있어요)", "Check octopush prices": "{0}에서 Octopush 가격을 확인할 수 있어요.", - octopushPhoneNumber: "휴대전화 번호 (intl format, eg : +33612345678) ", + octopushPhoneNumber: "휴대전화 번호 (intl format, 예시: +82 1023456789) ", octopushSMSSender: "보내는 사람 이름 : 3-11개의 영숫자 및 여백공간 (a-z, A-Z, 0-9)", "LunaSea Device ID": "LunaSea 장치 ID", "Apprise URL": "Apprise URL", @@ -324,17 +324,17 @@ export default { Content: "내용", Style: "스타일", info: "정보", - warning: "경고", - danger: "위험", + warning: "주의", + danger: "경고", primary: "기본", - light: "라이트", + light: "화이트", dark: "다크", - Post: "올리기", + Post: "게시", "Please input title and content": "제목과 내용을 작성해주세요.", Created: "생성 날짜", "Last Updated": "마지막 업데이트", Unpin: "제거", - "Switch to Light Theme": "라이트 테마로 전환", + "Switch to Light Theme": "화이트 테마로 전환", "Switch to Dark Theme": "다크 테마로 전환", "Show Tags": "태그 보이기", "Hide Tags": "태그 숨기기", @@ -361,8 +361,8 @@ export default { topicExplanation: "모니터링할 MQTT Topic", successMessage: "성공 메시지", successMessageExplanation: "성공으로 간주되는 MQTT 메시지", - error: "error", - critical: "critical", + error: "오류", + critical: "크리티컬", Customize: "커스터마이즈", "Custom Footer": "커스텀 Footer", "Custom CSS": "커스텀 CSS", @@ -406,7 +406,7 @@ export default { PhoneNumbers: "휴대전화 번호", TemplateCode: "템플릿 코드", SignName: "SignName", - "Sms template must contain parameters: ": "Sms 템플릿은 다음과 같은 파라미터가 포함되어야 해요:", + "Sms template must contain parameters: ": "SMS 템플릿은 다음과 같은 파라미터가 포함되어야 해요:", "Bark Endpoint": "Bark Endpoint", WebHookUrl: "웹훅 URL", SecretKey: "Secret Key", @@ -518,14 +518,14 @@ export default { "Show update if available": "사용 가능한 경우에 업데이트 표시", "Also check beta release": "베타 릴리즈 확인", "Using a Reverse Proxy?": "리버스 프록시를 사용하시나요?", - "Check how to config it for WebSocket": "웹소켓에 대한 설정 방법 확인", + "Check how to config it for WebSocket": "웹소켓 대한 설정 방법", "Steam Game Server": "스팀 게임 서버", "Most likely causes:": "원인:", - "The resource is no longer available.": "더이상 사용할 수 없어요.", + "The resource is no longer available.": "더이상 사용할 수 없어요...", "There might be a typing error in the address.": "주소에 오탈자가 있을 수 있어요.", "What you can try:": "해결 방법:", "Retype the address.": "주소 다시 입력하기", "Go back to the previous page.": "이전 페이지로 돌아가기", - "Coming Soon": "Coming Soon", + "Coming Soon": "Coming Soon...", wayToGetClickSendSMSToken: "{0}에서 API 사용자 이름과 키를 얻을 수 있어요.", }; From 1062e629c525d757a747b31bf2affa7cce168010 Mon Sep 17 00:00:00 2001 From: c0derMo <jaydeveloper@outlook.de> Date: Sun, 24 Jul 2022 12:50:43 +0000 Subject: [PATCH 74/99] Fix linting issues --- src/components/settings/Docker.vue | 4 +--- src/languages/en.js | 2 +- src/pages/EditMonitor.vue | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/settings/Docker.vue b/src/components/settings/Docker.vue index 7b99bb8b..c411c307 100644 --- a/src/components/settings/Docker.vue +++ b/src/components/settings/Docker.vue @@ -23,12 +23,10 @@ <script> import DockerHostDialog from "../../components/DockerHostDialog.vue"; -import ActionInput from "../ActionInput.vue"; export default { components: { DockerHostDialog, - ActionInput, }, data() { @@ -47,4 +45,4 @@ export default { }, } }; -</script> \ No newline at end of file +</script> diff --git a/src/languages/en.js b/src/languages/en.js index 60404da2..29d479c9 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -541,7 +541,7 @@ export default { "Docker Container": "Docker Container", "Container Name / ID": "Container Name / ID", "Docker Host": "Docker Host", - "Docker Hosts": "Docker Hosts" + "Docker Hosts": "Docker Hosts", "ntfy Topic": "ntfy Topic", "Domain": "Domain", "Workstation": "Workstation", diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index fd8788c3..ac6a3e2e 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -159,7 +159,7 @@ {{ $t("Not available, please setup.") }} </p> - <div class="mb-3" v-else> + <div v-else class="mb-3"> <label for="docker-host" class="form-label">{{ $t("Docker Host") }}</label> <select id="docket-host" v-model="monitor.docker_host" class="form-select"> <option v-for="host in $root.dockerHostList" :key="host.id" :value="host.id">{{ host.name }}</option> From 75f6ff8b587adb0efd96b1f3cfd88b4b5a430524 Mon Sep 17 00:00:00 2001 From: __filename <63600304+ankhgerel@users.noreply.github.com> Date: Mon, 25 Jul 2022 16:39:00 +0800 Subject: [PATCH 75/99] fix(locale): Edit multiple space Co-authored-by: Kyungyoon Kim <ruddbs5302@gmail.com> --- src/languages/ko-KR.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/ko-KR.js b/src/languages/ko-KR.js index 4d1d6194..570dc11a 100644 --- a/src/languages/ko-KR.js +++ b/src/languages/ko-KR.js @@ -231,7 +231,7 @@ export default { "Uptime Kuma URL": "Uptime Kuma URL", aboutWebhooks: "Webhook에 대한 설명: {0}", aboutChannelName: "Webhook 채널을 무시하려면 {0} 채널 이름칸에 채널 이름을 입력해주세요. 예: #기타-채널", - aboutKumaURL: "Uptime Kuma URL칸을 공백으로 두면 기본적으로 Github Project 페이지로 설정해요.", + aboutKumaURL: "Uptime Kuma URL칸을 공백으로 두면 기본적으로 Github Project 페이지로 설정해요.", emojiCheatSheet: "이모지 목록 시트: {0}", "rocket.chat": "Rocket.chat", pushover: "Pushover", From 694b4cadb33a19099451db3adbc0cd218cff4869 Mon Sep 17 00:00:00 2001 From: __filename <63600304+ankhgerel@users.noreply.github.com> Date: Mon, 25 Jul 2022 16:41:29 +0800 Subject: [PATCH 76/99] fix(locale): Edit typo Co-authored-by: Kyungyoon Kim <ruddbs5302@gmail.com> --- src/languages/ko-KR.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/ko-KR.js b/src/languages/ko-KR.js index 570dc11a..f44fbeee 100644 --- a/src/languages/ko-KR.js +++ b/src/languages/ko-KR.js @@ -521,7 +521,7 @@ export default { "Check how to config it for WebSocket": "웹소켓 대한 설정 방법", "Steam Game Server": "스팀 게임 서버", "Most likely causes:": "원인:", - "The resource is no longer available.": "더이상 사용할 수 없어요...", + "The resource is no longer available.": "더 이상 사용할 수 없어요...", "There might be a typing error in the address.": "주소에 오탈자가 있을 수 있어요.", "What you can try:": "해결 방법:", "Retype the address.": "주소 다시 입력하기", From b16cb6a337610564466dd4ca1ef7ffe199af020e Mon Sep 17 00:00:00 2001 From: __filename <63600304+ankhgerel@users.noreply.github.com> Date: Mon, 25 Jul 2022 20:11:51 +0800 Subject: [PATCH 77/99] fix(locale): Edit non-space place Co-authored-by: Kyungyoon Kim <ruddbs5302@gmail.com> --- src/languages/ko-KR.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/ko-KR.js b/src/languages/ko-KR.js index f44fbeee..f181389b 100644 --- a/src/languages/ko-KR.js +++ b/src/languages/ko-KR.js @@ -254,7 +254,7 @@ export default { octopushTypePremium: "프리미엄 (빠름) - 알림 기능에 적합해요)", octopushTypeLowCost: "저렴한 요금 (느림) - 가끔 차단될 수 있어요)", "Check octopush prices": "{0}에서 Octopush 가격을 확인할 수 있어요.", - octopushPhoneNumber: "휴대전화 번호 (intl format, 예시: +82 1023456789) ", + octopushPhoneNumber: "휴대전화 번호 (intl format, 예시: +821023456789) ", octopushSMSSender: "보내는 사람 이름 : 3-11개의 영숫자 및 여백공간 (a-z, A-Z, 0-9)", "LunaSea Device ID": "LunaSea 장치 ID", "Apprise URL": "Apprise URL", From d8253405b45147b6ad278ea5f5aa4c7e66149cf7 Mon Sep 17 00:00:00 2001 From: Mario Garrido <mariogarrido@7graus.com> Date: Tue, 26 Jul 2022 02:07:38 +0100 Subject: [PATCH 78/99] fix: add language to the language list --- src/i18n.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n.js b/src/i18n.js index d848cf3d..8495cd99 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -11,6 +11,7 @@ const languageList = { "es-ES": "Español", "eu": "Euskara", "fa": "Farsi", + "pt-PT": "Português (Portugal)", "pt-BR": "Português (Brasileiro)", "fr-FR": "Français (France)", "hu": "Magyar", From 4575f31094f4bdbbd8b10e3c913b783e7845a497 Mon Sep 17 00:00:00 2001 From: 0x01code <25381518+0x01code@users.noreply.github.com> Date: Fri, 29 Jul 2022 14:13:50 +0700 Subject: [PATCH 79/99] Add support for line notify providers (#1781) * add line notify support * add way to get line notify * Fix duplicate key 'HTTP Basic Auth' * Revert language files changes * Revert language files changes * Fix general message Co-authored-by: Louis Lam <louislam@users.noreply.github.com> --- server/notification-providers/linenotify.js | 43 +++++++++++++++++++++ server/notification.js | 2 + src/components/notifications/LineNotify.vue | 9 +++++ src/components/notifications/index.js | 2 + src/languages/en.js | 1 + src/languages/th-TH.js | 1 + 6 files changed, 58 insertions(+) create mode 100644 server/notification-providers/linenotify.js create mode 100644 src/components/notifications/LineNotify.vue diff --git a/server/notification-providers/linenotify.js b/server/notification-providers/linenotify.js new file mode 100644 index 00000000..8454152d --- /dev/null +++ b/server/notification-providers/linenotify.js @@ -0,0 +1,43 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); +const qs = require("qs"); +const { DOWN, UP } = require("../../src/util"); + +class LineNotify extends NotificationProvider { + + name = "LineNotify"; + + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + let okMsg = "Sent Successfully."; + try { + let lineAPIUrl = "https://notify-api.line.me/api/notify"; + let config = { + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "Authorization": "Bearer " + notification.lineNotifyAccessToken + } + }; + if (heartbeatJSON == null) { + let testMessage = { + "message": msg, + }; + await axios.post(lineAPIUrl, qs.stringify(testMessage), config); + } else if (heartbeatJSON["status"] === DOWN) { + let downMessage = { + "message": "\n[🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] + }; + await axios.post(lineAPIUrl, qs.stringify(downMessage), config); + } else if (heartbeatJSON["status"] === UP) { + let upMessage = { + "message": "\n[✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"] + }; + await axios.post(lineAPIUrl, qs.stringify(upMessage), config); + } + return okMsg; + } catch (error) { + this.throwGeneralAxiosError(error); + } + } +} + +module.exports = LineNotify; diff --git a/server/notification.js b/server/notification.js index a3b3a70b..ad1c8705 100644 --- a/server/notification.js +++ b/server/notification.js @@ -13,6 +13,7 @@ const GoogleChat = require("./notification-providers/google-chat"); const Gorush = require("./notification-providers/gorush"); const Gotify = require("./notification-providers/gotify"); const Line = require("./notification-providers/line"); +const LineNotify = require("./notification-providers/linenotify"); const LunaSea = require("./notification-providers/lunasea"); const Matrix = require("./notification-providers/matrix"); const Mattermost = require("./notification-providers/mattermost"); @@ -61,6 +62,7 @@ class Notification { new Gorush(), new Gotify(), new Line(), + new LineNotify(), new LunaSea(), new Matrix(), new Mattermost(), diff --git a/src/components/notifications/LineNotify.vue b/src/components/notifications/LineNotify.vue new file mode 100644 index 00000000..0f6897f4 --- /dev/null +++ b/src/components/notifications/LineNotify.vue @@ -0,0 +1,9 @@ +<template> + <div class="mb-3"> + <label for="line-notify-access-token" class="form-label">{{ $t("Access Token") }}</label> + <input id="line-notify-access-token" v-model="$parent.notification.lineNotifyAccessToken" type="text" class="form-control" :required="true"> + </div> + <i18n-t tag="div" keypath="wayToGetLineNotifyToken" class="form-text" style="margin-top: 8px;"> + <a href="https://notify-bot.line.me/" target="_blank">https://notify-bot.line.me/</a> + </i18n-t> +</template> diff --git a/src/components/notifications/index.js b/src/components/notifications/index.js index e5cbe8ce..c1b7da4a 100644 --- a/src/components/notifications/index.js +++ b/src/components/notifications/index.js @@ -11,6 +11,7 @@ import GoogleChat from "./GoogleChat.vue"; import Gorush from "./Gorush.vue"; import Gotify from "./Gotify.vue"; import Line from "./Line.vue"; +import LineNotify from "./LineNotify.vue"; import LunaSea from "./LunaSea.vue"; import Matrix from "./Matrix.vue"; import Mattermost from "./Mattermost.vue"; @@ -54,6 +55,7 @@ const NotificationFormList = { "gorush": Gorush, "gotify": Gotify, "line": Line, + "LineNotify": LineNotify, "lunasea": LunaSea, "matrix": Matrix, "mattermost": Mattermost, diff --git a/src/languages/en.js b/src/languages/en.js index 9aeedd9d..15bdcc8a 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -536,4 +536,5 @@ export default { "Domain": "Domain", "Workstation": "Workstation", disableCloudflaredNoAuthMsg: "You are in No Auth mode, password is not require.", + wayToGetLineNotifyToken: "You can get a access token from {0}", }; diff --git a/src/languages/th-TH.js b/src/languages/th-TH.js index a573206b..92c4eb80 100644 --- a/src/languages/th-TH.js +++ b/src/languages/th-TH.js @@ -518,4 +518,5 @@ export default { "Go back to the previous page.": "กลับไปที่หน้าก่อนหน้า", "Coming Soon": "เร็ว ๆ นี้", wayToGetClickSendSMSToken: "คุณสามารถรับ API Username และ API Key ได้จาก {0}", + wayToGetLineNotifyToken: "คุณสามารถรับ access token ได้จาก {0}", }; From f3322398e577c4ddf989daf12e2a366c6980d82b Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Fri, 29 Jul 2022 20:57:13 +0800 Subject: [PATCH 80/99] Fix and improve test docker host --- server/docker.js | 30 +++++++++++++++---- .../socket-handlers/docker-socket-handler.js | 14 +++++++-- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/server/docker.js b/server/docker.js index ed9e0854..1c939d64 100644 --- a/server/docker.js +++ b/server/docker.js @@ -59,7 +59,7 @@ class DockerHost { * @param {Object} dockerHost Docker host to check for * @returns {number} Total amount of containers on the host */ - static async getAmountContainer(dockerHost) { + static async testDockerHost(dockerHost) { const options = { url: "/containers/json?all=true", headers: { @@ -72,14 +72,32 @@ class DockerHost { }), }; - if (dockerHost.docker_type === "socket") { - options.socketPath = dockerHost.docker_daemon; - } else if (dockerHost.docker_type === "tcp") { - options.baseURL = dockerHost.docker_daemon; + if (dockerHost.dockerType === "socket") { + options.socketPath = dockerHost.dockerDaemon; + } else if (dockerHost.dockerType === "tcp") { + options.baseURL = dockerHost.dockerDaemon; } let res = await axios.request(options); - return res.data.length; + + if (Array.isArray(res.data)) { + + if (res.data.length > 1) { + + if ("ImageID" in res.data[0]) { + return res.data.length; + } else { + throw new Error("Invalid Docker response, is it Docker really a daemon?"); + } + + } else { + return res.data.length; + } + + } else { + throw new Error("Invalid Docker response, is it Docker really a daemon?"); + } + } } diff --git a/server/socket-handlers/docker-socket-handler.js b/server/socket-handlers/docker-socket-handler.js index 7f3646bb..5a53494d 100644 --- a/server/socket-handlers/docker-socket-handler.js +++ b/server/socket-handlers/docker-socket-handler.js @@ -1,6 +1,7 @@ const { sendDockerHostList } = require("../client"); const { checkLogin } = require("../util-server"); const { DockerHost } = require("../docker"); +const { log } = require("../../src/util"); /** * Handlers for docker hosts @@ -52,15 +53,22 @@ module.exports.dockerSocketHandler = (socket) => { try { checkLogin(socket); - let amount = await DockerHost.getAmountContainer(dockerHost); + let amount = await DockerHost.testDockerHost(dockerHost); + let msg; + + if (amount > 1) { + msg = "Connected Successfully. Amount of containers: " + amount; + } else { + msg = "Connected Successfully, but there are no containers?"; + } callback({ ok: true, - msg: "Amount of containers: " + amount, + msg, }); } catch (e) { - console.error(e); + log.error("docker", e); callback({ ok: false, From 8ced61697aea943aa0e25ff52f6b705715614242 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Sat, 30 Jul 2022 19:48:12 +0800 Subject: [PATCH 81/99] Fix save docker host issue --- server/client.js | 2 +- server/docker.js | 4 ++-- server/model/docker_host.js | 10 +++++----- src/components/DockerHostDialog.vue | 11 ++++++++++- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/server/client.js b/server/client.js index 69892e66..a0c52e1e 100644 --- a/server/client.js +++ b/server/client.js @@ -139,7 +139,7 @@ async function sendDockerHostList(socket) { ]); for (let bean of list) { - result.push(bean.export()); + result.push(bean.toJSON()); } io.to(socket.userID).emit("dockerHostList", result); diff --git a/server/docker.js b/server/docker.js index 1c939d64..177fa6cb 100644 --- a/server/docker.js +++ b/server/docker.js @@ -26,8 +26,8 @@ class DockerHost { } bean.user_id = userID; - bean.docker_daemon = dockerHost.docker_daemon; - bean.docker_type = dockerHost.docker_type; + bean.docker_daemon = dockerHost.dockerDaemon; + bean.docker_type = dockerHost.dockerType; bean.name = dockerHost.name; await R.store(bean); diff --git a/server/model/docker_host.js b/server/model/docker_host.js index 229a9a52..20598292 100644 --- a/server/model/docker_host.js +++ b/server/model/docker_host.js @@ -7,11 +7,11 @@ class DockerHost extends BeanModel { */ toJSON() { return { - id: this._id, - userId: this._user_id, - daemon: this._dockerDaemon, - type: this._dockerType, - name: this._name, + id: this.id, + userID: this.user_id, + dockerDaemon: this.docker_daemon, + dockerType: this.docker_type, + name: this.name, }; } } diff --git a/src/components/DockerHostDialog.vue b/src/components/DockerHostDialog.vue index d7cf2de0..681cc244 100644 --- a/src/components/DockerHostDialog.vue +++ b/src/components/DockerHostDialog.vue @@ -52,8 +52,9 @@ <script lang="ts"> import { Modal } from "bootstrap"; - import Confirm from "./Confirm.vue"; +import { useToast } from "vue-toastification"; +const toast = useToast(); export default { components: { @@ -88,14 +89,22 @@ export default { show(dockerHostID) { if (dockerHostID) { + let found = false; + this.id = dockerHostID; for (let n of this.$root.dockerHostList) { if (n.id === dockerHostID) { this.dockerHost = n; + found = true; break; } } + + if (!found) { + toast.error("Docker Host not found!"); + } + } else { this.id = null; this.dockerHost = { From 1223b56205c813301c5d0a476702ccc148c474a5 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Sat, 30 Jul 2022 19:57:51 +0800 Subject: [PATCH 82/99] Add example --- src/components/DockerHostDialog.vue | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/components/DockerHostDialog.vue b/src/components/DockerHostDialog.vue index 681cc244..92a8ce45 100644 --- a/src/components/DockerHostDialog.vue +++ b/src/components/DockerHostDialog.vue @@ -25,6 +25,14 @@ <div class="mb-3"> <label for="docker-daemon" class="form-label">{{ $t("Docker Daemon") }}</label> <input id="docker-daemon" v-model="dockerHost.dockerDaemon" type="text" class="form-control" required> + + <div class="form-text"> + {{ $t("Examples") }}: + <ul> + <li>/var/run/docker.sock</li> + <li>tcp://localhost:2375</li> + </ul> + </div> </div> </div> From 4e4156285a679dd21b8253dad24d165e0c6f3434 Mon Sep 17 00:00:00 2001 From: dtorner <dtorner@users.noreply.github.com> Date: Sun, 31 Jul 2022 11:13:36 +0200 Subject: [PATCH 83/99] Updated ES tramaslation Just some changes here and there, mainly caps and some words. TY to the developers for this good piece of code :-) --- src/languages/es-ES.js | 60 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/languages/es-ES.js b/src/languages/es-ES.js index 31538295..51327740 100644 --- a/src/languages/es-ES.js +++ b/src/languages/es-ES.js @@ -7,8 +7,8 @@ export default { maxRedirectDescription: "Número máximo de direcciones a seguir. Establecer a 0 para deshabilitar.", acceptedStatusCodesDescription: "Seleccionar los códigos de estado que se consideran como respuesta exitosa.", passwordNotMatchMsg: "La contraseña repetida no coincide.", - notificationDescription: "Por favor asigne una notificación a el/los monitor(es) para hacerlos funcional(es).", - keywordDescription: "Palabra clave en HTML plano o respuesta JSON y es sensible a mayúsculas", + notificationDescription: "Por favor asigna una notificación a el/los monitor(es) para hacerlos funcional(es).", + keywordDescription: "Palabra clave en HTML plano o respuesta JSON, es sensible a mayúsculas", pauseDashboardHome: "Pausado", deleteMonitorMsg: "¿Seguro que quieres eliminar este monitor?", deleteNotificationMsg: "¿Seguro que quieres eliminar esta notificación para todos los monitores?", @@ -35,7 +35,7 @@ export default { Pause: "Pausar", Name: "Nombre", Status: "Estado", - DateTime: "Fecha y Hora", + DateTime: "Fecha y hora", Message: "Mensaje", "No important events": "No hay eventos importantes", Resume: "Reanudar", @@ -50,7 +50,7 @@ export default { "-hour": "-hora", Response: "Respuesta", Ping: "Ping", - "Monitor Type": "Tipo de Monitor", + "Monitor Type": "Tipo de monitor", Keyword: "Palabra clave", "Friendly Name": "Nombre sencillo", URL: "URL", @@ -60,11 +60,11 @@ export default { Retries: "Reintentos", Advanced: "Avanzado", "Upside Down Mode": "Modo invertido", - "Max. Redirects": "Redirecciones Máximas", + "Max. Redirects": "Redirecciones máximas", "Accepted Status Codes": "Códigos de estado aceptados", Save: "Guardar", Notifications: "Notificaciones", - "Not available, please setup.": "No disponible, por favor configúrelo.", + "Not available, please setup.": "No disponible, por favor configúralo.", "Setup Notification": "Configurar notificación", Light: "Claro", Dark: "Oscuro", @@ -82,8 +82,8 @@ export default { "New Password": "Nueva contraseña", "Repeat New Password": "Repetir nueva contraseña", "Update Password": "Actualizar contraseña", - "Disable Auth": "Deshabilitar Autenticación", - "Enable Auth": "Habilitar Autenticación", + "Disable Auth": "Deshabilitar autenticación", + "Enable Auth": "Habilitar autenticación", "disableauth.message1": "Seguro que deseas <strong>deshabilitar la autenticación</strong>?", "disableauth.message2": "Es para <strong>quien implementa autenticación de terceros</strong> ante Uptime Kuma como por ejemplo Cloudflare Access.", "Please use this option carefully!": "Por favor usar con cuidado.", @@ -104,32 +104,32 @@ export default { Test: "Test", "Certificate Info": "Información del certificado", "Resolver Server": "Servidor de resolución", - "Resource Record Type": "Tipo de Registro", + "Resource Record Type": "Tipo de registro", "Last Result": "Último resultado", "Create your admin account": "Crea tu cuenta de administrador", "Repeat Password": "Repetir contraseña", respTime: "Tiempo de resp. (ms)", notAvailableShort: "N/A", Create: "Crear", - clearEventsMsg: "¿Está seguro de que desea eliminar todos los eventos de este monitor?", - clearHeartbeatsMsg: "¿Está seguro de que desea eliminar todos los latidos de este monitor?", - confirmClearStatisticsMsg: "¿Está seguro de que desea eliminar TODAS las estadísticas?", - "Clear Data": "Borrar Datos", + clearEventsMsg: "¿Estás seguro de que deseas eliminar todos los eventos de este monitor?", + clearHeartbeatsMsg: "¿Estás seguro de que deseas eliminar todos los latidos de este monitor?", + confirmClearStatisticsMsg: "¿Estás seguro de que deseas eliminar TODAS las estadísticas?", + "Clear Data": "Borrar datos", Events: "Eventos", Heartbeats: "Latidos", "Auto Get": "Obtener automáticamente", - enableDefaultNotificationDescription: "Para cada nuevo monitor, esta notificación estará habilitada de forma predeterminada. Aún puede deshabilitar la notificación por separado para cada monitor.", + enableDefaultNotificationDescription: "Para cada nuevo monitor, esta notificación estará habilitada de forma predeterminada. Aún puedes deshabilitar la notificación por separado para cada monitor.", "Default enabled": "Habilitado por defecto", "Also apply to existing monitors": "También se aplica a monitores existentes", Export: "Exportar", Import: "Importar", - backupDescription: "Puede hacer una copia de seguridad de todos los monitores y todas las notificaciones en un archivo JSON.", + backupDescription: "Puedes hacer una copia de seguridad de todos los monitores y todas las notificaciones en un archivo JSON.", backupDescription2: "PD: el historial y los datos de eventos no están incluidos.", - backupDescription3: "Los datos confidenciales, como los tokens de notificación, se incluyen en el archivo de exportación. Guárdelo con cuidado.", - alertNoFile: "Seleccione un archivo para importar.", - alertWrongFileType: "Seleccione un archivo JSON.", - twoFAVerifyLabel: "Ingrese su token para verificar que 2FA está funcionando", - tokenValidSettingsMsg: "¡El token es válido! Ahora puede guardar la configuración de 2FA.", + backupDescription3: "Los datos confidenciales, como los tokens de notificación, se incluyen en el archivo de exportación. Guárdalo con cuidado.", + alertNoFile: "Selecciona un archivo para importar.", + alertWrongFileType: "Selecciona un archivo JSON.", + twoFAVerifyLabel: "Ingresa tu token para verificar que 2FA está funcionando", + tokenValidSettingsMsg: "¡El token es válido! Ahora puedes guardar la configuración de 2FA.", confirmEnableTwoFAMsg: "¿Estás seguro de que quieres habilitar 2FA?", confirmDisableTwoFAMsg: "¿Estás seguro de que quieres desactivar 2FA?", "Apply on all existing monitors": "Aplicar en todos los monitores existentes", @@ -145,19 +145,19 @@ export default { "Show URI": "Mostrar URI", "Clear all statistics": "Borrar todas las estadísticas", retryCheckEverySecond: "Reintentar cada {0} segundo.", - importHandleDescription: "Elija 'Omitir existente' si desea omitir todos los monitores o notificaciones con el mismo nombre. 'Sobrescribir' eliminará todos los monitores y notificaciones existentes.", - confirmImportMsg: "¿Estás seguro de importar la copia de seguridad? Asegúrese de haber seleccionado la opción de importación correcta.", + importHandleDescription: "Elige 'Omitir existente' si deseas omitir todos los monitores o notificaciones con el mismo nombre. 'Sobrescribir' eliminará todos los monitores y notificaciones existentes.", + confirmImportMsg: "¿Estás seguro de importar la copia de seguridad? Asegúrate de haber seleccionado la opción de importación correcta.", "Heartbeat Retry Interval": "Intervalo de reintento de latido", "Import Backup": "Importar copia de seguridad", "Export Backup": "Exportar copia de seguridad", "Skip existing": "Omitir existente", Overwrite: "Sobrescribir", Options: "Opciones", - "Keep both": "Mantén ambos", + "Keep both": "Manténer ambos", Tags: "Etiquetas", - "Add New below or Select...": "Agregar nuevo a continuación o Seleccionar...", - "Tag with this name already exist.": "La etiqueta con este nombre ya existe.", - "Tag with this value already exist.": "La etiqueta con este valor ya existe.", + "Add New below or Select...": "Agregar nuevo a continuación o seleccionar...", + "Tag with this name already exist.": "Una etiqueta con este nombre ya existe.", + "Tag with this value already exist.": "Una etiqueta con este valor ya existe.", color: "color", "value (optional)": "valor (opcional)", Gray: "Gris", @@ -172,17 +172,17 @@ export default { "Avg. Ping": "Ping promedio", "Avg. Response": "Respuesta promedio", "Entry Page": "Página de entrada", - statusPageNothing: "No hay nada aquí, agregue un grupo o un monitor.", + statusPageNothing: "No hay nada aquí, agrega un grupo o un monitor.", "No Services": "Sin servicio", "All Systems Operational": "Todos los sistemas están operativos", "Partially Degraded Service": "Servicio parcialmente degradado", "Degraded Service": "Servicio degradado", - "Add Group": "Agregar Grupo", + "Add Group": "Agregar grupo", "Add a monitor": "Agregar un monitor", "Edit Status Page": "Editar página de estado", "Go to Dashboard": "Ir al panel de control", "Status Page": "Página de estado", - "Status Pages": "Página de estado", + "Status Pages": "Páginas de estado", telegram: "Telegram", webhook: "Webhook", smtp: "Email (SMTP)", @@ -205,5 +205,5 @@ export default { clearDataOlderThan: "Mantener los datos del historial del monitor durante {0} días.", records: "registros", "One record": "Un registro", - steamApiKeyDescription: "Para monitorear un servidor de juegos de Steam, necesita una clave Steam Web-API. Puede registrar su clave API aquí: ", + steamApiKeyDescription: "Para monitorear un servidor de juegos de Steam, necesitas una clave Steam Web-API. Puedes registrar tu clave API aquí: ", }; From ffb1a948feedc4e1919fd145b187fe31fa1db8e3 Mon Sep 17 00:00:00 2001 From: MrEddX <66828538+MrEddX@users.noreply.github.com> Date: Fri, 29 Jul 2022 21:04:33 +0300 Subject: [PATCH 84/99] Update bg-BG.js Translation Update --- src/languages/bg-BG.js | 142 +++++++++-------------------------------- 1 file changed, 29 insertions(+), 113 deletions(-) diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js index b2c185d9..15d330c1 100644 --- a/src/languages/bg-BG.js +++ b/src/languages/bg-BG.js @@ -12,15 +12,15 @@ export default { keywordDescription: "Търси ключова дума в чист html или JSON отговор - чувствителна е към регистъра", pauseDashboardHome: "Пауза", deleteMonitorMsg: "Наистина ли желаете да изтриете този монитор?", - deleteNotificationMsg: "Наистина ли желаете да изтриете това известие за всички монитори?", + deleteNotificationMsg: "Наистина ли желаете да изтриете това известяване за всички монитори?", resolverserverDescription: "Cloudflare е сървърът по подразбиране, но можете да го промените по всяко време.", rrtypeDescription: "Изберете ресурсния запис, който желаете да наблюдавате", pauseMonitorMsg: "Наистина ли желаете да поставите в режим пауза?", - enableDefaultNotificationDescription: "За всеки нов монитор това известие ще бъде активирано по подразбиране. Можете да го изключите за всеки отделен монитор.", + enableDefaultNotificationDescription: "За всеки нов монитор това известяване ще бъде активирано по подразбиране. Можете да го изключите за всеки отделен монитор.", clearEventsMsg: "Наистина ли желаете да изтриете всички събития за този монитор?", clearHeartbeatsMsg: "Наистина ли желаете да изтриете всички записи за честотни проверки на този монитор?", confirmClearStatisticsMsg: "Наистина ли желаете да изтриете всички статистически данни?", - importHandleDescription: "Изберете 'Пропусни съществуващите', ако желаете да пропуснете всеки монитор или известие със същото име. 'Презапис' ще изтрие всеки съществуващ монитор и известие.", + importHandleDescription: "Изберете 'Пропусни съществуващите', ако желаете да пропуснете всеки монитор или известяване със същото име. 'Презапис' ще изтрие всеки съществуващ монитор и известяване.", confirmImportMsg: "Сигурни ли сте, че желаете импортирането на архива? Моля, уверете се, че сте избрали правилната опция за импортиране.", twoFAVerifyLabel: "Моля, въведете вашия токен код, за да проверите дали 2FA работи", tokenValidSettingsMsg: "Токен кодът е валиден! Вече можете да запазите настройките за 2FA.", @@ -55,7 +55,8 @@ export default { Current: "Текущ", Uptime: "Достъпност", "Cert Exp.": "Вал. сертификат", - day: "ден | дни", + days: "дни", + day: "ден", "-day": "-дни", hour: "час", "-hour": "-часa", @@ -75,9 +76,9 @@ export default { "Max. Redirects": "Макс. брой пренасочвания", "Accepted Status Codes": "Допустими статус кодове", Save: "Запази", - Notifications: "Известия", + Notifications: "Известявания", "Not available, please setup.": "Не са налични. Моля, настройте.", - "Setup Notification": "Настрой известие", + "Setup Notification": "Настройки за известявания", Light: "Светла", Dark: "Тъмна", Auto: "Автоматично", @@ -89,16 +90,13 @@ export default { "Search Engine Visibility": "Видимост за търсачки", "Allow indexing": "Разреши индексиране", "Discourage search engines from indexing site": "Не позволявай на търсачките да индексират този сайт", - "Change Password": "Промяна на парола", + "Change Password": "Промени парола", "Current Password": "Текуща парола", "New Password": "Нова парола", "Repeat New Password": "Повторете новата парола", - "Update Password": "Актуализирай паролата", + "Update Password": "Актуализирай парола", "Disable Auth": "Изключи удостоверяване", "Enable Auth": "Включи удостоверяване", - "disableauth.message1": "Сигурни ли сте, че желаете да <strong>изключите удостоверяването</strong>?", - "disableauth.message2": "Използва се в случаите, когато <strong>има настроен алтернативен метод за удостоверяване</strong> преди Uptime Kuma, например Cloudflare Access, Authelia или друг механизъм за удостоверяване.", - "Please use this option carefully!": "Моля, използвайте с повишено внимание.", Logout: "Изход от профила", Leave: "Отказ", "I understand, please disable": "Разбирам. Моля, изключи", @@ -111,7 +109,7 @@ export default { Login: "Вход", "No Monitors, please": "Все още няма монитори. Моля, добавете поне ", "add one": "един.", - "Notification Type": "Тип известие", + "Notification Type": "Тип известяване", Email: "Имейл", Test: "Тест", "Certificate Info": "Информация за сертификат", @@ -133,9 +131,9 @@ export default { Events: "Събития", Heartbeats: "Проверки", "Auto Get": "Авт. попълване", - backupDescription: "Можете да архивирате всички монитори и всички известия в JSON файл.", + backupDescription: "Можете да архивирате всички монитори и всички известявания в JSON файл.", backupDescription2: "PS: Имайте предвид, че данните за история и събития няма да бъдат включени.", - backupDescription3: "Чувствителни данни, като токен кодове за известия, се съдържат в експортирания файл. Моля, бъдете внимателни с неговото съхранение.", + backupDescription3: "Чувствителни данни, като токен кодове за известяване, се съдържат в експортирания файл. Моля, бъдете внимателни с неговото съхранение.", alertNoFile: "Моля, изберете файл за импортиране.", alertWrongFileType: "Моля, изберете JSON файл.", "Clear all statistics": "Изтрий цялата статистика", @@ -147,7 +145,7 @@ export default { "Setup 2FA": "Настройка 2FA", "Enable 2FA": "Включи 2FA", "Disable 2FA": "Изключи 2FA", - "2FA Settings": "Настройка за 2FA", + "2FA Settings": "Настройки 2FA", "Two Factor Authentication": "Двуфакторно удостоверяване", Active: "Активно", Inactive: "Неактивно", @@ -204,7 +202,7 @@ export default { "Push URL": "Генериран Push URL адрес", needPushEvery: "Необходимо е да извършвате заявка към този URL адрес на всеки {0} секунди", pushOptionalParams: "Допълнителни, но не задължителни параметри: {0}", - defaultNotificationName: "Моето {notification} известие ({number})", + defaultNotificationName: "Моето {notification} известяване ({number})", here: "тук", Required: "Задължително поле", "Bot Token": "Бот токен", @@ -254,7 +252,7 @@ export default { "Notification Sound": "Звуков сигнал", "More info on:": "Повече информация на: {0}", pushoverDesc1: "Приоритет Спешно (2) по подразбиране изчаква 30 секунди между повторните опити и изтича след 1 час.", - pushoverDesc2: "Ако желаете да изпратите известия до различни устройства, попълнете полето Устройство.", + pushoverDesc2: "Ако желаете да изпратите известявания до различни устройства, попълнете полето Устройство.", "SMS Type": "SMS тип", octopushTypePremium: "Премиум (Бърз - препоръчителен в случай на тревога)", octopushTypeLowCost: "Евтин (Бавен - понякога бива блокиран от оператора)", @@ -277,7 +275,7 @@ export default { lineDevConsoleTo: "Line - Конзола за разработчици - {0}", "Basic Settings": "Основни настройки", "User ID": "Потребител ID", - "Messaging API": "API за съобщаване", + "Messaging API": "API за известяване", wayToGetLineChannelToken: "Необходимо е първо да посетите {0}, за да създадете (Messaging API) за доставчик и канал, след което може да вземете токен кода за канал и потребителско ID от споменатите по-горе елементи на менюто.", "Icon URL": "URL адрес за иконка", aboutIconURL: "Може да предоставите линк към картинка в поле \"URL Адрес за иконка\" за да отмените картинката на профила по подразбиране. Няма да се използва, ако вече сте настроили емотикон.", @@ -293,7 +291,7 @@ export default { matrixHomeserverURL: "Сървър URL адрес (започва с http(s):// и порт по желание)", "Internal Room Id": "ID на вътрешна стая", matrixDesc1: "Може да намерите \"ID на вътрешна стая\" в разширените настройки на стаята във вашия Matrix клиент. Примерен изглед: !QMdRCpUIfLwsfjxye6:home.server.", - matrixDesc2: "Силно препоръчваме да създадете НОВ потребител и да НЕ използвате токен кодът на вашия личен Matrix потребирел, т.к. той позволява пълен достъп до вашия акаунт и всички стаи към които сте се присъединили. Вместо това създайте нов потребител и го поканете само в стаята, където желаете да получавате известията. Токен код за достъп ще получите изпълнявайки {0}", + matrixDesc2: "Силно препоръчваме да създадете НОВ потребител и да НЕ използвате токен кодът на вашия личен Matrix потребирел, т.к. той позволява пълен достъп до вашия акаунт и всички стаи към които сте се присъединили. Вместо това създайте нов потребител и го поканете само в стаята, където желаете да получавате известяванията. Токен код за достъп ще получите изпълнявайки {0}", Method: "Метод", Body: "Съобщение", Headers: "Хедъри", @@ -301,7 +299,7 @@ export default { HeadersInvalidFormat: "Заявените хедъри не са валидни JSON: ", BodyInvalidFormat: "Заявеното съобщение не е валиден JSON: ", "Monitor History": "История на мониторите", - clearDataOlderThan: "Ще се съхранява за {0} дни.", + clearDataOlderThan: "Ще се съхранява {0} дни.", records: "записа", "One record": "Един запис", steamApiKeyDescription: "За да мониторирате Steam Gameserver се нуждаете от Steam Web-API ключ. Може да регистрирате Вашия API ключ тук: ", @@ -310,12 +308,12 @@ export default { PasswordsDoNotMatch: "Паролите не съвпадат.", "Current User": "Текущ потребител", recent: "Скорошни", - shrinkDatabaseDescription: "Инициира \"VACUUM\" за \"SQLite\" база данни. Ако Вашата база данни е създадена след версия 1.10.0, \"AUTO_VACUUM\" функцията е активна и това действие не е нужно.", + shrinkDatabaseDescription: "Инициира \"VACUUM\" за \"SQLite\" база данни. Ако Вашата база данни е създадена след версия 1.10.0, \"AUTO_VACUUM\" функцията е активна и това действие не нужно.", Done: "Готово", Info: "Информация", Security: "Сигурност", "Steam API Key": "Steam API ключ", - "Shrink Database": "Редуцирай базата данни", + "Shrink Database": "Редуциране база данни", "Pick a RR-Type...": "Изберете вида на ресурсния запис за мониторитане...", "Pick Accepted Status Codes...": "Изберете статус кодове, които да се считат за успешен отговор...", Default: "По подразбиране", @@ -355,8 +353,8 @@ export default { serwersmsSenderName: "SMS Подател име (регистриран през клиентския портал)", stackfield: "Stackfield", smtpDkimSettings: "DKIM Настройки", - smtpDkimDesc: "Моля, вижте {0} на Nodemailer DKIM за инструкции.", - documentation: "документацията", + smtpDkimDesc: "Моля, вижте Nodemailer DKIM {0} за инструкции.", + documentation: "документация", smtpDkimDomain: "Домейн", smtpDkimKeySelector: "Селектор на ключ", smtpDkimPrivateKey: "Частен ключ", @@ -373,12 +371,12 @@ export default { alertaAlertState: "Състояние на тревога", alertaRecoverState: "Състояние на възстановяване", deleteStatusPageMsg: "Сигурни ли сте, че желаете да изтриете тази статус страница?", - Proxies: "Прокси", + Proxies: "Проксита", default: "По подразбиране", enabled: "Включено", setAsDefault: "Зададен по подразбиране", deleteProxyMsg: "Сигурни ли сте, че желаете да изтриете това прокси за всички монитори?", - proxyDescription: "За да функционират трябва да бъдат зададени към монитор.", + proxyDescription: "Прокситата трябва да бъдат зададени към монитор за да функционират.", enableProxyDescription: "Това прокси няма да има ефект върху заявките за мониторинг, докато не бъде активирано. Може да контролирате временното деактивиране на проксито от всички монитори чрез статуса на активиране.", setAsDefaultProxyDescription: "Това проки ще бъде включено по подразбиране за новите монитори. Може да го изключите по отделно за всеки един монитор.", "Certificate Chain": "Верига на сертификата", @@ -403,7 +401,7 @@ export default { Retry: "Повтори", Topic: "Тема", "WeCom Bot Key": "WeCom бот ключ", - "Setup Proxy": "Настрой прокси", + "Setup Proxy": "Настройка за прокси", "Proxy Protocol": "Прокси протокол", "Proxy Server": "Прокси сървър", "Proxy server has authentication": "Прокси сървърът е с удостоверяване", @@ -413,8 +411,8 @@ export default { Running: "Работи", "Not running": "Не работи", "Remove Token": "Премахни токен", - Start: "Стартирай", - Stop: "Спри", + Start: "Старт", + Stop: "Стоп", "Uptime Kuma": "Uptime Kuma", "Add New Status Page": "Добави нова статус страница", Slug: "Слъг", @@ -424,7 +422,6 @@ export default { Next: "Следващ", "The slug is already taken. Please choose another slug.": "Този слъг вече се използва. Моля изберете друг.", "No Proxy": "Без прокси", - Authentication: "Удостоверяване", "HTTP Basic Auth": "HTTP основно удостоверяване", "New Status Page": "Нова статус страница", "Page Not Found": "Страницата не е открита", @@ -445,14 +442,7 @@ export default { "Issuer:": "Издател:", "Fingerprint:": "Пръстов отпечатък:", "No status pages": "Няма статус страници", - topic: "Тема", - topicExplanation: "MQTT тема за мониториране", - successMessage: "Съобщение при успех", - successMessageExplanation: "MQTT съобщение, което ще бъде считано за успех", - Customize: "Персонализирай", - "Custom Footer": "Персонализиран долен колонтитул", - "Custom CSS": "Потребителски CSS", - "Domain Name Expiry Notification": "Известие при изтичащ домейн", + "Domain Name Expiry Notification": "Известие за изтичащ домейн", Proxy: "Прокси", "Date Created": "Дата на създаване", onebotHttpAddress: "OneBot HTTP адрес", @@ -460,80 +450,6 @@ export default { onebotGroupMessage: "Група", onebotPrivateMessage: "Лично", onebotUserOrGroupId: "Група/Потребител ID", - onebotSafetyTips: "С цел безопасност трябва да зададете токен код за достъп", + onebotSafetyTips: "С цел сигурност, трябва да зададете токен код за достъп", "PushDeer Key": "PushDeer ключ", - "Footer Text": "Текст долен колонтитул", - "Show Powered By": "Покажи \"Създадено чрез\"", - "Domain Names": "Домейни", - signedInDisp: "Вписан като {0}", - signedInDispDisabled: "Удостоверяването е изключено.", - "Certificate Expiry Notification": "Известие за изтичане валидността на сертификата", - "API Username": "API Потребител", - "API Key": "API Ключ", - "Recipient Number": "Номер на получателя", - "From Name/Number": "От Име/Номер", - "Leave blank to use a shared sender number.": "Оставете празно, за да използвате споделен номер на подател.", - "Octopush API Version": "Octopush API версия", - "Legacy Octopush-DM": "Octopush-DM старa версия", - endpoint: "крайна точка", - octopushAPIKey: "\"API ключ\" от HTTP API удостоверяване в контролния панел", - octopushLogin: "\"Вписване\" от HTTP API удостоверяване в контролния панел", - promosmsLogin: "API Потребителско име", - promosmsPassword: "API Парола", - "pushoversounds pushover": "Pushover (по подразбиране)", - "pushoversounds bike": "Велосипед", - "pushoversounds bugle": "Тромпет", - "pushoversounds cashregister": "Касов апарат", - "pushoversounds classical": "Класическа музика", - "pushoversounds cosmic": "Космически", - "pushoversounds falling": "Падащ", - "pushoversounds gamelan": "Игра в мрежа", - "pushoversounds incoming": "Входящ", - "pushoversounds intermission": "Прекъсване", - "pushoversounds magic": "Магия", - "pushoversounds mechanical": "Механичен", - "pushoversounds pianobar": "Пиано бар", - "pushoversounds siren": "Сирена", - "pushoversounds spacealarm": "Космическа аларма", - "pushoversounds tugboat": "Буксир", - "pushoversounds alien": "Извънземна аларма (дълъг)", - "pushoversounds climb": "Изкачване (дълъг)", - "pushoversounds persistent": "Постоянен (дълъг)", - "pushoversounds echo": "Pushover ехо (дълъг)", - "pushoversounds updown": "Горе долу (дълъг)", - "pushoversounds vibrate": "Само вибрация", - "pushoversounds none": "Без (тих)", - pushyAPIKey: "Таен API ключ", - pushyToken: "Токен на устройство", - "Show update if available": "Покажи актуализация, ако е налична", - "Also check beta release": "Проверявай и за бета версии", - "Using a Reverse Proxy?": "Използвате ревърс прокси?", - "Check how to config it for WebSocket": "Проверете как да го конфигурирате за WebSocket", - "Steam Game Server": "Steam Game сървър", - "Most likely causes:": "Най-вероятни причини:", - "The resource is no longer available.": "Ресурсът вече не е наличен.", - "There might be a typing error in the address.": "Възможно е да е допусната грешка при изписването на адреса.", - "What you can try:": "Може да опитате:", - "Retype the address.": "Повторно въвеждане на адреса.", - "Go back to the previous page.": "Да се върнете към предишната страница.", - "Coming Soon": "Очаквайте скоро", - wayToGetClickSendSMSToken: "Може да получите API потребителско име и API ключ от {0} .", - dnsPortDescription: "DNS порт на сървъра. По подразбиране е 53, но може да бъде променен по всяко време.", - error: "грешка", - critical: "критично", - wayToGetPagerDutyKey: "Може да го получите като посетите Service -> Service Directory -> (Select a service) -> Integrations -> Add integration. Тук трябва да потърсите \"Events API V2\". Повече информация {0}", - "Integration Key": "Ключ за интегриране", - "Integration URL": "URL адрес за интеграция", - "Auto resolve or acknowledged": "Автоматично разрешаване или потвърждаване", - "do nothing": "не прави нищо", - "auto acknowledged": "автоматично потвърждаване", - "auto resolve": "автоматично разрешаване", - "Connection String": "Стринг за връзка", - Query: "Заявка", - settingsCertificateExpiry: "Изтичане валидността на TLS сертификата", - certificationExpiryDescription: "HTTPS мониторите ще задействат известие, ако е наличен изтичащ TLS сертификат, през следващите:", - "ntfy Topic": "ntfy Тема", - Domain: "Домейн", - Workstation: "Работна станция", - disableCloudflaredNoAuthMsg: "Тъй като сте в режим \"No Auth mode\", парола не се изисква.", }; From 96971f6776ecc800cab1589888e6463471ed470e Mon Sep 17 00:00:00 2001 From: MrEddX <66828538+MrEddX@users.noreply.github.com> Date: Fri, 29 Jul 2022 21:23:41 +0300 Subject: [PATCH 85/99] Update bg-BG.js - Translation Update - Fixed Some Accidentally Deleted Fields --- src/languages/bg-BG.js | 143 ++++++++++++++++++++++++++++++++--------- 1 file changed, 114 insertions(+), 29 deletions(-) diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js index 15d330c1..56035295 100644 --- a/src/languages/bg-BG.js +++ b/src/languages/bg-BG.js @@ -12,15 +12,15 @@ export default { keywordDescription: "Търси ключова дума в чист html или JSON отговор - чувствителна е към регистъра", pauseDashboardHome: "Пауза", deleteMonitorMsg: "Наистина ли желаете да изтриете този монитор?", - deleteNotificationMsg: "Наистина ли желаете да изтриете това известяване за всички монитори?", + deleteNotificationMsg: "Наистина ли желаете да изтриете това известие за всички монитори?", resolverserverDescription: "Cloudflare е сървърът по подразбиране, но можете да го промените по всяко време.", rrtypeDescription: "Изберете ресурсния запис, който желаете да наблюдавате", pauseMonitorMsg: "Наистина ли желаете да поставите в режим пауза?", - enableDefaultNotificationDescription: "За всеки нов монитор това известяване ще бъде активирано по подразбиране. Можете да го изключите за всеки отделен монитор.", + enableDefaultNotificationDescription: "За всеки нов монитор това известие ще бъде активирано по подразбиране. Можете да го изключите за всеки отделен монитор.", clearEventsMsg: "Наистина ли желаете да изтриете всички събития за този монитор?", clearHeartbeatsMsg: "Наистина ли желаете да изтриете всички записи за честотни проверки на този монитор?", confirmClearStatisticsMsg: "Наистина ли желаете да изтриете всички статистически данни?", - importHandleDescription: "Изберете 'Пропусни съществуващите', ако желаете да пропуснете всеки монитор или известяване със същото име. 'Презапис' ще изтрие всеки съществуващ монитор и известяване.", + importHandleDescription: "Изберете 'Пропусни съществуващите', ако желаете да пропуснете всеки монитор или известие със същото име. 'Презапис' ще изтрие всеки съществуващ монитор и известие.", confirmImportMsg: "Сигурни ли сте, че желаете импортирането на архива? Моля, уверете се, че сте избрали правилната опция за импортиране.", twoFAVerifyLabel: "Моля, въведете вашия токен код, за да проверите дали 2FA работи", tokenValidSettingsMsg: "Токен кодът е валиден! Вече можете да запазите настройките за 2FA.", @@ -55,8 +55,7 @@ export default { Current: "Текущ", Uptime: "Достъпност", "Cert Exp.": "Вал. сертификат", - days: "дни", - day: "ден", + day: "ден | дни", "-day": "-дни", hour: "час", "-hour": "-часa", @@ -76,9 +75,9 @@ export default { "Max. Redirects": "Макс. брой пренасочвания", "Accepted Status Codes": "Допустими статус кодове", Save: "Запази", - Notifications: "Известявания", + Notifications: "Известия", "Not available, please setup.": "Не са налични. Моля, настройте.", - "Setup Notification": "Настройки за известявания", + "Setup Notification": "Настрой известие", Light: "Светла", Dark: "Тъмна", Auto: "Автоматично", @@ -90,13 +89,16 @@ export default { "Search Engine Visibility": "Видимост за търсачки", "Allow indexing": "Разреши индексиране", "Discourage search engines from indexing site": "Не позволявай на търсачките да индексират този сайт", - "Change Password": "Промени парола", + "Change Password": "Промяна на парола", "Current Password": "Текуща парола", "New Password": "Нова парола", "Repeat New Password": "Повторете новата парола", - "Update Password": "Актуализирай парола", + "Update Password": "Актуализирай паролата", "Disable Auth": "Изключи удостоверяване", "Enable Auth": "Включи удостоверяване", + "disableauth.message1": "Сигурни ли сте, че желаете да <strong>изключите удостоверяването</strong>?", + "disableauth.message2": "Използва се в случаите, когато <strong>има настроен алтернативен метод за удостоверяване</strong> преди Uptime Kuma, например Cloudflare Access, Authelia или друг механизъм за удостоверяване.", + "Please use this option carefully!": "Моля, използвайте с повишено внимание.", Logout: "Изход от профила", Leave: "Отказ", "I understand, please disable": "Разбирам. Моля, изключи", @@ -109,7 +111,7 @@ export default { Login: "Вход", "No Monitors, please": "Все още няма монитори. Моля, добавете поне ", "add one": "един.", - "Notification Type": "Тип известяване", + "Notification Type": "Тип известие", Email: "Имейл", Test: "Тест", "Certificate Info": "Информация за сертификат", @@ -131,9 +133,9 @@ export default { Events: "Събития", Heartbeats: "Проверки", "Auto Get": "Авт. попълване", - backupDescription: "Можете да архивирате всички монитори и всички известявания в JSON файл.", + backupDescription: "Можете да архивирате всички монитори и всички известия в JSON файл.", backupDescription2: "PS: Имайте предвид, че данните за история и събития няма да бъдат включени.", - backupDescription3: "Чувствителни данни, като токен кодове за известяване, се съдържат в експортирания файл. Моля, бъдете внимателни с неговото съхранение.", + backupDescription3: "Чувствителни данни, като токен кодове за известия, се съдържат в експортирания файл. Моля, бъдете внимателни с неговото съхранение.", alertNoFile: "Моля, изберете файл за импортиране.", alertWrongFileType: "Моля, изберете JSON файл.", "Clear all statistics": "Изтрий цялата статистика", @@ -145,7 +147,7 @@ export default { "Setup 2FA": "Настройка 2FA", "Enable 2FA": "Включи 2FA", "Disable 2FA": "Изключи 2FA", - "2FA Settings": "Настройки 2FA", + "2FA Settings": "Настройка за 2FA", "Two Factor Authentication": "Двуфакторно удостоверяване", Active: "Активно", Inactive: "Неактивно", @@ -202,7 +204,7 @@ export default { "Push URL": "Генериран Push URL адрес", needPushEvery: "Необходимо е да извършвате заявка към този URL адрес на всеки {0} секунди", pushOptionalParams: "Допълнителни, но не задължителни параметри: {0}", - defaultNotificationName: "Моето {notification} известяване ({number})", + defaultNotificationName: "Моето {notification} известие ({number})", here: "тук", Required: "Задължително поле", "Bot Token": "Бот токен", @@ -252,7 +254,7 @@ export default { "Notification Sound": "Звуков сигнал", "More info on:": "Повече информация на: {0}", pushoverDesc1: "Приоритет Спешно (2) по подразбиране изчаква 30 секунди между повторните опити и изтича след 1 час.", - pushoverDesc2: "Ако желаете да изпратите известявания до различни устройства, попълнете полето Устройство.", + pushoverDesc2: "Ако желаете да изпратите известия до различни устройства, попълнете полето Устройство.", "SMS Type": "SMS тип", octopushTypePremium: "Премиум (Бърз - препоръчителен в случай на тревога)", octopushTypeLowCost: "Евтин (Бавен - понякога бива блокиран от оператора)", @@ -275,7 +277,7 @@ export default { lineDevConsoleTo: "Line - Конзола за разработчици - {0}", "Basic Settings": "Основни настройки", "User ID": "Потребител ID", - "Messaging API": "API за известяване", + "Messaging API": "API за съобщаване", wayToGetLineChannelToken: "Необходимо е първо да посетите {0}, за да създадете (Messaging API) за доставчик и канал, след което може да вземете токен кода за канал и потребителско ID от споменатите по-горе елементи на менюто.", "Icon URL": "URL адрес за иконка", aboutIconURL: "Може да предоставите линк към картинка в поле \"URL Адрес за иконка\" за да отмените картинката на профила по подразбиране. Няма да се използва, ако вече сте настроили емотикон.", @@ -291,7 +293,7 @@ export default { matrixHomeserverURL: "Сървър URL адрес (започва с http(s):// и порт по желание)", "Internal Room Id": "ID на вътрешна стая", matrixDesc1: "Може да намерите \"ID на вътрешна стая\" в разширените настройки на стаята във вашия Matrix клиент. Примерен изглед: !QMdRCpUIfLwsfjxye6:home.server.", - matrixDesc2: "Силно препоръчваме да създадете НОВ потребител и да НЕ използвате токен кодът на вашия личен Matrix потребирел, т.к. той позволява пълен достъп до вашия акаунт и всички стаи към които сте се присъединили. Вместо това създайте нов потребител и го поканете само в стаята, където желаете да получавате известяванията. Токен код за достъп ще получите изпълнявайки {0}", + matrixDesc2: "Силно препоръчваме да създадете НОВ потребител и да НЕ използвате токен кодът на вашия личен Matrix потребирел, т.к. той позволява пълен достъп до вашия акаунт и всички стаи към които сте се присъединили. Вместо това създайте нов потребител и го поканете само в стаята, където желаете да получавате известията. Токен код за достъп ще получите изпълнявайки {0}", Method: "Метод", Body: "Съобщение", Headers: "Хедъри", @@ -299,7 +301,7 @@ export default { HeadersInvalidFormat: "Заявените хедъри не са валидни JSON: ", BodyInvalidFormat: "Заявеното съобщение не е валиден JSON: ", "Monitor History": "История на мониторите", - clearDataOlderThan: "Ще се съхранява {0} дни.", + clearDataOlderThan: "Ще се съхранява за {0} дни.", records: "записа", "One record": "Един запис", steamApiKeyDescription: "За да мониторирате Steam Gameserver се нуждаете от Steam Web-API ключ. Може да регистрирате Вашия API ключ тук: ", @@ -308,12 +310,12 @@ export default { PasswordsDoNotMatch: "Паролите не съвпадат.", "Current User": "Текущ потребител", recent: "Скорошни", - shrinkDatabaseDescription: "Инициира \"VACUUM\" за \"SQLite\" база данни. Ако Вашата база данни е създадена след версия 1.10.0, \"AUTO_VACUUM\" функцията е активна и това действие не нужно.", + shrinkDatabaseDescription: "Инициира \"VACUUM\" за \"SQLite\" база данни. Ако Вашата база данни е създадена след версия 1.10.0, \"AUTO_VACUUM\" функцията е активна и това действие не е нужно.", Done: "Готово", Info: "Информация", Security: "Сигурност", "Steam API Key": "Steam API ключ", - "Shrink Database": "Редуциране база данни", + "Shrink Database": "Редуцирай базата данни", "Pick a RR-Type...": "Изберете вида на ресурсния запис за мониторитане...", "Pick Accepted Status Codes...": "Изберете статус кодове, които да се считат за успешен отговор...", Default: "По подразбиране", @@ -353,8 +355,8 @@ export default { serwersmsSenderName: "SMS Подател име (регистриран през клиентския портал)", stackfield: "Stackfield", smtpDkimSettings: "DKIM Настройки", - smtpDkimDesc: "Моля, вижте Nodemailer DKIM {0} за инструкции.", - documentation: "документация", + smtpDkimDesc: "Моля, вижте {0} на Nodemailer DKIM за инструкции.", + documentation: "документацията", smtpDkimDomain: "Домейн", smtpDkimKeySelector: "Селектор на ключ", smtpDkimPrivateKey: "Частен ключ", @@ -371,12 +373,12 @@ export default { alertaAlertState: "Състояние на тревога", alertaRecoverState: "Състояние на възстановяване", deleteStatusPageMsg: "Сигурни ли сте, че желаете да изтриете тази статус страница?", - Proxies: "Проксита", + Proxies: "Прокси", default: "По подразбиране", enabled: "Включено", setAsDefault: "Зададен по подразбиране", deleteProxyMsg: "Сигурни ли сте, че желаете да изтриете това прокси за всички монитори?", - proxyDescription: "Прокситата трябва да бъдат зададени към монитор за да функционират.", + proxyDescription: "За да функционират трябва да бъдат зададени към монитор.", enableProxyDescription: "Това прокси няма да има ефект върху заявките за мониторинг, докато не бъде активирано. Може да контролирате временното деактивиране на проксито от всички монитори чрез статуса на активиране.", setAsDefaultProxyDescription: "Това проки ще бъде включено по подразбиране за новите монитори. Може да го изключите по отделно за всеки един монитор.", "Certificate Chain": "Верига на сертификата", @@ -401,7 +403,7 @@ export default { Retry: "Повтори", Topic: "Тема", "WeCom Bot Key": "WeCom бот ключ", - "Setup Proxy": "Настройка за прокси", + "Setup Proxy": "Настрой прокси", "Proxy Protocol": "Прокси протокол", "Proxy Server": "Прокси сървър", "Proxy server has authentication": "Прокси сървърът е с удостоверяване", @@ -411,8 +413,8 @@ export default { Running: "Работи", "Not running": "Не работи", "Remove Token": "Премахни токен", - Start: "Старт", - Stop: "Стоп", + Start: "Стартирай", + Stop: "Спри", "Uptime Kuma": "Uptime Kuma", "Add New Status Page": "Добави нова статус страница", Slug: "Слъг", @@ -422,6 +424,7 @@ export default { Next: "Следващ", "The slug is already taken. Please choose another slug.": "Този слъг вече се използва. Моля изберете друг.", "No Proxy": "Без прокси", + Authentication: "Удостоверяване", "HTTP Basic Auth": "HTTP основно удостоверяване", "New Status Page": "Нова статус страница", "Page Not Found": "Страницата не е открита", @@ -442,7 +445,14 @@ export default { "Issuer:": "Издател:", "Fingerprint:": "Пръстов отпечатък:", "No status pages": "Няма статус страници", - "Domain Name Expiry Notification": "Известие за изтичащ домейн", + topic: "Тема", + topicExplanation: "MQTT тема за мониториране", + successMessage: "Съобщение при успех", + successMessageExplanation: "MQTT съобщение, което ще бъде считано за успех", + Customize: "Персонализирай", + "Custom Footer": "Персонализиран долен колонтитул", + "Custom CSS": "Потребителски CSS", + "Domain Name Expiry Notification": "Известие при изтичащ домейн", Proxy: "Прокси", "Date Created": "Дата на създаване", onebotHttpAddress: "OneBot HTTP адрес", @@ -450,6 +460,81 @@ export default { onebotGroupMessage: "Група", onebotPrivateMessage: "Лично", onebotUserOrGroupId: "Група/Потребител ID", - onebotSafetyTips: "С цел сигурност, трябва да зададете токен код за достъп", + onebotSafetyTips: "С цел безопасност трябва да зададете токен код за достъп", "PushDeer Key": "PushDeer ключ", + "Footer Text": "Текст долен колонтитул", + "Show Powered By": "Покажи \"Създадено чрез\"", + "Domain Names": "Домейни", + signedInDisp: "Вписан като {0}", + signedInDispDisabled: "Удостоверяването е изключено.", + "Certificate Expiry Notification": "Известие за изтичане валидността на сертификата", + "API Username": "API Потребител", + "API Key": "API Ключ", + "Recipient Number": "Номер на получателя", + "From Name/Number": "От Име/Номер", + "Leave blank to use a shared sender number.": "Оставете празно, за да използвате споделен номер на подател.", + "Octopush API Version": "Octopush API версия", + "Legacy Octopush-DM": "Octopush-DM старa версия", + endpoint: "крайна точка", + octopushAPIKey: "\"API ключ\" от HTTP API удостоверяване в контролния панел", + octopushLogin: "\"Вписване\" от HTTP API удостоверяване в контролния панел", + promosmsLogin: "API Потребителско име", + promosmsPassword: "API Парола", + "pushoversounds pushover": "Pushover (по подразбиране)", + "pushoversounds bike": "Велосипед", + "pushoversounds bugle": "Тромпет", + "pushoversounds cashregister": "Касов апарат", + "pushoversounds classical": "Класическа музика", + "pushoversounds cosmic": "Космически", + "pushoversounds falling": "Падащ", + "pushoversounds gamelan": "Игра в мрежа", + "pushoversounds incoming": "Входящ", + "pushoversounds intermission": "Прекъсване", + "pushoversounds magic": "Магия", + "pushoversounds mechanical": "Механичен", + "pushoversounds pianobar": "Пиано бар", + "pushoversounds siren": "Сирена", + "pushoversounds spacealarm": "Космическа аларма", + "pushoversounds tugboat": "Буксир", + "pushoversounds alien": "Извънземна аларма (дълъг)", + "pushoversounds climb": "Изкачване (дълъг)", + "pushoversounds persistent": "Постоянен (дълъг)", + "pushoversounds echo": "Pushover ехо (дълъг)", + "pushoversounds updown": "Горе долу (дълъг)", + "pushoversounds vibrate": "Само вибрация", + "pushoversounds none": "Без (тих)", + pushyAPIKey: "Таен API ключ", + pushyToken: "Токен на устройство", + "Show update if available": "Покажи актуализация, ако е налична", + "Also check beta release": "Проверявай и за бета версии", + "Using a Reverse Proxy?": "Използвате ревърс прокси?", + "Check how to config it for WebSocket": "Проверете как да го конфигурирате за WebSocket", + "Steam Game Server": "Steam Game сървър", + "Most likely causes:": "Най-вероятни причини:", + "The resource is no longer available.": "Ресурсът вече не е наличен.", + "There might be a typing error in the address.": "Възможно е да е допусната грешка при изписването на адреса.", + "What you can try:": "Може да опитате:", + "Retype the address.": "Повторно въвеждане на адреса.", + "Go back to the previous page.": "Да се върнете към предишната страница.", + "Coming Soon": "Очаквайте скоро", + wayToGetClickSendSMSToken: "Може да получите API потребителско име и API ключ от {0} .", + dnsPortDescription: "DNS порт на сървъра. По подразбиране е 53, но може да бъде променен по всяко време.", + error: "грешка", + critical: "критично", + wayToGetPagerDutyKey: "Може да го получите като посетите Service -> Service Directory -> (Select a service) -> Integrations -> Add integration. Тук трябва да потърсите \"Events API V2\". Повече информация {0}", + "Integration Key": "Ключ за интегриране", + "Integration URL": "URL адрес за интеграция", + "Auto resolve or acknowledged": "Автоматично разрешаване или потвърждаване", + "do nothing": "не прави нищо", + "auto acknowledged": "автоматично потвърждаване", + "auto resolve": "автоматично разрешаване", + "Connection String": "Стринг за връзка", + Query: "Заявка", + settingsCertificateExpiry: "Изтичане валидността на TLS сертификата", + certificationExpiryDescription: "HTTPS мониторите ще задействат известие, ако е наличен изтичащ TLS сертификат, през следващите:", + "ntfy Topic": "ntfy Тема", + Domain: "Домейн", + Workstation: "Работна станция", + disableCloudflaredNoAuthMsg: "Тъй като сте в режим \"No Auth mode\", парола не се изисква.", + wayToGetLineNotifyToken: "Може да получите токен код за достъп от {0}", }; From 96ec46765b68c23843dae3317ca70fb843da5b3a Mon Sep 17 00:00:00 2001 From: MrEddX <66828538+MrEddX@users.noreply.github.com> Date: Fri, 29 Jul 2022 21:24:57 +0300 Subject: [PATCH 86/99] Update en.js Just a typo. --- src/languages/en.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/en.js b/src/languages/en.js index 15bdcc8a..e9b5e2d3 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -536,5 +536,5 @@ export default { "Domain": "Domain", "Workstation": "Workstation", disableCloudflaredNoAuthMsg: "You are in No Auth mode, password is not require.", - wayToGetLineNotifyToken: "You can get a access token from {0}", + wayToGetLineNotifyToken: "You can get an access token from {0}", }; From 16d6885a88aec8fff716c4b0577ce59bb3f7305a Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Sun, 31 Jul 2022 18:11:40 +0800 Subject: [PATCH 87/99] Fix radio button and add description --- src/components/settings/ReverseProxy.vue | 12 ++++++++---- src/languages/en.js | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/settings/ReverseProxy.vue b/src/components/settings/ReverseProxy.vue index 85046cc2..0fab7629 100644 --- a/src/components/settings/ReverseProxy.vue +++ b/src/components/settings/ReverseProxy.vue @@ -103,12 +103,12 @@ v-model="settings.trustProxy" class="form-check-input" type="radio" - name="flexRadioDefault" + name="trustProxyYes" :value="true" required /> <label class="form-check-label" for="trustProxyYes"> - {{ $t("Trust 'X-Forwarded-*' headers") }} + {{ $t("Yes") }} </label> </div> <div class="form-check"> @@ -121,10 +121,14 @@ :value="false" required /> - <label class="form-check-label" for="trustProxyYes"> - {{ $t("Don't trust 'X-Forwarded-*' headers") }} + <label class="form-check-label" for="trustProxyNo"> + {{ $t("No") }} </label> </div> + + <div class="form-text"> + {{ $t("trustProxyDescription") }} + </div> </div> <div> diff --git a/src/languages/en.js b/src/languages/en.js index 3c3cdff4..2d66154d 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -540,4 +540,5 @@ export default { "Domain": "Domain", "Workstation": "Workstation", disableCloudflaredNoAuthMsg: "You are in No Auth mode, password is not require.", + trustProxyDescription: "Trust 'X-Forwarded-*' headers. If you want to get the correct client IP and your Uptime Kuma is behind such as Nginx or Apache, you should enable this.", }; From a0843745f977b6a11ffcff426e2efa78ebe6be97 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Sun, 31 Jul 2022 18:12:41 +0800 Subject: [PATCH 88/99] Remove unused language key --- src/languages/en.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 2d66154d..9f20cd5d 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -455,8 +455,6 @@ export default { "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.", "HTTP Headers": "HTTP Headers", "Trust Proxy": "Trust Proxy", - "Trust 'X-Forwarded-*' headers": "Trust 'X-Forwarded-*' headers", - "Don't trust 'X-Forwarded-*' headers": "Don't trust 'X-Forwarded-*' headers", "Other Software": "Other Software", "For example: nginx, Apache and Traefik.": "For example: nginx, Apache and Traefik.", "Please read": "Please read", From a3b16129381b0e90a6914ce774ac47c05e976581 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Sun, 31 Jul 2022 23:36:33 +0800 Subject: [PATCH 89/99] getClientIP respect trustProxy setting --- server/server.js | 44 +++++++++++++++++++----------------- server/uptime-kuma-server.js | 13 +++++++++++ 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/server/server.js b/server/server.js index 8a0dd871..61bd9d93 100644 --- a/server/server.js +++ b/server/server.js @@ -254,7 +254,9 @@ let needSetup = false; // *************************** socket.on("loginByToken", async (token, callback) => { - log.info("auth", `Login by token. IP=${getClientIp(socket)}`); + const clientIP = await server.getClientIP(socket); + + log.info("auth", `Login by token. IP=${clientIP}`); try { let decoded = jwt.verify(token, jwtSecret); @@ -270,14 +272,14 @@ let needSetup = false; afterLogin(socket, user); log.debug("auth", "afterLogin ok"); - log.info("auth", `Successfully logged in user ${decoded.username}. IP=${getClientIp(socket)}`); + log.info("auth", `Successfully logged in user ${decoded.username}. IP=${clientIP}`); callback({ ok: true, }); } else { - log.info("auth", `Inactive or deleted user ${decoded.username}. IP=${getClientIp(socket)}`); + log.info("auth", `Inactive or deleted user ${decoded.username}. IP=${clientIP}`); callback({ ok: false, @@ -286,7 +288,7 @@ let needSetup = false; } } catch (error) { - log.error("auth", `Invalid token. IP=${getClientIp(socket)}`); + log.error("auth", `Invalid token. IP=${clientIP}`); callback({ ok: false, @@ -297,7 +299,9 @@ let needSetup = false; }); socket.on("login", async (data, callback) => { - log.info("auth", `Login by username + password. IP=${getClientIp(socket)}`); + const clientIP = await server.getClientIP(socket); + + log.info("auth", `Login by username + password. IP=${clientIP}`); // Checking if (typeof callback !== "function") { @@ -310,7 +314,7 @@ let needSetup = false; // Login Rate Limit if (! await loginRateLimiter.pass(callback)) { - log.info("auth", `Too many failed requests for user ${data.username}. IP=${getClientIp(socket)}`); + log.info("auth", `Too many failed requests for user ${data.username}. IP=${clientIP}`); return; } @@ -320,7 +324,7 @@ let needSetup = false; if (user.twofa_status === 0) { afterLogin(socket, user); - log.info("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); + log.info("auth", `Successfully logged in user ${data.username}. IP=${clientIP}`); callback({ ok: true, @@ -332,7 +336,7 @@ let needSetup = false; if (user.twofa_status === 1 && !data.token) { - log.info("auth", `2FA token required for user ${data.username}. IP=${getClientIp(socket)}`); + log.info("auth", `2FA token required for user ${data.username}. IP=${clientIP}`); callback({ tokenRequired: true, @@ -350,7 +354,7 @@ let needSetup = false; socket.userID, ]); - log.info("auth", `Successfully logged in user ${data.username}. IP=${getClientIp(socket)}`); + log.info("auth", `Successfully logged in user ${data.username}. IP=${clientIP}`); callback({ ok: true, @@ -360,7 +364,7 @@ let needSetup = false; }); } else { - log.warn("auth", `Invalid token provided for user ${data.username}. IP=${getClientIp(socket)}`); + log.warn("auth", `Invalid token provided for user ${data.username}. IP=${clientIP}`); callback({ ok: false, @@ -370,7 +374,7 @@ let needSetup = false; } } else { - log.warn("auth", `Incorrect username or password for user ${data.username}. IP=${getClientIp(socket)}`); + log.warn("auth", `Incorrect username or password for user ${data.username}. IP=${clientIP}`); callback({ ok: false, @@ -442,6 +446,8 @@ let needSetup = false; }); socket.on("save2FA", async (currentPassword, callback) => { + const clientIP = await server.getClientIP(socket); + try { if (! await twoFaRateLimiter.pass(callback)) { return; @@ -454,7 +460,7 @@ let needSetup = false; socket.userID, ]); - log.info("auth", `Saved 2FA token. IP=${getClientIp(socket)}`); + log.info("auth", `Saved 2FA token. IP=${clientIP}`); callback({ ok: true, @@ -462,7 +468,7 @@ let needSetup = false; }); } catch (error) { - log.error("auth", `Error changing 2FA token. IP=${getClientIp(socket)}`); + log.error("auth", `Error changing 2FA token. IP=${clientIP}`); callback({ ok: false, @@ -472,6 +478,8 @@ let needSetup = false; }); socket.on("disable2FA", async (currentPassword, callback) => { + const clientIP = await server.getClientIP(socket); + try { if (! await twoFaRateLimiter.pass(callback)) { return; @@ -481,7 +489,7 @@ let needSetup = false; await doubleCheckPassword(socket, currentPassword); await TwoFA.disable2FA(socket.userID); - log.info("auth", `Disabled 2FA token. IP=${getClientIp(socket)}`); + log.info("auth", `Disabled 2FA token. IP=${clientIP}`); callback({ ok: true, @@ -489,7 +497,7 @@ let needSetup = false; }); } catch (error) { - log.error("auth", `Error disabling 2FA token. IP=${getClientIp(socket)}`); + log.error("auth", `Error disabling 2FA token. IP=${clientIP}`); callback({ ok: false, @@ -1684,12 +1692,6 @@ async function shutdownFunction(signal) { await cloudflaredStop(); } -function getClientIp(socket) { - return socket.client.conn.request.headers["x-forwarded-for"] - || socket.client.conn.request.headers["x-real-ip"] - || socket.client.conn.remoteAddress.replace(/^.*:/, ""); -} - /** Final function called before application exits */ function finalFunction() { log.info("server", "Graceful shutdown successful!"); diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 3362f72c..0f32017f 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -8,6 +8,7 @@ const { log } = require("../src/util"); const Database = require("./database"); const util = require("util"); const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent"); +const { setting } = require("./util-server"); /** * `module.exports` (alias: `server`) should be inside this class, in order to avoid circular dependency issue. @@ -128,6 +129,18 @@ class UptimeKumaServer { errorLogStream.end(); } + + async getClientIP(socket) { + const clientIP = socket.client.conn.remoteAddress.replace(/^.*:/, ""); + + if (await setting("trustProxy")) { + return socket.client.conn.request.headers["x-forwarded-for"] + || socket.client.conn.request.headers["x-real-ip"] + || clientIP; + } else { + return clientIP; + } + } } module.exports = { From 2389b604fe609cbc650d2761a52278cac0173391 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Sun, 31 Jul 2022 23:41:29 +0800 Subject: [PATCH 90/99] Use Settings.get --- server/uptime-kuma-server.js | 4 ++-- server/util-server.js | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 0f32017f..67b6ed0a 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -8,7 +8,7 @@ const { log } = require("../src/util"); const Database = require("./database"); const util = require("util"); const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent"); -const { setting } = require("./util-server"); +const { Settings } = require("./settings"); /** * `module.exports` (alias: `server`) should be inside this class, in order to avoid circular dependency issue. @@ -133,7 +133,7 @@ class UptimeKumaServer { async getClientIP(socket) { const clientIP = socket.client.conn.remoteAddress.replace(/^.*:/, ""); - if (await setting("trustProxy")) { + if (await Settings.get("trustProxy")) { return socket.client.conn.request.headers["x-forwarded-for"] || socket.client.conn.request.headers["x-real-ip"] || clientIP; diff --git a/server/util-server.js b/server/util-server.js index 84244b02..df711cf0 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -289,6 +289,7 @@ exports.postgresQuery = function (connectionString, query) { * Retrieve value of setting based on key * @param {string} key Key of setting to retrieve * @returns {Promise<any>} Value + * @deprecated Use await Settings.get(key) */ exports.setting = async function (key) { return await Settings.get(key); From f016caa51300f7b127950b5c8e81463d3fbdeafc Mon Sep 17 00:00:00 2001 From: Joseph Benguira <z51biz@gmail.com> Date: Sun, 31 Jul 2022 18:51:53 +0300 Subject: [PATCH 91/99] Avoid error "SQLITE_BUSY: database is locked" Avoid error "SQLITE_BUSY: database is locked" by allowing SQLITE to wait up to 5 seconds to do a write --- server/database.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/database.js b/server/database.js index 00fd48d9..b58daf87 100644 --- a/server/database.js +++ b/server/database.js @@ -146,6 +146,9 @@ class Database { } await R.exec("PRAGMA cache_size = -12000"); await R.exec("PRAGMA auto_vacuum = FULL"); + + //Avoid error "SQLITE_BUSY: database is locked" by allowing SQLITE to wait up to 5 seconds to do a write + await R.exec("PRAGMA busy_timeout = 5000;"); // This ensures that an operating system crash or power failure will not corrupt the database. // FULL synchronous is very safe, but it is also slower. From 82b9bfc5a0a4fdc6492bfedbd11a0bd7bfa10b38 Mon Sep 17 00:00:00 2001 From: Joseph Benguira <z51biz@gmail.com> Date: Sun, 31 Jul 2022 18:59:02 +0300 Subject: [PATCH 92/99] fixed Trailing spaces not allowed lint issue --- server/database.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/database.js b/server/database.js index b58daf87..4c374ca6 100644 --- a/server/database.js +++ b/server/database.js @@ -146,7 +146,7 @@ class Database { } await R.exec("PRAGMA cache_size = -12000"); await R.exec("PRAGMA auto_vacuum = FULL"); - + //Avoid error "SQLITE_BUSY: database is locked" by allowing SQLITE to wait up to 5 seconds to do a write await R.exec("PRAGMA busy_timeout = 5000;"); From 71d62ee1510a5c336d3d22901e231814bba0187f Mon Sep 17 00:00:00 2001 From: Joseph Benguira <z51biz@gmail.com> Date: Sun, 31 Jul 2022 19:00:19 +0300 Subject: [PATCH 93/99] removed ; after the PRAGMA command --- server/database.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/database.js b/server/database.js index 4c374ca6..5f87352b 100644 --- a/server/database.js +++ b/server/database.js @@ -148,7 +148,7 @@ class Database { await R.exec("PRAGMA auto_vacuum = FULL"); //Avoid error "SQLITE_BUSY: database is locked" by allowing SQLITE to wait up to 5 seconds to do a write - await R.exec("PRAGMA busy_timeout = 5000;"); + await R.exec("PRAGMA busy_timeout = 5000"); // This ensures that an operating system crash or power failure will not corrupt the database. // FULL synchronous is very safe, but it is also slower. From fb3fe17c2824e62a731270257746b9b214d17912 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Mon, 1 Aug 2022 15:42:58 +0800 Subject: [PATCH 94/99] Fix getClientIP Co-authored-by: Mateusz Hajder <6783135+mhajder@users.noreply.github.com> --- server/uptime-kuma-server.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 67b6ed0a..98de65a4 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -131,14 +131,18 @@ class UptimeKumaServer { } async getClientIP(socket) { - const clientIP = socket.client.conn.remoteAddress.replace(/^.*:/, ""); + let clientIP = socket.client.conn.remoteAddress; + + if (clientIP === undefined) { + clientIP = ""; + } if (await Settings.get("trustProxy")) { return socket.client.conn.request.headers["x-forwarded-for"] || socket.client.conn.request.headers["x-real-ip"] - || clientIP; + || clientIP.replace(/^.*:/, ""); } else { - return clientIP; + return clientIP.replace(/^.*:/, ""); } } } From d6a113396a0a3512c7ac5975eaafb5fba2c46a36 Mon Sep 17 00:00:00 2001 From: Joseph Benguira <z51biz@gmail.com> Date: Mon, 1 Aug 2022 13:18:19 +0300 Subject: [PATCH 95/99] Update server/database.js Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com> --- server/database.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/database.js b/server/database.js index 5f87352b..b4865b1f 100644 --- a/server/database.js +++ b/server/database.js @@ -147,7 +147,7 @@ class Database { await R.exec("PRAGMA cache_size = -12000"); await R.exec("PRAGMA auto_vacuum = FULL"); - //Avoid error "SQLITE_BUSY: database is locked" by allowing SQLITE to wait up to 5 seconds to do a write + // Avoid error "SQLITE_BUSY: database is locked" by allowing SQLITE to wait up to 5 seconds to do a write await R.exec("PRAGMA busy_timeout = 5000"); // This ensures that an operating system crash or power failure will not corrupt the database. From 2af754b5e85e36b8f1f3b4b376cd970c116d7c3f Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Thu, 11 Aug 2022 21:09:16 +0800 Subject: [PATCH 96/99] Update package-lock.json --- package-lock.json | 114 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/package-lock.json b/package-lock.json index 778e6bc3..0cf62fa7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "mqtt": "^4.2.8", "mssql": "^8.1.0", "node-cloudflared-tunnel": "~1.0.9", + "node-radius-client": "^1.0.0", "nodemailer": "~6.6.5", "notp": "~2.0.3", "password-hash": "~1.2.2", @@ -8215,6 +8216,12 @@ "readable-stream": "^3.6.0" } }, + "node_modules/hoek": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", + "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", + "deprecated": "This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues." + }, "node_modules/homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -8915,6 +8922,17 @@ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "devOptional": true }, + "node_modules/isemail": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", + "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", + "dependencies": { + "punycode": "2.x.x" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -12151,6 +12169,32 @@ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true }, + "node_modules/node-radius-client": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-radius-client/-/node-radius-client-1.0.0.tgz", + "integrity": "sha512-FkR9cMV5hNoX+kKDUTzuagvEixlLiaEJQ1/ywOdhahsihKrGDhVZmnCvmrCStA589MT3yuC/J2eKc6z68IGdBw==", + "dependencies": { + "joi": "^14.3.1", + "node-radius-utils": "^1.2.0", + "radius": "^1.1.4" + } + }, + "node_modules/node-radius-client/node_modules/joi": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", + "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==", + "deprecated": "This module has moved and is now available at @hapi/joi. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", + "dependencies": { + "hoek": "6.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" + } + }, + "node_modules/node-radius-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/node-radius-utils/-/node-radius-utils-1.2.0.tgz", + "integrity": "sha512-i3Sf6khnenl0aXumo0whAlfPWTaBqHxEnVBBxpu3dZ7q69NkPPv71rvPjlDZ5wkeKCTNNUTECljerS5kcYQxRw==" + }, "node_modules/node-releases": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", @@ -13429,6 +13473,14 @@ "node": ">=8" } }, + "node_modules/radius": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/radius/-/radius-1.1.4.tgz", + "integrity": "sha512-UWuzdF6xf3NpsXFZZmUEkxtEalDXj8hdmMXgbGzn7vOk6zXNsiIY2I6SJ1euHt7PTQuMoz2qDEJB+AfJDJgQYw==", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -15261,6 +15313,15 @@ "node": ">=0.6" } }, + "node_modules/topo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", + "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", + "deprecated": "This module has moved and is now available at @hapi/topo. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", + "dependencies": { + "hoek": "6.x.x" + } + }, "node_modules/toposort": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", @@ -22641,6 +22702,11 @@ "readable-stream": "^3.6.0" } }, + "hoek": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", + "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" + }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -23123,6 +23189,14 @@ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "devOptional": true }, + "isemail": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", + "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", + "requires": { + "punycode": "2.x.x" + } + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -25618,6 +25692,33 @@ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true }, + "node-radius-client": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-radius-client/-/node-radius-client-1.0.0.tgz", + "integrity": "sha512-FkR9cMV5hNoX+kKDUTzuagvEixlLiaEJQ1/ywOdhahsihKrGDhVZmnCvmrCStA589MT3yuC/J2eKc6z68IGdBw==", + "requires": { + "joi": "^14.3.1", + "node-radius-utils": "^1.2.0", + "radius": "^1.1.4" + }, + "dependencies": { + "joi": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", + "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==", + "requires": { + "hoek": "6.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" + } + } + } + }, + "node-radius-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/node-radius-utils/-/node-radius-utils-1.2.0.tgz", + "integrity": "sha512-i3Sf6khnenl0aXumo0whAlfPWTaBqHxEnVBBxpu3dZ7q69NkPPv71rvPjlDZ5wkeKCTNNUTECljerS5kcYQxRw==" + }, "node-releases": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", @@ -26532,6 +26633,11 @@ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, + "radius": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/radius/-/radius-1.1.4.tgz", + "integrity": "sha512-UWuzdF6xf3NpsXFZZmUEkxtEalDXj8hdmMXgbGzn7vOk6zXNsiIY2I6SJ1euHt7PTQuMoz2qDEJB+AfJDJgQYw==" + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -27967,6 +28073,14 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "topo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", + "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", + "requires": { + "hoek": "6.x.x" + } + }, "toposort": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", From a6007adce38755cb924d980fccf5250a9b040adc Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Sat, 13 Aug 2022 13:32:16 +0800 Subject: [PATCH 97/99] Update to 1.18.0-beta.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bac451d5..68a5863d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uptime-kuma", - "version": "1.17.1", + "version": "1.18.0-beta.1", "license": "MIT", "repository": { "type": "git", From 728e811969a2ecc4c3550d37fb75e1c893750d3c Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Sat, 13 Aug 2022 13:35:03 +0800 Subject: [PATCH 98/99] Update Apprise to 1.0.0 --- docker/alpine-base.dockerfile | 2 +- docker/debian-base.dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/alpine-base.dockerfile b/docker/alpine-base.dockerfile index cde65bb6..1d74de05 100644 --- a/docker/alpine-base.dockerfile +++ b/docker/alpine-base.dockerfile @@ -4,5 +4,5 @@ WORKDIR /app # Install apprise, iputils for non-root ping, setpriv RUN apk add --no-cache iputils setpriv dumb-init python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib && \ - pip3 --no-cache-dir install apprise==0.9.9 && \ + pip3 --no-cache-dir install apprise==1.0.0 && \ rm -rf /root/.cache diff --git a/docker/debian-base.dockerfile b/docker/debian-base.dockerfile index f90968a8..20bef3dd 100644 --- a/docker/debian-base.dockerfile +++ b/docker/debian-base.dockerfile @@ -11,7 +11,7 @@ WORKDIR /app RUN apt update && \ apt --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \ sqlite3 iputils-ping util-linux dumb-init && \ - pip3 --no-cache-dir install apprise==0.9.9 && \ + pip3 --no-cache-dir install apprise==1.0.0 && \ rm -rf /var/lib/apt/lists/* && \ apt --yes autoremove From af944242839616ed0a990fdba2e2f43fd043d4c4 Mon Sep 17 00:00:00 2001 From: Louis Lam <louislam@users.noreply.github.com> Date: Sat, 13 Aug 2022 14:04:17 +0800 Subject: [PATCH 99/99] Update to 1.18.0-beta.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 68a5863d..981ca191 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uptime-kuma", - "version": "1.18.0-beta.1", + "version": "1.18.0-beta.0", "license": "MIT", "repository": { "type": "git",