From c3e21041f1272311210ae664073e40883c6a4064 Mon Sep 17 00:00:00 2001 From: marysieek Date: Wed, 27 Jan 2021 20:13:59 +0100 Subject: [PATCH 1/9] Add new config attributes --- src/Castle.ts | 8 ++++++++ src/models/configuration.ts | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/src/Castle.ts b/src/Castle.ts index 6ddd2e1..6e1f5eb 100644 --- a/src/Castle.ts +++ b/src/Castle.ts @@ -51,6 +51,10 @@ export class Castle { failoverStrategy = FailoverStrategy.allow, logLevel = 'error', doNotTrack = false, + ipHeaders = [], + trustedProxies = [], + trustProxyChain = false, + trustedProxyDepth = 0 }: Configuration) { if (!apiSecret) { throw new Error( @@ -70,6 +74,10 @@ export class Castle { failoverStrategy, logLevel, doNotTrack, + ipHeaders, + trustedProxies, + trustProxyChain, + trustedProxyDepth }; this.logger = pino({ prettyPrint: { diff --git a/src/models/configuration.ts b/src/models/configuration.ts index 8e2b6e6..ea5178e 100644 --- a/src/models/configuration.ts +++ b/src/models/configuration.ts @@ -11,4 +11,8 @@ export type Configuration = { failoverStrategy?: FailoverStrategy; logLevel?: pino.Level; doNotTrack?: boolean; + ipHeaders?: string[]; + trustedProxies?: string[]; + trustProxyChain?: boolean; + trustedProxyDepth?: number; }; From 6c8d7e08d716eee521cebd2cb7f169d82ab74d56 Mon Sep 17 00:00:00 2001 From: marysieek Date: Wed, 27 Jan 2021 20:23:21 +0100 Subject: [PATCH 2/9] Update the README.md --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a687bdd..33885f1 100644 --- a/README.md +++ b/README.md @@ -36,15 +36,19 @@ const castle = Castle({ apiSecret: 'YOUR SECRET HERE' }); #### Config options -| Config option | Explanation | -| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| apiSecret | `string` - This can be found in the castle dashboard. | -| timeout | `number` - Time before returning the failover strategy. Default value is 500. | -| allowlisted | `string[]` - An array of strings matching the headers you want to pass fully to the service. | -| denylisted | `string[]` - An array of of strings matching the headers you do not want to pass fully to the service. | +| Config option | Explanation | +| ----------------- | ----------- | +| apiSecret | `string` - This can be found in the castle dashboard. | +| timeout | `number` - Time before returning the failover strategy. Default value is 500. | +| allowlisted | `string[]` - An array of strings matching the headers you want to pass fully to the service. | +| denylisted | `string[]` - An array of of strings matching the headers you do not want to pass fully to the service. | | failoverStrategy | `string` - If the request to our service would for some reason time out, this is where you select the automatic response from `authenticate`. Options are `allow`, `deny`, `challenge`. | -| logLevel | `string` - Corresponds to standard log levels: `trace`, `debug`, `info`, `warn`, `error`, `fatal`. Useful levels are `info` and `error`. | -| doNotTrack | `boolean` - False by default, setting it to true turns off all requests and triggers automatic failover on `authenticate`. Used for development and testing. | +| logLevel | `string` - Corresponds to standard log levels: `trace`, `debug`, `info`, `warn`, `error`, `fatal`. Useful levels are `info` and `error`. | +| doNotTrack | `boolean` - False by default, setting it to true turns off all requests and triggers automatic failover on `authenticate`. Used for development and testing. | +| ipHeaders | `string[]` - IP Headers to look for a client IP address. | +| trustedProxies | `string[]` - Trusted public proxies list. | +| trustProxyChain | `boolean` - False by default, defines if trusting all of the proxy IPs in X-Forwarded-For is enabled. | +| trustedProxyDepth | `number` - Number of trusted proxies used in the chain. | ## Actions From 6978677ca6e70aebc3d523c17fc9ca5529ae5693 Mon Sep 17 00:00:00 2001 From: marysieek Date: Wed, 27 Jan 2021 21:38:31 +0100 Subject: [PATCH 3/9] Add basic implementation of ips extract --- src/Castle.ts | 17 +++-- ...{default-allowlist.ts => configuration.ts} | 16 +++++ src/constants/index.ts | 2 +- src/ips/ips.module.ts | 1 + src/ips/services/index.ts | 1 + src/ips/services/ips-extract.service.ts | 67 +++++++++++++++++++ src/models/configuration.ts | 2 +- 7 files changed, 97 insertions(+), 9 deletions(-) rename src/constants/{default-allowlist.ts => configuration.ts} (54%) create mode 100644 src/ips/ips.module.ts create mode 100644 src/ips/services/index.ts create mode 100644 src/ips/services/ips-extract.service.ts diff --git a/src/Castle.ts b/src/Castle.ts index 6e1f5eb..926f75a 100644 --- a/src/Castle.ts +++ b/src/Castle.ts @@ -2,7 +2,11 @@ import fetch from 'node-fetch'; import AbortController from 'abort-controller'; import pino from 'pino'; -import { DEFAULT_ALLOWLIST } from './constants'; +import { + DEFAULT_ALLOWLIST, + DEFAULT_API_URL, + DEFAULT_TIMEOUT, +} from './constants'; import { AuthenticateResult, Configuration, Payload } from './models'; import { CommandAuthenticateService, @@ -14,9 +18,6 @@ import { } from './failover/failover.module'; import { LoggerService } from './logger/logger.module'; -const DEFAULT_API_URL = 'https://api.castle.io/v1'; -const DEFAULT_TIMEOUT = 1000; - // The body on the request is a stream and can only be // read once, by default. This is a workaround so that the // logging functions can read the body independently @@ -54,7 +55,7 @@ export class Castle { ipHeaders = [], trustedProxies = [], trustProxyChain = false, - trustedProxyDepth = 0 + trustedProxyDepth = 0, }: Configuration) { if (!apiSecret) { throw new Error( @@ -75,9 +76,11 @@ export class Castle { logLevel, doNotTrack, ipHeaders, - trustedProxies, + trustedProxies: trustedProxies.length + ? trustedProxies.map((proxy) => new RegExp(proxy)) + : [], trustProxyChain, - trustedProxyDepth + trustedProxyDepth, }; this.logger = pino({ prettyPrint: { diff --git a/src/constants/default-allowlist.ts b/src/constants/configuration.ts similarity index 54% rename from src/constants/default-allowlist.ts rename to src/constants/configuration.ts index 8db3178..4ca8936 100644 --- a/src/constants/default-allowlist.ts +++ b/src/constants/configuration.ts @@ -1,3 +1,5 @@ +export const DEFAULT_API_URL = 'https://api.castle.io/v1'; +export const DEFAULT_TIMEOUT = 1000; export const DEFAULT_ALLOWLIST = [ 'accept', 'accept-charset', @@ -23,3 +25,17 @@ export const DEFAULT_ALLOWLIST = [ 'x-castle-client-id', 'x-requested-with', ]; +export const TRUSTED_PROXIES = [ + new RegExp( + [ + /^127\.0\.0\.1$/, + /^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./, + /^::1\Z|\Afd[0-9a-f]{2}:.+|/, + /^localhost$|/, + /^unix$|/, + /^unix:/, + ] + .map((r) => r.source) + .join('') + ), +]; diff --git a/src/constants/index.ts b/src/constants/index.ts index 3fad63a..75a1114 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -1 +1 @@ -export * from './default-allowlist'; +export * from './configuration'; diff --git a/src/ips/ips.module.ts b/src/ips/ips.module.ts new file mode 100644 index 0000000..e371345 --- /dev/null +++ b/src/ips/ips.module.ts @@ -0,0 +1 @@ +export * from './services'; diff --git a/src/ips/services/index.ts b/src/ips/services/index.ts new file mode 100644 index 0000000..e806208 --- /dev/null +++ b/src/ips/services/index.ts @@ -0,0 +1 @@ +export * from './ips-extract.service'; diff --git a/src/ips/services/ips-extract.service.ts b/src/ips/services/ips-extract.service.ts new file mode 100644 index 0000000..7be19fd --- /dev/null +++ b/src/ips/services/ips-extract.service.ts @@ -0,0 +1,67 @@ +import { IncomingHttpHeaders } from 'http'; +import { Configuration } from '../../models'; +import { TRUSTED_PROXIES } from '../../constants'; + +// ordered list of ip headers for ip extraction +const DEFAULT = ['X-Forwarded-For', 'Remote-Addr']; +// list of header which are used with proxy depth setting +const DEPTH_RELATED = ['X-Forwarded-For']; + +const checkInternal = (ipAddress: string, proxies: Array) => { + return proxies.some((proxyRegexp) => proxyRegexp.test(ipAddress)); +}; + +const limitProxyDepth = (ips, ipHeader, trustedProxyDepth) => { + if (DEPTH_RELATED.includes(ipHeader)) { + ips.pop(trustedProxyDepth); + } + return ips; +}; + +const IPsFrom = (ipHeader, headers, trustedProxyDepth) => { + const headerValue = headers.get(ipHeader); + + if (!headerValue) { + return []; + } + const ips = headerValue.strip().split(/[,\s]+/); + limitProxyDepth(ips, ipHeader, trustedProxyDepth); +}; + +const removeProxies = (ips, trustProxyChain, proxiesList) => { + if (trustProxyChain) { + return ips[0]; + } + const filteredIps = ips.filter((ip) => !checkInternal(ip, proxiesList)); + return filteredIps[filteredIps.length - 1]; +}; + +export const IPsExtractService = { + call: ( + headers: IncomingHttpHeaders, + { + ipHeaders, + trustedProxies, + trustProxyChain, + trustedProxyDepth, + }: Configuration + ) => { + const ipHeadersList = ipHeaders.length ? ipHeaders : DEFAULT; + const proxiesList = trustedProxies.concat(TRUSTED_PROXIES); + let allIPs = []; + + for (const ipHeader of ipHeadersList) { + const IPs = IPsFrom(ipHeader, headers, trustedProxyDepth); + const IPValue = removeProxies(IPs, trustProxyChain, proxiesList); + + if (IPValue) { + return IPValue; + } + + allIPs.push(IPs); + } + + // fallback to first listed ip + return allIPs[0]; + }, +}; diff --git a/src/models/configuration.ts b/src/models/configuration.ts index ea5178e..1815ba6 100644 --- a/src/models/configuration.ts +++ b/src/models/configuration.ts @@ -12,7 +12,7 @@ export type Configuration = { logLevel?: pino.Level; doNotTrack?: boolean; ipHeaders?: string[]; - trustedProxies?: string[]; + trustedProxies?: RegExp[]; trustProxyChain?: boolean; trustedProxyDepth?: number; }; From 594df084f9d80c1c1cf0093a880e53442daef5c7 Mon Sep 17 00:00:00 2001 From: marysieek Date: Wed, 27 Jan 2021 21:40:42 +0100 Subject: [PATCH 4/9] Prettier fixes --- src/ips/services/ips-extract.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ips/services/ips-extract.service.ts b/src/ips/services/ips-extract.service.ts index 7be19fd..cd86ba8 100644 --- a/src/ips/services/ips-extract.service.ts +++ b/src/ips/services/ips-extract.service.ts @@ -7,7 +7,7 @@ const DEFAULT = ['X-Forwarded-For', 'Remote-Addr']; // list of header which are used with proxy depth setting const DEPTH_RELATED = ['X-Forwarded-For']; -const checkInternal = (ipAddress: string, proxies: Array) => { +const checkInternal = (ipAddress: string, proxies: any[]) => { return proxies.some((proxyRegexp) => proxyRegexp.test(ipAddress)); }; @@ -48,7 +48,7 @@ export const IPsExtractService = { ) => { const ipHeadersList = ipHeaders.length ? ipHeaders : DEFAULT; const proxiesList = trustedProxies.concat(TRUSTED_PROXIES); - let allIPs = []; + const allIPs = []; for (const ipHeader of ipHeadersList) { const IPs = IPsFrom(ipHeader, headers, trustedProxyDepth); From 66d33cc578bf299630ce22ebcf35ceb51a7d72af Mon Sep 17 00:00:00 2001 From: marysieek Date: Thu, 28 Jan 2021 14:59:33 +0100 Subject: [PATCH 5/9] Add ip headers related tests --- src/constants/configuration.ts | 4 +- src/ips/services/ips-extract.service.ts | 21 ++- test/ips/services/ips-extract.service.test.ts | 139 ++++++++++++++++++ 3 files changed, 150 insertions(+), 14 deletions(-) create mode 100644 test/ips/services/ips-extract.service.test.ts diff --git a/src/constants/configuration.ts b/src/constants/configuration.ts index 4ca8936..65a833a 100644 --- a/src/constants/configuration.ts +++ b/src/constants/configuration.ts @@ -28,8 +28,8 @@ export const DEFAULT_ALLOWLIST = [ export const TRUSTED_PROXIES = [ new RegExp( [ - /^127\.0\.0\.1$/, - /^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./, + /^127\.0\.0\.1$|/, + /^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\.|/, /^::1\Z|\Afd[0-9a-f]{2}:.+|/, /^localhost$|/, /^unix$|/, diff --git a/src/ips/services/ips-extract.service.ts b/src/ips/services/ips-extract.service.ts index cd86ba8..9416c5c 100644 --- a/src/ips/services/ips-extract.service.ts +++ b/src/ips/services/ips-extract.service.ts @@ -3,9 +3,9 @@ import { Configuration } from '../../models'; import { TRUSTED_PROXIES } from '../../constants'; // ordered list of ip headers for ip extraction -const DEFAULT = ['X-Forwarded-For', 'Remote-Addr']; +const DEFAULT = ['x-forwarded-for', 'remote-addr']; // list of header which are used with proxy depth setting -const DEPTH_RELATED = ['X-Forwarded-For']; +const DEPTH_RELATED = ['x-forwarded-for']; const checkInternal = (ipAddress: string, proxies: any[]) => { return proxies.some((proxyRegexp) => proxyRegexp.test(ipAddress)); @@ -13,19 +13,19 @@ const checkInternal = (ipAddress: string, proxies: any[]) => { const limitProxyDepth = (ips, ipHeader, trustedProxyDepth) => { if (DEPTH_RELATED.includes(ipHeader)) { - ips.pop(trustedProxyDepth); + ips.splice(ips.length - 1, trustedProxyDepth); } return ips; }; const IPsFrom = (ipHeader, headers, trustedProxyDepth) => { - const headerValue = headers.get(ipHeader); + const headerValue = headers[ipHeader]; if (!headerValue) { return []; } - const ips = headerValue.strip().split(/[,\s]+/); - limitProxyDepth(ips, ipHeader, trustedProxyDepth); + const ips = headerValue.trim().split(/[,\s]+/); + return limitProxyDepth(ips, ipHeader, trustedProxyDepth); }; const removeProxies = (ips, trustProxyChain, proxiesList) => { @@ -48,17 +48,14 @@ export const IPsExtractService = { ) => { const ipHeadersList = ipHeaders.length ? ipHeaders : DEFAULT; const proxiesList = trustedProxies.concat(TRUSTED_PROXIES); - const allIPs = []; - + let allIPs = []; for (const ipHeader of ipHeadersList) { - const IPs = IPsFrom(ipHeader, headers, trustedProxyDepth); + const IPs = IPsFrom(ipHeader, headers, ~~trustedProxyDepth); const IPValue = removeProxies(IPs, trustProxyChain, proxiesList); - if (IPValue) { return IPValue; } - - allIPs.push(IPs); + allIPs = [...allIPs, ...IPs]; } // fallback to first listed ip diff --git a/test/ips/services/ips-extract.service.test.ts b/test/ips/services/ips-extract.service.test.ts new file mode 100644 index 0000000..2830b90 --- /dev/null +++ b/test/ips/services/ips-extract.service.test.ts @@ -0,0 +1,139 @@ +import { IPsExtractService } from '../../../src/ips/ips.module'; + +describe('IPsExtractService', () => { + describe('call', () => { + describe('when regular IPs', () => { + const headers = { + 'x-forwarded-for': '1.2.3.5', + }; + + const config = { + apiSecret: 'test', + ipHeaders: [], + trustedProxies: [], + }; + + it('extracts correct IPs', () => { + expect(IPsExtractService.call(headers, config)).toEqual('1.2.3.5'); + }); + }); + + describe('when we need to use other IP header', () => { + const headers = { + 'cf-connecting-ip': '1.2.3.4', + 'x-forwarded-for': '1.1.1.1, 1.2.2.2, 1.2.3.5', + }; + + describe('regular format', () => { + const config = { + apiSecret: 'test', + ipHeaders: ['cf-connecting-ip', 'x-forwarded-for'], + trustedProxies: [], + }; + + it('extracts correct IPs', () => { + expect(IPsExtractService.call(headers, config)).toEqual('1.2.3.4'); + }); + }); + + describe('with value from trusted proxies it get seconds header', () => { + const config = { + apiSecret: 'test', + ipHeaders: ['cf-connecting-ip', 'x-forwarded-for'], + trustedProxies: [new RegExp('1.2.3.4')], + }; + + it('extracts correct IPs', () => { + expect(IPsExtractService.call(headers, config)).toEqual('1.2.3.5'); + }); + }); + }); + + describe('when all the trusted proxies', () => { + const headers = { + 'x-forwarded-for': '127.0.0.1,10.0.0.1,172.31.0.1,192.168.0.1', + 'remote-addr': '127.0.0.1', + }; + + const config = { + apiSecret: 'test', + ipHeaders: [], + trustedProxies: [], + }; + + it('fallbacks to first available header when all headers are marked trusted proxy', () => { + expect(IPsExtractService.call(headers, config)).toEqual('127.0.0.1'); + }); + }); + + describe('when trustProxyChain option', () => { + const headers = { + 'x-forwarded-for': '6.6.6.6, 2.2.2.3, 6.6.6.5', + 'remote-addr': '6.6.6.4', + }; + + const config = { + apiSecret: 'test', + ipHeaders: [], + trustedProxies: [], + trustProxyChain: true, + }; + + it('selects first available header', () => { + expect(IPsExtractService.call(headers, config)).toEqual('6.6.6.6'); + }); + }); + + describe('when trustedProxyDepth option', () => { + const headers = { + 'x-forwarded-for': '6.6.6.6, 2.2.2.3, 6.6.6.5', + 'remote-addr': '6.6.6.4', + }; + + const config = { + apiSecret: 'test', + ipHeaders: [], + trustedProxies: [], + trustedProxyDepth: 1, + }; + + it('selects first available header', () => { + expect(IPsExtractService.call(headers, config)).toEqual('2.2.2.3'); + }); + }); + + describe('when list of not trusted IPs provided in x-forwarded-for', () => { + const headers = { + 'x-forwarded-for': '6.6.6.6, 2.2.2.3, 192.168.0.7', + 'client-ip': '6.6.6.6', + }; + + const config = { + apiSecret: 'test', + ipHeaders: [], + trustedProxies: [], + }; + + it('does not allow to spoof IP', () => { + expect(IPsExtractService.call(headers, config)).toEqual('2.2.2.3'); + }); + }); + + describe('when marked 2.2.2.3 as trusted proxy', () => { + const headers = { + 'x-forwarded-for': '6.6.6.6, 2.2.2.3, 192.168.0.7', + 'client-ip': '6.6.6.6', + }; + + const config = { + apiSecret: 'test', + ipHeaders: [], + trustedProxies: [new RegExp(/^2.2.2.\d$/)], + }; + + it('does not allow to spoof IP', () => { + expect(IPsExtractService.call(headers, config)).toEqual('6.6.6.6'); + }); + }); + }); +}); From e6e01b3a50b878c8136214a5151a5b2c343f35b0 Mon Sep 17 00:00:00 2001 From: marysieek Date: Thu, 28 Jan 2021 15:05:20 +0100 Subject: [PATCH 6/9] Remove bitwise operator --- src/ips/services/ips-extract.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ips/services/ips-extract.service.ts b/src/ips/services/ips-extract.service.ts index 9416c5c..f2ee9ba 100644 --- a/src/ips/services/ips-extract.service.ts +++ b/src/ips/services/ips-extract.service.ts @@ -50,7 +50,7 @@ export const IPsExtractService = { const proxiesList = trustedProxies.concat(TRUSTED_PROXIES); let allIPs = []; for (const ipHeader of ipHeadersList) { - const IPs = IPsFrom(ipHeader, headers, ~~trustedProxyDepth); + const IPs = IPsFrom(ipHeader, headers, trustedProxyDepth); const IPValue = removeProxies(IPs, trustProxyChain, proxiesList); if (IPValue) { return IPValue; From c2c2b6b61a7dc04a404fbf568229641063fa9f4a Mon Sep 17 00:00:00 2001 From: marysieek Date: Thu, 28 Jan 2021 17:47:27 +0100 Subject: [PATCH 7/9] Fix tests --- src/context/services/context-get-default.service.ts | 2 ++ src/headers/services/headers-extract.service.ts | 2 +- src/ips/services/ips-extract.service.ts | 11 +++++++---- .../services/context-get-default.service.test.ts | 10 +++++++++- .../core-generate-request-body.service.test.ts | 8 ++++++-- 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/context/services/context-get-default.service.ts b/src/context/services/context-get-default.service.ts index 3e51a77..33fe5c2 100644 --- a/src/context/services/context-get-default.service.ts +++ b/src/context/services/context-get-default.service.ts @@ -1,5 +1,6 @@ import { Configuration } from '../../models'; import { HeadersExtractService } from '../../headers/headers.module'; +import { IPsExtractService } from '../../ips/ips.module'; import { version } from '../../../package.json'; export const ContextGetDefaultService = { @@ -7,6 +8,7 @@ export const ContextGetDefaultService = { return { client_id: context.client_id || false, headers: HeadersExtractService.call(context.headers, configuration), + ip: IPsExtractService.call(context.headers, configuration), library: { name: 'castle-node', version, diff --git a/src/headers/services/headers-extract.service.ts b/src/headers/services/headers-extract.service.ts index 73316e2..5916ca8 100644 --- a/src/headers/services/headers-extract.service.ts +++ b/src/headers/services/headers-extract.service.ts @@ -8,7 +8,7 @@ const ALWAYS_DENYLISTED = ['cookie', 'authorization']; export const HeadersExtractService = { call: ( headers: IncomingHttpHeaders, - { allowlisted, denylisted }: Configuration + { allowlisted = [], denylisted = [] }: Configuration ) => { return reduce( headers, diff --git a/src/ips/services/ips-extract.service.ts b/src/ips/services/ips-extract.service.ts index f2ee9ba..3b1b85a 100644 --- a/src/ips/services/ips-extract.service.ts +++ b/src/ips/services/ips-extract.service.ts @@ -19,6 +19,9 @@ const limitProxyDepth = (ips, ipHeader, trustedProxyDepth) => { }; const IPsFrom = (ipHeader, headers, trustedProxyDepth) => { + if (!headers) { + return []; + } const headerValue = headers[ipHeader]; if (!headerValue) { @@ -40,10 +43,10 @@ export const IPsExtractService = { call: ( headers: IncomingHttpHeaders, { - ipHeaders, - trustedProxies, - trustProxyChain, - trustedProxyDepth, + ipHeaders = [], + trustedProxies = [], + trustProxyChain = false, + trustedProxyDepth = 0, }: Configuration ) => { const ipHeadersList = ipHeaders.length ? ipHeaders : DEFAULT; diff --git a/test/context/services/context-get-default.service.test.ts b/test/context/services/context-get-default.service.test.ts index eb63957..1995a26 100644 --- a/test/context/services/context-get-default.service.test.ts +++ b/test/context/services/context-get-default.service.test.ts @@ -4,21 +4,29 @@ import { version } from '../../../package.json'; describe('ContextGetDefaultService', () => { describe('call', () => { const expected = { - headers: {}, + headers: { + 'x-forwarded-for': '1.2.3.4', + }, library: { name: 'castle-node', version, }, client_id: 'client_id', + ip: '1.2.3.4', }; const config = { apiSecret: 'test', apiUrl: 'castle.io', + denylisted: [], + allowlisted: [], }; const context = { client_id: 'client_id', + headers: { + 'x-forwarded-for': '1.2.3.4', + }, }; it('generates default context', () => { diff --git a/test/core/services/core-generate-request-body.service.test.ts b/test/core/services/core-generate-request-body.service.test.ts index 0fa792b..05fe2dd 100644 --- a/test/core/services/core-generate-request-body.service.test.ts +++ b/test/core/services/core-generate-request-body.service.test.ts @@ -19,7 +19,9 @@ describe('CoreGenerateRequestBody', () => { context: { ip: '127.0.0.1', client_id: 'client_id', - headers: {}, + headers: { + 'x-forwarded-for': '127.0.0.1', + }, library: { name: 'castle-node', version, @@ -37,7 +39,9 @@ describe('CoreGenerateRequestBody', () => { context: { ip: '127.0.0.1', client_id: 'client_id', - headers: {}, + headers: { + 'x-forwarded-for': '127.0.0.1', + }, }, }; From 9c4bb4581da18950ae86a54b47eefd2a2b6c152a Mon Sep 17 00:00:00 2001 From: marysieek Date: Thu, 28 Jan 2021 18:10:46 +0100 Subject: [PATCH 8/9] Add missing header --- test/Castle.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Castle.test.ts b/test/Castle.test.ts index 9e3e353..46be12b 100644 --- a/test/Castle.test.ts +++ b/test/Castle.test.ts @@ -17,6 +17,7 @@ const sampleRequestData = { client_id: 'clientid', headers: { Cookie: 'SECRET=pleasedontbehere', + 'x-forwarded-for': '8.8.8.8', }, }, }; From b6d9b5374b7daf56833f6f8f9fde7d9a2909c161 Mon Sep 17 00:00:00 2001 From: marysieek Date: Thu, 28 Jan 2021 18:49:41 +0100 Subject: [PATCH 9/9] Remove unneeded check --- src/Castle.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Castle.ts b/src/Castle.ts index 926f75a..3bd877c 100644 --- a/src/Castle.ts +++ b/src/Castle.ts @@ -76,9 +76,7 @@ export class Castle { logLevel, doNotTrack, ipHeaders, - trustedProxies: trustedProxies.length - ? trustedProxies.map((proxy) => new RegExp(proxy)) - : [], + trustedProxies: trustedProxies.map((proxy) => new RegExp(proxy)), trustProxyChain, trustedProxyDepth, };