From 315b7f7627208ae5d57eef0dd182d785c558e75a Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Mon, 26 Nov 2018 12:38:13 +0000 Subject: [PATCH] fix: better input validation for add (#876) License: MIT Signed-off-by: Alan Shaw --- .gitignore | 1 + .npmignore | 2 +- package.json | 4 ++-- src/files-regular/add-from-url.js | 4 ++-- src/files-regular/add.js | 24 ++++++++++++++++-------- src/files-regular/get-readable-stream.js | 2 +- src/files-regular/ls-readable-stream.js | 2 +- src/utils/send-files-stream.js | 2 +- test/dag.spec.js | 6 +++--- test/interface.spec.js | 2 +- 10 files changed, 29 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index d14c49494..77203bd99 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ docs test/setup/tmp-disposable-nodes-addrs.json dist coverage +.nyc_output **/*.swp examples/sub-module/**/bundle.js examples/sub-module/**/*-minified.js diff --git a/.npmignore b/.npmignore index 2f3481d98..e20403d47 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,5 @@ node_modules *.log coverage - +.nyc_output test diff --git a/package.json b/package.json index b901f8e6a..dd26a582d 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "url": "https://github.com/ipfs/js-ipfs-api" }, "devDependencies": { - "aegir": "^17.0.1", + "aegir": "^17.1.1", "browser-process-platform": "~0.1.1", "chai": "^4.2.0", "cross-env": "^5.2.0", @@ -85,7 +85,7 @@ "eslint-plugin-react": "^7.11.1", "go-ipfs-dep": "~0.4.18", "gulp": "^3.9.1", - "interface-ipfs-core": "~0.86.0", + "interface-ipfs-core": "~0.87.0", "ipfsd-ctl": "~0.40.0", "nock": "^10.0.2", "pull-stream": "^3.6.9", diff --git a/src/files-regular/add-from-url.js b/src/files-regular/add-from-url.js index e9e4be184..e926a7c81 100644 --- a/src/files-regular/add-from-url.js +++ b/src/files-regular/add-from-url.js @@ -1,7 +1,7 @@ 'use strict' const promisify = require('promisify-es6') -const parseUrl = require('url').parse +const { URL } = require('url') const request = require('../utils/request') const SendOneFile = require('../utils/send-one-file-multiple-results') const FileResultStreamConverter = require('../utils/file-result-stream-converter') @@ -35,7 +35,7 @@ module.exports = (send) => { const validUrl = (url) => typeof url === 'string' && url.startsWith('http') const requestWithRedirect = (url, opts, sendOneFile, callback) => { - const parsedUrl = parseUrl(url) + const parsedUrl = new URL(url) const req = request(parsedUrl.protocol)(url, (res) => { if (res.statusCode >= 400) { diff --git a/src/files-regular/add.js b/src/files-regular/add.js index f706843a8..97fe3a5e5 100644 --- a/src/files-regular/add.js +++ b/src/files-regular/add.js @@ -4,7 +4,7 @@ const promisify = require('promisify-es6') const ConcatStream = require('concat-stream') const once = require('once') const isStream = require('is-stream') -const OtherBuffer = require('buffer').Buffer +const isString = require('lodash/isString') const isSource = require('is-pull-stream').isSource const FileResultStreamConverter = require('../utils/file-result-stream-converter') const SendFilesStream = require('../utils/send-files-stream') @@ -25,15 +25,23 @@ module.exports = (send) => { } options.converter = FileResultStreamConverter - const ok = Buffer.isBuffer(_files) || - isStream.readable(_files) || - Array.isArray(_files) || - OtherBuffer.isBuffer(_files) || - typeof _files === 'object' || - isSource(_files) + // Buffer, pull stream or Node.js stream + const isBufferOrStream = obj => Buffer.isBuffer(obj) || isStream.readable(obj) || isSource(obj) + // An object like { content?, path? }, where content isBufferOrStream and path isString + const isContentObject = obj => { + if (typeof obj !== 'object') return false + // path is optional if content is present + if (obj.content) return isBufferOrStream(obj.content) + // path must be a non-empty string if no content + return Boolean(obj.path) && isString(obj.path) + } + // An input atom: a buffer, stream or content object + const isInput = obj => isBufferOrStream(obj) || isContentObject(obj) + // All is ok if data isInput or data is an array of isInput + const ok = isInput(_files) || (Array.isArray(_files) && _files.every(isInput)) if (!ok) { - return callback(new Error('first arg must be a buffer, readable stream, pull stream, an object or array of objects')) + return callback(new Error('invalid input: expected buffer, readable stream, pull stream, object or array of objects')) } const files = [].concat(_files) diff --git a/src/files-regular/get-readable-stream.js b/src/files-regular/get-readable-stream.js index 4c74dd0a7..0bace519f 100644 --- a/src/files-regular/get-readable-stream.js +++ b/src/files-regular/get-readable-stream.js @@ -10,7 +10,7 @@ module.exports = (send) => { return (path, opts) => { opts = opts || {} - const pt = new Stream.PassThrough({objectMode: true}) + const pt = new Stream.PassThrough({ objectMode: true }) try { path = cleanCID(path) diff --git a/src/files-regular/ls-readable-stream.js b/src/files-regular/ls-readable-stream.js index 9a15e1060..514b8dd31 100644 --- a/src/files-regular/ls-readable-stream.js +++ b/src/files-regular/ls-readable-stream.js @@ -12,7 +12,7 @@ module.exports = (arg) => { opts = {} } - const pt = new Stream.PassThrough({objectMode: true}) + const pt = new Stream.PassThrough({ objectMode: true }) send({ path: 'ls', args: args, qs: opts }, (err, results) => { if (err) { return callback(err) } diff --git a/src/utils/send-files-stream.js b/src/utils/send-files-stream.js index 46a57e383..aff2cdcc9 100644 --- a/src/utils/send-files-stream.js +++ b/src/utils/send-files-stream.js @@ -43,7 +43,7 @@ module.exports = (send, path) => { const next = once(_next) try { const files = prepareFile(file, options) - .map((file) => Object.assign({headers: headers(file)}, file)) + .map((file) => Object.assign({ headers: headers(file) }, file)) writing = true eachSeries( diff --git a/test/dag.spec.js b/test/dag.spec.js index fc967e7cf..a944f5c57 100644 --- a/test/dag.spec.js +++ b/test/dag.spec.js @@ -39,7 +39,7 @@ describe('.dag', function () { const data = Buffer.from('some data') DAGNode.create(data, (err, node) => { expect(err).to.not.exist() - ipfs.dag.put(node, {format: 'dag-pb', hashAlg: 'sha2-256'}, (err, cid) => { + ipfs.dag.put(node, { format: 'dag-pb', hashAlg: 'sha2-256' }, (err, cid) => { expect(err).to.not.exist() cid = cid.toV0() expect(cid.codec).to.equal('dag-pb') @@ -56,8 +56,8 @@ describe('.dag', function () { }) it('should be able to put and get a DAG node with format dag-cbor', (done) => { - const cbor = {foo: 'dag-cbor-bar'} - ipfs.dag.put(cbor, {format: 'dag-cbor', hashAlg: 'sha2-256'}, (err, cid) => { + const cbor = { foo: 'dag-cbor-bar' } + ipfs.dag.put(cbor, { format: 'dag-cbor', hashAlg: 'sha2-256' }, (err, cid) => { expect(err).to.not.exist() expect(cid.codec).to.equal('dag-cbor') cid = cid.toBaseEncodedString('base32') diff --git a/test/interface.spec.js b/test/interface.spec.js index d3be72bae..eef7f0434 100644 --- a/test/interface.spec.js +++ b/test/interface.spec.js @@ -7,7 +7,7 @@ const CommonFactory = require('./utils/interface-common-factory') const IPFSApi = require('../src') const isWindows = process.platform && process.platform === 'win32' -describe.only('interface-ipfs-core tests', () => { +describe('interface-ipfs-core tests', () => { const defaultCommonFactory = CommonFactory.create() tests.bitswap(defaultCommonFactory, {