From 4aa5f7d3a44c5fe92589797b07450782a10aee1f Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Tue, 4 Aug 2020 17:26:36 +0200 Subject: [PATCH 1/9] feat: add support for ed25519 and secp256k1 keys --- packages/ipfs/package.json | 2 +- packages/ipfs/test/core/init.spec.js | 28 ++++++++++++++++++++ packages/ipfs/test/core/key-exchange.spec.js | 26 ++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/ipfs/package.json b/packages/ipfs/package.json index c1af7a5f4a..8ad119b4a6 100644 --- a/packages/ipfs/package.json +++ b/packages/ipfs/package.json @@ -129,7 +129,7 @@ "iterable-ndjson": "^1.1.0", "jsondiffpatch": "^0.4.1", "just-safe-set": "^2.1.0", - "libp2p": "^0.28.5", + "libp2p": "libp2p/js-libp2p#feat/more-keys", "libp2p-bootstrap": "^0.11.0", "libp2p-crypto": "^0.17.8", "libp2p-delegated-content-routing": "^0.5.0", diff --git a/packages/ipfs/test/core/init.spec.js b/packages/ipfs/test/core/init.spec.js index 222e4f0067..7fffa8cf18 100644 --- a/packages/ipfs/test/core/init.spec.js +++ b/packages/ipfs/test/core/init.spec.js @@ -9,6 +9,8 @@ const { nanoid } = require('nanoid') const IPFS = require('../../src/core') const privateKey = 'CAASqAkwggSkAgEAAoIBAQChVmiObYo6pkKrMSd3OzW1cTL+RDmX1rkETYGKWV9TPXMNgElFTYoYHqT9QZomj5RI8iUmHccjzqr4J0mV+E0NpvHHOLlmDZ82lAw2Zx7saUkeQWvC0S9Z0o3aTx2sSubZV53rSomkZgQH4fYTs4RERejV4ltzLFdzQQBwWrBvlagpPHUCxKDUCnE5oIzdbD26ltWViPBWr7TfotzC8Lyi/tceqCpHMUJGMbsVgypnlgpey07MBvs71dVh5LcRen/ztsQO6Yju4D3QgWoyD0SIUdJFvBzEwL9bSiA3QjUc/fkGd7EcdN5bebYOqAi4ZIiAMLp3i4+B8Tzq/acull43AgMBAAECggEBAIDgZE75o4SsEO9tKWht7L5OeXxxBUyMImkUfJkGQUZd/MzZIC5y/Q+9UvBW+gs5gCsw+onTGaM50Iq/32Ej4nE4XURVxIuH8BmJ86N1hlc010qK2cjajqeCsPulXT+m6XbOLYCpnv+q2idt0cL1EH/1FEPeOEztK8ION4qIdw36SoykfTx/RqtkKHtS01AwN82EOPbWk7huyQT5R5MsCZmRJXBFkpNtiL+8619BH2aVlghHO4NouF9wQjdz/ysVuyYg+3rX2cpGjuHDTZ6hVQiJD1lF6D+dua7UPyHYAG2iRQiKZmCjitt9ywzPxiRaYF/aZ02FEMWckZulR09axskCgYEAzjl6ER8WwxYHn4tHse+CrIIF2z5cscdrh7KSwd3Rse9hIIBDJ/0KkvoYd1IcWrS8ywLrRfSLIjEU9u7IN1m+IRVWJ61fXNqOHm9clAu6qNhCN6W2+JfxDkUygTwmsq0v3huO+qkiMQz+a4nAXJe8Utd36ywgPhVGxFa/7x1v1N0CgYEAyEdiYRFf1aQZcO7+B2FH+tkGJsB30VIBhcpG9EukuQUUulLHhScc/KRj+EFAACLdkTqlVI0xVYIWaaCXwoQCWKixjZ5mYPC+bBLgn4IoDS6XTdHtR7Vn3UUvGTKsM0/z4e8/0eSzGNCHoYez9IoBlPNic0sQuST4jzgS2RYnFCMCgYASWSzSLyjwTJp7CIJlg4Dl5l+tBRxsOOkJVssV8q2AnmLO6HqRKUNylkvs+eJJ88DEc0sJm1txvFo4KkCoJBT1jpduyk8szMlOTew3w99kvHEP0G+6KJKrCV8X/okW5q/WnC8ZgEjpglV0rfnugxWfbUpfIzrvKydzuqAzHzRfBQKBgQDANtKSeoxRjEbmfljLWHAure8bbgkQmfXgI7xpZdfXwqqcECpw/pLxXgycDHOSLeQcJ/7Y4RGCEXHVOk2sX+mokW6mjmmPjD4VlyCBtfcef6KzC1EBS3c9g9KqCln+fTOBmY7UsPu6SxiAzK7HeVP/Un8gS+Dm8DalrZlZQ8uJpQKBgF6mL/Xo/XUOiz2jAD18l8Y6s49bA9H2CoLpBGTV1LfY5yTFxRy4R3qnX/IzsKy567sbtkEFKJxplc/RzCQfrgbdj7k26SbKtHR3yERaFGRYq8UeAHeYC1/N19LF5BMQL4y5R4PJ1SFPeJCL/wXiMqs1maTqvKqtc4bbegNdwlxn' +const edPrivateKey = 'CAESYFeZamw+9QdwHgSmcvPmfLUpmWTtYpUeycbXcfnkTnDI7OaPmE6V8i+Lw7FNB5CtYuDFKUsOS5h+AogyF/Dft4Ds5o+YTpXyL4vDsU0HkK1i4MUpSw5LmH4CiDIX8N+3gA==' +const secpPrivateKey = 'CAISIKCfwZsMEwmzLxGv9duM6j6YQzMx2V46+Yl3laV24Qus' // This gets replaced by `create-repo-browser.js` in the browser const createTempRepo = require('../utils/create-repo-nodejs.js') @@ -44,6 +46,18 @@ describe('init', function () { expect(config.Keychain).to.exist() }) + it('should init successfully (ed25519)', async () => { + await ipfs.init({ bits: 512, pass: nanoid() }) + + const res = await repo.exists() + expect(res).to.equal(true) + + const config = await repo.config.getAll() + + expect(config.Identity).to.exist() + expect(config.Keychain).to.exist() + }) + it('should set # of bits in key', async function () { this.timeout(40 * 1000) @@ -60,6 +74,20 @@ describe('init', function () { expect(config.Identity.PeerID).is.equal('QmRsooYQasV5f5r834NSpdUtmejdQcpxXkK6qsozZWEihC') }) + it('should allow a pregenerated ed25519 key to be used', async () => { + await ipfs.init({ privateKey: edPrivateKey }) + + const config = await repo.config.getAll() + expect(config.Identity.PeerID).is.equal('12D3KooWRm8J3iL796zPFi2EtGGtUJn58AG67gcqzMFHZnnsTzqD') + }) + + it('should allow a pregenerated secp256k1 key to be used', async () => { + await ipfs.init({ privateKey: secpPrivateKey }) + + const config = await repo.config.getAll() + expect(config.Identity.PeerID).is.equal('16Uiu2HAm5qw8UyXP2RLxQUx5KvtSN8DsTKz8quRGqGNC3SYiaB8E') + }) + it('should write init docs', async () => { await ipfs.init({ bits: 512, pass: nanoid() }) const multihash = 'QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB' diff --git a/packages/ipfs/test/core/key-exchange.spec.js b/packages/ipfs/test/core/key-exchange.spec.js index 16a54704cb..8d59b852cd 100644 --- a/packages/ipfs/test/core/key-exchange.spec.js +++ b/packages/ipfs/test/core/key-exchange.spec.js @@ -35,4 +35,30 @@ describe('key exchange', function () { expect(key).to.have.property('name', 'clone') expect(key).to.have.property('id') }) + + it('should create ed25519 keys', async () => { + const name = 'my-ed-key' + const pass = 'password for my ed key' + const key = await ipfs.key.gen(name, { type: 'ed25519' }) + // export it + const exportedKey = await ipfs.key.export(name, pass) + // delete it + await ipfs.key.rm(name) + // import it back to the same name + const imported = await ipfs.key.import(name, exportedKey, pass) + expect(imported.id).to.equal(key.id) + }) + + it('should create secp256k1 keys', async () => { + const name = 'my-secp-key' + const pass = 'password for my secp key' + const key = await ipfs.key.gen(name, { type: 'secp256k1' }) + // export it + const exportedKey = await ipfs.key.export(name, pass) + // delete it + await ipfs.key.rm(name) + // import it back to the same name + const imported = await ipfs.key.import(name, exportedKey, pass) + expect(imported.id).to.equal(key.id) + }) }) From 37338aa7265e87405f242a15e2bfa1723792abb5 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Tue, 4 Aug 2020 19:00:18 +0200 Subject: [PATCH 2/9] feat(ipfs): add algorithm param to init options for key type --- packages/ipfs/docs/MODULE.md | 3 ++- packages/ipfs/src/cli/commands/init.js | 7 +++++++ packages/ipfs/src/core/components/init.js | 10 +++++----- packages/ipfs/test/cli/init.js | 8 ++++++++ packages/ipfs/test/core/init.spec.js | 24 +++++++++++++++-------- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/packages/ipfs/docs/MODULE.md b/packages/ipfs/docs/MODULE.md index 9e05865ba9..9aa2012d6b 100644 --- a/packages/ipfs/docs/MODULE.md +++ b/packages/ipfs/docs/MODULE.md @@ -94,7 +94,8 @@ Note that *initializing* a repo is different from creating an instance of [`ipfs Instead of a boolean, you may provide an object with custom initialization options. All properties are optional: - `emptyRepo` (boolean) Whether to remove built-in assets, like the instructional tour and empty mutable file system, from the repo. (Default: `false`) -- `bits` (number) Number of bits to use in the generated key pair. (Default: `2048`) +- `algorithm` (string) The type of key to use. Supports `rsa`, `ed25519`, `secp256k1`. (Default: `rsa`) +- `bits` (number) Number of bits to use in the generated key pair (rsa only). (Default: `2048`) - `privateKey` (string/PeerId) A pre-generated private key to use. Can be either a base64 string or a [PeerId](https://github.com/libp2p/js-peer-id) instance. **NOTE: This overrides `bits`.** ```js // Generating a Peer ID: diff --git a/packages/ipfs/src/cli/commands/init.js b/packages/ipfs/src/cli/commands/init.js index 76fa703d71..9b13636e51 100644 --- a/packages/ipfs/src/cli/commands/init.js +++ b/packages/ipfs/src/cli/commands/init.js @@ -17,6 +17,12 @@ module.exports = { describe: 'Node config, this should be a path to a file or JSON and will be merged with the default config. See https://github.com/ipfs/js-ipfs#optionsconfig', type: 'string' }) + .option('algorithm', { + type: 'string', + alias: 'a', + default: 'rsa', + describe: 'Cryptographic algorithm to use for key generation. Supports [rsa, ed25519, secp256k1]' + }) .option('bits', { type: 'number', alias: 'b', @@ -72,6 +78,7 @@ module.exports = { try { await node.init({ + algorithm: argv.algorithm, bits: argv.bits, privateKey: argv.privateKey, emptyRepo: argv.emptyRepo, diff --git a/packages/ipfs/src/core/components/init.js b/packages/ipfs/src/core/components/init.js index 3474d14bd4..b751462c05 100644 --- a/packages/ipfs/src/core/components/init.js +++ b/packages/ipfs/src/core/components/init.js @@ -174,7 +174,7 @@ module.exports = ({ return apiManager.api } -async function initNewRepo (repo, { privateKey, emptyRepo, bits, profiles, config, pass, print }) { +async function initNewRepo (repo, { privateKey, emptyRepo, algorithm, bits, profiles, config, pass, print }) { emptyRepo = emptyRepo || false bits = bits == null ? 2048 : Number(bits) @@ -188,7 +188,7 @@ async function initNewRepo (repo, { privateKey, emptyRepo, bits, profiles, confi throw new Error('repo already exists') } - const peerId = await createPeerId({ privateKey, bits, print }) + const peerId = await createPeerId({ privateKey, algorithm, bits, print }) log('identity generated') @@ -257,7 +257,7 @@ async function initExistingRepo (repo, { config: newConfig, profiles, pass }) { return { peerId, keychain: libp2p.keychain } } -function createPeerId ({ privateKey, bits, print }) { +function createPeerId ({ privateKey, algorithm = 'rsa', bits, print }) { if (privateKey) { log('using user-supplied private-key') return typeof privateKey === 'object' @@ -265,8 +265,8 @@ function createPeerId ({ privateKey, bits, print }) { : PeerId.createFromPrivKey(Buffer.from(privateKey, 'base64')) } else { // Generate peer identity keypair + transform to desired format + add to config. - print('generating %s-bit RSA keypair...', bits) - return PeerId.create({ bits }) + print('generating %s-bit (rsa only) %s keypair...', bits, algorithm) + return PeerId.create({ keyType: algorithm, bits }) } } diff --git a/packages/ipfs/test/cli/init.js b/packages/ipfs/test/cli/init.js index f7bf81f826..601733332c 100644 --- a/packages/ipfs/test/cli/init.js +++ b/packages/ipfs/test/cli/init.js @@ -4,6 +4,8 @@ const { expect } = require('interface-ipfs-core/src/utils/mocha') const path = require('path') const fs = require('fs') +const PeerId = require('peer-id') +const { supportedKeys } = require('libp2p-crypto/src/keys') const clean = require('../utils/clean') const { nanoid } = require('nanoid') const ipfsExec = require('../utils/ipfs-exec') @@ -49,6 +51,12 @@ describe('init', function () { expect(out2).to.equal(readme) }) + it('algorithm', async function () { + await ipfs('init --algorithm ed25519') + const peerId = await PeerId.createFromPrivKey(repoConfSync().Identity.PrivKey) + expect(peerId.privKey).is.instanceOf(supportedKeys.ed25519.Ed25519PrivateKey) + }) + it('bits', async function () { await ipfs('init --bits 1024') expect(repoDirSync('blocks')).to.have.length.above(2) diff --git a/packages/ipfs/test/core/init.spec.js b/packages/ipfs/test/core/init.spec.js index 7fffa8cf18..2bf36b9533 100644 --- a/packages/ipfs/test/core/init.spec.js +++ b/packages/ipfs/test/core/init.spec.js @@ -6,6 +6,8 @@ const { expect } = require('interface-ipfs-core/src/utils/mocha') const { isNode } = require('ipfs-utils/src/env') const { Buffer } = require('buffer') const { nanoid } = require('nanoid') +const PeerId = require('peer-id') +const { supportedKeys } = require('libp2p-crypto/src/keys') const IPFS = require('../../src/core') const privateKey = 'CAASqAkwggSkAgEAAoIBAQChVmiObYo6pkKrMSd3OzW1cTL+RDmX1rkETYGKWV9TPXMNgElFTYoYHqT9QZomj5RI8iUmHccjzqr4J0mV+E0NpvHHOLlmDZ82lAw2Zx7saUkeQWvC0S9Z0o3aTx2sSubZV53rSomkZgQH4fYTs4RERejV4ltzLFdzQQBwWrBvlagpPHUCxKDUCnE5oIzdbD26ltWViPBWr7TfotzC8Lyi/tceqCpHMUJGMbsVgypnlgpey07MBvs71dVh5LcRen/ztsQO6Yju4D3QgWoyD0SIUdJFvBzEwL9bSiA3QjUc/fkGd7EcdN5bebYOqAi4ZIiAMLp3i4+B8Tzq/acull43AgMBAAECggEBAIDgZE75o4SsEO9tKWht7L5OeXxxBUyMImkUfJkGQUZd/MzZIC5y/Q+9UvBW+gs5gCsw+onTGaM50Iq/32Ej4nE4XURVxIuH8BmJ86N1hlc010qK2cjajqeCsPulXT+m6XbOLYCpnv+q2idt0cL1EH/1FEPeOEztK8ION4qIdw36SoykfTx/RqtkKHtS01AwN82EOPbWk7huyQT5R5MsCZmRJXBFkpNtiL+8619BH2aVlghHO4NouF9wQjdz/ysVuyYg+3rX2cpGjuHDTZ6hVQiJD1lF6D+dua7UPyHYAG2iRQiKZmCjitt9ywzPxiRaYF/aZ02FEMWckZulR09axskCgYEAzjl6ER8WwxYHn4tHse+CrIIF2z5cscdrh7KSwd3Rse9hIIBDJ/0KkvoYd1IcWrS8ywLrRfSLIjEU9u7IN1m+IRVWJ61fXNqOHm9clAu6qNhCN6W2+JfxDkUygTwmsq0v3huO+qkiMQz+a4nAXJe8Utd36ywgPhVGxFa/7x1v1N0CgYEAyEdiYRFf1aQZcO7+B2FH+tkGJsB30VIBhcpG9EukuQUUulLHhScc/KRj+EFAACLdkTqlVI0xVYIWaaCXwoQCWKixjZ5mYPC+bBLgn4IoDS6XTdHtR7Vn3UUvGTKsM0/z4e8/0eSzGNCHoYez9IoBlPNic0sQuST4jzgS2RYnFCMCgYASWSzSLyjwTJp7CIJlg4Dl5l+tBRxsOOkJVssV8q2AnmLO6HqRKUNylkvs+eJJ88DEc0sJm1txvFo4KkCoJBT1jpduyk8szMlOTew3w99kvHEP0G+6KJKrCV8X/okW5q/WnC8ZgEjpglV0rfnugxWfbUpfIzrvKydzuqAzHzRfBQKBgQDANtKSeoxRjEbmfljLWHAure8bbgkQmfXgI7xpZdfXwqqcECpw/pLxXgycDHOSLeQcJ/7Y4RGCEXHVOk2sX+mokW6mjmmPjD4VlyCBtfcef6KzC1EBS3c9g9KqCln+fTOBmY7UsPu6SxiAzK7HeVP/Un8gS+Dm8DalrZlZQ8uJpQKBgF6mL/Xo/XUOiz2jAD18l8Y6s49bA9H2CoLpBGTV1LfY5yTFxRy4R3qnX/IzsKy567sbtkEFKJxplc/RzCQfrgbdj7k26SbKtHR3yERaFGRYq8UeAHeYC1/N19LF5BMQL4y5R4PJ1SFPeJCL/wXiMqs1maTqvKqtc4bbegNdwlxn' @@ -42,20 +44,26 @@ describe('init', function () { const config = await repo.config.getAll() - expect(config.Identity).to.exist() expect(config.Keychain).to.exist() - }) - it('should init successfully (ed25519)', async () => { - await ipfs.init({ bits: 512, pass: nanoid() }) + const peerId = await PeerId.createFromPrivKey(config.Identity.PrivKey) + expect(peerId.privKey).is.instanceOf(supportedKeys.rsa.RsaPrivateKey) + }) - const res = await repo.exists() - expect(res).to.equal(true) + it('should init with a key algorithm (ed25519)', async () => { + await ipfs.init({ algorithm: 'ed25519' }) const config = await repo.config.getAll() + const peerId = await PeerId.createFromPrivKey(config.Identity.PrivKey) + expect(peerId.privKey).is.instanceOf(supportedKeys.ed25519.Ed25519PrivateKey) + }) - expect(config.Identity).to.exist() - expect(config.Keychain).to.exist() + it('should init with a key algorithm (secp256k1)', async () => { + await ipfs.init({ algorithm: 'secp256k1' }) + + const config = await repo.config.getAll() + const peerId = await PeerId.createFromPrivKey(config.Identity.PrivKey) + expect(peerId.privKey).is.instanceOf(supportedKeys.secp256k1.Secp256k1PrivateKey) }) it('should set # of bits in key', async function () { From d95f6363b98b2bd6e93e1a9b5dfc9746fb7098e6 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 5 Aug 2020 13:15:43 +0200 Subject: [PATCH 3/9] test(ipfs): add create test for browser verification --- packages/ipfs/test/core/create-node.spec.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/ipfs/test/core/create-node.spec.js b/packages/ipfs/test/core/create-node.spec.js index e9db246332..4e66babfd4 100644 --- a/packages/ipfs/test/core/create-node.spec.js +++ b/packages/ipfs/test/core/create-node.spec.js @@ -6,10 +6,13 @@ const { expect } = require('interface-ipfs-core/src/utils/mocha') const sinon = require('sinon') const { isNode } = require('ipfs-utils/src/env') const tmpDir = require('ipfs-utils/src/temp-dir') +const PeerId = require('peer-id') +const { supportedKeys } = require('libp2p-crypto/src/keys') const IPFS = require('../../src/core') // This gets replaced by `create-repo-browser.js` in the browser const createTempRepo = require('../utils/create-repo-nodejs.js') +const { console } = require('ipfs-utils/src/globalthis') describe('create node', function () { let tempRepo @@ -58,6 +61,21 @@ describe('create node', function () { await node.stop() }) + it('should create and initialize with algorithm', async () => { + const ipfs = await IPFS.create({ + init: { algorithm: 'ed25519' }, + start: false, + repo: tempRepo, + config: { Addresses: { Swarm: [] } } + }) + + const id = await ipfs.id() + const config = await ipfs.config.getAll() + const peerId = await PeerId.createFromPrivKey(config.Identity.PrivKey) + expect(peerId.privKey).is.instanceOf(supportedKeys.ed25519.Ed25519PrivateKey) + expect(id.id).to.equal(peerId.toB58String()) + }) + it('should create and initialize but not start', async () => { const ipfs = await IPFS.create({ init: { bits: 512 }, From 78eb45c2b85bd368440fc0376d89ddf410443a65 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 5 Aug 2020 19:11:46 +0200 Subject: [PATCH 4/9] chore: update libp2p and libp2p-crypto --- packages/ipfs/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ipfs/package.json b/packages/ipfs/package.json index 8ad119b4a6..4a7cdddb45 100644 --- a/packages/ipfs/package.json +++ b/packages/ipfs/package.json @@ -129,9 +129,9 @@ "iterable-ndjson": "^1.1.0", "jsondiffpatch": "^0.4.1", "just-safe-set": "^2.1.0", - "libp2p": "libp2p/js-libp2p#feat/more-keys", + "libp2p": "^0.28.10", "libp2p-bootstrap": "^0.11.0", - "libp2p-crypto": "^0.17.8", + "libp2p-crypto": "^0.17.9", "libp2p-delegated-content-routing": "^0.5.0", "libp2p-delegated-peer-routing": "^0.5.0", "libp2p-floodsub": "^0.21.0", From fa4376401073b3a220c0a5ddf3f40a0df4e13950 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 5 Aug 2020 18:38:14 +0200 Subject: [PATCH 5/9] fix: support keychain without pass --- packages/ipfs/test/core/init.spec.js | 16 ++++++++++++++-- packages/ipfs/test/core/key-exchange.spec.js | 6 +----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/ipfs/test/core/init.spec.js b/packages/ipfs/test/core/init.spec.js index 2bf36b9533..782b7dd977 100644 --- a/packages/ipfs/test/core/init.spec.js +++ b/packages/ipfs/test/core/init.spec.js @@ -37,6 +37,18 @@ describe('init', function () { afterEach(() => repo.teardown()) it('should init successfully', async () => { + await ipfs.init({ bits: 512 }) + + const res = await repo.exists() + expect(res).to.equal(true) + + const config = await repo.config.getAll() + + expect(config.Identity).to.exist() + expect(config.Keychain).to.exist() + }) + + it('should init successfully with a keychain pass', async () => { await ipfs.init({ bits: 512, pass: nanoid() }) const res = await repo.exists() @@ -69,7 +81,7 @@ describe('init', function () { it('should set # of bits in key', async function () { this.timeout(40 * 1000) - await ipfs.init({ bits: 1024, pass: nanoid() }) + await ipfs.init({ bits: 1024 }) const config = await repo.config.getAll() expect(config.Identity.PrivKey.length).is.above(256) @@ -97,7 +109,7 @@ describe('init', function () { }) it('should write init docs', async () => { - await ipfs.init({ bits: 512, pass: nanoid() }) + await ipfs.init({ bits: 512 }) const multihash = 'QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB' const node = await ipfs.object.get(multihash, { enc: 'base58' }) diff --git a/packages/ipfs/test/core/key-exchange.spec.js b/packages/ipfs/test/core/key-exchange.spec.js index 8d59b852cd..b8d7642b63 100644 --- a/packages/ipfs/test/core/key-exchange.spec.js +++ b/packages/ipfs/test/core/key-exchange.spec.js @@ -14,11 +14,7 @@ describe('key exchange', function () { const passwordPem = nanoid() before(async () => { - ipfs = (await df.spawn({ - ipfsOptions: { - pass: nanoid() - } - })).api + ipfs = (await df.spawn()).api }) after(() => df.clean()) From 2f89e87551857690411e807c71e76a5b15c32fe4 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 5 Aug 2020 20:26:33 +0200 Subject: [PATCH 6/9] fix: name publish doesnt need a pass fix: make ttl actually optional --- packages/ipfs/src/core/components/name/publish.js | 8 ++++---- packages/ipfs/src/http/api/resources/name.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ipfs/src/core/components/name/publish.js b/packages/ipfs/src/core/components/name/publish.js index 0908d9df9c..753def749b 100644 --- a/packages/ipfs/src/core/components/name/publish.js +++ b/packages/ipfs/src/core/components/name/publish.js @@ -21,16 +21,16 @@ const { resolvePath } = require('./utils') * @param {IPFS} self * @returns {Object} */ -module.exports = ({ ipns, dag, peerId, isOnline, keychain, options: constructorOptions }) => { +module.exports = ({ ipns, dag, peerId, isOnline, keychain }) => { const lookupKey = async keyName => { if (keyName === 'self') { return peerId.privKey } try { - const pass = constructorOptions.pass - const pem = await keychain.exportKey(keyName, pass) - const privateKey = await crypto.keys.import(pem, pass) + // We're exporting and immediately importing the key, so we can just use a throw away password + const pem = await keychain.exportKey(keyName, 'temp') + const privateKey = await crypto.keys.import(pem, 'temp') return privateKey } catch (err) { log.error(err) diff --git a/packages/ipfs/src/http/api/resources/name.js b/packages/ipfs/src/http/api/resources/name.js index 4bb39d2671..a7663728af 100644 --- a/packages/ipfs/src/http/api/resources/name.js +++ b/packages/ipfs/src/http/api/resources/name.js @@ -80,7 +80,7 @@ exports.publish = { name: Joi.string().required(), resolve: Joi.boolean().default(true), lifetime: Joi.string().default('24h'), - ttl: Joi.string(), + ttl: Joi.string().allow(''), key: Joi.string().default('self'), allowOffline: Joi.boolean(), timeout: Joi.timeout() From be7c4a46cfcecb02a74eaf99382480933f427601 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 5 Aug 2020 23:03:11 +0200 Subject: [PATCH 7/9] fix: remove http api support for key.export --- packages/interface-ipfs-core/package.json | 1 + .../interface-ipfs-core/src/key/export.js | 37 --------------- .../interface-ipfs-core/src/key/import.js | 19 ++++---- packages/interface-ipfs-core/src/key/index.js | 1 - packages/ipfs-http-client/src/key/export.js | 26 ----------- packages/ipfs-http-client/src/key/index.js | 1 - packages/ipfs/src/http/api/resources/key.js | 44 ------------------ packages/ipfs/src/http/api/routes/key.js | 5 --- packages/ipfs/test/http-api/inject/key.js | 45 ------------------- 9 files changed, 11 insertions(+), 168 deletions(-) delete mode 100644 packages/interface-ipfs-core/src/key/export.js delete mode 100644 packages/ipfs-http-client/src/key/export.js diff --git a/packages/interface-ipfs-core/package.json b/packages/interface-ipfs-core/package.json index cff0f8dfdb..d9b83216d9 100644 --- a/packages/interface-ipfs-core/package.json +++ b/packages/interface-ipfs-core/package.json @@ -52,6 +52,7 @@ "it-drain": "^1.0.1", "it-last": "^1.0.1", "it-pushable": "^1.3.1", + "libp2p-crypto": "^0.17.9", "multiaddr": "^7.4.3", "multibase": "^1.0.1", "multihashing-async": "^1.0.0", diff --git a/packages/interface-ipfs-core/src/key/export.js b/packages/interface-ipfs-core/src/key/export.js deleted file mode 100644 index 160af76ce4..0000000000 --- a/packages/interface-ipfs-core/src/key/export.js +++ /dev/null @@ -1,37 +0,0 @@ -/* eslint-env mocha */ -'use strict' - -const { nanoid } = require('nanoid') -const { getDescribe, getIt, expect } = require('../utils/mocha') -const testTimeout = require('../utils/test-timeout') - -/** @typedef { import("ipfsd-ctl/src/factory") } Factory */ -/** - * @param {Factory} common - * @param {Object} options - */ -module.exports = (common, options) => { - const describe = getDescribe(options) - const it = getIt(options) - - describe('.key.export', () => { - let ipfs - - before(async () => { - ipfs = (await common.spawn()).api - }) - - after(() => common.clean()) - - it('should respect timeout option when exporting a key', () => { - return testTimeout(() => ipfs.key.export('self', nanoid(), { - timeout: 1 - })) - }) - - it('should export "self" key', async function () { - const pem = await ipfs.key.export('self', nanoid()) - expect(pem).to.exist() - }) - }) -} diff --git a/packages/interface-ipfs-core/src/key/import.js b/packages/interface-ipfs-core/src/key/import.js index 6bc116e6c6..9c7721ad65 100644 --- a/packages/interface-ipfs-core/src/key/import.js +++ b/packages/interface-ipfs-core/src/key/import.js @@ -2,6 +2,7 @@ 'use strict' const { nanoid } = require('nanoid') +const keys = require('libp2p-crypto/src/keys') const { getDescribe, getIt, expect } = require('../utils/mocha') const testTimeout = require('../utils/test-timeout') @@ -26,10 +27,10 @@ module.exports = (common, options) => { it('should respect timeout option when importing a key', async () => { const password = nanoid() - const pem = await ipfs.key.export('self', password) - expect(pem).to.exist() + const key = await keys.generateKeyPair('ed25519') + const exported = key.export(password) - await testTimeout(() => ipfs.key.import('derp', pem, password, { + await testTimeout(() => ipfs.key.import('derp', exported, password, { timeout: 1 })) }) @@ -37,13 +38,13 @@ module.exports = (common, options) => { it('should import an exported key', async () => { const password = nanoid() - const pem = await ipfs.key.export('self', password) - expect(pem).to.exist() + const key = await keys.generateKeyPair('ed25519') + const exported = await key.export(password) - const key = await ipfs.key.import('clone', pem, password) - expect(key).to.exist() - expect(key).to.have.property('name', 'clone') - expect(key).to.have.property('id') + const importedKey = await ipfs.key.import('clone', exported, password) + expect(importedKey).to.exist() + expect(importedKey).to.have.property('name', 'clone') + expect(importedKey).to.have.property('id') }) }) } diff --git a/packages/interface-ipfs-core/src/key/index.js b/packages/interface-ipfs-core/src/key/index.js index cbe2aaa358..a96414e4a0 100644 --- a/packages/interface-ipfs-core/src/key/index.js +++ b/packages/interface-ipfs-core/src/key/index.js @@ -6,7 +6,6 @@ const tests = { list: require('./list'), rename: require('./rename'), rm: require('./rm'), - export: require('./export'), import: require('./import') } diff --git a/packages/ipfs-http-client/src/key/export.js b/packages/ipfs-http-client/src/key/export.js deleted file mode 100644 index 1692fef16f..0000000000 --- a/packages/ipfs-http-client/src/key/export.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict' - -const configure = require('../lib/configure') -const toUrlSearchParams = require('../lib/to-url-search-params') - -module.exports = configure(api => { - return async (name, password, options = {}) => { - if (typeof password !== 'string') { - options = password || {} - password = null - } - - const res = await api.post('key/export', { - timeout: options.timeout, - signal: options.signal, - searchParams: toUrlSearchParams({ - arg: name, - password: password, - ...options - }), - headers: options.headers - }) - - return res.text() - } -}) diff --git a/packages/ipfs-http-client/src/key/index.js b/packages/ipfs-http-client/src/key/index.js index de12c732c8..c9d9c59f08 100644 --- a/packages/ipfs-http-client/src/key/index.js +++ b/packages/ipfs-http-client/src/key/index.js @@ -5,6 +5,5 @@ module.exports = config => ({ list: require('./list')(config), rename: require('./rename')(config), rm: require('./rm')(config), - export: require('./export')(config), import: require('./import')(config) }) diff --git a/packages/ipfs/src/http/api/resources/key.js b/packages/ipfs/src/http/api/resources/key.js index b9d2a5b44d..c935f9a6a0 100644 --- a/packages/ipfs/src/http/api/resources/key.js +++ b/packages/ipfs/src/http/api/resources/key.js @@ -181,50 +181,6 @@ exports.gen = { } } -exports.export = { - options: { - validate: { - options: { - allowUnknown: true, - stripUnknown: true - }, - query: Joi.object().keys({ - name: Joi.string().required(), - password: Joi.string().required(), - timeout: Joi.timeout() - }) - .rename('arg', 'name', { - override: true, - ignoreUndefined: true - }) - } - }, - handler: async (request, h) => { - const { - app: { - signal - }, - server: { - app: { - ipfs - } - }, - query: { - name, - password, - timeout - } - } = request - - const pem = await ipfs.key.export(name, password, { - signal, - timeout - }) - - return h.response(pem).type('application/x-pem-file') - } -} - exports.import = { options: { validate: { diff --git a/packages/ipfs/src/http/api/routes/key.js b/packages/ipfs/src/http/api/routes/key.js index 8290f617e5..c4bdb42bb3 100644 --- a/packages/ipfs/src/http/api/routes/key.js +++ b/packages/ipfs/src/http/api/routes/key.js @@ -23,11 +23,6 @@ module.exports = [ path: '/api/v0/key/rename', ...resources.key.rename }, - { - method: 'POST', - path: '/api/v0/key/export', - ...resources.key.export - }, { method: 'POST', path: '/api/v0/key/import', diff --git a/packages/ipfs/test/http-api/inject/key.js b/packages/ipfs/test/http-api/inject/key.js index 96cc59cd2b..7ae199b2e4 100644 --- a/packages/ipfs/test/http-api/inject/key.js +++ b/packages/ipfs/test/http-api/inject/key.js @@ -18,7 +18,6 @@ describe('/key', function () { rm: sinon.stub(), rename: sinon.stub(), gen: sinon.stub(), - export: sinon.stub(), import: sinon.stub() } } @@ -228,50 +227,6 @@ describe('/key', function () { }) }) - describe('/export', () => { - const defaultOptions = { - signal: sinon.match.instanceOf(AbortSignal), - timeout: undefined - } - - it('only accepts POST', () => { - return testHttpMethod('/api/v0/key/export') - }) - - it('should export a key', async () => { - const name = 'name' - const password = 'password' - - ipfs.key.export.withArgs(name, password, defaultOptions).returns('pem') - - const res = await http({ - method: 'POST', - url: `/api/v0/key/export?arg=${name}&password=${password}` - }, { ipfs }) - - expect(res).to.have.property('statusCode', 200) - expect(res).to.have.property('result', 'pem') - }) - - it('accepts a timeout', async () => { - const name = 'name' - const password = 'password' - - ipfs.key.export.withArgs(name, password, { - ...defaultOptions, - timeout: 1000 - }).returns('pem') - - const res = await http({ - method: 'POST', - url: `/api/v0/key/export?arg=${name}&password=${password}&timeout=1s` - }, { ipfs }) - - expect(res).to.have.property('statusCode', 200) - expect(res).to.have.property('result', 'pem') - }) - }) - describe('/import', () => { const defaultOptions = { signal: sinon.match.instanceOf(AbortSignal), From 1091e901be0f17ffa6e94147e7b2cc98dc067de9 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Thu, 6 Aug 2020 17:29:13 +0200 Subject: [PATCH 8/9] docs(example): make browserify example test more reliable --- examples/browser-browserify/public/index.html | 2 +- examples/browser-browserify/src/index.js | 10 ++++++++-- examples/browser-browserify/test.js | 3 +-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/browser-browserify/public/index.html b/examples/browser-browserify/public/index.html index cebc18fcd4..8d00381454 100644 --- a/examples/browser-browserify/public/index.html +++ b/examples/browser-browserify/public/index.html @@ -15,7 +15,7 @@

JS IPFS - Add data to IPFS from the browser

- +