From d92003e1726f0dfd3f162973d2f29064a6dbf709 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Fri, 26 Apr 2024 19:05:56 -0600 Subject: [PATCH 01/72] SNMP Initial Commits This commit introduces a new SNMP monitor feature to the application, allowing users to monitor devices using SNMP (Simple Network Management Protocol). --- .../2024-04-26-0000-snmp-monitor.js | 10 + package-lock.json | 6 + package.json | 1 + server/monitor-types/snmp.js | 69 + server/uptime-kuma-server.js | 2 + src/pages/.EditMonitor.vue.swp | Bin 0 -> 102400 bytes src/pages/EditMonitor.vue | 1273 ++++++++--------- 7 files changed, 714 insertions(+), 647 deletions(-) create mode 100644 db/knex_migrations/2024-04-26-0000-snmp-monitor.js create mode 100644 server/monitor-types/snmp.js create mode 100644 src/pages/.EditMonitor.vue.swp diff --git a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js new file mode 100644 index 000000000..8b93ecd49 --- /dev/null +++ b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js @@ -0,0 +1,10 @@ +exports.up = function (knex) { + return knex.schema + .alterTable("monitor", function (table) { + table.string("snmp_community_string", 255).defaultTo("public"); // Add community_string column + table.string("snmp_oid").notNullable(); // Add oid column + table.enum("snmp_version", ["1", "2c", "3"]).defaultTo("2c"); // Add snmp_version column with enum values + table.float("snmp_control_value").notNullable(); // Add control_value column as float + table.string("snmp_condition").notNullable(); // Add oid column + }); +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a6ef4f036..7728a0cfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,6 +72,7 @@ "redbean-node": "~0.3.0", "redis": "~4.5.1", "semver": "~7.5.4", + "snmp-native": "^1.2.0", "socket.io": "~4.6.1", "socket.io-client": "~4.6.1", "socks-proxy-agent": "6.1.1", @@ -12609,6 +12610,11 @@ "npm": ">= 3.0.0" } }, + "node_modules/snmp-native": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/snmp-native/-/snmp-native-1.2.0.tgz", + "integrity": "sha512-JIyuLX3bQmuAI4gHztHSQd3M/M2hqgLhiHBZYEk8YnYRJ2ooxqwON4gUQfgp/WCZVDca4tIX3vFJgv6lz5iY+g==" + }, "node_modules/socket.io": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.2.tgz", diff --git a/package.json b/package.json index 567efa1b5..7ee8afb41 100644 --- a/package.json +++ b/package.json @@ -137,6 +137,7 @@ "redbean-node": "~0.3.0", "redis": "~4.5.1", "semver": "~7.5.4", + "snmp-native": "^1.2.0", "socket.io": "~4.6.1", "socket.io-client": "~4.6.1", "socks-proxy-agent": "6.1.1", diff --git a/server/monitor-types/snmp.js b/server/monitor-types/snmp.js new file mode 100644 index 000000000..4ddc88230 --- /dev/null +++ b/server/monitor-types/snmp.js @@ -0,0 +1,69 @@ +const { MonitorType } = require("./monitor-type"); +const { UP, DOWN } = require("../../src/util"); +const snmp = require("snmp-native"); + +class SNMPMonitorType extends MonitorType { + name = "snmp"; + + /** + * Checks the SNMP value against the condition and control value. + * @param {object} monitor The monitor object associated with the check. + * @param {object} heartbeat The heartbeat object to update. + * @param {object} _server Unused server object. + */ + async check(monitor, heartbeat, _server) { + try { + const session = new snmp.Session({ host: monitor.ipAddress, community: monitor.snmpCommunityString, version: monitor.snmpVersion }); + + session.get({ oid: monitor.snmpOid }, (err, varbinds) => { + if (err) { + heartbeat.status = DOWN; + heartbeat.msg = `Error: ${err.message}`; + return; + } + + // Assuming only one varbind is returned + const value = varbinds[0].value; + + // Convert value to appropriate type based on SNMP type (assuming it's integer or string for simplicity) + const numericValue = parseInt(value); + const stringValue = value.toString(); + + // Check against condition and control value + switch (monitor.snmpCondition) { + case '>': + heartbeat.status = numericValue > monitor.snmpControlValue ? UP : DOWN; + break; + case '>=': + heartbeat.status = numericValue >= monitor.snmpControlValue ? UP : DOWN; + break; + case '<': + heartbeat.status = numericValue < monitor.snmpControlValue ? UP : DOWN; + break; + case '<=': + heartbeat.status = numericValue <= monitor.snmpControlValue ? UP : DOWN; + break; + case '==': + heartbeat.status = value === monitor.snmpControlValue ? UP : DOWN; + break; + case 'contains': + heartbeat.status = stringValue.includes(monitor.snmpControlValue) ? UP : DOWN; + break; + default: + heartbeat.status = DOWN; + heartbeat.msg = `Invalid condition: ${monitor.snmpCondition}`; + } + + session.close(); + }); + } catch (err) { + heartbeat.status = DOWN; + heartbeat.msg = `Error: ${err.message}`; + } + } + +} + +module.exports = { + SNMPMonitorType, +}; diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index bcf497b58..db7b47970 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -113,6 +113,7 @@ class UptimeKumaServer { UptimeKumaServer.monitorTypeList["tailscale-ping"] = new TailscalePing(); UptimeKumaServer.monitorTypeList["dns"] = new DnsMonitorType(); UptimeKumaServer.monitorTypeList["mqtt"] = new MqttMonitorType(); + UptimeKumaServer.monitorTypeList["snmp"] = new SNMPMonitorType(); // Allow all CORS origins (polling) in development let cors = undefined; @@ -516,3 +517,4 @@ const { RealBrowserMonitorType } = require("./monitor-types/real-browser-monitor const { TailscalePing } = require("./monitor-types/tailscale-ping"); const { DnsMonitorType } = require("./monitor-types/dns"); const { MqttMonitorType } = require("./monitor-types/mqtt"); +const { SNMPMonitorType } = require("./monitor-types/snmp"); diff --git a/src/pages/.EditMonitor.vue.swp b/src/pages/.EditMonitor.vue.swp new file mode 100644 index 0000000000000000000000000000000000000000..638a932fef267fe4c62c92fee964e9c04b6a3abf GIT binary patch literal 102400 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

YJAmoRLUs*4My8DGvjt47%#lUps#XGD|G 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 Ping + @@ -100,19 +103,19 @@ -

+
-
+
-
+
@@ -159,12 +162,7 @@
- +
@@ -198,22 +196,7 @@
- +
@@ -246,646 +229,639 @@ - -
+ +
- -
+ +
- - - - - - -
- - -
- - - -
-
- - -
-
- - - - - - - - - - - - - - - - -
- - -
- -
- - -
- {{ $t("retriesDescription") }} -
-
- -
- - -
- - -
- - -
- -
- - -
- -

{{ $t("Advanced") }}

- -
- - -
-
-
- -
- - -
- -
- - -
- {{ $t("upsideDownModeDescription") }} -
-
- -
- - -
- {{ $t("gamedigGuessPortDescription") }} -
-
- - -
- - -
- - - - - -
- - -
- - -
- - -
- -
-
-
-
+
+ + +
- -

{{ $t("Notifications") }}

-

+ + + + + + +

+ + +
+ + + +
+
+ + +
+
+ + + + + + + + + + + + + + + + +
+ + +
+ +
+ + +
+ {{ $t("retriesDescription") }} +
+
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +

{{ $t("Advanced") }}

+ +
+ + +
+
+
+ +
+ + +
+ +
+ + +
+ {{ $t("upsideDownModeDescription") }} +
+
+ +
+ + +
+ {{ $t("gamedigGuessPortDescription") }} +
+
+ + +
+ + +
+ + + + + +
+ + +
+ + +
+ + +
+ +
+ +
+
+ +
+
+ + +

{{ $t("Notifications") }}

+

+ {{ $t("Not available, please setup.") }} +

+ +
+ + + + + {{ $t("Default") }} +
+ + + + +
+

{{ $t("Proxy") }}

+

{{ $t("Not available, please setup.") }}

-
- +
+ + +
-
- -
-

{{ $t("Proxy") }}

-

- {{ $t("Not available, please setup.") }} -

- -
- - + + + - + + @@ -926,7 +902,7 @@ const monitorDefaults = { packetSize: 56, expiryNotification: false, maxredirects: 10, - accepted_statuscodes: [ "200-299" ], + accepted_statuscodes: ["200-299"], dns_resolve_type: "A", dns_resolve_server: "1.1.1.1", docker_container: "", @@ -947,7 +923,10 @@ const monitorDefaults = { kafkaProducerSsl: false, kafkaProducerAllowAutoTopicCreation: false, gamedigGivenPortOnly: true, - remote_browser: null + remote_browser: null, + port: 161, + communityString: 'public', + oid: '1.3.6.1.2.1.1.1.0', }; export default { @@ -996,7 +975,7 @@ export default { ipRegex() { // Allow to test with simple dns server with port (127.0.0.1:5300) - if (! isDev) { + if (!isDev) { return this.ipRegexPattern; } return null; @@ -1053,15 +1032,15 @@ export default { }, protoServicePlaceholder() { - return this.$t("Example:", [ "Health" ]); + return this.$t("Example:", ["Health"]); }, protoMethodPlaceholder() { - return this.$t("Example:", [ "check" ]); + return this.$t("Example:", ["check"]); }, protoBufDataPlaceholder() { - return this.$t("Example:", [ ` + return this.$t("Example:", [` syntax = "proto3"; package grpc.health.v1; @@ -1088,7 +1067,7 @@ message HealthCheckResponse { }, bodyPlaceholder() { if (this.monitor && this.monitor.httpBodyEncoding && this.monitor.httpBodyEncoding === "xml") { - return this.$t("Example:", [ ` + return this.$t("Example:", [` @@ -1097,16 +1076,16 @@ message HealthCheckResponse { ` ]); } if (this.monitor && this.monitor.httpBodyEncoding === "form") { - return this.$t("Example:", [ "key1=value1&key2=value2" ]); + return this.$t("Example:", ["key1=value1&key2=value2"]); } - return this.$t("Example:", [ ` + return this.$t("Example:", [` { "key": "value" }` ]); }, headersPlaceholder() { - return this.$t("Example:", [ ` + return this.$t("Example:", [` { "HeaderName": "HeaderValue" }` ]); @@ -1131,8 +1110,8 @@ message HealthCheckResponse { // Only groups, not itself, not a decendant result = result.filter( monitor => monitor.type === "group" && - monitor.id !== this.monitor.id && - !this.monitor.childrenIDs?.includes(monitor.id) + monitor.id !== this.monitor.id && + !this.monitor.childrenIDs?.includes(monitor.id) ); // Filter result by active state, weight and alphabetical @@ -1251,7 +1230,7 @@ message HealthCheckResponse { "monitor.type"() { if (this.monitor.type === "push") { - if (! this.monitor.pushToken) { + if (!this.monitor.pushToken) { // ideally this would require checking if the generated token is already used // it's very unlikely to get a collision though (62^32 ~ 2.27265788 * 10^57 unique tokens) this.monitor.pushToken = genSecret(pushTokenLength); @@ -1259,7 +1238,7 @@ message HealthCheckResponse { } // Set default port for DNS if not already defined - if (! this.monitor.port || this.monitor.port === "53" || this.monitor.port === "1812") { + if (!this.monitor.port || this.monitor.port === "53" || this.monitor.port === "1812") { if (this.monitor.type === "dns") { this.monitor.port = "53"; } else if (this.monitor.type === "radius") { @@ -1399,7 +1378,7 @@ message HealthCheckResponse { this.monitor.pathName = undefined; this.monitor.screenshot = undefined; - this.monitor.name = this.$t("cloneOf", [ this.monitor.name ]); + this.monitor.name = this.$t("cloneOf", [this.monitor.name]); this.$refs.tagsManager.newTags = this.monitor.tags.map((monitorTag) => { return { id: monitorTag.tag_id, @@ -1486,7 +1465,7 @@ message HealthCheckResponse { this.monitor.body = JSON.stringify(JSON.parse(this.monitor.body), null, 4); } - const monitorTypesWithEncodingAllowed = [ "http", "keyword", "json-query" ]; + const monitorTypesWithEncodingAllowed = ["http", "keyword", "json-query"]; if (this.monitor.type && !monitorTypesWithEncodingAllowed.includes(this.monitor.type)) { this.monitor.httpBodyEncoding = null; } @@ -1564,7 +1543,7 @@ message HealthCheckResponse { async startParentGroupMonitor() { await sleep(2000); - await this.$root.getSocket().emit("resumeMonitor", this.monitor.parent, () => {}); + await this.$root.getSocket().emit("resumeMonitor", this.monitor.parent, () => { }); }, /** @@ -1610,7 +1589,7 @@ message HealthCheckResponse { // Clamp timeout clampTimeout(timeout) { // limit to 80% of interval, narrowly avoiding epsilon bug - const maxTimeout = ~~(this.monitor.interval * 8 ) / 10; + const maxTimeout = ~~(this.monitor.interval * 8) / 10; const clamped = Math.max(0, Math.min(timeout, maxTimeout)); // 0 will be treated as 80% of interval @@ -1630,9 +1609,9 @@ message HealthCheckResponse { +textarea { + min-height: 200px; +} + \ No newline at end of file From a3cdd69995a138a27fac31866e3993b3a44d3c67 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Mon, 29 Apr 2024 13:56:32 -0600 Subject: [PATCH 02/72] Use net-snmp instead of snmp-native net-snmp over snmp-native is: -more robust -more popular -better documented -supports v3 --- package-lock.json | 16 ++++++++++------ package.json | 2 +- server/monitor-types/snmp.js | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7728a0cfe..0e09c595c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,6 +54,7 @@ "mssql": "~8.1.4", "mysql2": "~3.6.2", "nanoid": "~3.3.4", + "net-snmp": "^3.11.2", "node-cloudflared-tunnel": "~1.0.9", "node-radius-client": "~1.0.0", "nodemailer": "~6.9.13", @@ -72,7 +73,6 @@ "redbean-node": "~0.3.0", "redis": "~4.5.1", "semver": "~7.5.4", - "snmp-native": "^1.2.0", "socket.io": "~4.6.1", "socket.io-client": "~4.6.1", "socks-proxy-agent": "6.1.1", @@ -10337,6 +10337,15 @@ "node": ">= 0.6" } }, + "node_modules/net-snmp": { + "version": "3.11.2", + "resolved": "https://registry.npmjs.org/net-snmp/-/net-snmp-3.11.2.tgz", + "integrity": "sha512-QKy2JQHIBsSK344dUxYRZv7tU0ANk8f8fzKD/Mmq/cCxm/cPbtiT7009QEgxdViW/gGjqGIOiLHxkCc+JhZltg==", + "dependencies": { + "asn1-ber": "^1.2.1", + "smart-buffer": "^4.1.0" + } + }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -12610,11 +12619,6 @@ "npm": ">= 3.0.0" } }, - "node_modules/snmp-native": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/snmp-native/-/snmp-native-1.2.0.tgz", - "integrity": "sha512-JIyuLX3bQmuAI4gHztHSQd3M/M2hqgLhiHBZYEk8YnYRJ2ooxqwON4gUQfgp/WCZVDca4tIX3vFJgv6lz5iY+g==" - }, "node_modules/socket.io": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.2.tgz", diff --git a/package.json b/package.json index 7ee8afb41..49cc56ffc 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "mssql": "~8.1.4", "mysql2": "~3.6.2", "nanoid": "~3.3.4", + "net-snmp": "^3.11.2", "node-cloudflared-tunnel": "~1.0.9", "node-radius-client": "~1.0.0", "nodemailer": "~6.9.13", @@ -137,7 +138,6 @@ "redbean-node": "~0.3.0", "redis": "~4.5.1", "semver": "~7.5.4", - "snmp-native": "^1.2.0", "socket.io": "~4.6.1", "socket.io-client": "~4.6.1", "socks-proxy-agent": "6.1.1", diff --git a/server/monitor-types/snmp.js b/server/monitor-types/snmp.js index 4ddc88230..433fc527f 100644 --- a/server/monitor-types/snmp.js +++ b/server/monitor-types/snmp.js @@ -1,6 +1,6 @@ const { MonitorType } = require("./monitor-type"); const { UP, DOWN } = require("../../src/util"); -const snmp = require("snmp-native"); +const snmp = require("net-snmp"); class SNMPMonitorType extends MonitorType { name = "snmp"; From ff5890a11f0ef3e69959d04e5a43c7b808663787 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Mon, 29 Apr 2024 15:59:21 -0600 Subject: [PATCH 03/72] Updated a comment --- db/knex_migrations/2024-04-26-0000-snmp-monitor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js index 8b93ecd49..489a44241 100644 --- a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js +++ b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js @@ -1,7 +1,7 @@ exports.up = function (knex) { return knex.schema .alterTable("monitor", function (table) { - table.string("snmp_community_string", 255).defaultTo("public"); // Add community_string column + table.string("snmp_community_string", 255).defaultTo("public"); // Add snmp_community_string column table.string("snmp_oid").notNullable(); // Add oid column table.enum("snmp_version", ["1", "2c", "3"]).defaultTo("2c"); // Add snmp_version column with enum values table.float("snmp_control_value").notNullable(); // Add control_value column as float From 4a882be6bac6884a84acf930645ae2f93c18ec7f Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Mon, 29 Apr 2024 15:59:59 -0600 Subject: [PATCH 04/72] Further SNMP monitor development Further testing of SNMP feat, however I'm running into the issue `Error in SNMP check: RequestTimedOutError: Request timed out` when the check function is called. I am unsure as to why since my local SNMP script works great with very similar code. --- server/monitor-types/snmp.js | 65 +++++++++++++++++++++++++----------- src/pages/EditMonitor.vue | 10 ++++-- 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/server/monitor-types/snmp.js b/server/monitor-types/snmp.js index 433fc527f..92c0f4875 100644 --- a/server/monitor-types/snmp.js +++ b/server/monitor-types/snmp.js @@ -12,51 +12,76 @@ class SNMPMonitorType extends MonitorType { * @param {object} _server Unused server object. */ async check(monitor, heartbeat, _server) { + + console.log("IP Address:", monitor._hostname); + console.log("SNMP Community String:", monitor._snmpCommunityString); + console.log("SNMP OID:", monitor._snmpOid); + console.log("SNMP Version:", monitor._snmpVersion); + console.log("SNMP Condition:", monitor._snmpCondition); + console.log("SNMP Control Value:", monitor._snmpControlValue); + + const options = { + port: monitor._port || 161, + retries: 1, + timeout: 1000, + version: getKey(snmp.Version, monitor._snmpVersion) || snmp.Version2c, + }; + + function getKey(obj, value) { + return Object.keys(obj).find(key => obj[key] === value) || null; + } + try { - const session = new snmp.Session({ host: monitor.ipAddress, community: monitor.snmpCommunityString, version: monitor.snmpVersion }); + const session = snmp.createSession(monitor._ipAddress, monitor._snmpCommunityString, options); - session.get({ oid: monitor.snmpOid }, (err, varbinds) => { - if (err) { - heartbeat.status = DOWN; - heartbeat.msg = `Error: ${err.message}`; - return; - } + const varbinds = await new Promise((resolve, reject) => { + session.get([monitor._snmpOid], (error, varbinds) => { + if (error) { + reject(error); + } else { + resolve(varbinds); + } + }); + }); - // Assuming only one varbind is returned + console.log("Received varbinds:", varbinds); // Log the received varbinds for debugging + + if (varbinds && varbinds.length > 0) { const value = varbinds[0].value; - - // Convert value to appropriate type based on SNMP type (assuming it's integer or string for simplicity) const numericValue = parseInt(value); const stringValue = value.toString(); - // Check against condition and control value switch (monitor.snmpCondition) { case '>': - heartbeat.status = numericValue > monitor.snmpControlValue ? UP : DOWN; + heartbeat.status = numericValue > monitor._snmpControlValue ? UP : DOWN; break; case '>=': - heartbeat.status = numericValue >= monitor.snmpControlValue ? UP : DOWN; + heartbeat.status = numericValue >= monitor._snmpControlValue ? UP : DOWN; break; case '<': - heartbeat.status = numericValue < monitor.snmpControlValue ? UP : DOWN; + heartbeat.status = numericValue < monitor._snmpControlValue ? UP : DOWN; break; case '<=': - heartbeat.status = numericValue <= monitor.snmpControlValue ? UP : DOWN; + heartbeat.status = numericValue <= monitor._snmpControlValue ? UP : DOWN; break; case '==': - heartbeat.status = value === monitor.snmpControlValue ? UP : DOWN; + heartbeat.status = value === monitor._snmpControlValue ? UP : DOWN; break; case 'contains': - heartbeat.status = stringValue.includes(monitor.snmpControlValue) ? UP : DOWN; + heartbeat.status = stringValue.includes(monitor._snmpControlValue) ? UP : DOWN; break; default: heartbeat.status = DOWN; - heartbeat.msg = `Invalid condition: ${monitor.snmpCondition}`; + heartbeat.msg = `Invalid condition: ${monitor._snmpCondition}`; } + } else { + heartbeat.status = DOWN; + heartbeat.msg = 'No varbinds returned from SNMP session'; + } - session.close(); - }); + session.close(); // Close the session after use } catch (err) { + console.error("Error in SNMP check:", err); // Log any errors heartbeat.status = DOWN; heartbeat.msg = `Error: ${err.message}`; } diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index d082d3e2f..c21c4a14b 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -924,9 +924,6 @@ const monitorDefaults = { kafkaProducerAllowAutoTopicCreation: false, gamedigGivenPortOnly: true, remote_browser: null, - port: 161, - communityString: 'public', - oid: '1.3.6.1.2.1.1.1.0', }; export default { @@ -1243,11 +1240,18 @@ message HealthCheckResponse { this.monitor.port = "53"; } else if (this.monitor.type === "radius") { this.monitor.port = "1812"; + } else if (this.monitor.type === "snmp") { + this.monitor.port = "161"; } else { this.monitor.port = undefined; } } + // Set default SNMP version + if (!this.monitor.snmpVersion) { + this.monitor.snmpVersion = "2c"; + } + // Get the game list from server if (this.monitor.type === "gamedig") { this.$root.getSocket().emit("getGameList", (res) => { From 99dc4cfb46c2dcf805829b7b34cb33be0376ded5 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Mon, 29 Apr 2024 22:24:51 -0600 Subject: [PATCH 05/72] Wrong variable used Thanks for pointing it out @CommanderStorm! --- server/monitor-types/snmp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/monitor-types/snmp.js b/server/monitor-types/snmp.js index 92c0f4875..1752ab717 100644 --- a/server/monitor-types/snmp.js +++ b/server/monitor-types/snmp.js @@ -32,7 +32,7 @@ class SNMPMonitorType extends MonitorType { } try { - const session = snmp.createSession(monitor._ipAddress, monitor._snmpCommunityString, options); + const session = snmp.createSession(monitor.hostname, monitor.snmpCommunityString, options); const varbinds = await new Promise((resolve, reject) => { session.get([monitor._snmpOid], (error, varbinds) => { From 138075a2af26414dfb0f014cc1cd050bfcd58395 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Tue, 30 Apr 2024 15:10:43 -0600 Subject: [PATCH 06/72] Update db migration: allow nulls DB must allow nulls otherwise this will break other monitors. --- db/knex_migrations/2024-04-26-0000-snmp-monitor.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js index 489a44241..2a5604b3d 100644 --- a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js +++ b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js @@ -2,9 +2,10 @@ exports.up = function (knex) { return knex.schema .alterTable("monitor", function (table) { table.string("snmp_community_string", 255).defaultTo("public"); // Add snmp_community_string column - table.string("snmp_oid").notNullable(); // Add oid column + table.string("snmp_oid").defaultTo(null); // Add oid column table.enum("snmp_version", ["1", "2c", "3"]).defaultTo("2c"); // Add snmp_version column with enum values - table.float("snmp_control_value").notNullable(); // Add control_value column as float - table.string("snmp_condition").notNullable(); // Add oid column + table.float("snmp_control_value").defaultTo(null); // Add control_value column as float + table.string("snmp_condition").defaultTo(null); // Add oid column }); +}; }; \ No newline at end of file From 9c8024c7fafa92c2eebc988ae70100452b7b1aa9 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Tue, 30 Apr 2024 15:11:21 -0600 Subject: [PATCH 07/72] Update db migration: down function knex requires down function --- db/knex_migrations/2024-04-26-0000-snmp-monitor.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js index 2a5604b3d..284ec567f 100644 --- a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js +++ b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js @@ -8,4 +8,7 @@ exports.up = function (knex) { table.string("snmp_condition").defaultTo(null); // Add oid column }); }; + +exports.down = function (knex) { + // Nothing to do here }; \ No newline at end of file From 9d28fcff1a8aeb85c802d2a8234c2119caef3a28 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Tue, 30 Apr 2024 15:13:16 -0600 Subject: [PATCH 08/72] Update bean model backend Updates appropriate values async when editing the SNMP monitor --- server/model/monitor.js | 5 +++++ server/server.js | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/server/model/monitor.js b/server/model/monitor.js index 80cff6f97..98dd216e2 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -161,6 +161,10 @@ class Monitor extends BeanModel { kafkaProducerMessage: this.kafkaProducerMessage, screenshot, remote_browser: this.remote_browser, + snmpOid: this.snmpOid, + snmpCondition: this.snmpCondition, + snmpControlValue: this.snmpControlValue, + snmpVersion: this.snmpVersion, }; if (includeSensitiveData) { @@ -190,6 +194,7 @@ class Monitor extends BeanModel { tlsCert: this.tlsCert, tlsKey: this.tlsKey, kafkaProducerSaslOptions: JSON.parse(this.kafkaProducerSaslOptions), + snmpCommunityString: this.snmpCommunityString, }; } diff --git a/server/server.js b/server/server.js index d5e3f215f..c4ca06425 100644 --- a/server/server.js +++ b/server/server.js @@ -830,6 +830,11 @@ let needSetup = false; monitor.kafkaProducerAllowAutoTopicCreation; bean.gamedigGivenPortOnly = monitor.gamedigGivenPortOnly; bean.remote_browser = monitor.remote_browser; + bean.snmpVersion = monitor.snmpVersion; + bean.snmpCommunityString = monitor.snmpCommunityString; + bean.snmpOid = monitor.snmpOid; + bean.snmpCondition = monitor.snmpCondition; + bean.snmpControlValue = monitor.snmpControlValue; bean.validate(); From 4593afbdbb7a9e6e473a3407a6795e5701256b06 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Tue, 30 Apr 2024 15:15:37 -0600 Subject: [PATCH 09/72] Frontend input validation --- src/pages/EditMonitor.vue | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index c21c4a14b..62f596f00 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -245,19 +245,19 @@
- +
- +
- @@ -268,7 +268,8 @@
- + +
From 9848ce49f36edb23ddd8b45022148eaeceea3509 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Tue, 30 Apr 2024 15:16:45 -0600 Subject: [PATCH 10/72] Minor frontend styling --- src/pages/EditMonitor.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 62f596f00..56f3bc872 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -255,7 +255,7 @@
-
+
-
+
From 704ffd3f4b2da668157dc8053df65068ea5010c4 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Tue, 30 Apr 2024 15:18:25 -0600 Subject: [PATCH 11/72] Finalized SNMP monitor --- server/monitor-types/snmp.js | 69 +++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/server/monitor-types/snmp.js b/server/monitor-types/snmp.js index 1752ab717..2fa397161 100644 --- a/server/monitor-types/snmp.js +++ b/server/monitor-types/snmp.js @@ -1,5 +1,5 @@ const { MonitorType } = require("./monitor-type"); -const { UP, DOWN } = require("../../src/util"); +const { UP, DOWN, log } = require("../../src/util"); const snmp = require("net-snmp"); class SNMPMonitorType extends MonitorType { @@ -13,18 +13,17 @@ class SNMPMonitorType extends MonitorType { */ async check(monitor, heartbeat, _server) { - console.log("IP Address:", monitor._hostname); - console.log("SNMP Community String:", monitor._snmpCommunityString); - console.log("SNMP OID:", monitor._snmpOid); - console.log("SNMP Version:", monitor._snmpVersion); - console.log("SNMP Condition:", monitor._snmpCondition); - console.log("SNMP Control Value:", monitor._snmpControlValue); + log.debug("monitor", `SNMP: Community String: ${monitor.snmpCommunityString}`); + log.debug("monitor", `SNMP: OID: ${monitor.snmpOid}`); + log.debug("monitor", `SNMP: Version: ${monitor.snmpVersion}`); + log.debug("monitor", `SNMP: Condition: ${monitor.snmpCondition}`); + log.debug("monitor", `SNMP: Control Value: ${monitor.snmpControlValue}`); const options = { - port: monitor._port || 161, - retries: 1, + port: monitor.port || '161', + retries: monitor.maxretries, timeout: 1000, - version: getKey(snmp.Version, monitor._snmpVersion) || snmp.Version2c, + version: getKey(snmp.Version, monitor.snmpVersion) || snmp.Version2c, }; function getKey(obj, value) { @@ -34,56 +33,70 @@ class SNMPMonitorType extends MonitorType { try { const session = snmp.createSession(monitor.hostname, monitor.snmpCommunityString, options); + // Handle errors during session creation + session.on('error', (error) => { + heartbeat.status = DOWN; + heartbeat.msg = `SNMP: Error creating SNMP session: ${error.message}`; + log.debug("monitor", `SNMP: ${heartbeat.msg}`); + }); + const varbinds = await new Promise((resolve, reject) => { - session.get([monitor._snmpOid], (error, varbinds) => { + session.get([monitor.snmpOid], (error, varbinds) => { if (error) { reject(error); } else { + log.debug("monitor", `SNMP: Received varbinds: Type: ${getKey(snmp.ObjectType, varbinds[0].type)}, Value: ${varbinds[0].value}`); // Log the received varbinds for debugging resolve(varbinds); } }); }); - console.log("Received varbinds:", varbinds); // Log the received varbinds for debugging - - if (varbinds && varbinds.length > 0) { + if (varbinds.length === 0 || getKey(snmp.ObjectType, varbinds[0].type) === 'NoSuchInstance') { + throw new Error(`No varbinds returned from SNMP session (OID: ${monitor.snmpOid})`); + } else { const value = varbinds[0].value; const numericValue = parseInt(value); - const stringValue = value.toString(); + const stringValue = value.toString('ascii'); switch (monitor.snmpCondition) { case '>': - heartbeat.status = numericValue > monitor._snmpControlValue ? UP : DOWN; + heartbeat.status = numericValue > monitor.snmpControlValue ? UP : DOWN; break; case '>=': - heartbeat.status = numericValue >= monitor._snmpControlValue ? UP : DOWN; + heartbeat.status = numericValue >= monitor.snmpControlValue ? UP : DOWN; break; case '<': - heartbeat.status = numericValue < monitor._snmpControlValue ? UP : DOWN; + heartbeat.status = numericValue < monitor.snmpControlValue ? UP : DOWN; break; case '<=': - heartbeat.status = numericValue <= monitor._snmpControlValue ? UP : DOWN; + heartbeat.status = numericValue <= monitor.snmpControlValue ? UP : DOWN; break; case '==': - heartbeat.status = value === monitor._snmpControlValue ? UP : DOWN; + if (!isNaN(value) && !isNaN(monitor.snmpControlValue)) { + // Both values are numeric, parse them as numbers + heartbeat.status = parseFloat(value) === parseFloat(monitor.snmpControlValue) ? UP : DOWN; + } else { + // At least one of the values is not numeric, compare them as strings + heartbeat.status = value.toString() === monitor.snmpControlValue.toString() ? UP : DOWN; + } break; case 'contains': - heartbeat.status = stringValue.includes(monitor._snmpControlValue) ? UP : DOWN; + heartbeat.status = stringValue.includes(monitor.snmpControlValue) ? UP : DOWN; break; default: heartbeat.status = DOWN; - heartbeat.msg = `Invalid condition: ${monitor._snmpCondition}`; + heartbeat.msg = `Invalid condition: ${monitor.snmpCondition}`; + break; } - } else { - heartbeat.status = DOWN; - heartbeat.msg = 'No varbinds returned from SNMP session'; - } + heartbeat.msg = `SNMP value ` + (heartbeat.status ? `passes` : `does not pass`) + ` comparison: ${value.toString('ascii')} ${monitor.snmpCondition} ${monitor.snmpControlValue}`; + } session.close(); // Close the session after use + } catch (err) { - console.error("Error in SNMP check:", err); // Log any errors heartbeat.status = DOWN; - heartbeat.msg = `Error: ${err.message}`; + heartbeat.msg = `SNMP Error: ${err.message}`; + log.debug("monitor", `SNMP: ${heartbeat.msg}`); } } From ba47aca51fd4e398b54763e3a71a8f95c028b0a7 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Tue, 30 Apr 2024 17:54:29 -0600 Subject: [PATCH 12/72] Apply suggestions from code review Co-authored-by: Frank Elsinga --- server/monitor-types/snmp.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/server/monitor-types/snmp.js b/server/monitor-types/snmp.js index 2fa397161..49835dd9c 100644 --- a/server/monitor-types/snmp.js +++ b/server/monitor-types/snmp.js @@ -6,19 +6,10 @@ class SNMPMonitorType extends MonitorType { name = "snmp"; /** - * Checks the SNMP value against the condition and control value. - * @param {object} monitor The monitor object associated with the check. - * @param {object} heartbeat The heartbeat object to update. - * @param {object} _server Unused server object. + * @inheritdoc */ async check(monitor, heartbeat, _server) { - log.debug("monitor", `SNMP: Community String: ${monitor.snmpCommunityString}`); - log.debug("monitor", `SNMP: OID: ${monitor.snmpOid}`); - log.debug("monitor", `SNMP: Version: ${monitor.snmpVersion}`); - log.debug("monitor", `SNMP: Condition: ${monitor.snmpCondition}`); - log.debug("monitor", `SNMP: Control Value: ${monitor.snmpControlValue}`); - const options = { port: monitor.port || '161', retries: monitor.maxretries, @@ -37,7 +28,7 @@ class SNMPMonitorType extends MonitorType { session.on('error', (error) => { heartbeat.status = DOWN; heartbeat.msg = `SNMP: Error creating SNMP session: ${error.message}`; - log.debug("monitor", `SNMP: ${heartbeat.msg}`); + log.debug("monitor", heartbeat.msg); }); const varbinds = await new Promise((resolve, reject) => { @@ -45,7 +36,7 @@ class SNMPMonitorType extends MonitorType { if (error) { reject(error); } else { - log.debug("monitor", `SNMP: Received varbinds: Type: ${getKey(snmp.ObjectType, varbinds[0].type)}, Value: ${varbinds[0].value}`); // Log the received varbinds for debugging + log.debug("monitor", `SNMP: Received varbinds (Type=${getKey(snmp.ObjectType, varbinds[0].type)}): ${varbinds[0].value}`); resolve(varbinds); } }); @@ -91,7 +82,7 @@ class SNMPMonitorType extends MonitorType { heartbeat.msg = `SNMP value ` + (heartbeat.status ? `passes` : `does not pass`) + ` comparison: ${value.toString('ascii')} ${monitor.snmpCondition} ${monitor.snmpControlValue}`; } - session.close(); // Close the session after use + session.close(); } catch (err) { heartbeat.status = DOWN; From 7459654e11b5c580989246f3127a451f625ea22e Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Tue, 30 Apr 2024 18:04:59 -0600 Subject: [PATCH 13/72] ES Lint Compliant --- .../2024-04-26-0000-snmp-monitor.js | 4 +-- server/monitor-types/snmp.js | 30 +++++++++++-------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js index 284ec567f..2b9474c83 100644 --- a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js +++ b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js @@ -3,7 +3,7 @@ exports.up = function (knex) { .alterTable("monitor", function (table) { table.string("snmp_community_string", 255).defaultTo("public"); // Add snmp_community_string column table.string("snmp_oid").defaultTo(null); // Add oid column - table.enum("snmp_version", ["1", "2c", "3"]).defaultTo("2c"); // Add snmp_version column with enum values + table.enum("snmp_version", [ "1", "2c", "3" ]).defaultTo("2c"); // Add snmp_version column with enum values table.float("snmp_control_value").defaultTo(null); // Add control_value column as float table.string("snmp_condition").defaultTo(null); // Add oid column }); @@ -11,4 +11,4 @@ exports.up = function (knex) { exports.down = function (knex) { // Nothing to do here -}; \ No newline at end of file +}; diff --git a/server/monitor-types/snmp.js b/server/monitor-types/snmp.js index 49835dd9c..3ae11890c 100644 --- a/server/monitor-types/snmp.js +++ b/server/monitor-types/snmp.js @@ -11,12 +11,18 @@ class SNMPMonitorType extends MonitorType { async check(monitor, heartbeat, _server) { const options = { - port: monitor.port || '161', + port: monitor.port || "161", retries: monitor.maxretries, timeout: 1000, version: getKey(snmp.Version, monitor.snmpVersion) || snmp.Version2c, }; + /** + * Retrieves the key from the provided object corresponding to the given value. + * @param {object} obj - The object to search. + * @param {*} value - The value to search for. + * @returns {string|null} - The key associated with the value, or null if not found. + */ function getKey(obj, value) { return Object.keys(obj).find(key => obj[key] === value) || null; } @@ -25,14 +31,14 @@ class SNMPMonitorType extends MonitorType { const session = snmp.createSession(monitor.hostname, monitor.snmpCommunityString, options); // Handle errors during session creation - session.on('error', (error) => { + session.on("error", (error) => { heartbeat.status = DOWN; heartbeat.msg = `SNMP: Error creating SNMP session: ${error.message}`; log.debug("monitor", heartbeat.msg); }); const varbinds = await new Promise((resolve, reject) => { - session.get([monitor.snmpOid], (error, varbinds) => { + session.get([ monitor.snmpOid ], (error, varbinds) => { if (error) { reject(error); } else { @@ -42,27 +48,27 @@ class SNMPMonitorType extends MonitorType { }); }); - if (varbinds.length === 0 || getKey(snmp.ObjectType, varbinds[0].type) === 'NoSuchInstance') { + if (varbinds.length === 0 || getKey(snmp.ObjectType, varbinds[0].type) === "NoSuchInstance") { throw new Error(`No varbinds returned from SNMP session (OID: ${monitor.snmpOid})`); } else { const value = varbinds[0].value; const numericValue = parseInt(value); - const stringValue = value.toString('ascii'); + const stringValue = value.toString("ascii"); switch (monitor.snmpCondition) { - case '>': + case ">": heartbeat.status = numericValue > monitor.snmpControlValue ? UP : DOWN; break; - case '>=': + case ">=": heartbeat.status = numericValue >= monitor.snmpControlValue ? UP : DOWN; break; - case '<': + case "<": heartbeat.status = numericValue < monitor.snmpControlValue ? UP : DOWN; break; - case '<=': + case "<=": heartbeat.status = numericValue <= monitor.snmpControlValue ? UP : DOWN; break; - case '==': + case "==": if (!isNaN(value) && !isNaN(monitor.snmpControlValue)) { // Both values are numeric, parse them as numbers heartbeat.status = parseFloat(value) === parseFloat(monitor.snmpControlValue) ? UP : DOWN; @@ -71,7 +77,7 @@ class SNMPMonitorType extends MonitorType { heartbeat.status = value.toString() === monitor.snmpControlValue.toString() ? UP : DOWN; } break; - case 'contains': + case "contains": heartbeat.status = stringValue.includes(monitor.snmpControlValue) ? UP : DOWN; break; default: @@ -79,7 +85,7 @@ class SNMPMonitorType extends MonitorType { heartbeat.msg = `Invalid condition: ${monitor.snmpCondition}`; break; } - heartbeat.msg = `SNMP value ` + (heartbeat.status ? `passes` : `does not pass`) + ` comparison: ${value.toString('ascii')} ${monitor.snmpCondition} ${monitor.snmpControlValue}`; + heartbeat.msg = "SNMP value " + (heartbeat.status ? "passes" : "does not pass") + ` comparison: ${value.toString("ascii")} ${monitor.snmpCondition} ${monitor.snmpControlValue}`; } session.close(); From e944492da87d4fa86c19ec0d3c3688186064fbab Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Tue, 30 Apr 2024 18:06:03 -0600 Subject: [PATCH 14/72] Corrected down function https://github.com/louislam/uptime-kuma/pull/4717/files/b4bd003626986be1faab7142710f9443273d89fc#r1585590243 --- db/knex_migrations/2024-04-26-0000-snmp-monitor.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js index 2b9474c83..6cf871005 100644 --- a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js +++ b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js @@ -10,5 +10,11 @@ exports.up = function (knex) { }; exports.down = function (knex) { - // Nothing to do here + return knex.schema.alterTable("monitor", function (table) { + table.dropColumn("snmp_community_string"); + table.dropColumn("snmp_oid"); + table.dropColumn("snmp_version"); + table.dropColumn("snmp_control_value"); + table.dropColumn("snmp_condition"); + }); }; From 97a9094d7c5db66a0bf9c5c0cdac4925fc2af509 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Tue, 30 Apr 2024 18:14:36 -0600 Subject: [PATCH 15/72] ES Lint Compliant --- src/pages/EditMonitor.vue | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 56f3bc872..b1193e21a 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -258,10 +258,10 @@
@@ -271,23 +271,23 @@
+
-
-
- - -
+
+ + +
From 9ba0f68a866f4ba11602addbda362169af4b6907 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Tue, 30 Apr 2024 18:19:18 -0600 Subject: [PATCH 16/72] Remove supurfluous log.debug Co-Authored-By: Frank Elsinga --- server/monitor-types/snmp.js | 1 - 1 file changed, 1 deletion(-) diff --git a/server/monitor-types/snmp.js b/server/monitor-types/snmp.js index 3ae11890c..7b30a6174 100644 --- a/server/monitor-types/snmp.js +++ b/server/monitor-types/snmp.js @@ -93,7 +93,6 @@ class SNMPMonitorType extends MonitorType { } catch (err) { heartbeat.status = DOWN; heartbeat.msg = `SNMP Error: ${err.message}`; - log.debug("monitor", `SNMP: ${heartbeat.msg}`); } } From ba84f014441e9da03e16f23269d0064fe1adcb25 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Wed, 1 May 2024 09:15:35 -0600 Subject: [PATCH 17/72] Delete .EditMonitor.vue.swp Co-Authored-By: Frank Elsinga --- src/pages/.EditMonitor.vue.swp | Bin 102400 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/pages/.EditMonitor.vue.swp diff --git a/src/pages/.EditMonitor.vue.swp b/src/pages/.EditMonitor.vue.swp deleted file mode 100644 index 638a932fef267fe4c62c92fee964e9c04b6a3abf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102400 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

YJAmoRLUs*4My8DGvjt47%#lUps#XGD|G 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 Date: Wed, 1 May 2024 10:29:13 -0600 Subject: [PATCH 18/72] ES Lint Compliant Also changed line endings from 'LF' to 'CRLF' --- src/pages/EditMonitor.vue | 1060 ++++++++++++++++++------------------- 1 file changed, 530 insertions(+), 530 deletions(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index b1193e21a..3eccb7ac5 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -289,580 +289,580 @@

- - - - - -
- - -
- - - -
-
- - -
-
- - - - - - - - - - - - - - - - -
- - -
- -
- - -
- {{ $t("retriesDescription") }} +
-
- - -
+
+
- -
- - -
- -
- - -
- -

{{ $t("Advanced") }}

- -
- - -
-
-
- -
- - -
- -
- - -
- {{ $t("upsideDownModeDescription") }} -
-
- -
- - -
- {{ $t("gamedigGuessPortDescription") }} -
-
- - -
- - -
- - - - - -
- - -
- - -
- - -
- -
- -
-
- -
-
- - -

{{ $t("Notifications") }}

-

- {{ $t("Not available, please setup.") }} -

- -
- - - - - {{ $t("Default") }} -
- - - - -
-

{{ $t("Proxy") }}

-

+ +

{{ $t("Notifications") }}

+

{{ $t("Not available, please setup.") }}

-
- - -
+
+ -
- - -
- -
- - - - - - - - @@ -903,7 +903,7 @@ const monitorDefaults = { packetSize: 56, expiryNotification: false, maxredirects: 10, - accepted_statuscodes: ["200-299"], + accepted_statuscodes: [ "200-299" ], dns_resolve_type: "A", dns_resolve_server: "1.1.1.1", docker_container: "", @@ -1030,15 +1030,15 @@ export default { }, protoServicePlaceholder() { - return this.$t("Example:", ["Health"]); + return this.$t("Example:", [ "Health" ]); }, protoMethodPlaceholder() { - return this.$t("Example:", ["check"]); + return this.$t("Example:", [ "check" ]); }, protoBufDataPlaceholder() { - return this.$t("Example:", [` + return this.$t("Example:", [ ` syntax = "proto3"; package grpc.health.v1; @@ -1065,7 +1065,7 @@ message HealthCheckResponse { }, bodyPlaceholder() { if (this.monitor && this.monitor.httpBodyEncoding && this.monitor.httpBodyEncoding === "xml") { - return this.$t("Example:", [` + return this.$t("Example:", [ ` @@ -1074,16 +1074,16 @@ message HealthCheckResponse { ` ]); } if (this.monitor && this.monitor.httpBodyEncoding === "form") { - return this.$t("Example:", ["key1=value1&key2=value2"]); + return this.$t("Example:", [ "key1=value1&key2=value2" ]); } - return this.$t("Example:", [` + return this.$t("Example:", [ ` { "key": "value" }` ]); }, headersPlaceholder() { - return this.$t("Example:", [` + return this.$t("Example:", [ ` { "HeaderName": "HeaderValue" }` ]); @@ -1383,7 +1383,7 @@ message HealthCheckResponse { this.monitor.pathName = undefined; this.monitor.screenshot = undefined; - this.monitor.name = this.$t("cloneOf", [this.monitor.name]); + this.monitor.name = this.$t("cloneOf", [ this.monitor.name ]); this.$refs.tagsManager.newTags = this.monitor.tags.map((monitorTag) => { return { id: monitorTag.tag_id, @@ -1470,7 +1470,7 @@ message HealthCheckResponse { this.monitor.body = JSON.stringify(JSON.parse(this.monitor.body), null, 4); } - const monitorTypesWithEncodingAllowed = ["http", "keyword", "json-query"]; + const monitorTypesWithEncodingAllowed = [ "http", "keyword", "json-query" ]; if (this.monitor.type && !monitorTypesWithEncodingAllowed.includes(this.monitor.type)) { this.monitor.httpBodyEncoding = null; } @@ -1619,4 +1619,4 @@ message HealthCheckResponse { textarea { min-height: 200px; } - \ No newline at end of file + From d83c2b90c9d8b82b5c994d34ee2de71233e237c9 Mon Sep 17 00:00:00 2001 From: Matt Visnovsky Date: Thu, 2 May 2024 09:50:09 -0600 Subject: [PATCH 19/72] Revert unintentional changes to EditMonitor.vue Reverts unintentional changes committed in: d92003e1726f0dfd3f162973d2f29064a6dbf709 --- src/pages/EditMonitor.vue | 137 +++++++++++++++++++++++++++++--------- 1 file changed, 105 insertions(+), 32 deletions(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 3eccb7ac5..a6ae1250b 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -162,7 +162,12 @@
- +
@@ -196,7 +201,22 @@
- +
@@ -313,7 +333,19 @@ - +
{{ $t("rrtypeDescription") }} @@ -333,7 +365,16 @@
- +
@@ -403,19 +444,19 @@
-
{{ $t("RadiusSecretDescription") }}
+
{{ $t( "RadiusSecretDescription") }}
-
{{ $t("RadiusCalledStationIdDescription") }}
+
{{ $t( "RadiusCalledStationIdDescription") }}
-
{{ $t("RadiusCallingStationIdDescription") }}
+
{{ $t( "RadiusCallingStationIdDescription") }}
@@ -439,13 +480,13 @@
- +
@@ -460,21 +501,21 @@
- +
@@ -482,7 +523,7 @@

{{ $t("Advanced") }}

-
+
-
+
-