diff --git a/src/index.js b/src/index.js index 8fb0d76..fdd1e33 100644 --- a/src/index.js +++ b/src/index.js @@ -3,11 +3,11 @@ const root = require('window-or-global') const IpfsApi = require('ipfs-http-client') -const multiaddr = require('multiaddr') const tryCompanion = require('./companion') const tryWindow = require('./window.ipfs') const tryApi = require('./js-ipfs-api') const tryJsIpfs = require('./js-ipfs') +const { isURL, isMultiaddress } = require('./utils') const defaultOptions = { tryWindow: true, @@ -151,7 +151,7 @@ async function getIpfs (opts, { store, getState, dispatch }) { } } if (opts.tryApi) { - const { apiAddress, defaultApiAddress } = getState().ipfs + let { apiAddress, defaultApiAddress } = getState().ipfs const { location } = root const res = await tryApi({ apiAddress, defaultApiAddress, location, IpfsApi, ipfsConnectionTest }) if (res) { @@ -169,19 +169,6 @@ async function getIpfs (opts, { store, getState, dispatch }) { dispatch({ type: 'IPFS_INIT_FAILED' }) } -function isMultiaddress (addr) { - if (addr === null || addr === undefined || typeof addr === 'undefined') { - return false - } - - try { - multiaddr(addr) - return true - } catch (_) { - return false - } -} - function getUserOpts (key) { let userOpts = null if (root.localStorage) { @@ -214,7 +201,7 @@ function saveUserOpts (key, val) { function getUserProvidedIpfsApi () { const ipfsApi = getUserOpts('ipfsApi') - if (ipfsApi && !isMultiaddress(ipfsApi)) { + if (ipfsApi && !isMultiaddress(ipfsApi) && !isURL(ipfsApi)) { console.warn(`The ipfsApi address ${ipfsApi} is invalid.`) return null } diff --git a/src/js-ipfs-api/index.js b/src/js-ipfs-api/index.js index d1caeae..e09020a 100644 --- a/src/js-ipfs-api/index.js +++ b/src/js-ipfs-api/index.js @@ -1,4 +1,6 @@ +/* eslint-env browser, webextensions */ const toMultiaddr = require('uri-to-multiaddr') +const { isURL } = require('../utils') const provider = 'js-ipfs-api' // 1. Try user specified API address @@ -41,8 +43,10 @@ async function tryApi ({ IpfsApi, apiAddress, defaultApiAddress, location, ipfsC // Helper to construct and test an api client. Returns an js-ipfs-api instance or null async function maybeApi ({ apiAddress, apiOpts, ipfsConnectionTest, IpfsApi }) { + const address = isURL(apiAddress) ? parseURL(apiAddress) : apiAddress + try { - const ipfs = new IpfsApi(apiAddress, apiOpts) + const ipfs = new IpfsApi(address, apiOpts) await ipfsConnectionTest(ipfs) return { ipfs, provider, apiAddress } } catch (error) { @@ -50,4 +54,21 @@ async function maybeApi ({ apiAddress, apiOpts, ipfsConnectionTest, IpfsApi }) { } } +function parseURL (addr) { + const url = new URL(addr) + + const opts = { + host: url.hostname, + port: url.port, + protocol: url.protocol.slice(0, -1), + headers: {} + } + + if (url.username) { + opts.headers.authorization = `Basic ${btoa(unescape(encodeURIComponent(url.username + ':' + url.password)))}` + } + + return opts +} + module.exports = tryApi diff --git a/src/js-ipfs-api/index.test.js b/src/js-ipfs-api/index.test.js index c5e21f8..e088d3d 100644 --- a/src/js-ipfs-api/index.test.js +++ b/src/js-ipfs-api/index.test.js @@ -115,3 +115,41 @@ it('Should use the defaultApiAddress if location fails', async (done) => { expect(config.protocol).toEqual('http') done() }) + +it('Should use the apiAddress (url)', async (done) => { + const opts = { + apiAddress: 'http://1.1.1.1:1111', + defaultApiAddress: '/ip4/127.0.0.1/tcp/5001', + location: new URL('http://localhost:5001'), + IpfsApi: IpfsApi, + ipfsConnectionTest: jest.fn().mockResolvedValueOnce(true) + } + const res = await tryApi(opts) + expect(res.apiAddress).toEqual(opts.apiAddress) + expect(res.provider).toEqual('js-ipfs-api') + expect(opts.ipfsConnectionTest.mock.calls.length).toBe(1) + const config = res.ipfs.getEndpointConfig() + expect(config.host).toEqual('1.1.1.1') + expect(config.port).toEqual('1111') + expect(config.protocol).toEqual('http') + done() +}) + +it('Should use the apiAddress (url with basic auth)', async (done) => { + const opts = { + apiAddress: 'http://user:pass@1.1.1.1:1111', + defaultApiAddress: '/ip4/127.0.0.1/tcp/5001', + location: new URL('http://localhost:5001'), + IpfsApi: IpfsApi, + ipfsConnectionTest: jest.fn().mockResolvedValueOnce(true) + } + const res = await tryApi(opts) + expect(res.apiAddress).toEqual(opts.apiAddress) + expect(res.provider).toEqual('js-ipfs-api') + expect(opts.ipfsConnectionTest.mock.calls.length).toBe(1) + const config = res.ipfs.getEndpointConfig() + expect(config.host).toEqual('1.1.1.1') + expect(config.port).toEqual('1111') + expect(config.protocol).toEqual('http') + done() +}) diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..34a6e05 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,32 @@ +'use strict' +/* eslint-env browser, webextensions */ + +const multiaddr = require('multiaddr') + +function isMultiaddress (addr) { + if (addr === null || addr === undefined || typeof addr === 'undefined') { + return false + } + + try { + multiaddr(addr) + return true + } catch (_) { + return false + } +} + +function isURL (addr) { + try { + // eslint-disable-next-line + new URL(addr) + return true + } catch (e) { + return false + } +} + +module.exports = { + isMultiaddress, + isURL +}