From 2303302eef59e04ab124274c35a7f39cd89c28e1 Mon Sep 17 00:00:00 2001 From: matts <22215332+devopsmatt@users.noreply.github.com> Date: Thu, 9 Oct 2025 14:05:39 -0700 Subject: [PATCH] chore(deps): update compression dependencys and vendor the radius dependency (#6168) Co-authored-by: Frank Elsinga --- README.md | 18 ++--- package-lock.json | 71 +++--------------- package.json | 5 +- server/radius-client.js | 160 ++++++++++++++++++++++++++++++++++++++++ server/util-server.js | 4 +- 5 files changed, 183 insertions(+), 75 deletions(-) create mode 100644 server/radius-client.js diff --git a/README.md b/README.md index 34e34020f..ea7fb3277 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Uptime Kuma is an easy-to-use self-hosted monitoring tool. Try it! -Demo Server (Location: Frankfurt - Germany): https://demo.kuma.pet/start-demo +Demo Server (Location: Frankfurt - Germany): It is a temporary live demo, all data will be deleted after 10 minutes. Sponsored by [Uptime Kuma Sponsors](https://github.com/louislam/uptime-kuma#%EF%B8%8F-sponsors). @@ -50,7 +50,7 @@ Uptime Kuma is now running on . > [!NOTE] > If you want to limit exposure to localhost (without exposing port for other users or to use a [reverse proxy](https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy)), you can expose the port like this: -> +> > ```bash > docker run -d --restart=always -p 127.0.0.1:3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1 > ``` @@ -85,7 +85,7 @@ npm install pm2 -g && pm2 install pm2-logrotate pm2 start server/server.js --name uptime-kuma ``` -Uptime Kuma is now running on http://localhost:3001 +Uptime Kuma is now running on More useful PM2 Commands @@ -101,19 +101,19 @@ pm2 save && pm2 startup If you need more options or need to browse via a reverse proxy, please read: -https://github.com/louislam/uptime-kuma/wiki/%F0%9F%94%A7-How-to-Install + ## 🆙 How to Update Please read: -https://github.com/louislam/uptime-kuma/wiki/%F0%9F%86%99-How-to-Update + ## 🆕 What's Next? I will assign requests/issues to the next milestone. -https://github.com/louislam/uptime-kuma/milestones + ## ❤️ Sponsors @@ -174,11 +174,11 @@ We DO NOT accept all types of pull requests and do not want to waste your time. There are a lot of pull requests right now, but I don't have time to test them all. If you want to help, you can check this: -https://github.com/louislam/uptime-kuma/wiki/Test-Pull-Requests + ### Test Beta Version -Check out the latest beta release here: https://github.com/louislam/uptime-kuma/releases +Check out the latest beta release here: ### Bug Reports / Feature Requests @@ -192,5 +192,3 @@ If you want to translate Uptime Kuma into your language, please visit [Weblate R Feel free to correct the grammar in the documentation or code. My mother language is not English and my grammar is not that great. - - diff --git a/package-lock.json b/package-lock.json index 575b33e8d..5cdacb8b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "chroma-js": "~2.4.2", "command-exists": "~1.2.9", "compare-versions": "~3.6.0", - "compression": "~1.7.4", + "compression": "~1.8.1", "country-flag-emoji-polyfill": "^0.1.8", "croner": "~8.1.0", "dayjs": "~1.11.5", @@ -60,7 +60,7 @@ "nanoid": "~3.3.4", "net-snmp": "^3.11.2", "node-cloudflared-tunnel": "~1.0.9", - "node-radius-client": "~1.0.0", + "node-radius-utils": "~1.2.0", "nodemailer": "~6.9.13", "nostr-tools": "^2.10.4", "notp": "~2.0.3", @@ -74,6 +74,7 @@ "promisify-child-process": "~4.1.2", "protobufjs": "~7.2.4", "qs": "~6.10.4", + "radius": "~1.1.4", "redbean-node": "~0.3.0", "redis": "~4.5.1", "semver": "~7.5.4", @@ -7065,16 +7066,16 @@ } }, "node_modules/compression": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", - "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "license": "MIT", "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", - "on-headers": "~1.0.2", + "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" }, @@ -10302,13 +10303,6 @@ "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.", - "license": "BSD-3-Clause" - }, "node_modules/hookable": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", @@ -11251,18 +11245,6 @@ "dev": true, "license": "MIT" }, - "node_modules/isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "license": "BSD-3-Clause", - "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", @@ -11293,18 +11275,6 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "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.", - "license": "BSD-3-Clause", - "dependencies": { - "hoek": "6.x.x", - "isemail": "3.x.x", - "topo": "3.x.x" - } - }, "node_modules/jose": { "version": "4.15.9", "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", @@ -12784,17 +12754,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "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==", - "license": "MIT", - "dependencies": { - "joi": "^14.3.1", - "node-radius-utils": "^1.2.0", - "radius": "^1.1.4" - } - }, "node_modules/node-radius-utils": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/node-radius-utils/-/node-radius-utils-1.2.0.tgz", @@ -13074,9 +13033,9 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -16675,16 +16634,6 @@ "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.", - "license": "BSD-3-Clause", - "dependencies": { - "hoek": "6.x.x" - } - }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", diff --git a/package.json b/package.json index 99e2b60aa..6bef0fa99 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "chroma-js": "~2.4.2", "command-exists": "~1.2.9", "compare-versions": "~3.6.0", - "compression": "~1.7.4", + "compression": "~1.8.1", "country-flag-emoji-polyfill": "^0.1.8", "croner": "~8.1.0", "dayjs": "~1.11.5", @@ -119,7 +119,6 @@ "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", "nostr-tools": "^2.10.4", "notp": "~2.0.3", @@ -133,6 +132,8 @@ "promisify-child-process": "~4.1.2", "protobufjs": "~7.2.4", "qs": "~6.10.4", + "radius": "~1.1.4", + "node-radius-utils": "~1.2.0", "redbean-node": "~0.3.0", "redis": "~4.5.1", "semver": "~7.5.4", diff --git a/server/radius-client.js b/server/radius-client.js new file mode 100644 index 000000000..57242f8af --- /dev/null +++ b/server/radius-client.js @@ -0,0 +1,160 @@ +/** + * Custom RADIUS Client Implementation + * + * This is a lightweight RADIUS client implementation using the base `radius` package + * Due to lack of maintenance in node-radius-client this was forked + * + * Implements RADIUS Access-Request functionality compatible with the original + * node-radius-client API used in Uptime Kuma. + */ + +const dgram = require("dgram"); +const radius = require("radius"); + +/** + * RADIUS Client class + */ +class RadiusClient { + /** + * @param {object} options Client configuration + * @param {string} options.host RADIUS server hostname + * @param {number} options.hostPort RADIUS server port (default: 1812) + * @param {number} options.timeout Request timeout in milliseconds (default: 2500) + * @param {number} options.retries Number of retry attempts (default: 1) + * @param {Array} options.dictionaries RADIUS dictionaries for attribute encoding + */ + constructor(options) { + this.host = options.host; + this.port = options.hostPort || 1812; + this.timeout = options.timeout || 2500; + this.retries = options.retries || 1; + this.dictionaries = options.dictionaries || []; + } + + /** + * Send RADIUS Access-Request + * @param {object} params Request parameters + * @param {string} params.secret RADIUS shared secret + * @param {Array} params.attributes Array of [attribute, value] pairs + * @returns {Promise} RADIUS response + */ + accessRequest(params) { + return new Promise((resolve, reject) => { + const { secret, attributes } = params; + + // Build RADIUS packet + const packet = { + code: "Access-Request", + secret: secret, + attributes: {} + }; + + // Convert attributes array to object + attributes.forEach(([ attr, value ]) => { + packet.attributes[attr] = value; + }); + + // Encode packet + let encodedPacket; + try { + encodedPacket = radius.encode(packet); + } catch (error) { + return reject(new Error(`RADIUS packet encoding failed: ${error.message}`)); + } + + // Create UDP socket + const socket = dgram.createSocket("udp4"); + let attempts = 0; + let responseReceived = false; + let timeoutHandle; + + /** + * Send RADIUS request with retry logic + * @returns {void} + */ + const sendRequest = () => { + attempts++; + + socket.send(encodedPacket, 0, encodedPacket.length, this.port, this.host, (err) => { + if (err) { + socket.close(); + return reject(new Error(`Failed to send RADIUS request: ${err.message}`)); + } + + // Set timeout for this attempt + timeoutHandle = setTimeout(() => { + if (responseReceived) { + return; + } + + if (attempts < this.retries + 1) { + // Retry + sendRequest(); + } else { + // All retries exhausted + socket.close(); + reject(new Error(`RADIUS request timeout after ${attempts} attempts`)); + } + }, this.timeout); + }); + }; + + // Handle response + socket.on("message", (msg) => { + if (responseReceived) { + return; + } + + responseReceived = true; + clearTimeout(timeoutHandle); + + let response; + try { + response = radius.decode({ packet: msg, + secret: secret }); + } catch (error) { + socket.close(); + return reject(new Error(`RADIUS response decoding failed: ${error.message}`)); + } + + socket.close(); + + // Map response code to match node-radius-client format + const responseCode = response.code; + + if (responseCode === "Access-Accept") { + resolve({ code: "Access-Accept", + ...response }); + } else if (responseCode === "Access-Reject") { + // Reject as error to match original behavior + const error = new Error("Access-Reject"); + error.response = { code: "Access-Reject" }; + reject(error); + } else if (responseCode === "Access-Challenge") { + // Challenge response + const error = new Error("Access-Challenge"); + error.response = { code: "Access-Challenge" }; + reject(error); + } else { + resolve({ code: responseCode, + ...response }); + } + }); + + // Handle socket errors + socket.on("error", (err) => { + if (!responseReceived) { + responseReceived = true; + clearTimeout(timeoutHandle); + socket.close(); + reject(new Error(`RADIUS socket error: ${err.message}`)); + } + }); + + // Start first request + sendRequest(); + }); + } +} + +module.exports = RadiusClient; diff --git a/server/util-server.js b/server/util-server.js index d4a37970d..ecad276b3 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -19,7 +19,7 @@ const { NtlmClient } = require("./modules/axios-ntlm/lib/ntlmClient.js"); const { Settings } = require("./settings"); const grpc = require("@grpc/grpc-js"); const protojs = require("protobufjs"); -const radiusClient = require("node-radius-client"); +const RadiusClient = require("./radius-client"); const redis = require("redis"); const oidc = require("openid-client"); const tls = require("tls"); @@ -498,7 +498,7 @@ exports.radius = function ( port = 1812, timeout = 2500, ) { - const client = new radiusClient({ + const client = new RadiusClient({ host: hostname, hostPort: port, timeout: timeout,