From 7985cf19b0bcf8b74e4dd9c514799c0dfafb2931 Mon Sep 17 00:00:00 2001
From: achingbrain <alex@achingbrain.net>
Date: Tue, 25 Aug 2020 10:59:39 +0100
Subject: [PATCH 1/3] feat: update hapi to v20

Updates hapi ecosystem modules to v20

BREAKING CHANGES:

- Hapi has dropped support for node < 12
---
 packages/ipfs-http-client/package.json        |  2 +-
 packages/ipfs/package.json                    | 14 +--
 .../ipfs/src/http/api/resources/config.js     |  3 +
 packages/ipfs/src/http/api/resources/dht.js   |  6 ++
 .../ipfs/src/http/api/resources/files/cp.js   |  5 +-
 .../src/http/api/resources/files/mkdir.js     |  5 +-
 .../ipfs/src/http/api/resources/files/mv.js   |  5 +-
 .../src/http/api/resources/files/touch.js     |  5 +-
 .../src/http/api/resources/files/write.js     | 11 +--
 .../ipfs/src/http/api/resources/pubsub.js     |  3 +
 packages/ipfs/src/http/error-handler.js       |  4 +-
 .../ipfs/src/http/gateway/routes/gateway.js   | 10 +-
 packages/ipfs/src/http/utils/joi.js           | 94 +++++++++++++------
 .../http/utils/multipart-request-parser.js    |  9 +-
 packages/ipfs/test/http-api/inject/block.js   | 10 +-
 15 files changed, 104 insertions(+), 82 deletions(-)

diff --git a/packages/ipfs-http-client/package.json b/packages/ipfs-http-client/package.json
index 9ef7a9d920..954833459c 100644
--- a/packages/ipfs-http-client/package.json
+++ b/packages/ipfs-http-client/package.json
@@ -58,7 +58,7 @@
     "it-tar": "^1.2.2",
     "it-to-buffer": "^1.0.0",
     "it-to-stream": "^0.1.1",
-    "merge-options": "^2.0.0",
+    "merge-options": "^3.0.1",
     "multiaddr": "^8.0.0",
     "multiaddr-to-uri": "^6.0.0",
     "multibase": "^3.0.0",
diff --git a/packages/ipfs/package.json b/packages/ipfs/package.json
index 9cd62d09d8..b268ed9862 100644
--- a/packages/ipfs/package.json
+++ b/packages/ipfs/package.json
@@ -62,11 +62,10 @@
     "dep-check": "aegir dep-check"
   },
   "dependencies": {
-    "@hapi/ammo": "^3.1.2",
-    "@hapi/boom": "^7.4.3",
-    "@hapi/content": "^4.1.0",
-    "@hapi/hapi": "^18.4.0",
-    "@hapi/joi": "^15.1.0",
+    "@hapi/ammo": "^5.0.1",
+    "@hapi/boom": "^9.1.0",
+    "@hapi/content": "^5.0.2",
+    "@hapi/hapi": "^20.0.0",
     "abort-controller": "^3.0.0",
     "any-signal": "^1.1.0",
     "array-shuffle": "^1.0.1",
@@ -88,7 +87,7 @@
     "fnv1a": "^1.0.1",
     "get-folder-size": "^2.0.0",
     "hamt-sharding": "^1.0.0",
-    "hapi-pino": "^6.1.0",
+    "hapi-pino": "^8.2.0",
     "hashlru": "^2.3.0",
     "interface-datastore": "^2.0.0",
     "ipfs-bitswap": "^3.0.0",
@@ -126,6 +125,7 @@
     "it-tar": "^1.2.2",
     "it-to-stream": "^0.1.1",
     "iterable-ndjson": "^1.1.0",
+    "joi": "^17.2.1",
     "jsondiffpatch": "^0.4.1",
     "just-safe-set": "^2.1.0",
     "libp2p": "libp2p/js-libp2p#0.29.x",
@@ -145,7 +145,7 @@
     "libp2p-webrtc-star": "^0.19.0",
     "libp2p-websockets": "^0.14.0",
     "mafmt": "^8.0.0",
-    "merge-options": "^2.0.0",
+    "merge-options": "^3.0.1",
     "mortice": "^2.0.0",
     "multiaddr": "^8.0.0",
     "multiaddr-to-uri": "^6.0.0",
diff --git a/packages/ipfs/src/http/api/resources/config.js b/packages/ipfs/src/http/api/resources/config.js
index 5cecd021d4..1d1e863035 100644
--- a/packages/ipfs/src/http/api/resources/config.js
+++ b/packages/ipfs/src/http/api/resources/config.js
@@ -232,6 +232,9 @@ exports.replace = {
       parse: false,
       output: 'stream'
     },
+    response: {
+      emptyStatusCode: 200
+    },
     pre: [{
       assign: 'args',
       method: async (request, h) => {
diff --git a/packages/ipfs/src/http/api/resources/dht.js b/packages/ipfs/src/http/api/resources/dht.js
index 04e0536a42..4f91c00210 100644
--- a/packages/ipfs/src/http/api/resources/dht.js
+++ b/packages/ipfs/src/http/api/resources/dht.js
@@ -217,6 +217,9 @@ exports.provide = {
           override: true,
           ignoreUndefined: true
         })
+    },
+    response: {
+      emptyStatusCode: 200
     }
   },
   async handler (request, h) {
@@ -255,6 +258,9 @@ exports.put = {
         arg: Joi.array().length(2).items(Joi.binary()).required(),
         timeout: Joi.timeout()
       })
+    },
+    response: {
+      emptyStatusCode: 200
     }
   },
   async handler (request, h) {
diff --git a/packages/ipfs/src/http/api/resources/files/cp.js b/packages/ipfs/src/http/api/resources/files/cp.js
index b0a1a51e32..99e564f512 100644
--- a/packages/ipfs/src/http/api/resources/files/cp.js
+++ b/packages/ipfs/src/http/api/resources/files/cp.js
@@ -14,10 +14,7 @@ const mfsCp = {
         parents: Joi.boolean().default(false),
         flush: Joi.boolean().default(true),
         hashAlg: Joi.string().default('sha2-256'),
-        cidVersion: Joi.number().integer().valid([
-          0,
-          1
-        ]).default(0),
+        cidVersion: Joi.number().integer().valid(0, 1).default(0),
         shardSplitThreshold: Joi.number().integer().min(0).default(1000),
         timeout: Joi.timeout()
       })
diff --git a/packages/ipfs/src/http/api/resources/files/mkdir.js b/packages/ipfs/src/http/api/resources/files/mkdir.js
index 2dbb0fec85..a0ae41c6ec 100644
--- a/packages/ipfs/src/http/api/resources/files/mkdir.js
+++ b/packages/ipfs/src/http/api/resources/files/mkdir.js
@@ -17,10 +17,7 @@ const mfsMkdir = {
         mtimeNsecs: Joi.number().integer().min(0),
         parents: Joi.boolean().default(false),
         hashAlg: Joi.string().default('sha2-256'),
-        cidVersion: Joi.number().integer().valid([
-          0,
-          1
-        ]).default(0),
+        cidVersion: Joi.number().integer().valid(0, 1).default(0),
         flush: Joi.boolean().default(true),
         shardSplitThreshold: Joi.number().integer().min(0).default(1000),
         timeout: Joi.timeout()
diff --git a/packages/ipfs/src/http/api/resources/files/mv.js b/packages/ipfs/src/http/api/resources/files/mv.js
index c68e93884b..028ed27067 100644
--- a/packages/ipfs/src/http/api/resources/files/mv.js
+++ b/packages/ipfs/src/http/api/resources/files/mv.js
@@ -14,10 +14,7 @@ const mfsMv = {
         recursive: Joi.boolean().default(false),
         parents: Joi.boolean().default(false),
         hashAlg: Joi.string().default('sha2-256'),
-        cidVersion: Joi.number().integer().valid([
-          0,
-          1
-        ]).default(0),
+        cidVersion: Joi.number().integer().valid(0, 1).default(0),
         flush: Joi.boolean().default(true),
         shardSplitThreshold: Joi.number().integer().min(0).default(1000),
         timeout: Joi.timeout()
diff --git a/packages/ipfs/src/http/api/resources/files/touch.js b/packages/ipfs/src/http/api/resources/files/touch.js
index 3a8a82daca..444576581a 100644
--- a/packages/ipfs/src/http/api/resources/files/touch.js
+++ b/packages/ipfs/src/http/api/resources/files/touch.js
@@ -15,10 +15,7 @@ const mfsTouch = {
         mtime: Joi.number().integer(),
         mtimeNsecs: Joi.number().integer().min(0),
         hashAlg: Joi.string().default('sha2-256'),
-        cidVersion: Joi.number().integer().valid([
-          0,
-          1
-        ]).default(0),
+        cidVersion: Joi.number().integer().valid(0, 1).default(0),
         flush: Joi.boolean().default(true),
         shardSplitThreshold: Joi.number().integer().min(0).default(1000),
         timeout: Joi.timeout()
diff --git a/packages/ipfs/src/http/api/resources/files/write.js b/packages/ipfs/src/http/api/resources/files/write.js
index 0103b7a476..60661b9e82 100644
--- a/packages/ipfs/src/http/api/resources/files/write.js
+++ b/packages/ipfs/src/http/api/resources/files/write.js
@@ -24,18 +24,11 @@ const mfsWrite = {
         create: Joi.boolean().default(false),
         truncate: Joi.boolean().default(false),
         rawLeaves: Joi.boolean().default(false),
-        cidVersion: Joi.number().integer().valid([
-          0,
-          1
-        ]).default(0),
+        cidVersion: Joi.number().integer().valid(0, 1).default(0),
         hashAlg: Joi.string().default('sha2-256'),
         parents: Joi.boolean().default(false),
         progress: Joi.func(),
-        strategy: Joi.string().valid([
-          'flat',
-          'balanced',
-          'trickle'
-        ]).default('trickle'),
+        strategy: Joi.string().valid('flat', 'balanced', 'trickle').default('trickle'),
         flush: Joi.boolean().default(true),
         reduceSingleLeafToSelf: Joi.boolean().default(false),
         shardSplitThreshold: Joi.number().integer().min(0).default(1000),
diff --git a/packages/ipfs/src/http/api/resources/pubsub.js b/packages/ipfs/src/http/api/resources/pubsub.js
index 2d2d8685c9..900355f9a2 100644
--- a/packages/ipfs/src/http/api/resources/pubsub.js
+++ b/packages/ipfs/src/http/api/resources/pubsub.js
@@ -83,6 +83,9 @@ exports.publish = {
       parse: false,
       output: 'stream'
     },
+    response: {
+      emptyStatusCode: 200
+    },
     pre: [{
       assign: 'data',
       method: async (request, h) => {
diff --git a/packages/ipfs/src/http/error-handler.js b/packages/ipfs/src/http/error-handler.js
index e1027211f1..f63e2e36b3 100644
--- a/packages/ipfs/src/http/error-handler.js
+++ b/packages/ipfs/src/http/error-handler.js
@@ -35,8 +35,8 @@ module.exports = server => {
         response: res.output.payload
       }
 
-      server.logger().error(debug)
-      server.logger().error(res)
+      server.logger.error(debug)
+      server.logger.error(res)
     }
 
     return h.response({
diff --git a/packages/ipfs/src/http/gateway/routes/gateway.js b/packages/ipfs/src/http/gateway/routes/gateway.js
index 57d563aa6b..659758f2c8 100644
--- a/packages/ipfs/src/http/gateway/routes/gateway.js
+++ b/packages/ipfs/src/http/gateway/routes/gateway.js
@@ -1,6 +1,6 @@
 'use strict'
 
-const Joi = require('@hapi/joi')
+const Joi = require('joi')
 const resources = require('../resources')
 
 module.exports = [
@@ -10,9 +10,9 @@ module.exports = [
     options: {
       handler: resources.gateway.handler,
       validate: {
-        params: {
+        params: Joi.object({
           path: Joi.string().required()
-        }
+        })
       },
       response: {
         ranges: false // disable built-in support, handler does it manually
@@ -28,9 +28,9 @@ module.exports = [
     options: {
       handler: resources.gateway.handler,
       validate: {
-        params: {
+        params: Joi.object({
           path: Joi.string().required()
-        }
+        })
       },
       response: {
         ranges: false // disable built-in support, handler does it manually
diff --git a/packages/ipfs/src/http/utils/joi.js b/packages/ipfs/src/http/utils/joi.js
index 65e7f7c9fa..2bd6797efd 100644
--- a/packages/ipfs/src/http/utils/joi.js
+++ b/packages/ipfs/src/http/utils/joi.js
@@ -1,6 +1,6 @@
 'use strict'
 
-const Joi = require('@hapi/joi')
+const Joi = require('joi')
 const CID = require('cids')
 const parseDuration = require('parse-duration').default
 const multiaddr = require('multiaddr')
@@ -41,87 +41,122 @@ module.exports = Joi
   .extend(
     (joi) => {
       return {
-        name: 'cid',
+        type: 'cid',
         base: joi.any(),
-        pre (value, state, options) {
+        validate (value, helpers) {
+          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
+            return { value, errors: helpers.error('required') }
+          }
+        },
+        coerce (value, helpers) {
           if (!value) {
             return
           }
 
-          return toCID(value)
+          return { value: toCID(value) }
         }
       }
     },
     (joi) => {
       return {
-        name: 'ipfsPath',
+        type: 'ipfsPath',
         base: joi.string(),
-        coerce (value, state, options) {
+        validate (value, helpers) {
+          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
+            return { value, errors: helpers.error('required') }
+          }
+        },
+        coerce (value, helpers) {
           if (!value) {
             return
           }
 
-          return toIpfsPath(value)
+          return { value: toIpfsPath(value) }
         }
       }
     },
     (joi) => {
       return {
-        name: 'peerId',
+        type: 'peerId',
         base: joi.string(),
-        pre (value, state, options) {
+        validate (value, helpers) {
+          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
+            return { value, errors: helpers.error('required') }
+          }
+        },
+        coerce (value, helpers) {
           if (!value) {
             return
           }
 
-          return new CID(value).toString()
+          return { value: new CID(value).toString() }
         }
       }
     },
     (joi) => {
       return {
-        name: 'multiaddr',
+        type: 'multiaddr',
         base: joi.string(),
-        pre (value, state, options) {
+        validate (value, helpers) {
+          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
+            return { value, errors: helpers.error('required') }
+          }
+        },
+        coerce (value, helpers) {
           if (!value) {
             return
           }
 
-          return multiaddr(value).toString()
+          return { value: multiaddr(value).toString() }
         }
       }
     },
     (joi) => {
       return {
-        name: 'timeout',
-        base: joi.string(),
-        pre (value, state, options) {
+        type: 'timeout',
+        base: joi.number(),
+        validate (value, helpers) {
+          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
+            return { value, errors: helpers.error('required') }
+          }
+        },
+        coerce (value, helpers) {
           if (!value) {
             return
           }
 
-          return parseDuration(value)
+          return { value: parseDuration(value) }
         }
       }
     },
     (joi) => {
       return {
-        name: 'cidAndPath',
+        type: 'cidAndPath',
         base: joi.any(),
-        pre (value, state, options) {
+        validate (value, helpers) {
+          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
+            return { value, errors: helpers.error('required') }
+          }
+        },
+        coerce (value, helpers) {
           if (!value) {
             return
           }
 
-          return toCidAndPath(value)
+          return { value: toCidAndPath(value) }
         }
       }
     },
     (joi) => {
       return {
-        name: 'cidBase',
+        type: 'cidBase',
         base: joi.string(),
-        pre (value, state, options) {
+        validate (value, helpers) {
+          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
+            return { value, errors: helpers.error('required') }
+          }
+        },
+        coerce (value, helpers) {
           if (!value) {
             return
           }
@@ -130,20 +165,25 @@ module.exports = Joi
             throw new Error('Invalid base name')
           }
 
-          return value
+          return { value }
         }
       }
     },
     (joi) => {
       return {
-        name: 'json',
-        base: joi.string(),
-        pre (value, state, options) {
+        type: 'json',
+        base: joi.any(),
+        validate (value, helpers) {
+          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
+            return { value, errors: helpers.error('required') }
+          }
+        },
+        coerce (value, helpers) {
           if (!value) {
             return
           }
 
-          return JSON.parse(value)
+          return { value: JSON.parse(value) }
         }
       }
     })
diff --git a/packages/ipfs/src/http/utils/multipart-request-parser.js b/packages/ipfs/src/http/utils/multipart-request-parser.js
index f621cf85c8..00c52715a7 100644
--- a/packages/ipfs/src/http/utils/multipart-request-parser.js
+++ b/packages/ipfs/src/http/utils/multipart-request-parser.js
@@ -5,6 +5,7 @@ const multipart = require('it-multipart')
 const uint8ArrayConcat = require('uint8arrays/concat')
 const uint8ArrayToString = require('uint8arrays/to-string')
 const qs = require('querystring')
+const drain = require('it-drain')
 
 const multipartFormdataType = 'multipart/form-data'
 const applicationDirectory = 'application/x-directory'
@@ -41,12 +42,6 @@ const collect = async (stream) => {
   return uint8ArrayConcat(buffers, size)
 }
 
-const ignore = async (stream) => {
-  for await (const _ of stream) { // eslint-disable-line no-unused-vars
-
-  }
-}
-
 async function * parseEntry (stream, options) {
   for await (const part of stream) {
     if (!part.headers['content-type']) {
@@ -113,7 +108,7 @@ async function * parser (stream, options) {
         mode: entry.mode
       }
 
-      await ignore(entry.body)
+      await drain(entry.body)
     }
 
     if (entry.type === 'symlink') {
diff --git a/packages/ipfs/test/http-api/inject/block.js b/packages/ipfs/test/http-api/inject/block.js
index 3379c43e60..69319eed3e 100644
--- a/packages/ipfs/test/http-api/inject/block.js
+++ b/packages/ipfs/test/http-api/inject/block.js
@@ -302,17 +302,11 @@ describe('/block', () => {
     })
 
     it('should not stat a block for invalid cid-base option', async () => {
-      const form = new FormData()
-      form.append('data', Buffer.from('TEST' + Date.now()))
-      const headers = form.getHeaders()
-
-      const payload = await streamToPromise(form)
       const res = await http({
         method: 'POST',
-        url: '/api/v0/block/stat?cid-base=invalid',
-        headers,
-        payload
+        url: '/api/v0/block/stat?cid-base=invalid'
       }, { ipfs })
+
       expect(res).to.have.property('statusCode', 400)
       expect(res).to.have.nested.property('result.Message').that.includes('Invalid request query input')
     })

From d77466611caf05b450af07d81beeb8af5297ee72 Mon Sep 17 00:00:00 2001
From: achingbrain <alex@achingbrain.net>
Date: Tue, 25 Aug 2020 14:16:31 +0100
Subject: [PATCH 2/3] chore: upgrade deps, centralise empty status config

---
 .../explore-ethereum-blockchain/package.json  |  2 +-
 .../http-client-browser-pubsub/package.json   |  2 +-
 .../http-client-bundle-webpack/package.json   |  2 +-
 examples/http-client-name-api/package.json    |  2 +-
 packages/interface-ipfs-core/package.json     |  2 +-
 packages/ipfs-http-client/package.json        |  2 +-
 packages/ipfs/package.json                    |  4 +-
 .../ipfs/src/http/api/resources/config.js     |  3 --
 packages/ipfs/src/http/api/resources/dht.js   |  6 ---
 .../ipfs/src/http/api/resources/pubsub.js     |  3 --
 packages/ipfs/src/http/index.js               | 10 +++-
 packages/ipfs/src/http/utils/joi.js           | 54 +++++--------------
 12 files changed, 30 insertions(+), 62 deletions(-)

diff --git a/examples/explore-ethereum-blockchain/package.json b/examples/explore-ethereum-blockchain/package.json
index 562ceba4fc..f199c02d4e 100644
--- a/examples/explore-ethereum-blockchain/package.json
+++ b/examples/explore-ethereum-blockchain/package.json
@@ -12,7 +12,7 @@
   "devDependencies": {
     "ipfs": "^0.49.0",
     "ipfs-http-client": "^46.0.0",
-    "ipfsd-ctl": "^5.0.0",
+    "ipfsd-ctl": "^7.0.0",
     "test-ipfs-example": "^2.0.3"
   }
 }
diff --git a/examples/http-client-browser-pubsub/package.json b/examples/http-client-browser-pubsub/package.json
index 2eb24f82fb..c7e31e96d3 100644
--- a/examples/http-client-browser-pubsub/package.json
+++ b/examples/http-client-browser-pubsub/package.json
@@ -21,7 +21,7 @@
     "execa": "^4.0.0",
     "go-ipfs": "^0.6.0",
     "ipfs": "^0.49.0",
-    "ipfsd-ctl": "^5.0.0",
+    "ipfsd-ctl": "^7.0.0",
     "parcel-bundler": "^1.12.4",
     "test-ipfs-example": "^2.0.3"
   }
diff --git a/examples/http-client-bundle-webpack/package.json b/examples/http-client-bundle-webpack/package.json
index a08781d979..8ad0b68cdf 100644
--- a/examples/http-client-bundle-webpack/package.json
+++ b/examples/http-client-bundle-webpack/package.json
@@ -24,7 +24,7 @@
     "copy-webpack-plugin": "^5.0.4",
     "execa": "^4.0.0",
     "ipfs": "^0.49.0",
-    "ipfsd-ctl": "^5.0.0",
+    "ipfsd-ctl": "^7.0.0",
     "react-hot-loader": "^4.12.21",
     "test-ipfs-example": "^2.0.3",
     "webpack": "^4.43.0",
diff --git a/examples/http-client-name-api/package.json b/examples/http-client-name-api/package.json
index 17e5f548c4..76200a5491 100644
--- a/examples/http-client-name-api/package.json
+++ b/examples/http-client-name-api/package.json
@@ -17,7 +17,7 @@
   "devDependencies": {
     "execa": "^4.0.0",
     "go-ipfs": "^0.6.0",
-    "ipfsd-ctl": "^5.0.0",
+    "ipfsd-ctl": "^7.0.0",
     "parcel-bundler": "^1.12.4",
     "test-ipfs-example": "^2.0.3"
   },
diff --git a/packages/interface-ipfs-core/package.json b/packages/interface-ipfs-core/package.json
index 808d63943d..93dde85de4 100644
--- a/packages/interface-ipfs-core/package.json
+++ b/packages/interface-ipfs-core/package.json
@@ -63,7 +63,7 @@
   },
   "devDependencies": {
     "aegir": "^26.0.0",
-    "ipfsd-ctl": "^6.0.0"
+    "ipfsd-ctl": "^7.0.0"
   },
   "contributors": [
     "Alan Shaw <alan.shaw@protocol.ai>",
diff --git a/packages/ipfs-http-client/package.json b/packages/ipfs-http-client/package.json
index 954833459c..253edefe7f 100644
--- a/packages/ipfs-http-client/package.json
+++ b/packages/ipfs-http-client/package.json
@@ -75,7 +75,7 @@
     "cross-env": "^7.0.0",
     "go-ipfs": "^0.6.0",
     "interface-ipfs-core": "^0.139.1",
-    "ipfsd-ctl": "^6.0.0",
+    "ipfsd-ctl": "^7.0.0",
     "it-all": "^1.0.1",
     "it-concat": "^1.0.0",
     "it-pipe": "^1.1.0",
diff --git a/packages/ipfs/package.json b/packages/ipfs/package.json
index b268ed9862..925006c2d1 100644
--- a/packages/ipfs/package.json
+++ b/packages/ipfs/package.json
@@ -142,7 +142,7 @@
     "libp2p-record": "^0.9.0",
     "libp2p-secio": "^0.13.0",
     "libp2p-tcp": "^0.15.0",
-    "libp2p-webrtc-star": "^0.19.0",
+    "libp2p-webrtc-star": "^0.20.0",
     "libp2p-websockets": "^0.14.0",
     "mafmt": "^8.0.0",
     "merge-options": "^3.0.1",
@@ -180,7 +180,7 @@
     "go-ipfs": "^0.6.0",
     "interface-ipfs-core": "^0.139.1",
     "ipfs-interop": "github:ipfs/interop#refactor/streaming-pin-api",
-    "ipfsd-ctl": "^6.0.0",
+    "ipfsd-ctl": "^7.0.0",
     "iso-random-stream": "^1.1.1",
     "it-to-buffer": "^1.0.0",
     "nanoid": "^3.0.2",
diff --git a/packages/ipfs/src/http/api/resources/config.js b/packages/ipfs/src/http/api/resources/config.js
index 1d1e863035..5cecd021d4 100644
--- a/packages/ipfs/src/http/api/resources/config.js
+++ b/packages/ipfs/src/http/api/resources/config.js
@@ -232,9 +232,6 @@ exports.replace = {
       parse: false,
       output: 'stream'
     },
-    response: {
-      emptyStatusCode: 200
-    },
     pre: [{
       assign: 'args',
       method: async (request, h) => {
diff --git a/packages/ipfs/src/http/api/resources/dht.js b/packages/ipfs/src/http/api/resources/dht.js
index 4f91c00210..fe0c70b2cd 100644
--- a/packages/ipfs/src/http/api/resources/dht.js
+++ b/packages/ipfs/src/http/api/resources/dht.js
@@ -218,9 +218,6 @@ exports.provide = {
           ignoreUndefined: true
         })
     },
-    response: {
-      emptyStatusCode: 200
-    }
   },
   async handler (request, h) {
     const {
@@ -259,9 +256,6 @@ exports.put = {
         timeout: Joi.timeout()
       })
     },
-    response: {
-      emptyStatusCode: 200
-    }
   },
   async handler (request, h) {
     const {
diff --git a/packages/ipfs/src/http/api/resources/pubsub.js b/packages/ipfs/src/http/api/resources/pubsub.js
index 900355f9a2..2d2d8685c9 100644
--- a/packages/ipfs/src/http/api/resources/pubsub.js
+++ b/packages/ipfs/src/http/api/resources/pubsub.js
@@ -83,9 +83,6 @@ exports.publish = {
       parse: false,
       output: 'stream'
     },
-    response: {
-      emptyStatusCode: 200
-    },
     pre: [{
       assign: 'data',
       method: async (request, h) => {
diff --git a/packages/ipfs/src/http/index.js b/packages/ipfs/src/http/index.js
index 9cc8c43422..3079428a06 100644
--- a/packages/ipfs/src/http/index.js
+++ b/packages/ipfs/src/http/index.js
@@ -74,7 +74,10 @@ class HttpApi {
       // CORS is enabled by default
       // TODO: shouldn't, fix this
       routes: {
-        cors: true
+        cors: true,
+        response: {
+            emptyStatusCode: 200
+        }
       },
       // Disable Compression
       // Why? Streaming compression in Hapi is not stable enough,
@@ -171,7 +174,10 @@ class HttpApi {
       host,
       port,
       routes: {
-        cors: true
+        cors: true,
+        response: {
+            emptyStatusCode: 200
+        }
       }
     })
     server.app.ipfs = ipfs
diff --git a/packages/ipfs/src/http/utils/joi.js b/packages/ipfs/src/http/utils/joi.js
index 2bd6797efd..9353364dd4 100644
--- a/packages/ipfs/src/http/utils/joi.js
+++ b/packages/ipfs/src/http/utils/joi.js
@@ -37,17 +37,19 @@ const toCID = (value) => {
   return new CID(value.toString().replace('/ipfs/', ''))
 }
 
+const reqiureIfRequired = (value, helpers) => {
+  if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
+    return { value, errors: helpers.error('required') }
+  }
+}
+
 module.exports = Joi
   .extend(
     (joi) => {
       return {
         type: 'cid',
         base: joi.any(),
-        validate (value, helpers) {
-          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
-            return { value, errors: helpers.error('required') }
-          }
-        },
+        validate: reqiureIfRequired,
         coerce (value, helpers) {
           if (!value) {
             return
@@ -61,11 +63,7 @@ module.exports = Joi
       return {
         type: 'ipfsPath',
         base: joi.string(),
-        validate (value, helpers) {
-          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
-            return { value, errors: helpers.error('required') }
-          }
-        },
+        validate: reqiureIfRequired,
         coerce (value, helpers) {
           if (!value) {
             return
@@ -79,11 +77,7 @@ module.exports = Joi
       return {
         type: 'peerId',
         base: joi.string(),
-        validate (value, helpers) {
-          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
-            return { value, errors: helpers.error('required') }
-          }
-        },
+        validate: reqiureIfRequired,
         coerce (value, helpers) {
           if (!value) {
             return
@@ -97,11 +91,7 @@ module.exports = Joi
       return {
         type: 'multiaddr',
         base: joi.string(),
-        validate (value, helpers) {
-          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
-            return { value, errors: helpers.error('required') }
-          }
-        },
+        validate: reqiureIfRequired,
         coerce (value, helpers) {
           if (!value) {
             return
@@ -115,11 +105,7 @@ module.exports = Joi
       return {
         type: 'timeout',
         base: joi.number(),
-        validate (value, helpers) {
-          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
-            return { value, errors: helpers.error('required') }
-          }
-        },
+        validate: reqiureIfRequired,
         coerce (value, helpers) {
           if (!value) {
             return
@@ -133,11 +119,7 @@ module.exports = Joi
       return {
         type: 'cidAndPath',
         base: joi.any(),
-        validate (value, helpers) {
-          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
-            return { value, errors: helpers.error('required') }
-          }
-        },
+        validate: reqiureIfRequired,
         coerce (value, helpers) {
           if (!value) {
             return
@@ -151,11 +133,7 @@ module.exports = Joi
       return {
         type: 'cidBase',
         base: joi.string(),
-        validate (value, helpers) {
-          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
-            return { value, errors: helpers.error('required') }
-          }
-        },
+        validate: reqiureIfRequired,
         coerce (value, helpers) {
           if (!value) {
             return
@@ -173,11 +151,7 @@ module.exports = Joi
       return {
         type: 'json',
         base: joi.any(),
-        validate (value, helpers) {
-          if (helpers.schema.$_getFlag('presence') === 'required' && !value) {
-            return { value, errors: helpers.error('required') }
-          }
-        },
+        validate: reqiureIfRequired,
         coerce (value, helpers) {
           if (!value) {
             return

From 1703fba5cb44ef4703fa29d8a28b7a22f4804367 Mon Sep 17 00:00:00 2001
From: achingbrain <alex@achingbrain.net>
Date: Tue, 25 Aug 2020 15:07:15 +0100
Subject: [PATCH 3/3] chore: linting

---
 packages/ipfs/src/http/api/resources/dht.js | 4 ++--
 packages/ipfs/src/http/index.js             | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/packages/ipfs/src/http/api/resources/dht.js b/packages/ipfs/src/http/api/resources/dht.js
index fe0c70b2cd..04e0536a42 100644
--- a/packages/ipfs/src/http/api/resources/dht.js
+++ b/packages/ipfs/src/http/api/resources/dht.js
@@ -217,7 +217,7 @@ exports.provide = {
           override: true,
           ignoreUndefined: true
         })
-    },
+    }
   },
   async handler (request, h) {
     const {
@@ -255,7 +255,7 @@ exports.put = {
         arg: Joi.array().length(2).items(Joi.binary()).required(),
         timeout: Joi.timeout()
       })
-    },
+    }
   },
   async handler (request, h) {
     const {
diff --git a/packages/ipfs/src/http/index.js b/packages/ipfs/src/http/index.js
index 3079428a06..ce35b3d3ce 100644
--- a/packages/ipfs/src/http/index.js
+++ b/packages/ipfs/src/http/index.js
@@ -76,7 +76,7 @@ class HttpApi {
       routes: {
         cors: true,
         response: {
-            emptyStatusCode: 200
+          emptyStatusCode: 200
         }
       },
       // Disable Compression
@@ -176,7 +176,7 @@ class HttpApi {
       routes: {
         cors: true,
         response: {
-            emptyStatusCode: 200
+          emptyStatusCode: 200
         }
       }
     })