diff --git a/package.json b/package.json index ee6e7af6..af2cf68a 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "dependencies": { "@headlessui/react": "^1.7.2", "@kubernetes/client-node": "^0.17.1", + "@supercharge/request-ip": "^1.2.0", "classnames": "^2.3.2", "compare-versions": "^5.0.1", "dockerode": "^3.3.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec4bc025..0f3f6adf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,9 @@ dependencies: '@kubernetes/client-node': specifier: ^0.17.1 version: 0.17.1 + '@supercharge/request-ip': + specifier: ^1.2.0 + version: 1.2.0 classnames: specifier: ^2.3.2 version: 2.3.2 @@ -400,6 +403,10 @@ packages: resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==} dev: true + /@supercharge/request-ip@1.2.0: + resolution: {integrity: sha512-wlt6JW69MHqLY2M6Sm/jVyCojNRKq2CBvwH0Hbx24SFhDQQGkgEjeKxVutDxHSyrWixFaOSLXC27euzxijhyMQ==} + dev: false + /@swc/helpers@0.4.11: resolution: {integrity: sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==} dependencies: @@ -645,6 +652,7 @@ packages: /autoprefixer@10.4.14(postcss@8.4.21): resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} engines: {node: ^10 || ^12 || >=14} + hasBin: true peerDependencies: postcss: ^8.1.0 dependencies: @@ -1221,6 +1229,7 @@ packages: /eslint-config-prettier@8.8.0(eslint@8.37.0): resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==} + hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: @@ -2374,6 +2383,7 @@ packages: /next@12.3.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-VcyMJUtLZBGzLKo3oMxrEF0stxh8HwuW976pAzlHhI3t8qJ4SROjCrSh1T24bhrbjw55wfZXAbXPGwPt5FLRfQ==} engines: {node: '>=12.22.0'} + hasBin: true peerDependencies: fibers: '>= 3.1.0' node-sass: ^6.0.0 || ^7.0.0 @@ -3229,6 +3239,7 @@ packages: /tailwindcss@3.3.0(postcss@8.4.21): resolution: {integrity: sha512-hOXlFx+YcklJ8kXiCAfk/FMyr4Pm9ck477G0m/us2344Vuj355IpoEDB5UmGAsSpTBmr+4ZhjzW04JuFXkb/fw==} engines: {node: '>=12.13.0'} + hasBin: true peerDependencies: postcss: ^8.0.9 dependencies: @@ -3450,6 +3461,7 @@ packages: /update-browserslist-db@1.0.10(browserslist@4.21.5): resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} + hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: diff --git a/src/utils/config/scope.js b/src/utils/config/scope.js index ad3cedaf..81a613bd 100644 --- a/src/utils/config/scope.js +++ b/src/utils/config/scope.js @@ -1,3 +1,5 @@ +import { getClientIp } from "@supercharge/request-ip"; + import { getSettings } from "utils/config/config"; function checkIPRange(ip, ipSpace) { @@ -25,7 +27,7 @@ function checkIPRange(ip, ipSpace) { return false; } -function isRequestProxied(req) { +function isRequestProxied(remoteAddress) { const settings = getSettings(); // Check if trustedproxies is set const trustedProxies = settings?.trustedproxies; @@ -34,7 +36,7 @@ function isRequestProxied(req) { // is in the trustedproxies address space using CIDR notation. if (trustedProxies) { // Get the connection IP and strip IPv6 from the hybrid IPv4-IPv6 socket - const ip = req.connection.remoteAddress.replace(/^.*:/, ''); + const ip = remoteAddress.replace(/^.*:/, ''); for (let i = 0; i < trustedProxies.length; i += 1) { const proxy = trustedProxies[i].trim(); @@ -47,17 +49,12 @@ function isRequestProxied(req) { return false; } -export function getClientIP(req) { - // Check if the request is proxied - const proxied = isRequestProxied(req); - // If the request is proxied, get the forwarded IP address - // from the X-Real-IP header - const forwarded = req.headers["x-real-ip"]; - // If not get the connection IP address - const ip = req.connection.remoteAddress.replace(/^.*:/, ''); - - // Conditionally return the forwarded IP address or the connection IP address - return proxied ? (forwarded || ip) : ip; +export function getRealClientIP(req) { + const {remoteAddress} = req.socket; + const proxied = isRequestProxied(remoteAddress); + + // If request is proxied we can trust headers, otherwise we return the socket IP + return proxied ? getClientIp(req) || remoteAddress : remoteAddress; } export function isInLocalScope(req) { @@ -68,7 +65,7 @@ export function isInLocalScope(req) { // If localscope is set, check if the client IP // is in the localscope address space using CIDR notation. if (localScope) { - const ip = getClientIP(req); + const ip = getRealClientIP(req); for (let i = 0; i < localScope.length; i += 1) { const localIP = localScope[i].trim(); @@ -80,4 +77,3 @@ export function isInLocalScope(req) { } return false; } - \ No newline at end of file