Skip to content

Commit

Permalink
fix: strip authorization and cookie headers on redirect to new host (#45
Browse files Browse the repository at this point in the history
)

* chore: cleanup dummy txt files left behind by tests

* fix: strip authorization and cookie headers on redirect to new host
  • Loading branch information
nlf committed Mar 8, 2022
1 parent a00252f commit 50d919a
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 0 deletions.
8 changes: 8 additions & 0 deletions lib/index.js
Expand Up @@ -204,6 +204,14 @@ const fetch = async (url, opts) => {
timeout: request.timeout,
}

// if the redirect is to a new hostname, strip the authorization and cookie headers
const parsedOriginal = new URL(request.url)
const parsedRedirect = new URL(locationURL)
if (parsedOriginal.hostname !== parsedRedirect.hostname) {
requestOpts.headers.delete('authorization')
requestOpts.headers.delete('cookie')
}

// HTTP-redirect fetch step 11
if (res.statusCode === 303 || (
(res.statusCode === 301 || res.statusCode === 302) &&
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -27,6 +27,7 @@
"abort-controller": "^3.0.0",
"abortcontroller-polyfill": "~1.7.3",
"form-data": "^4.0.0",
"nock": "^13.2.4",
"parted": "^0.1.1",
"string-to-arraybuffer": "^1.0.2",
"tap": "^15.1.6"
Expand Down
46 changes: 46 additions & 0 deletions test/index.js
Expand Up @@ -24,6 +24,7 @@ const http = require('http')
// use of url.parse here is intentional and for coverage purposes
// eslint-disable-next-line node/no-deprecated-api
const { parse: parseURL, URLSearchParams } = require('url')
const nock = require('nock')

const vm = require('vm')
const {
Expand Down Expand Up @@ -184,6 +185,42 @@ t.test('follow redirects', t => {
})))
})

t.test('redirect to different host strips headers', async (t) => {
nock.disableNetConnect()
t.teardown(() => {
nock.cleanAll()
nock.enableNetConnect()
})

const first = nock('http://x.y', {
reqheaders: {
authorization: 'totally-authed-request',
cookie: 'fake-cookie',
},
})
.get('/')
.reply(301, null, { location: 'http://a.b' })

const second = nock('http://a.b', {
badheaders: ['authorization', 'cookie'],
})
.get('/')
.reply(200)

const res = await fetch('http://x.y', {
headers: {
authorization: 'totally-authed-request',
cookie: 'fake-cookie',
},
})
await res.text() // drain the response stream

t.ok(first.isDone(), 'initial request made')
t.ok(second.isDone(), 'redirect followed')
t.equal(res.status, 200)
t.ok(res.ok)
})

t.test('follow POST request redirect with GET', t => {
const codes = [301, 302]
t.plan(codes.length)
Expand Down Expand Up @@ -1045,6 +1082,15 @@ t.test('POST with form-data as body', t => {
})

t.test('POST with form-data using stream as body', t => {
t.teardown(() => {
const root = path.dirname(__dirname)
// parted's multipart form parser writes a temporary file to disk, this removes it
fs.readdirSync(root).filter((file) => {
return file.startsWith('dummy.') && file.endsWith('.txt')
}).forEach((file) => {
fs.unlinkSync(path.join(root, file))
})
})
const form = new FormData()
form.append('my_field', fs.createReadStream(path.join(__dirname, 'fixtures/dummy.txt')))

Expand Down

0 comments on commit 50d919a

Please sign in to comment.