Fix dashboard redirects leaking internal port
Build & Deploy / Build & Push Docker Image (push) Successful in 2m54s
Test / Type Check (all packages) (push) Successful in 53s
Build & Deploy / Deploy to VPS (push) Successful in 4s
Test / API Unit Tests (push) Successful in 48s
Test / Homepage Unit Tests (push) Successful in 43s
Test / Storefront Unit Tests (push) Successful in 40s
Test / Admin Unit Tests (push) Successful in 42s
Test / Dashboard Unit Tests (push) Successful in 41s
Test / API Integration Tests (push) Successful in 1m1s
Build & Deploy / Build & Push Docker Image (push) Successful in 2m54s
Test / Type Check (all packages) (push) Successful in 53s
Build & Deploy / Deploy to VPS (push) Successful in 4s
Test / API Unit Tests (push) Successful in 48s
Test / Homepage Unit Tests (push) Successful in 43s
Test / Storefront Unit Tests (push) Successful in 40s
Test / Admin Unit Tests (push) Successful in 42s
Test / Dashboard Unit Tests (push) Successful in 41s
Test / API Integration Tests (push) Successful in 1m1s
This commit is contained in:
@@ -77,7 +77,7 @@ describe('dashboard middleware', () => {
|
|||||||
|
|
||||||
const response = middleware(request('http://dashboard:3001/dashboard/team') as never)
|
const response = middleware(request('http://dashboard:3001/dashboard/team') as never)
|
||||||
|
|
||||||
expect(response).toEqual({ kind: 'redirect', url: 'https://rentaldrivego.example:3001/dashboard/sign-in?redirect=%2Fdashboard%2Fteam' })
|
expect(response).toEqual({ kind: 'redirect', url: 'https://rentaldrivego.example/dashboard/sign-in?redirect=%2Fdashboard%2Fteam' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('uses trusted forwarded host/proto when building the dashboard sign-in redirect', async () => {
|
it('uses trusted forwarded host/proto when building the dashboard sign-in redirect', async () => {
|
||||||
@@ -90,7 +90,7 @@ describe('dashboard middleware', () => {
|
|||||||
},
|
},
|
||||||
}) as never)
|
}) as never)
|
||||||
|
|
||||||
expect(response).toEqual({ kind: 'redirect', url: 'https://workspace.customer.example:3001/dashboard/sign-in?redirect=%2Fdashboard%2Fbilling' })
|
expect(response).toEqual({ kind: 'redirect', url: 'https://workspace.customer.example/dashboard/sign-in?redirect=%2Fdashboard%2Fbilling' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('ignores internal forwarded hosts when building the dashboard sign-in redirect', async () => {
|
it('ignores internal forwarded hosts when building the dashboard sign-in redirect', async () => {
|
||||||
@@ -103,7 +103,7 @@ describe('dashboard middleware', () => {
|
|||||||
},
|
},
|
||||||
}) as never)
|
}) as never)
|
||||||
|
|
||||||
expect(response).toEqual({ kind: 'redirect', url: 'https://market.example.com:3001/dashboard/sign-in?redirect=%2Fdashboard%2Ffleet' })
|
expect(response).toEqual({ kind: 'redirect', url: 'https://market.example.com/dashboard/sign-in?redirect=%2Fdashboard%2Ffleet' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('redirects signed-in users away from the sign-in page', async () => {
|
it('redirects signed-in users away from the sign-in page', async () => {
|
||||||
|
|||||||
@@ -38,16 +38,27 @@ function resolveProxyUrl(req: NextRequest, pathname: string): URL {
|
|||||||
if (forwardedHost && !isInternalHost(forwardedHost)) {
|
if (forwardedHost && !isInternalHost(forwardedHost)) {
|
||||||
url.host = forwardedHost
|
url.host = forwardedHost
|
||||||
url.protocol = (forwardedProto ?? 'http') + ':'
|
url.protocol = (forwardedProto ?? 'http') + ':'
|
||||||
|
if (!hasExplicitPort(forwardedHost) || isInternalAppPort(url.port)) url.port = ''
|
||||||
} else if (!isInternalHost(req.nextUrl.host)) {
|
} else if (!isInternalHost(req.nextUrl.host)) {
|
||||||
url.host = req.nextUrl.host
|
url.host = req.nextUrl.host
|
||||||
url.protocol = req.nextUrl.protocol
|
url.protocol = req.nextUrl.protocol
|
||||||
|
if (!hasExplicitPort(req.nextUrl.host) || isInternalAppPort(url.port)) url.port = ''
|
||||||
} else {
|
} else {
|
||||||
url.host = storefrontOrigin.host
|
url.host = storefrontOrigin.host
|
||||||
url.protocol = storefrontOrigin.protocol
|
url.protocol = storefrontOrigin.protocol
|
||||||
|
if (!hasExplicitPort(storefrontOrigin.host) || isInternalAppPort(url.port)) url.port = ''
|
||||||
}
|
}
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasExplicitPort(host: string): boolean {
|
||||||
|
return /^[^:]+:\d+$/.test(host)
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInternalAppPort(port: string): boolean {
|
||||||
|
return ['3000', '3001', '3002', '3004', '4000'].includes(port)
|
||||||
|
}
|
||||||
|
|
||||||
function isInternalHost(host: string | null): boolean {
|
function isInternalHost(host: string | null): boolean {
|
||||||
if (!host) return false
|
if (!host) return false
|
||||||
const hostname = host.split(':')[0]?.toLowerCase()
|
const hostname = host.split(':')[0]?.toLowerCase()
|
||||||
|
|||||||
Reference in New Issue
Block a user