diff --git a/server/server.js b/server/server.js index 0c08da078..61bd9d93a 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,10 +1692,6 @@ async function shutdownFunction(signal) { await cloudflaredStop(); } -function getClientIp(socket) { - return 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 3362f72ca..67b6ed0a3 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 { Settings } = require("./settings"); /** * `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 Settings.get("trustProxy")) { + return socket.client.conn.request.headers["x-forwarded-for"] + || socket.client.conn.request.headers["x-real-ip"] + || clientIP; + } else { + return clientIP; + } + } } module.exports = { diff --git a/server/util-server.js b/server/util-server.js index 84244b02b..df711cf05 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} Value + * @deprecated Use await Settings.get(key) */ exports.setting = async function (key) { return await Settings.get(key);