Skip to content

Commit b44e29e

Browse files
authored
feat(request): allow to use a boolean for trustProxy (#76)
1 parent 8dd52ef commit b44e29e

File tree

3 files changed

+112
-1
lines changed

3 files changed

+112
-1
lines changed

src/define_config.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,16 @@ import proxyAddr from 'proxy-addr'
1111
import string from '@poppinss/utils/string'
1212
import type { ServerConfig } from './types/server.js'
1313

14+
type UserDefinedServerConfig = Partial<
15+
Omit<ServerConfig, 'trustProxy'> & {
16+
trustProxy: ((address: string, distance: number) => boolean) | boolean | string
17+
}
18+
>
19+
1420
/**
1521
* Define configuration for the HTTP server
1622
*/
17-
export function defineConfig(config: Partial<ServerConfig>): ServerConfig {
23+
export function defineConfig(config: UserDefinedServerConfig): ServerConfig {
1824
const normalizedConfig = {
1925
allowMethodSpoofing: false,
2026
trustProxy: proxyAddr.compile('loopback'),
@@ -52,5 +58,13 @@ export function defineConfig(config: Partial<ServerConfig>): ServerConfig {
5258
normalizedConfig.cookie.maxAge = string.seconds.parse(normalizedConfig.cookie.maxAge)
5359
}
5460

61+
if (typeof normalizedConfig.trustProxy === 'boolean') {
62+
const tpValue = normalizedConfig.trustProxy
63+
normalizedConfig.trustProxy = (_, __) => tpValue
64+
} else if (typeof normalizedConfig.trustProxy === 'string') {
65+
const tpValue = normalizedConfig.trustProxy
66+
normalizedConfig.trustProxy = proxyAddr.compile(tpValue)
67+
}
68+
5569
return normalizedConfig
5670
}

tests/define_config.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,16 @@ test.group('Define config', () => {
4646
useAsyncLocalStorage: false,
4747
})
4848
})
49+
50+
test('compile trustProxy config when boolean', ({ assert }) => {
51+
const config = defineConfig({ trustProxy: true })
52+
53+
assert.typeOf(config.trustProxy, 'function')
54+
})
55+
56+
test('comfile trustProxy config when string', ({ assert }) => {
57+
const config = defineConfig({ trustProxy: 'loopback' })
58+
59+
assert.typeOf(config.trustProxy, 'function')
60+
})
4961
})

tests/request.spec.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import pem from 'pem'
1111
import supertest from 'supertest'
12+
import proxyAddr from 'proxy-addr'
1213
import { test } from '@japa/runner'
1314
import Middleware from '@poppinss/middleware'
1415
import { createServer as httpsServer } from 'node:https'
@@ -517,6 +518,90 @@ test.group('Request', () => {
517518
})
518519
})
519520

521+
test('do not trust proxy when trustProxy does not allow it', async ({ assert }) => {
522+
const { url } = await httpServer.create((req, res) => {
523+
req.headers['x-forwarded-for'] = '10.10.10.10'
524+
const request = new RequestFactory()
525+
.merge({
526+
req,
527+
res,
528+
encryption,
529+
config: {
530+
trustProxy: proxyAddr.compile('192.168.1.0/24'),
531+
},
532+
})
533+
.create()
534+
res.writeHead(200, { 'content-type': 'application/json' })
535+
res.end(JSON.stringify({ ip: request.ip() }))
536+
})
537+
538+
const { body } = await supertest(url).get('/')
539+
assert.notEqual(body.ip, '10.10.10.10')
540+
})
541+
542+
test('trust proxy when trustProxy allows it', async ({ assert }) => {
543+
const { url } = await httpServer.create((req, res) => {
544+
req.headers['x-forwarded-for'] = '10.10.10.10'
545+
const request = new RequestFactory()
546+
.merge({
547+
req,
548+
res,
549+
encryption,
550+
config: {
551+
trustProxy: proxyAddr.compile('loopback'),
552+
},
553+
})
554+
.create()
555+
res.writeHead(200, { 'content-type': 'application/json' })
556+
res.end(JSON.stringify({ ip: request.ip() }))
557+
})
558+
559+
const { body } = await supertest(url).get('/')
560+
assert.equal(body.ip, '10.10.10.10')
561+
})
562+
563+
test('trust all proxies when trustProxy is true', async ({ assert }) => {
564+
const { url } = await httpServer.create((req, res) => {
565+
req.headers['x-forwarded-for'] = '10.10.10.10'
566+
const request = new RequestFactory()
567+
.merge({
568+
req,
569+
res,
570+
encryption,
571+
config: {
572+
trustProxy: (_, __) => true,
573+
},
574+
})
575+
.create()
576+
res.writeHead(200, { 'content-type': 'application/json' })
577+
res.end(JSON.stringify({ ip: request.ip() }))
578+
})
579+
580+
const { body } = await supertest(url).get('/')
581+
assert.equal(body.ip, '10.10.10.10')
582+
})
583+
584+
test('trust no proxy when trustProxy is false', async ({ assert }) => {
585+
const { url } = await httpServer.create((req, res) => {
586+
req.headers['x-forwarded-for'] = '10.10.10.10'
587+
const request = new RequestFactory()
588+
.merge({
589+
req,
590+
res,
591+
encryption,
592+
config: {
593+
trustProxy: (_, __) => false,
594+
},
595+
})
596+
.create()
597+
res.writeHead(200, { 'content-type': 'application/json' })
598+
res.end(JSON.stringify({ ip: request.ip() }))
599+
})
600+
601+
const { body } = await supertest(url).get('/')
602+
assert.notEqual(body.ip, '10.10.10.10')
603+
})
604+
520605
test('return request url without query string', async ({ assert }) => {
521606
const { url } = await httpServer.create((req, res) => {
522607
const request = new RequestFactory().merge({ req, res, encryption }).create()

0 commit comments

Comments
 (0)