Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit 943d4a8

Browse files
authored
fix: make http api only accept POST requests (#2977)
* fix: make http api only accept POST requests This is to prevent people maliciously controlling your local node by injecting images into webpages with URLs of API endpoints. BREAKING CHANGE: Where we used to accept all and any HTTP methods, now only POST is accepted. The API client will now only send POST requests too. * test: add tests to make sure we are post-only * chore: upgrade ipfs-utils * fix: return 405 instead of 404 for bad methods * fix: reject browsers that do not send an origin Also fixes running interface tests over http in browsers against js-ipfs
1 parent e54da1d commit 943d4a8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+966
-466
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ jobs:
6464
- stage: check
6565
script:
6666
- npm run build -- $RUN_SINCE --scope={ipfs,ipfs-http-client} -- -- --bundlesize
67-
- npm run dep-check -- $RUN_SINCE -- -- -- -i wrtc -i electron-webrtc
67+
- npm run dep-check -- $RUN_SINCE -- -- -- -i electron-webrtc
6868
- npm run lint -- $RUN_SINCE --concurrency 1
6969

7070
- stage: test

packages/interface-ipfs-core/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"dirty-chai": "^2.0.1",
3939
"ipfs-block": "^0.8.1",
4040
"ipfs-unixfs": "^1.0.1",
41-
"ipfs-utils": "^1.2.4",
41+
"ipfs-utils": "ipfs/js-ipfs-utils#fix/add-iterator-method-to-response",
4242
"ipld-dag-cbor": "^0.15.1",
4343
"ipld-dag-pb": "^0.18.3",
4444
"is-ipfs": "^1.0.0",

packages/ipfs-core-utils/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"dependencies": {
3131
"buffer": "^5.4.2",
3232
"err-code": "^2.0.0",
33-
"ipfs-utils": "^1.2.4"
33+
"ipfs-utils": "ipfs/js-ipfs-utils#fix/add-iterator-method-to-response"
3434
},
3535
"devDependencies": {
3636
"aegir": "21.4.5",

packages/ipfs-http-client/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"form-data": "^3.0.0",
4848
"ipfs-block": "^0.8.1",
4949
"ipfs-core-utils": "^0.1.1",
50-
"ipfs-utils": "^1.2.4",
50+
"ipfs-utils": "ipfs/js-ipfs-utils#fix/add-iterator-method-to-response",
5151
"ipld-dag-cbor": "^0.15.1",
5252
"ipld-dag-pb": "^0.18.3",
5353
"ipld-raw": "^4.0.1",

packages/ipfs-http-client/src/add.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ module.exports = configure((api) => {
1010
return async function * add (input, options = {}) {
1111
const progressFn = options.progress
1212

13-
const res = await api.ndjson('add', {
14-
method: 'POST',
13+
const res = await api.post('add', {
1514
searchParams: toUrlSearchParams(null, {
1615
...options,
1716
'stream-channels': true,
@@ -24,7 +23,7 @@ module.exports = configure((api) => {
2423
)
2524
})
2625

27-
for await (let file of res) {
26+
for await (let file of res.ndjson()) {
2827
file = toCamel(file)
2928

3029
if (progressFn && file.bytes) {

packages/ipfs-http-client/src/block/rm.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ module.exports = configure(api => {
2323
searchParams.append('arg', new CID(cid).toString())
2424
})
2525

26-
const res = await api.ndjson('block/rm', {
26+
const res = await api.post('block/rm', {
2727
timeout: options.timeout,
2828
signal: options.signal,
2929
searchParams: searchParams
3030
})
3131

32-
for await (const removed of res) {
32+
for await (const removed of res.ndjson()) {
3333
yield toCoreInterface(removed)
3434
}
3535
}

packages/ipfs-http-client/src/cat.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict'
22

33
const CID = require('cids')
4-
const { Buffer } = require('buffer')
54
const merge = require('merge-options')
65
const configure = require('./lib/configure')
76

@@ -13,15 +12,13 @@ module.exports = configure(api => {
1312
arg: typeof path === 'string' ? path : new CID(path).toString()
1413
}
1514
)
16-
const res = await api.iterator('cat', {
17-
method: 'POST',
15+
16+
const res = await api.post('cat', {
1817
timeout: options.timeout,
1918
signal: options.signal,
2019
searchParams: options
2120
})
2221

23-
for await (const chunk of res) {
24-
yield Buffer.from(chunk)
25-
}
22+
yield * res.iterator()
2623
}
2724
})

packages/ipfs-http-client/src/dht/find-peer.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ module.exports = configure(api => {
99
return async function findPeer (peerId, options = {}) {
1010
options.arg = `${Buffer.isBuffer(peerId) ? new CID(peerId) : peerId}`
1111

12-
const res = await api.ndjson('dht/findpeer', {
12+
const res = await api.post('dht/findpeer', {
1313
timeout: options.timeout,
1414
signal: options.signal,
1515
searchParams: options
1616
})
1717

18-
for await (const data of res) {
18+
for await (const data of res.ndjson()) {
1919
if (data.Type === 3) {
2020
throw new Error(data.Extra)
2121
}

packages/ipfs-http-client/src/dht/find-provs.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ const configure = require('../lib/configure')
77
module.exports = configure(api => {
88
return async function * findProvs (cid, options = {}) {
99
options.arg = `${new CID(cid)}`
10-
const res = await api.ndjson('dht/findprovs', {
11-
method: 'POST',
10+
const res = await api.post('dht/findprovs', {
1211
timeout: options.timeout,
1312
signal: options.signal,
1413
searchParams: options
1514
})
1615

17-
for await (const message of res) {
16+
for await (const message of res.ndjson()) {
1817
// 3 = QueryError
1918
// https://github.com/libp2p/go-libp2p-core/blob/6e566d10f4a5447317a66d64c7459954b969bdab/routing/query.go#L18
2019
// https://github.com/libp2p/go-libp2p-kad-dht/blob/master/routing.go#L525-L526

packages/ipfs-http-client/src/dht/get.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,13 @@ module.exports = configure(api => {
1111
}
1212

1313
options.key = encodeBufferURIComponent(key)
14-
const res = await api.ndjson('dht/get', {
15-
method: 'POST',
14+
const res = await api.post('dht/get', {
1615
timeout: options.timeout,
1716
signal: options.signal,
1817
searchParams: options
1918
})
2019

21-
for await (const message of res) {
20+
for await (const message of res.ndjson()) {
2221
// 3 = QueryError
2322
// https://github.com/libp2p/go-libp2p-core/blob/6e566d10f4a5447317a66d64c7459954b969bdab/routing/query.go#L18
2423
// https://github.com/ipfs/go-ipfs/blob/eb11f569b064b960d1aba4b5b8ca155a3bd2cb21/core/commands/dht.go#L472-L473

packages/ipfs-http-client/src/dht/provide.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@ module.exports = configure(api => {
1212
const searchParams = new URLSearchParams(options)
1313
cids.forEach(cid => searchParams.append('arg', `${new CID(cid)}`))
1414

15-
const res = await api.ndjson('dht/provide', {
16-
method: 'POST',
15+
const res = await api.post('dht/provide', {
1716
timeout: options.timeout,
1817
signal: options.signal,
1918
searchParams
2019
})
2120

22-
for await (let message of res) {
21+
for await (let message of res.ndjson()) {
2322
// 3 = QueryError
2423
// https://github.com/libp2p/go-libp2p-core/blob/6e566d10f4a5447317a66d64c7459954b969bdab/routing/query.go#L18
2524
// https://github.com/ipfs/go-ipfs/blob/eb11f569b064b960d1aba4b5b8ca155a3bd2cb21/core/commands/dht.go#L283-L284

packages/ipfs-http-client/src/dht/put.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ module.exports = configure(api => {
1111

1212
searchParams.append('arg', key)
1313
searchParams.append('arg', value)
14-
const res = await api.ndjson('dht/put', {
14+
const res = await api.post('dht/put', {
1515
timeout: options.timeout,
1616
signal: options.signal,
1717
searchParams
1818
})
1919

20-
for await (let message of res) {
20+
for await (let message of res.ndjson()) {
2121
// 3 = QueryError
2222
// https://github.com/libp2p/go-libp2p-core/blob/6e566d10f4a5447317a66d64c7459954b969bdab/routing/query.go#L18
2323
// https://github.com/ipfs/go-ipfs/blob/eb11f569b064b960d1aba4b5b8ca155a3bd2cb21/core/commands/dht.go#L472-L473

packages/ipfs-http-client/src/dht/query.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ const configure = require('../lib/configure')
88
module.exports = configure(api => {
99
return async function * query (peerId, options = {}) {
1010
options.arg = new CID(peerId)
11-
const res = await api.ndjson('dht/query', {
11+
const res = await api.post('dht/query', {
1212
timeout: options.timeout,
1313
signal: options.signal,
1414
searchParams: options
1515
})
1616

17-
for await (let message of res) {
17+
for await (let message of res.ndjson()) {
1818
message = toCamel(message)
1919
message.id = new CID(message.id)
2020
message.responses = (message.responses || []).map(({ ID, Addrs }) => ({

packages/ipfs-http-client/src/files/ls.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ module.exports = configure(api => {
1212
path = '/'
1313
}
1414

15-
const res = await api.ndjson('files/ls', {
16-
method: 'POST',
15+
const res = await api.post('files/ls', {
1716
timeout: options.timeout,
1817
signal: options.signal,
1918
searchParams: toUrlSearchParams(
@@ -30,7 +29,7 @@ module.exports = configure(api => {
3029
)
3130
})
3231

33-
for await (const result of res) {
32+
for await (const result of res.ndjson()) {
3433
// go-ipfs does not yet support the "stream" option
3534
if ('Entries' in result) {
3635
for (const entry of result.Entries || []) {

packages/ipfs-http-client/src/get.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,15 @@ module.exports = configure(api => {
99
return async function * get (path, options = {}) {
1010
options.arg = `${Buffer.isBuffer(path) ? new CID(path) : path}`
1111

12-
const res = await api.iterator('get', {
13-
method: 'POST',
12+
const res = await api.post('get', {
1413
timeout: options.timeout,
1514
signal: options.signal,
1615
searchParams: options
1716
})
1817

1918
const extractor = Tar.extract()
2019

21-
for await (const { header, body } of extractor(res)) {
20+
for await (const { header, body } of extractor(res.iterator())) {
2221
if (header.type === 'directory') {
2322
yield {
2423
path: header.name

packages/ipfs-http-client/src/lib/core.js

+14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const { URL } = require('iso-url')
77
const parseDuration = require('parse-duration')
88
const log = require('debug')('ipfs-http-client:lib:error-handler')
99
const HTTP = require('ipfs-utils/src/http')
10+
const merge = require('merge-options')
1011

1112
const isMultiaddr = (input) => {
1213
try {
@@ -126,6 +127,19 @@ class Client extends HTTP {
126127
return out
127128
}
128129
})
130+
131+
delete this.get
132+
delete this.put
133+
delete this.delete
134+
delete this.options
135+
136+
const fetch = this.fetch
137+
138+
this.fetch = (resource, options = {}) => {
139+
return fetch.call(this, resource, merge(options, {
140+
method: 'POST'
141+
}))
142+
}
129143
}
130144
}
131145

packages/ipfs-http-client/src/log/tail.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ const configure = require('../lib/configure')
44

55
module.exports = configure(api => {
66
return async function * tail (options = {}) {
7-
const res = await api.ndjson('log/tail', {
7+
const res = await api.post('log/tail', {
88
timeout: options.timeout,
99
signal: options.signal,
1010
searchParams: options
1111
})
1212

13-
yield * res
13+
yield * res.ndjson()
1414
}
1515
})

packages/ipfs-http-client/src/ls.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ module.exports = configure(api => {
99
const searchParams = new URLSearchParams(options)
1010
searchParams.set('arg', `${Buffer.isBuffer(path) ? new CID(path) : path}`)
1111

12-
const res = await api.ndjson('ls', {
13-
method: 'POST',
12+
const res = await api.post('ls', {
1413
timeout: options.timeout,
1514
signal: options.signal,
1615
searchParams
1716
})
1817

19-
for await (let result of res) {
18+
for await (let result of res.ndjson()) {
2019
result = result.Objects
2120

2221
if (!result) {

packages/ipfs-http-client/src/name/resolve.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ module.exports = configure(api => {
88
searchParams.set('arg', path)
99
searchParams.set('stream', options.stream || true)
1010

11-
const res = await api.ndjson('name/resolve', {
11+
const res = await api.post('name/resolve', {
1212
timeout: options.timeout,
1313
signal: options.signal,
1414
searchParams
1515
})
1616

17-
for await (const result of res) {
17+
for await (const result of res.ndjson()) {
1818
yield result.Path
1919
}
2020
}

packages/ipfs-http-client/src/pin/ls.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@ module.exports = configure(api => {
1616
searchParams.set('stream', options.stream || true)
1717
path.forEach(p => searchParams.append('arg', `${p}`))
1818

19-
const source = api.ndjson('pin/ls', {
20-
method: 'POST',
19+
const res = await api.post('pin/ls', {
2120
timeout: options.timeout,
2221
signal: options.signal,
2322
searchParams
2423
})
2524

26-
for await (const pin of source) {
25+
for await (const pin of res.ndjson()) {
2726
if (pin.Keys) { // non-streaming response
2827
// eslint-disable-next-line guard-for-in
2928
for (const key in pin.Keys) {

packages/ipfs-http-client/src/ping.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ const toCamel = require('./lib/object-to-camel')
44
const configure = require('./lib/configure')
55

66
module.exports = configure(api => {
7-
return function ping (peerId, options = {}) {
7+
return async function * ping (peerId, options = {}) {
88
const searchParams = new URLSearchParams(options)
99
searchParams.set('arg', `${peerId}`)
1010

11-
return api.ndjson('ping', {
12-
method: 'POST',
11+
const res = await api.post('ping', {
1312
timeout: options.timeout,
1413
signal: options.signal,
1514
searchParams,
1615
transform: toCamel
1716
})
17+
18+
yield * res.ndjson()
1819
}
1920
})

packages/ipfs-http-client/src/pubsub/subscribe.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const bs58 = require('bs58')
44
const { Buffer } = require('buffer')
55
const log = require('debug')('ipfs-http-client:pubsub:subscribe')
66
const SubscriptionTracker = require('./subscription-tracker')
7-
const { streamToAsyncIterator, ndjson } = require('../lib/core')
87
const configure = require('../lib/configure')
98

109
module.exports = configure((api, options) => {
@@ -32,8 +31,7 @@ module.exports = configure((api, options) => {
3231
}, 1000)
3332

3433
try {
35-
res = await api.stream('pubsub/sub', {
36-
method: 'POST',
34+
res = await api.post('pubsub/sub', {
3735
timeout: options.timeout,
3836
signal: options.signal,
3937
searchParams
@@ -45,7 +43,7 @@ module.exports = configure((api, options) => {
4543

4644
clearTimeout(ffWorkaround)
4745

48-
readMessages(ndjson(streamToAsyncIterator(res)), {
46+
readMessages(res.ndjson(), {
4947
onMessage: handler,
5048
onEnd: () => subsTracker.unsubscribe(topic, handler),
5149
onError: options.onError

0 commit comments

Comments
 (0)