From 8c9bed37fab08aca7e9618cb013f1cf1a4d288c5 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 19 Jul 2019 10:57:41 +0200 Subject: [PATCH] feat: allow /ipns/webui.ipfs.io on api port We want to allow user to try out the latest versions of the webui before they are officially released with js-ipfs. Context: https://github.com/ipfs-shipyard/ipfs-companion/issues/736 go-ipfs counterpart: https://github.com/ipfs/go-ipfs/pull/6530 License: MIT Signed-off-by: Marcin Rataj --- src/http/api/routes/webui.js | 43 ++++++++++++++++++++--- test/http-api/inject/webui.js | 66 +++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 test/http-api/inject/webui.js diff --git a/src/http/api/routes/webui.js b/src/http/api/routes/webui.js index 9d6926f6aa..c621c75a22 100644 --- a/src/http/api/routes/webui.js +++ b/src/http/api/routes/webui.js @@ -1,9 +1,25 @@ 'use strict' const Joi = require('@hapi/joi') +const Boom = require('@hapi/boom') const resources = require('../../gateway/resources') +const webuiPath = '/ipfs/QmQNHd1suZTktPRhP7DD4nKWG46ZRSxkwHocycHVrK3dYW' + +const failAction = (request, h, err) => { + // match go-ipfs and return 404 without any details if path validation failed + if (err.name === 'ValidationError') throw Boom.notFound() + return err +} + module.exports = [ + { + method: '*', + path: '/webui', + handler (request, h) { + return h.redirect(webuiPath) + } + }, { method: '*', path: '/ipfs/{path*}', @@ -11,8 +27,9 @@ module.exports = [ handler: resources.gateway.handler, validate: { params: { - path: Joi.string().required() - } + path: Joi.string().regex(new RegExp(webuiPath.replace('/ipfs/', '^'))).required() + }, + failAction }, response: { ranges: false // disable built-in support, handler does it manually @@ -24,9 +41,25 @@ module.exports = [ }, { method: '*', - path: '/webui', - handler (request, h) { - return h.redirect('/ipfs/QmQNHd1suZTktPRhP7DD4nKWG46ZRSxkwHocycHVrK3dYW') + path: '/ipns/{path*}', + options: { + handler: resources.gateway.handler, + validate: { + params: { + path: Joi.alternatives().try( + // be careful here, someone could register webui.ipfs.io.evil.com + Joi.string().regex(/^webui\.ipfs\.io\//), // ends with '/'' + Joi.string().regex(/^webui\.ipfs\.io$/) // redirect will add '/' + ).required() + }, + failAction + }, + response: { + ranges: false // disable built-in support, handler does it manually + }, + ext: { + onPostHandler: { method: resources.gateway.afterHandler } + } } } ] diff --git a/test/http-api/inject/webui.js b/test/http-api/inject/webui.js new file mode 100644 index 0000000000..f9af5c2998 --- /dev/null +++ b/test/http-api/inject/webui.js @@ -0,0 +1,66 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect + +module.exports = (http) => { + describe('Web UI', function () { + let api + + before(() => { + api = http.api._httpApi._apiServers[0] + }) + + it('allow /webui', async () => { + const res = await api.inject({ + method: 'GET', + url: '/webui' + }) + // it should return a redirect + expect(res.statusCode).to.equal(302) + expect(res.headers.location).to.exist() + }) + + it('disallow /ipfs/ paths that are not webui', async () => { + const res = await api.inject({ + method: 'GET', + url: '/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn' // empty dir + }) + expect(res.statusCode).to.equal(404) + }) + + it('disallow /ipns/ paths that are not webui', async () => { + const res = await api.inject({ + method: 'GET', + url: '/ipns/ipfs.io' // empty dir + }) + expect(res.statusCode).to.equal(404) + }) + + /* DNSLink + fetching actual webui is too slow to include in the test :'-( + it('/ipns/webui.ipfs.io', async () => { + const res = await api.inject({ + method: 'GET', + url: '/ipns/webui.ipfs.io' + }) + expect(res.statusCode).to.equal(302) + expect(res.headers.location).to.exist() + }) + + it('/ipns/webui.ipfs.io/', async () => { + const res = await api.inject({ + method: 'GET', + url: '/ipns/webui.ipfs.io/' + }) + expect(res.statusCode).to.equal(200) + }) + it('/ipns/ipfs.io/', async () => { + const res = await api.inject({ + method: 'GET', + url: '/ipns/ipfs.io/' + }) + expect(res.statusCode).to.equal(404) + }) + */ + }) +}