@libp2p/keychain 0.6.2 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ import { logger } from '@libp2p/logger'
4
4
  import sanitize from 'sanitize-filename'
5
5
  import mergeOptions from 'merge-options'
6
6
  import { Key } from 'interface-datastore/key'
7
- import errCode from 'err-code'
7
+ import { CodeError } from '@libp2p/interfaces/errors'
8
8
  import { codes } from './errors.js'
9
9
  import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
10
10
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
@@ -50,7 +50,7 @@ const defaultOptions = {
50
50
  }
51
51
  }
52
52
 
53
- function validateKeyName (name: string) {
53
+ function validateKeyName (name: string): boolean {
54
54
  if (name == null) {
55
55
  return false
56
56
  }
@@ -66,7 +66,7 @@ function validateKeyName (name: string) {
66
66
  * This assumes than an error indicates that the keychain is under attack. Delay returning an
67
67
  * error to make brute force attacks harder.
68
68
  */
69
- async function randomDelay () {
69
+ async function randomDelay (): Promise<void> {
70
70
  const min = 200
71
71
  const max = 1000
72
72
  const delay = Math.random() * (max - min) + min
@@ -77,14 +77,14 @@ async function randomDelay () {
77
77
  /**
78
78
  * Converts a key name into a datastore name
79
79
  */
80
- function DsName (name: string) {
80
+ function DsName (name: string): Key {
81
81
  return new Key(keyPrefix + name)
82
82
  }
83
83
 
84
84
  /**
85
85
  * Converts a key name into a datastore info name
86
86
  */
87
- function DsInfoName (name: string) {
87
+ function DsInfoName (name: string): Key {
88
88
  return new Key(infoPrefix + name)
89
89
  }
90
90
 
@@ -155,7 +155,7 @@ export class DefaultKeyChain implements KeyChain {
155
155
  *
156
156
  * @returns {object}
157
157
  */
158
- static get options () {
158
+ static get options (): typeof defaultOptions {
159
159
  return defaultOptions
160
160
  }
161
161
 
@@ -169,26 +169,26 @@ export class DefaultKeyChain implements KeyChain {
169
169
  async createKey (name: string, type: KeyType, size = 2048): Promise<KeyInfo> {
170
170
  if (!validateKeyName(name) || name === 'self') {
171
171
  await randomDelay()
172
- throw errCode(new Error('Invalid key name'), codes.ERR_INVALID_KEY_NAME)
172
+ throw new CodeError('Invalid key name', codes.ERR_INVALID_KEY_NAME)
173
173
  }
174
174
 
175
175
  if (typeof type !== 'string') {
176
176
  await randomDelay()
177
- throw errCode(new Error('Invalid key type'), codes.ERR_INVALID_KEY_TYPE)
177
+ throw new CodeError('Invalid key type', codes.ERR_INVALID_KEY_TYPE)
178
178
  }
179
179
 
180
180
  const dsname = DsName(name)
181
181
  const exists = await this.components.datastore.has(dsname)
182
182
  if (exists) {
183
183
  await randomDelay()
184
- throw errCode(new Error('Key name already exists'), codes.ERR_KEY_ALREADY_EXISTS)
184
+ throw new CodeError('Key name already exists', codes.ERR_KEY_ALREADY_EXISTS)
185
185
  }
186
186
 
187
187
  switch (type.toLowerCase()) {
188
188
  case 'rsa':
189
189
  if (!Number.isSafeInteger(size) || size < 2048) {
190
190
  await randomDelay()
191
- throw errCode(new Error('Invalid RSA key size'), codes.ERR_INVALID_KEY_SIZE)
191
+ throw new CodeError('Invalid RSA key size', codes.ERR_INVALID_KEY_SIZE)
192
192
  }
193
193
  break
194
194
  default:
@@ -202,13 +202,13 @@ export class DefaultKeyChain implements KeyChain {
202
202
  const cached = privates.get(this)
203
203
 
204
204
  if (cached == null) {
205
- throw errCode(new Error('dek missing'), codes.ERR_INVALID_PARAMETERS)
205
+ throw new CodeError('dek missing', codes.ERR_INVALID_PARAMETERS)
206
206
  }
207
207
 
208
208
  const dek = cached.dek
209
209
  const pem = await keypair.export(dek)
210
210
  keyInfo = {
211
- name: name,
211
+ name,
212
212
  id: kid
213
213
  }
214
214
  const batch = this.components.datastore.batch()
@@ -229,7 +229,7 @@ export class DefaultKeyChain implements KeyChain {
229
229
  *
230
230
  * @returns {Promise<KeyInfo[]>}
231
231
  */
232
- async listKeys () {
232
+ async listKeys (): Promise<KeyInfo[]> {
233
233
  const query = {
234
234
  prefix: infoPrefix
235
235
  }
@@ -248,7 +248,13 @@ export class DefaultKeyChain implements KeyChain {
248
248
  async findKeyById (id: string): Promise<KeyInfo> {
249
249
  try {
250
250
  const keys = await this.listKeys()
251
- return keys.find((k) => k.id === id)
251
+ const key = keys.find((k) => k.id === id)
252
+
253
+ if (key == null) {
254
+ throw new CodeError(`Key with id '${id}' does not exist.`, codes.ERR_KEY_NOT_FOUND)
255
+ }
256
+
257
+ return key
252
258
  } catch (err: any) {
253
259
  await randomDelay()
254
260
  throw err
@@ -264,7 +270,7 @@ export class DefaultKeyChain implements KeyChain {
264
270
  async findKeyByName (name: string): Promise<KeyInfo> {
265
271
  if (!validateKeyName(name)) {
266
272
  await randomDelay()
267
- throw errCode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME)
273
+ throw new CodeError(`Invalid key name '${name}'`, codes.ERR_INVALID_KEY_NAME)
268
274
  }
269
275
 
270
276
  const dsname = DsInfoName(name)
@@ -274,7 +280,7 @@ export class DefaultKeyChain implements KeyChain {
274
280
  } catch (err: any) {
275
281
  await randomDelay()
276
282
  log.error(err)
277
- throw errCode(new Error(`Key '${name}' does not exist.`), codes.ERR_KEY_NOT_FOUND)
283
+ throw new CodeError(`Key '${name}' does not exist.`, codes.ERR_KEY_NOT_FOUND)
278
284
  }
279
285
  }
280
286
 
@@ -284,10 +290,10 @@ export class DefaultKeyChain implements KeyChain {
284
290
  * @param {string} name - The local key name; must already exist.
285
291
  * @returns {Promise<KeyInfo>}
286
292
  */
287
- async removeKey (name: string) {
293
+ async removeKey (name: string): Promise<KeyInfo> {
288
294
  if (!validateKeyName(name) || name === 'self') {
289
295
  await randomDelay()
290
- throw errCode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME)
296
+ throw new CodeError(`Invalid key name '${name}'`, codes.ERR_INVALID_KEY_NAME)
291
297
  }
292
298
  const dsname = DsName(name)
293
299
  const keyInfo = await this.findKeyByName(name)
@@ -308,11 +314,11 @@ export class DefaultKeyChain implements KeyChain {
308
314
  async renameKey (oldName: string, newName: string): Promise<KeyInfo> {
309
315
  if (!validateKeyName(oldName) || oldName === 'self') {
310
316
  await randomDelay()
311
- throw errCode(new Error(`Invalid old key name '${oldName}'`), codes.ERR_OLD_KEY_NAME_INVALID)
317
+ throw new CodeError(`Invalid old key name '${oldName}'`, codes.ERR_OLD_KEY_NAME_INVALID)
312
318
  }
313
319
  if (!validateKeyName(newName) || newName === 'self') {
314
320
  await randomDelay()
315
- throw errCode(new Error(`Invalid new key name '${newName}'`), codes.ERR_NEW_KEY_NAME_INVALID)
321
+ throw new CodeError(`Invalid new key name '${newName}'`, codes.ERR_NEW_KEY_NAME_INVALID)
316
322
  }
317
323
  const oldDsname = DsName(oldName)
318
324
  const newDsname = DsName(newName)
@@ -322,7 +328,7 @@ export class DefaultKeyChain implements KeyChain {
322
328
  const exists = await this.components.datastore.has(newDsname)
323
329
  if (exists) {
324
330
  await randomDelay()
325
- throw errCode(new Error(`Key '${newName}' already exists`), codes.ERR_KEY_ALREADY_EXISTS)
331
+ throw new CodeError(`Key '${newName}' already exists`, codes.ERR_KEY_ALREADY_EXISTS)
326
332
  }
327
333
 
328
334
  try {
@@ -347,14 +353,14 @@ export class DefaultKeyChain implements KeyChain {
347
353
  /**
348
354
  * Export an existing key as a PEM encrypted PKCS #8 string
349
355
  */
350
- async exportKey (name: string, password: string) {
356
+ async exportKey (name: string, password: string): Promise<string> {
351
357
  if (!validateKeyName(name)) {
352
358
  await randomDelay()
353
- throw errCode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME)
359
+ throw new CodeError(`Invalid key name '${name}'`, codes.ERR_INVALID_KEY_NAME)
354
360
  }
355
361
  if (password == null) {
356
362
  await randomDelay()
357
- throw errCode(new Error('Password is required'), codes.ERR_PASSWORD_REQUIRED)
363
+ throw new CodeError('Password is required', codes.ERR_PASSWORD_REQUIRED)
358
364
  }
359
365
 
360
366
  const dsname = DsName(name)
@@ -364,7 +370,7 @@ export class DefaultKeyChain implements KeyChain {
364
370
  const cached = privates.get(this)
365
371
 
366
372
  if (cached == null) {
367
- throw errCode(new Error('dek missing'), codes.ERR_INVALID_PARAMETERS)
373
+ throw new CodeError('dek missing', codes.ERR_INVALID_PARAMETERS)
368
374
  }
369
375
 
370
376
  const dek = cached.dek
@@ -379,7 +385,7 @@ export class DefaultKeyChain implements KeyChain {
379
385
  /**
380
386
  * Export an existing key as a PeerId
381
387
  */
382
- async exportPeerId (name: string) {
388
+ async exportPeerId (name: string): Promise<PeerId> {
383
389
  const password = 'temporary-password'
384
390
  const pem = await this.exportKey(name, password)
385
391
  const privateKey = await importKey(pem, password)
@@ -398,17 +404,17 @@ export class DefaultKeyChain implements KeyChain {
398
404
  async importKey (name: string, pem: string, password: string): Promise<KeyInfo> {
399
405
  if (!validateKeyName(name) || name === 'self') {
400
406
  await randomDelay()
401
- throw errCode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME)
407
+ throw new CodeError(`Invalid key name '${name}'`, codes.ERR_INVALID_KEY_NAME)
402
408
  }
403
409
  if (pem == null) {
404
410
  await randomDelay()
405
- throw errCode(new Error('PEM encoded key is required'), codes.ERR_PEM_REQUIRED)
411
+ throw new CodeError('PEM encoded key is required', codes.ERR_PEM_REQUIRED)
406
412
  }
407
413
  const dsname = DsName(name)
408
414
  const exists = await this.components.datastore.has(dsname)
409
415
  if (exists) {
410
416
  await randomDelay()
411
- throw errCode(new Error(`Key '${name}' already exists`), codes.ERR_KEY_ALREADY_EXISTS)
417
+ throw new CodeError(`Key '${name}' already exists`, codes.ERR_KEY_ALREADY_EXISTS)
412
418
  }
413
419
 
414
420
  let privateKey
@@ -416,7 +422,7 @@ export class DefaultKeyChain implements KeyChain {
416
422
  privateKey = await importKey(pem, password)
417
423
  } catch (err: any) {
418
424
  await randomDelay()
419
- throw errCode(new Error('Cannot read the key, most likely the password is wrong'), codes.ERR_CANNOT_READ_KEY)
425
+ throw new CodeError('Cannot read the key, most likely the password is wrong', codes.ERR_CANNOT_READ_KEY)
420
426
  }
421
427
 
422
428
  let kid
@@ -425,7 +431,7 @@ export class DefaultKeyChain implements KeyChain {
425
431
  const cached = privates.get(this)
426
432
 
427
433
  if (cached == null) {
428
- throw errCode(new Error('dek missing'), codes.ERR_INVALID_PARAMETERS)
434
+ throw new CodeError('dek missing', codes.ERR_INVALID_PARAMETERS)
429
435
  }
430
436
 
431
437
  const dek = cached.dek
@@ -436,7 +442,7 @@ export class DefaultKeyChain implements KeyChain {
436
442
  }
437
443
 
438
444
  const keyInfo = {
439
- name: name,
445
+ name,
440
446
  id: kid
441
447
  }
442
448
  const batch = this.components.datastore.batch()
@@ -453,13 +459,13 @@ export class DefaultKeyChain implements KeyChain {
453
459
  async importPeer (name: string, peer: PeerId): Promise<KeyInfo> {
454
460
  try {
455
461
  if (!validateKeyName(name)) {
456
- throw errCode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME)
462
+ throw new CodeError(`Invalid key name '${name}'`, codes.ERR_INVALID_KEY_NAME)
457
463
  }
458
464
  if (peer == null) {
459
- throw errCode(new Error('PeerId is required'), codes.ERR_MISSING_PRIVATE_KEY)
465
+ throw new CodeError('PeerId is required', codes.ERR_MISSING_PRIVATE_KEY)
460
466
  }
461
467
  if (peer.privateKey == null) {
462
- throw errCode(new Error('PeerId.privKey is required'), codes.ERR_MISSING_PRIVATE_KEY)
468
+ throw new CodeError('PeerId.privKey is required', codes.ERR_MISSING_PRIVATE_KEY)
463
469
  }
464
470
 
465
471
  const privateKey = await unmarshalPrivateKey(peer.privateKey)
@@ -468,19 +474,19 @@ export class DefaultKeyChain implements KeyChain {
468
474
  const exists = await this.components.datastore.has(dsname)
469
475
  if (exists) {
470
476
  await randomDelay()
471
- throw errCode(new Error(`Key '${name}' already exists`), codes.ERR_KEY_ALREADY_EXISTS)
477
+ throw new CodeError(`Key '${name}' already exists`, codes.ERR_KEY_ALREADY_EXISTS)
472
478
  }
473
479
 
474
480
  const cached = privates.get(this)
475
481
 
476
482
  if (cached == null) {
477
- throw errCode(new Error('dek missing'), codes.ERR_INVALID_PARAMETERS)
483
+ throw new CodeError('dek missing', codes.ERR_INVALID_PARAMETERS)
478
484
  }
479
485
 
480
486
  const dek = cached.dek
481
487
  const pem = await privateKey.export(dek)
482
488
  const keyInfo: KeyInfo = {
483
- name: name,
489
+ name,
484
490
  id: peer.toString()
485
491
  }
486
492
  const batch = this.components.datastore.batch()
@@ -500,7 +506,7 @@ export class DefaultKeyChain implements KeyChain {
500
506
  async getPrivateKey (name: string): Promise<string> {
501
507
  if (!validateKeyName(name)) {
502
508
  await randomDelay()
503
- throw errCode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME)
509
+ throw new CodeError(`Invalid key name '${name}'`, codes.ERR_INVALID_KEY_NAME)
504
510
  }
505
511
 
506
512
  try {
@@ -510,31 +516,31 @@ export class DefaultKeyChain implements KeyChain {
510
516
  } catch (err: any) {
511
517
  await randomDelay()
512
518
  log.error(err)
513
- throw errCode(new Error(`Key '${name}' does not exist.`), codes.ERR_KEY_NOT_FOUND)
519
+ throw new CodeError(`Key '${name}' does not exist.`, codes.ERR_KEY_NOT_FOUND)
514
520
  }
515
521
  }
516
522
 
517
523
  /**
518
524
  * Rotate keychain password and re-encrypt all associated keys
519
525
  */
520
- async rotateKeychainPass (oldPass: string, newPass: string) {
526
+ async rotateKeychainPass (oldPass: string, newPass: string): Promise<void> {
521
527
  if (typeof oldPass !== 'string') {
522
528
  await randomDelay()
523
- throw errCode(new Error(`Invalid old pass type '${typeof oldPass}'`), codes.ERR_INVALID_OLD_PASS_TYPE)
529
+ throw new CodeError(`Invalid old pass type '${typeof oldPass}'`, codes.ERR_INVALID_OLD_PASS_TYPE)
524
530
  }
525
531
  if (typeof newPass !== 'string') {
526
532
  await randomDelay()
527
- throw errCode(new Error(`Invalid new pass type '${typeof newPass}'`), codes.ERR_INVALID_NEW_PASS_TYPE)
533
+ throw new CodeError(`Invalid new pass type '${typeof newPass}'`, codes.ERR_INVALID_NEW_PASS_TYPE)
528
534
  }
529
535
  if (newPass.length < 20) {
530
536
  await randomDelay()
531
- throw errCode(new Error(`Invalid pass length ${newPass.length}`), codes.ERR_INVALID_PASS_LENGTH)
537
+ throw new CodeError(`Invalid pass length ${newPass.length}`, codes.ERR_INVALID_PASS_LENGTH)
532
538
  }
533
539
  log('recreating keychain')
534
540
  const cached = privates.get(this)
535
541
 
536
542
  if (cached == null) {
537
- throw errCode(new Error('dek missing'), codes.ERR_INVALID_PARAMETERS)
543
+ throw new CodeError('dek missing', codes.ERR_INVALID_PARAMETERS)
538
544
  }
539
545
 
540
546
  const oldDek = cached.dek
package/src/util.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * @param {Array} array
9
9
  * @param {function(*)} asyncCompare - An async function that returns a boolean
10
10
  */
11
- export async function findAsync <T> (array: T[], asyncCompare: (val: T) => Promise<any>) {
11
+ export async function findAsync <T> (array: T[], asyncCompare: (val: T) => Promise<any>): Promise<T | undefined> {
12
12
  const promises = array.map(asyncCompare)
13
13
  const results = await Promise.all(promises)
14
14
  const index = results.findIndex(result => result)