Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit 7e0e85c

Browse files
authored
fix: support keychain without pass (#3212)
- add support for ed25519 and secp256k1 keys for the ipfs PeerId - add support for using ed25519 and secp256k1 keys with ipns - add support for keychain without a pass, this fixes several keychain commands - fix `name publish`, ttl should be optional but wasn't being allowed Includes changes in #3208 Key gen and key listing now works: ```sh $ jsipfs key gen --type=ed25519 my-ed-key generated QmUPJZ3ghsnkRVgYjrMrSC8MbbZTzcezn6mH7vY9vTbrMY my-ed-key $ jsipfs key list QmUPJZ3ghsnkRVgYjrMrSC8MbbZTzcezn6mH7vY9vTbrMY my-ed-key QmYPxJJb8Mpa6JjQj7hCTF4ajn2SE1HFLRoAnCbymTGzyC self ``` IPNS Publishing now works properly, including using other key types: ```sh jsipfs name publish -k my-ed-key /ipfs/QmP7WDyEdkFu2nfj35SUEB7fk3iKCHpcrCVbGk1HXZU22a Published to 12D3KooWGmSq6u3yZeXqeqSmQpJWKQGGdCxrZQAUZBzsbSM2kCE6: /ipfs/QmP7WDyEdkFu2nfj35SUEB7fk3iKCHpcrCVbGk1HXZU22a ``` I also fixed a couple of the example tests, they weren't waiting for IPFS to start before executing the tests, which could cause them to intermittently fail. BREAKING CHANGE: remove support for key.export over the http api
1 parent b1a2713 commit 7e0e85c

File tree

26 files changed

+150
-198
lines changed

26 files changed

+150
-198
lines changed

examples/browser-browserify/public/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<body>
1616
<h1>JS IPFS - Add data to IPFS from the browser</h1>
1717
<textarea id="source" placeholder="Enter some text here"></textarea>
18-
<button id="store">Add text to ipfs</button>
18+
<button id="store" style="display: none">Add text to ipfs</button>
1919
<div id="output" style="display: none">
2020
<div>found in ipfs:</div>
2121
<div class="content" id="cid">[ipfs cid]</div>

examples/browser-browserify/src/index.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
const IPFS = require('ipfs')
44

55
document.addEventListener('DOMContentLoaded', async () => {
6-
const node = await IPFS.create({ repo: String(Math.random() + Date.now()) })
6+
const node = await IPFS.create({
7+
repo: String(Math.random() + Date.now()),
8+
init: { alogorithm: 'ed25519' }
9+
10+
})
11+
const button = document.getElementById('store')
712

813
console.log('IPFS node is ready')
914

@@ -25,5 +30,6 @@ document.addEventListener('DOMContentLoaded', async () => {
2530
}
2631
}
2732

28-
document.getElementById('store').onclick = store
33+
button.onclick = store
34+
button.setAttribute('style', 'display: inline')
2935
})

examples/browser-browserify/test.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ module.exports = {
99
.waitForElementVisible('#source')
1010
.setValue('#source', 'hello')
1111
.waitForElementVisible('#store')
12-
.pause(1000)
1312
.click('#store')
14-
.waitForElementVisible('#output')
13+
.waitForElementVisible('#output', 5e3, 100)
1514

1615
browser.expect.element('#cid').text.to.contain('QmWfVY9y3xjsixTgbd9AorQxH7VtMpzfx2HaWtsoUYecaX')
1716
browser.expect.element('#content').text.to.contain('hello')

examples/circuit-relaying/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ <h1>IPFS Simple Messaging</h1>
4646
<div class="row">
4747
<div class="box row">
4848
<label>Peer id:</label>
49-
<ul id="peer-id"></ul>
49+
<ul id="peer-id" style="display:none"></ul>
5050
</div>
5151
<div class="box addrs-box">
5252
<label>Addresses:</label>

examples/circuit-relaying/src/app.js

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ document.addEventListener('DOMContentLoaded', async () => {
5454

5555
let room = createRoom(roomName)
5656

57+
$peerId.setAttribute('style', '')
5758
$peerId.innerHTML = `<li>${info.id}</li>`
5859

5960
$send.addEventListener('click', () => {

examples/circuit-relaying/src/helpers.js

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ const $msgs = document.querySelector('#msgs')
77
const $addrs = document.querySelector('#addrs')
88
const $peers = document.querySelector('#peers')
99
const $pAddrs = document.querySelector('#peers-addrs')
10-
const delay = require('delay')
1110

1211
const NAMESPACE = 'ipfs-quick-msg'
1312

examples/circuit-relaying/test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@ module.exports[pkg.name] = function (browser) {
9191

9292
browser
9393
.url(process.env.IPFS_EXAMPLE_TEST_URL)
94-
.waitForElementVisible('#peer')
94+
.waitForElementVisible('#peer-id') // Wait for ipfs to start
9595
.clearValue('#peer')
9696
.setValue('#peer', process.env.IPFS_RELAY_ADDRESS)
97-
.pause(1000)
97+
.pause(100)
9898
.click('#connect')
9999

100100
browser.expect.element('#peers-addrs').text.to.contain(process.env.IPFS_RELAY_ID)

packages/interface-ipfs-core/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"it-drain": "^1.0.1",
5353
"it-last": "^1.0.1",
5454
"it-pushable": "^1.3.1",
55+
"libp2p-crypto": "^0.17.9",
5556
"multiaddr": "^7.4.3",
5657
"multibase": "^1.0.1",
5758
"multihashing-async": "^1.0.0",

packages/interface-ipfs-core/src/key/export.js

-37
This file was deleted.

packages/interface-ipfs-core/src/key/import.js

+10-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
'use strict'
33

44
const { nanoid } = require('nanoid')
5+
const keys = require('libp2p-crypto/src/keys')
56
const { getDescribe, getIt, expect } = require('../utils/mocha')
67
const testTimeout = require('../utils/test-timeout')
78

@@ -26,24 +27,24 @@ module.exports = (common, options) => {
2627
it('should respect timeout option when importing a key', async () => {
2728
const password = nanoid()
2829

29-
const pem = await ipfs.key.export('self', password)
30-
expect(pem).to.exist()
30+
const key = await keys.generateKeyPair('ed25519')
31+
const exported = key.export(password)
3132

32-
await testTimeout(() => ipfs.key.import('derp', pem, password, {
33+
await testTimeout(() => ipfs.key.import('derp', exported, password, {
3334
timeout: 1
3435
}))
3536
})
3637

3738
it('should import an exported key', async () => {
3839
const password = nanoid()
3940

40-
const pem = await ipfs.key.export('self', password)
41-
expect(pem).to.exist()
41+
const key = await keys.generateKeyPair('ed25519')
42+
const exported = await key.export(password)
4243

43-
const key = await ipfs.key.import('clone', pem, password)
44-
expect(key).to.exist()
45-
expect(key).to.have.property('name', 'clone')
46-
expect(key).to.have.property('id')
44+
const importedKey = await ipfs.key.import('clone', exported, password)
45+
expect(importedKey).to.exist()
46+
expect(importedKey).to.have.property('name', 'clone')
47+
expect(importedKey).to.have.property('id')
4748
})
4849
})
4950
}

packages/interface-ipfs-core/src/key/index.js

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ const tests = {
66
list: require('./list'),
77
rename: require('./rename'),
88
rm: require('./rm'),
9-
export: require('./export'),
109
import: require('./import')
1110
}
1211

packages/ipfs-http-client/src/key/export.js

-26
This file was deleted.

packages/ipfs-http-client/src/key/index.js

-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@ module.exports = config => ({
55
list: require('./list')(config),
66
rename: require('./rename')(config),
77
rm: require('./rm')(config),
8-
export: require('./export')(config),
98
import: require('./import')(config)
109
})

packages/ipfs/docs/MODULE.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ Note that *initializing* a repo is different from creating an instance of [`ipfs
9494
Instead of a boolean, you may provide an object with custom initialization options. All properties are optional:
9595

9696
- `emptyRepo` (boolean) Whether to remove built-in assets, like the instructional tour and empty mutable file system, from the repo. (Default: `false`)
97-
- `bits` (number) Number of bits to use in the generated key pair. (Default: `2048`)
97+
- `algorithm` (string) The type of key to use. Supports `rsa`, `ed25519`, `secp256k1`. (Default: `rsa`)
98+
- `bits` (number) Number of bits to use in the generated key pair (rsa only). (Default: `2048`)
9899
- `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`.**
99100
```js
100101
// Generating a Peer ID:

packages/ipfs/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@
129129
"iterable-ndjson": "^1.1.0",
130130
"jsondiffpatch": "^0.4.1",
131131
"just-safe-set": "^2.1.0",
132-
"libp2p": "^0.28.5",
132+
"libp2p": "^0.28.10",
133133
"libp2p-bootstrap": "^0.11.0",
134-
"libp2p-crypto": "^0.17.8",
134+
"libp2p-crypto": "^0.17.9",
135135
"libp2p-delegated-content-routing": "^0.5.0",
136136
"libp2p-delegated-peer-routing": "^0.5.0",
137137
"libp2p-floodsub": "^0.21.0",

packages/ipfs/src/cli/commands/init.js

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ module.exports = {
1717
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',
1818
type: 'string'
1919
})
20+
.option('algorithm', {
21+
type: 'string',
22+
alias: 'a',
23+
default: 'rsa',
24+
describe: 'Cryptographic algorithm to use for key generation. Supports [rsa, ed25519, secp256k1]'
25+
})
2026
.option('bits', {
2127
type: 'number',
2228
alias: 'b',
@@ -72,6 +78,7 @@ module.exports = {
7278

7379
try {
7480
await node.init({
81+
algorithm: argv.algorithm,
7582
bits: argv.bits,
7683
privateKey: argv.privateKey,
7784
emptyRepo: argv.emptyRepo,

packages/ipfs/src/core/components/init.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ module.exports = ({
174174
return apiManager.api
175175
}
176176

177-
async function initNewRepo (repo, { privateKey, emptyRepo, bits, profiles, config, pass, print }) {
177+
async function initNewRepo (repo, { privateKey, emptyRepo, algorithm, bits, profiles, config, pass, print }) {
178178
emptyRepo = emptyRepo || false
179179
bits = bits == null ? 2048 : Number(bits)
180180

@@ -188,7 +188,7 @@ async function initNewRepo (repo, { privateKey, emptyRepo, bits, profiles, confi
188188
throw new Error('repo already exists')
189189
}
190190

191-
const peerId = await createPeerId({ privateKey, bits, print })
191+
const peerId = await createPeerId({ privateKey, algorithm, bits, print })
192192

193193
log('identity generated')
194194

@@ -257,16 +257,16 @@ async function initExistingRepo (repo, { config: newConfig, profiles, pass }) {
257257
return { peerId, keychain: libp2p.keychain }
258258
}
259259

260-
function createPeerId ({ privateKey, bits, print }) {
260+
function createPeerId ({ privateKey, algorithm = 'rsa', bits, print }) {
261261
if (privateKey) {
262262
log('using user-supplied private-key')
263263
return typeof privateKey === 'object'
264264
? privateKey
265265
: PeerId.createFromPrivKey(Buffer.from(privateKey, 'base64'))
266266
} else {
267267
// Generate peer identity keypair + transform to desired format + add to config.
268-
print('generating %s-bit RSA keypair...', bits)
269-
return PeerId.create({ bits })
268+
print('generating %s-bit (rsa only) %s keypair...', bits, algorithm)
269+
return PeerId.create({ keyType: algorithm, bits })
270270
}
271271
}
272272

packages/ipfs/src/core/components/name/publish.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ const { resolvePath } = require('./utils')
2121
* @param {IPFS} self
2222
* @returns {Object}
2323
*/
24-
module.exports = ({ ipns, dag, peerId, isOnline, keychain, options: constructorOptions }) => {
24+
module.exports = ({ ipns, dag, peerId, isOnline, keychain }) => {
2525
const lookupKey = async keyName => {
2626
if (keyName === 'self') {
2727
return peerId.privKey
2828
}
2929

3030
try {
31-
const pass = constructorOptions.pass
32-
const pem = await keychain.exportKey(keyName, pass)
33-
const privateKey = await crypto.keys.import(pem, pass)
31+
// We're exporting and immediately importing the key, so we can just use a throw away password
32+
const pem = await keychain.exportKey(keyName, 'temp')
33+
const privateKey = await crypto.keys.import(pem, 'temp')
3434
return privateKey
3535
} catch (err) {
3636
log.error(err)

packages/ipfs/src/http/api/resources/key.js

-44
Original file line numberDiff line numberDiff line change
@@ -181,50 +181,6 @@ exports.gen = {
181181
}
182182
}
183183

184-
exports.export = {
185-
options: {
186-
validate: {
187-
options: {
188-
allowUnknown: true,
189-
stripUnknown: true
190-
},
191-
query: Joi.object().keys({
192-
name: Joi.string().required(),
193-
password: Joi.string().required(),
194-
timeout: Joi.timeout()
195-
})
196-
.rename('arg', 'name', {
197-
override: true,
198-
ignoreUndefined: true
199-
})
200-
}
201-
},
202-
handler: async (request, h) => {
203-
const {
204-
app: {
205-
signal
206-
},
207-
server: {
208-
app: {
209-
ipfs
210-
}
211-
},
212-
query: {
213-
name,
214-
password,
215-
timeout
216-
}
217-
} = request
218-
219-
const pem = await ipfs.key.export(name, password, {
220-
signal,
221-
timeout
222-
})
223-
224-
return h.response(pem).type('application/x-pem-file')
225-
}
226-
}
227-
228184
exports.import = {
229185
options: {
230186
validate: {

packages/ipfs/src/http/api/resources/name.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ exports.publish = {
8080
name: Joi.string().required(),
8181
resolve: Joi.boolean().default(true),
8282
lifetime: Joi.string().default('24h'),
83-
ttl: Joi.string(),
83+
ttl: Joi.string().allow(''),
8484
key: Joi.string().default('self'),
8585
allowOffline: Joi.boolean(),
8686
timeout: Joi.timeout()

packages/ipfs/src/http/api/routes/key.js

-5
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@ module.exports = [
2323
path: '/api/v0/key/rename',
2424
...resources.key.rename
2525
},
26-
{
27-
method: 'POST',
28-
path: '/api/v0/key/export',
29-
...resources.key.export
30-
},
3126
{
3227
method: 'POST',
3328
path: '/api/v0/key/import',

0 commit comments

Comments
 (0)