diff --git a/package-lock.json b/package-lock.json index 420b7a923..36c6c3bc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -76,7 +76,7 @@ "qs": "~6.10.4", "radius": "~1.1.4", "redbean-node": "~0.3.0", - "redis": "~4.5.1", + "redis": "~5.9.0", "semver": "~7.5.4", "socket.io": "~4.8.0", "socket.io-client": "~4.8.0", @@ -2718,62 +2718,63 @@ "license": "BSD-3-Clause" }, "node_modules/@redis/bloom": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.1.0.tgz", - "integrity": "sha512-9QovlxmpRtvxVbN0UBcv8WfdSMudNZZTFqCsnBszcQXqaZb/TVe30ScgGEO7u1EAIacTPAo7/oCYjYAxiHLanQ==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.9.0.tgz", + "integrity": "sha512-W9D8yfKTWl4tP8lkC3MRYkMz4OfbuzE/W8iObe0jFgoRmgMfkBV+Vj38gvIqZPImtY0WB34YZkX3amYuQebvRQ==", "license": "MIT", + "engines": { + "node": ">= 18" + }, "peerDependencies": { - "@redis/client": "^1.0.0" + "@redis/client": "^5.9.0" } }, "node_modules/@redis/client": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.4.2.tgz", - "integrity": "sha512-oUdEjE0I7JS5AyaAjkD3aOXn9NhO7XKyPyXEyrgFDu++VrVBHUPnV6dgEya9TcMuj5nIJRuCzCm8ZP+c9zCHPw==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.9.0.tgz", + "integrity": "sha512-EI0Ti5pojD2p7TmcS7RRa+AJVahdQvP/urpcSbK/K9Rlk6+dwMJTQ354pCNGCwfke8x4yKr5+iH85wcERSkwLQ==", "license": "MIT", "dependencies": { - "cluster-key-slot": "1.1.1", - "generic-pool": "3.9.0", - "yallist": "4.0.0" + "cluster-key-slot": "1.1.2" }, "engines": { - "node": ">=14" - } - }, - "node_modules/@redis/graph": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", - "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", - "license": "MIT", - "peerDependencies": { - "@redis/client": "^1.0.0" + "node": ">= 18" } }, "node_modules/@redis/json": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", - "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.9.0.tgz", + "integrity": "sha512-Bm2jjLYaXdUWPb9RaEywxnjmzw7dWKDZI4MS79mTWPV16R982jVWBj6lY2ZGelJbwxHtEVg4/FSVgYDkuO/MxA==", "license": "MIT", + "engines": { + "node": ">= 18" + }, "peerDependencies": { - "@redis/client": "^1.0.0" + "@redis/client": "^5.9.0" } }, "node_modules/@redis/search": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.0.tgz", - "integrity": "sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.9.0.tgz", + "integrity": "sha512-jdk2csmJ29DlpvCIb2ySjix2co14/0iwIT3C0I+7ZaToXgPbgBMB+zfEilSuncI2F9JcVxHki0YtLA0xX3VdpA==", "license": "MIT", + "engines": { + "node": ">= 18" + }, "peerDependencies": { - "@redis/client": "^1.0.0" + "@redis/client": "^5.9.0" } }, "node_modules/@redis/time-series": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", - "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.9.0.tgz", + "integrity": "sha512-W6ILxcyOqhnI7ELKjJXOktIg3w4+aBHugDbVpgVLPZ+YDjObis1M0v7ZzwlpXhlpwsfePfipeSK+KWNuymk52w==", "license": "MIT", + "engines": { + "node": ">= 18" + }, "peerDependencies": { - "@redis/client": "^1.0.0" + "@redis/client": "^5.9.0" } }, "node_modules/@rollup/rollup-android-arm-eabi": { @@ -6116,9 +6117,9 @@ } }, "node_modules/cluster-key-slot": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", - "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", "license": "Apache-2.0", "engines": { "node": ">=0.10.0" @@ -8927,15 +8928,6 @@ "node": ">= 0.4" } }, - "node_modules/generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -13508,20 +13500,19 @@ } }, "node_modules/redis": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.5.1.tgz", - "integrity": "sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-5.9.0.tgz", + "integrity": "sha512-E8dQVLSyH6UE/C9darFuwq4usOPrqfZ1864kI4RFbr5Oj9ioB9qPF0oJMwX7s8mf6sPYrz84x/Dx1PGF3/0EaQ==", "license": "MIT", - "workspaces": [ - "./packages/*" - ], "dependencies": { - "@redis/bloom": "1.1.0", - "@redis/client": "1.4.2", - "@redis/graph": "1.1.0", - "@redis/json": "1.0.4", - "@redis/search": "1.1.0", - "@redis/time-series": "1.0.4" + "@redis/bloom": "5.9.0", + "@redis/client": "5.9.0", + "@redis/json": "5.9.0", + "@redis/search": "5.9.0", + "@redis/time-series": "5.9.0" + }, + "engines": { + "node": ">= 18" } }, "node_modules/reflect.getprototypeof": { diff --git a/package.json b/package.json index d9614df7f..9e3c7bf84 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "radius": "~1.1.4", "node-radius-utils": "~1.2.0", "redbean-node": "~0.3.0", - "redis": "~4.5.1", + "redis": "~5.9.0", "semver": "~7.5.4", "socket.io": "~4.8.0", "socket.io-client": "~4.8.0", diff --git a/server/model/monitor.js b/server/model/monitor.js index 398378292..a442c0ab5 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -9,7 +9,7 @@ const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, MAX_INTERVAL_SECOND, MI PING_PER_REQUEST_TIMEOUT_MIN, PING_PER_REQUEST_TIMEOUT_MAX, PING_PER_REQUEST_TIMEOUT_DEFAULT } = require("../../src/util"); const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius, grpcQuery, - redisPingAsync, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal + kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal } = require("../util-server"); const { R } = require("redbean-node"); const { BeanModel } = require("redbean-node/dist/bean-model"); @@ -851,13 +851,6 @@ class Monitor extends BeanModel { bean.msg = resp.code; bean.status = UP; bean.ping = dayjs().valueOf() - startTime; - } else if (this.type === "redis") { - let startTime = dayjs().valueOf(); - - bean.msg = await redisPingAsync(this.databaseConnectionString, !this.ignoreTls); - bean.status = UP; - bean.ping = dayjs().valueOf() - startTime; - } else if (this.type in UptimeKumaServer.monitorTypeList) { let startTime = dayjs().valueOf(); const monitorType = UptimeKumaServer.monitorTypeList[this.type]; diff --git a/server/monitor-types/redis.js b/server/monitor-types/redis.js new file mode 100644 index 000000000..72b078eb2 --- /dev/null +++ b/server/monitor-types/redis.js @@ -0,0 +1,57 @@ +const { MonitorType } = require("./monitor-type"); +const { UP } = require("../../src/util"); +const redis = require("redis"); + +class RedisMonitorType extends MonitorType { + name = "redis"; + + /** + * @inheritdoc + */ + async check(monitor, heartbeat, _server) { + heartbeat.msg = await this.redisPingAsync(monitor.databaseConnectionString, !monitor.ignoreTls); + heartbeat.status = UP; + } + + /** + * Redis server ping + * @param {string} dsn The redis connection string + * @param {boolean} rejectUnauthorized If false, allows unverified server certificates. + * @returns {Promise} Response from redis server + */ + redisPingAsync(dsn, rejectUnauthorized) { + return new Promise((resolve, reject) => { + const client = redis.createClient({ + url: dsn, + socket: { + rejectUnauthorized + } + }); + client.on("error", (err) => { + if (client.isOpen) { + client.disconnect(); + } + reject(err); + }); + client.connect().then(() => { + if (!client.isOpen) { + client.emit("error", new Error("connection isn't open")); + } + client.ping().then((res, err) => { + if (client.isOpen) { + client.disconnect(); + } + if (err) { + reject(err); + } else { + resolve(res); + } + }).catch(error => reject(error)); + }); + }); + } +} + +module.exports = { + RedisMonitorType, +}; diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index a04e6bd49..3c84bf646 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -119,6 +119,7 @@ class UptimeKumaServer { UptimeKumaServer.monitorTypeList["mongodb"] = new MongodbMonitorType(); UptimeKumaServer.monitorTypeList["rabbitmq"] = new RabbitMqMonitorType(); UptimeKumaServer.monitorTypeList["manual"] = new ManualMonitorType(); + UptimeKumaServer.monitorTypeList["redis"] = new RedisMonitorType(); // Allow all CORS origins (polling) in development let cors = undefined; @@ -560,4 +561,6 @@ const { SNMPMonitorType } = require("./monitor-types/snmp"); const { MongodbMonitorType } = require("./monitor-types/mongodb"); const { RabbitMqMonitorType } = require("./monitor-types/rabbitmq"); const { ManualMonitorType } = require("./monitor-types/manual"); +const { RedisMonitorType } = require("./monitor-types/redis"); const Monitor = require("./model/monitor"); + diff --git a/server/util-server.js b/server/util-server.js index 462b80578..3de6e777f 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -20,7 +20,6 @@ const { Settings } = require("./settings"); const grpc = require("@grpc/grpc-js"); const protojs = require("protobufjs"); const RadiusClient = require("./radius-client"); -const redis = require("redis"); const oidc = require("openid-client"); const tls = require("tls"); const { exists } = require("fs"); @@ -523,44 +522,6 @@ exports.radius = function ( }); }; -/** - * Redis server ping - * @param {string} dsn The redis connection string - * @param {boolean} rejectUnauthorized If false, allows unverified server certificates. - * @returns {Promise} Response from server - */ -exports.redisPingAsync = function (dsn, rejectUnauthorized) { - return new Promise((resolve, reject) => { - const client = redis.createClient({ - url: dsn, - socket: { - rejectUnauthorized - } - }); - client.on("error", (err) => { - if (client.isOpen) { - client.disconnect(); - } - reject(err); - }); - client.connect().then(() => { - if (!client.isOpen) { - client.emit("error", new Error("connection isn't open")); - } - client.ping().then((res, err) => { - if (client.isOpen) { - client.disconnect(); - } - if (err) { - reject(err); - } else { - resolve(res); - } - }).catch(error => reject(error)); - }); - }); -}; - /** * Retrieve value of setting based on key * @param {string} key Key of setting to retrieve diff --git a/test/manual-test-radius-tls/certs/redis.crt b/test/manual-test-radius-tls/certs/redis.crt new file mode 100644 index 000000000..29e371978 --- /dev/null +++ b/test/manual-test-radius-tls/certs/redis.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCTCCAfGgAwIBAgIUF6AMqH3K5nlbnWuHAMu12MUjqCUwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MTExNTIwMTk0OFoXDTI2MTEx +NTIwMTk0OFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtRVPm2BOFyaRoFVP3g+OO8YYvUUzVnMlp8T+FkQUWQ3g +Xzk3k059ca67uPhfujRQ0S+e4FTPyHPrbCh73aTtFfpg1BTlEcuOAXUpxrtSpXbY +D4XvO5OZK3QmFIkUOfOMoJoi0Iv75CgVlcGnQOxPY5A12+uyzMNGPFWBX42qgeW9 +huijfqE3jwN2gM05ryA6EBk1TIewUTMycTFI3t3YLJyZdNMG4kmphIJ/Ie6Na4u3 +YaKXp9o+VCN8t5bd/IYhFW8PznlXbv2NU83ARjmfk7Vc0OrvTUsr9+NTPOdFFoCp +sAbxogO/hZpv3UtX9lzk22MpzcBbpzPodXAikNZeswIDAQABo1MwUTAdBgNVHQ4E +FgQU9PhfZPxI1PB50DdRrI82U1cRPvkwHwYDVR0jBBgwFoAU9PhfZPxI1PB50DdR +rI82U1cRPvkwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAclr4 +M5PjA1nqTZfbdaerA5uvyPnIdjc6Ms6ZvP75h6kHxvUJj9kcoSbg/2nqyCY6UJod +oOPTJZppB+xfHD6ahPLO30IPw1HPr+OfTaiwBoZMnjGn08p5dAjyG0hAyHciDClY +UAxQld+5NNI82QEx5BJ3mcpO5Mi36SW7Kck2TnCza6JxjOmtFi4BLMFsnRD9Vepu +vIvu3DrCxnpYdCV6zUT55414NKCPsut7YHqkDc4gOUHcQ0QOQSRwhaGpLnkfwihe +DkHgJvcBlBOMcr2UCQvXPwPPP1dJ4Y9OQrjGxCnSeDy89cu5/6z/ZBy2ygGHehGZ +zx5PrQLiqgdChdwb6w== +-----END CERTIFICATE----- diff --git a/test/manual-test-radius-tls/certs/redis.key b/test/manual-test-radius-tls/certs/redis.key new file mode 100644 index 000000000..a3e02b210 --- /dev/null +++ b/test/manual-test-radius-tls/certs/redis.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1FU+bYE4XJpGg +VU/eD447xhi9RTNWcyWnxP4WRBRZDeBfOTeTTn1xrru4+F+6NFDRL57gVM/Ic+ts +KHvdpO0V+mDUFOURy44BdSnGu1KldtgPhe87k5krdCYUiRQ584ygmiLQi/vkKBWV +wadA7E9jkDXb67LMw0Y8VYFfjaqB5b2G6KN+oTePA3aAzTmvIDoQGTVMh7BRMzJx +MUje3dgsnJl00wbiSamEgn8h7o1ri7dhopen2j5UI3y3lt38hiEVbw/OeVdu/Y1T +zcBGOZ+TtVzQ6u9NSyv341M850UWgKmwBvGiA7+Fmm/dS1f2XOTbYynNwFunM+h1 +cCKQ1l6zAgMBAAECggEAcfZ4hEOmwcEfMzWdrxZBIHM6jJtphMWw9BXxBthPqgAm +ricXR9jE7+/U6sM9k7VrC0uaBHq7zd7OUeJkmgg6wXMyzyZbR8jAlUBES3MGv2W8 +8oALIIZyhjtx38ipdxNE9KossOz4WQ21D+uxNBXEnNdcXgzHGUDoCf6SDi3dGiQI +kloSkoyuHv3HiJdmUCII0EWVoDW0YnhKs4xpYwt0xlQ3IFA1FeqhYN3GwDb7hnp4 +HmefiydHW+rWPgXPzI3tIo6LgN+nMBPAAa95u9XfswRmBcZIhTxzlg7HaJJ1yP2B +HmyJBG20HX1RY0IHAgAQy2jA2HPIRdpQNU2FJGi34QKBgQDvMDRqr6qQjLSq8dkG +H7olc10gZHHTyY25aQG+m54SXMEdmU5zhbMoShnfQ/HVtWCAd3b5kwUBSjXacQiL +kMBV6S5+FQ+27nfgx8szqUJJi09iU43xcBDYSyJCohkM/HrHSElN3c1Y9//SneqJ +Zjeg+80+p7LvsgMM4MOKad0DowKBgQDBz5o9m9FZ+nHC1eXwUYVYNXA9wter9Erd +WosPWKnhGTJ2mNebn0aSVlagiZtyMUMps4IyWEvBHMIt0wJz2T5v+SDx9VN0si7q +Jy1i1uDO56tSHDZaN+QT/WDeaHTpzl3I28K7lqM6PDx1KQ/kqlTnWHD3wnXQ2Hfh +xXYgdeNpsQKBgQDaT+w3yBhtERBByrZkIYc8cXx5eVRvktJ5fX9rIwx3BBP7WRdC +17B7QI82ugQ8I+1ttBxylR8HW12mAG9lO3xhrZCS4dRTCnt+Pb2ZbI6lI7MUMuEm +kju9v24I1Xz53mSOCctmd+DaqJjl+t68BAEYPVvLKTNoFdk04t13M0LX8wKBgQCU +7+/M5oA0UES6AFxKmKsLRU2y+Jd6miop/tmcentZ814XS49tFTJLZLP/fKALWhYN +5tfnzniwt2P1iRF6a3kS3XVW2zs+E2wAHwk+ynhKKDg8yldub0MDpZSaddVak274 +2wDD3ZgkOYQQWPTQuaCzhACUNUkKrD88Ld2ARnfzkQKBgGTEOwN+aaOn/bU9Dm+y +Xg1tezMmxFcnewZVak+91xU6K+PS9B3GbszAs5MMYXo3UQXCUlXUI71XI7WG50LJ +NmwClF05ZcH/qYpp1mK/w6i+7VnqN0RAkD0hA3AyivmF5VCI/hzZanxLnPDvMbxS +wpjLPuBRTukoNvxJGT16z8L+ +-----END PRIVATE KEY----- diff --git a/test/manual-test-radius-tls/compose.yaml b/test/manual-test-radius-tls/compose.yaml new file mode 100644 index 000000000..d6ff8337c --- /dev/null +++ b/test/manual-test-radius-tls/compose.yaml @@ -0,0 +1,15 @@ +# Start the server: +# docker compose up +services: + redis: + image: redis:latest + ports: + - "6380:6380" + volumes: + - ./certs:/certs + command: > + redis-server + --tls-port 6380 --port 0 + --tls-cert-file /certs/redis.crt + --tls-key-file /certs/redis.key + --tls-auth-clients no diff --git a/test/manual-test-radius/compose.yaml b/test/manual-test-radius/compose.yaml new file mode 100644 index 000000000..7f2b1fc81 --- /dev/null +++ b/test/manual-test-radius/compose.yaml @@ -0,0 +1,8 @@ +# Start the server: +# docker compose up +services: + redis: + image: redis:latest + ports: + - "6379:6379" + command: redis-server --port 6379