Skip to content

Commit 6065923

Browse files
vasco-santosjacobheun
authored andcommittedMay 28, 2020
chore: integrate libp2p-keychain into js-libp2p (#633)
Integrates the libp2p-keychain codebase into this repo
1 parent 2b45fee commit 6065923

13 files changed

+1261
-918
lines changed
 

‎.aegir.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const after = async () => {
4545
}
4646

4747
module.exports = {
48-
bundlesize: { maxSize: '185kB' },
48+
bundlesize: { maxSize: '200kB' },
4949
hooks: {
5050
pre: before,
5151
post: after

‎doc/API.md

+319
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,17 @@
4444
* [`connectionManager.get`](#connectionmanagerget)
4545
* [`connectionManager.setPeerValue`](#connectionmanagersetpeervalue)
4646
* [`connectionManager.size`](#connectionmanagersize)
47+
* [`keychain.createKey`](#keychaincreatekey)
48+
* [`keychain.renameKey`](#keychainrenamekey)
49+
* [`keychain.removeKey`](#keychainremovekey)
50+
* [`keychain.exportKey`](#keychainexportkey)
51+
* [`keychain.importKey`](#keychainimportkey)
52+
* [`keychain.importPeer`](#keychainimportpeer)
53+
* [`keychain.listKeys`](#keychainlistkeys)
54+
* [`keychain.findKeyById`](#keychainfindkeybyid)
55+
* [`keychain.findKeyByName`](#keychainfindkeybyname)
56+
* [`keychain.cms.encrypt`](#keychaincmsencrypt)
57+
* [`keychain.cms.decrypt`](#keychaincmsdecrypt)
4758
* [`metrics.global`](#metricsglobal)
4859
* [`metrics.peers`](#metricspeers)
4960
* [`metrics.protocols`](#metricsprotocols)
@@ -75,6 +86,7 @@ Creates an instance of Libp2p.
7586
| [options.connectionManager] | `object` | libp2p Connection Manager configuration |
7687
| [options.datastore] | `object` | must implement [ipfs/interface-datastore](https://github.com/ipfs/interface-datastore) (in memory datastore will be used if not provided) |
7788
| [options.dialer] | `object` | libp2p Dialer configuration
89+
| [options.keychain] | [`object`](./CONFIGURATION.md#setup-with-keychain) | keychain configuration |
7890
| [options.metrics] | `object` | libp2p Metrics configuration
7991
| [options.peerId] | [`PeerId`][peer-id] | peerId instance (it will be created if not provided) |
8092
| [options.peerStore] | `object` | libp2p PeerStore configuration |
@@ -125,6 +137,36 @@ Required keys in the `options` object:
125137

126138
## Libp2p Instance Methods
127139

140+
### loadKeychain
141+
142+
Load keychain keys from the datastore, importing the private key as 'self', if needed.
143+
144+
`libp2p.loadKeychain()`
145+
146+
#### Returns
147+
148+
| Type | Description |
149+
|------|-------------|
150+
| `Promise` | Promise resolves when the keychain is ready |
151+
152+
#### Example
153+
154+
```js
155+
const Libp2p = require('libp2p')
156+
157+
// ...
158+
159+
const libp2p = await Libp2p.create({
160+
// ...
161+
keychain: {
162+
pass: '0123456789pass1234567890'
163+
}
164+
})
165+
166+
// load keychain
167+
await libp2p.loadKeychain()
168+
```
169+
128170
### start
129171

130172
Starts the libp2p node.
@@ -1254,6 +1296,283 @@ libp2p.connectionManager.size
12541296
// 10
12551297
```
12561298

1299+
### keychain.createKey
1300+
1301+
Create a key in the keychain.
1302+
1303+
`libp2p.keychain.createKey(name, type, size)`
1304+
1305+
#### Parameters
1306+
1307+
| Name | Type | Description |
1308+
|------|------|-------------|
1309+
| name | `string` | The local key name. It cannot already exist. |
1310+
| type | `string` | One of the key types; 'rsa' |
1311+
| size | `number` | The key size in bits. |
1312+
1313+
#### Returns
1314+
1315+
| Type | Description |
1316+
|------|-------------|
1317+
| `Promise<{ id, name }>` | Key info object |
1318+
1319+
#### Example
1320+
1321+
```js
1322+
const keyInfo = await libp2p.keychain.createKey('keyTest', 'rsa', 4096)
1323+
```
1324+
1325+
### keychain.renameKey
1326+
1327+
Rename a key in the keychain.
1328+
1329+
`libp2p.keychain.renameKey(oldName, newName)`
1330+
1331+
#### Parameters
1332+
1333+
| Name | Type | Description |
1334+
|------|------|-------------|
1335+
| name | `string` | The old local key name. It must already exist. |
1336+
| type | `string` | The new local key name. It must not already exist. |
1337+
1338+
#### Returns
1339+
1340+
| Type | Description |
1341+
|------|-------------|
1342+
| `Promise<{ id, name }>` | Key info object |
1343+
1344+
#### Example
1345+
1346+
```js
1347+
await libp2p.keychain.createKey('keyTest', 'rsa', 4096)
1348+
const keyInfo = await libp2p.keychain.renameKey('keyTest', 'keyNewNtest')
1349+
```
1350+
1351+
### keychain.removeKey
1352+
1353+
Removes a key from the keychain.
1354+
1355+
`libp2p.keychain.removeKey(name)`
1356+
1357+
#### Parameters
1358+
1359+
| Name | Type | Description |
1360+
|------|------|-------------|
1361+
| name | `string` | The local key name. It must already exist. |
1362+
1363+
#### Returns
1364+
1365+
| Type | Description |
1366+
|------|-------------|
1367+
| `Promise<{ id, name }>` | Key info object |
1368+
1369+
#### Example
1370+
1371+
```js
1372+
await libp2p.keychain.createKey('keyTest', 'rsa', 4096)
1373+
const keyInfo = await libp2p.keychain.removeKey('keyTest')
1374+
```
1375+
1376+
### keychain.exportKey
1377+
1378+
Export an existing key as a PEM encrypted PKCS #8 string.
1379+
1380+
`libp2p.keychain.exportKey(name, password)`
1381+
1382+
#### Parameters
1383+
1384+
| Name | Type | Description |
1385+
|------|------|-------------|
1386+
| name | `string` | The local key name. It must already exist. |
1387+
| password | `string` | The password to use. |
1388+
1389+
#### Returns
1390+
1391+
| Type | Description |
1392+
|------|-------------|
1393+
| `Promise<string>` | Key as a PEM encrypted PKCS #8 |
1394+
1395+
#### Example
1396+
1397+
```js
1398+
await libp2p.keychain.createKey('keyTest', 'rsa', 4096)
1399+
const pemKey = await libp2p.keychain.exportKey('keyTest', 'password123')
1400+
```
1401+
1402+
### keychain.importKey
1403+
1404+
Import a new key from a PEM encoded PKCS #8 string.
1405+
1406+
`libp2p.keychain.importKey(name, pem, password)`
1407+
1408+
#### Parameters
1409+
1410+
| Name | Type | Description |
1411+
|------|------|-------------|
1412+
| name | `string` | The local key name. It must not exist. |
1413+
| pem | `string` | The PEM encoded PKCS #8 string. |
1414+
| password | `string` | The password to use. |
1415+
1416+
#### Returns
1417+
1418+
| Type | Description |
1419+
|------|-------------|
1420+
| `Promise<{ id, name }>` | Key info object |
1421+
1422+
#### Example
1423+
1424+
```js
1425+
await libp2p.keychain.createKey('keyTest', 'rsa', 4096)
1426+
const pemKey = await libp2p.keychain.exportKey('keyTest', 'password123')
1427+
const keyInfo = await libp2p.keychain.importKey('keyTestImport', pemKey, 'password123')
1428+
```
1429+
1430+
### keychain.importPeer
1431+
1432+
Import a new key from a PeerId.
1433+
1434+
`libp2p.keychain.importPeer(name, peerId)`
1435+
1436+
#### Parameters
1437+
1438+
| Name | Type | Description |
1439+
|------|------|-------------|
1440+
| name | `string` | The local key name. It must not exist. |
1441+
| peerId | ['PeerId'][peer-id] | The PEM encoded PKCS #8 string. |
1442+
1443+
#### Returns
1444+
1445+
| Type | Description |
1446+
|------|-------------|
1447+
| `Promise<{ id, name }>` | Key info object |
1448+
1449+
#### Example
1450+
1451+
```js
1452+
const keyInfo = await libp2p.keychain.importPeer('keyTestImport', peerId)
1453+
```
1454+
1455+
### keychain.listKeys
1456+
1457+
List all the keys.
1458+
1459+
`libp2p.keychain.listKeys()`
1460+
1461+
#### Returns
1462+
1463+
| Type | Description |
1464+
|------|-------------|
1465+
| `Promise<Array<{ id, name }>>` | Array of Key info |
1466+
1467+
#### Example
1468+
1469+
```js
1470+
const keyInfos = await libp2p.keychain.listKeys()
1471+
```
1472+
1473+
### keychain.findKeyById
1474+
1475+
Find a key by it's id.
1476+
1477+
`libp2p.keychain.findKeyById(id)`
1478+
1479+
#### Parameters
1480+
1481+
| Name | Type | Description |
1482+
|------|------|-------------|
1483+
| id | `string` | The universally unique key identifier. |
1484+
1485+
#### Returns
1486+
1487+
| Type | Description |
1488+
|------|-------------|
1489+
| `Promise<{ id, name }>` | Key info object |
1490+
1491+
#### Example
1492+
1493+
```js
1494+
const keyInfo = await libp2p.keychain.createKey('keyTest', 'rsa', 4096)
1495+
const keyInfo2 = await libp2p.keychain.findKeyById(keyInfo.id)
1496+
```
1497+
1498+
### keychain.findKeyByName
1499+
1500+
Find a key by it's name.
1501+
1502+
`libp2p.keychain.findKeyByName(id)`
1503+
1504+
#### Parameters
1505+
1506+
| Name | Type | Description |
1507+
|------|------|-------------|
1508+
| id | `string` | The local key name. |
1509+
1510+
#### Returns
1511+
1512+
| Type | Description |
1513+
|------|-------------|
1514+
| `Promise<{ id, name }>` | Key info object |
1515+
1516+
#### Example
1517+
1518+
```js
1519+
const keyInfo = await libp2p.keychain.createKey('keyTest', 'rsa', 4096)
1520+
const keyInfo2 = await libp2p.keychain.findKeyByName('keyTest')
1521+
```
1522+
1523+
### keychain.cms.encrypt
1524+
1525+
Encrypt protected data using the Cryptographic Message Syntax (CMS).
1526+
1527+
`libp2p.keychain.cms.encrypt(name, data)`
1528+
1529+
#### Parameters
1530+
1531+
| Name | Type | Description |
1532+
|------|------|-------------|
1533+
| name | `string` | The local key name. |
1534+
| data | `Buffer` | The data to encrypt. |
1535+
1536+
#### Returns
1537+
1538+
| Type | Description |
1539+
|------|-------------|
1540+
| `Promise<Buffer>` | Encrypted data as a PKCS #7 message in DER. |
1541+
1542+
#### Example
1543+
1544+
```js
1545+
const keyInfo = await libp2p.keychain.createKey('keyTest', 'rsa', 4096)
1546+
const enc = await libp2p.keychain.cms.encrypt('keyTest', Buffer.from('data'))
1547+
```
1548+
1549+
### keychain.cms.decrypt
1550+
1551+
Decrypt protected data using the Cryptographic Message Syntax (CMS).
1552+
The keychain must contain one of the keys used to encrypt the data. If none of the keys exists, an Error is returned with the property 'missingKeys'.
1553+
1554+
`libp2p.keychain.cms.decrypt(cmsData)`
1555+
1556+
#### Parameters
1557+
1558+
| Name | Type | Description |
1559+
|------|------|-------------|
1560+
| cmsData | `string` | The CMS encrypted data to decrypt. |
1561+
1562+
#### Returns
1563+
1564+
| Type | Description |
1565+
|------|-------------|
1566+
| `Promise<Buffer>` | Decrypted data. |
1567+
1568+
#### Example
1569+
1570+
```js
1571+
const keyInfo = await libp2p.keychain.createKey('keyTest', 'rsa', 4096)
1572+
const enc = await libp2p.keychain.cms.encrypt('keyTest', Buffer.from('data'))
1573+
const decData = await libp2p.keychain.cms.decrypt(enc)
1574+
```
1575+
12571576
### metrics.global
12581577

12591578
A [`Stats`](#stats) object of tracking the global bandwidth of the libp2p node.

‎doc/CONFIGURATION.md

+32
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- [Customizing DHT](#customizing-dht)
2121
- [Setup with Content and Peer Routing](#setup-with-content-and-peer-routing)
2222
- [Setup with Relay](#setup-with-relay)
23+
- [Setup with Keychain](#setup-with-keychain)
2324
- [Configuring Dialing](#configuring-dialing)
2425
- [Configuring Connection Manager](#configuring-connection-manager)
2526
- [Configuring Metrics](#configuring-metrics)
@@ -422,6 +423,37 @@ const node = await Libp2p.create({
422423
})
423424
```
424425

426+
#### Setup with Keychain
427+
428+
Libp2p allows you to setup a secure key chain to manage your keys. The keychain configuration object should have the following properties:
429+
430+
| Name | Type | Description |
431+
|------|------|-------------|
432+
| pass | `string` | Passphrase to use in the keychain (minimum of 20 characters). |
433+
| datastore | `object` | must implement [ipfs/interface-datastore](https://github.com/ipfs/interface-datastore) |
434+
435+
```js
436+
const Libp2p = require('libp2p')
437+
const TCP = require('libp2p-tcp')
438+
const MPLEX = require('libp2p-mplex')
439+
const SECIO = require('libp2p-secio')
440+
const LevelStore = require('datastore-level')
441+
442+
const node = await Libp2p.create({
443+
modules: {
444+
transport: [TCP],
445+
streamMuxer: [MPLEX],
446+
connEncryption: [SECIO]
447+
},
448+
keychain: {
449+
pass: 'notsafepassword123456789',
450+
datastore: new LevelStore('path/to/store')
451+
}
452+
})
453+
454+
await libp2p.loadKeychain()
455+
```
456+
425457
#### Configuring Dialing
426458

427459
Dialing in libp2p can be configured to limit the rate of dialing, and how long dials are allowed to take. The below configuration example shows the default values for the dialer.

‎src/config.js

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict'
22

3+
const { MemoryDatastore } = require('interface-datastore')
34
const mergeOptions = require('merge-options')
45
const Constants = require('./constants')
56

@@ -17,6 +18,9 @@ const DefaultConfig = {
1718
maxDialsPerPeer: Constants.MAX_PER_PEER_DIALS,
1819
dialTimeout: Constants.DIAL_TIMEOUT
1920
},
21+
keychain: {
22+
datastore: new MemoryDatastore()
23+
},
2024
metrics: {
2125
enabled: false
2226
},

‎src/index.js

+31
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const AddressManager = require('./address-manager')
1919
const ConnectionManager = require('./connection-manager')
2020
const Circuit = require('./circuit')
2121
const Dialer = require('./dialer')
22+
const Keychain = require('./keychain')
2223
const Metrics = require('./metrics')
2324
const TransportManager = require('./transport-manager')
2425
const Upgrader = require('./upgrader')
@@ -74,6 +75,22 @@ class Libp2p extends EventEmitter {
7475
})
7576
}
7677

78+
// Create keychain
79+
if (this._options.keychain.pass) {
80+
log('creating keychain')
81+
82+
const datastore = this._options.keychain.datastore
83+
const keychainOpts = Keychain.generateOptions()
84+
85+
this.keychain = new Keychain(datastore, {
86+
passPhrase: this._options.keychain.pass,
87+
...keychainOpts,
88+
...this._options.keychain
89+
})
90+
91+
log('keychain constructed')
92+
}
93+
7794
// Setup the Upgrader
7895
this.upgrader = new Upgrader({
7996
localPeer: this.peerId,
@@ -249,6 +266,20 @@ class Libp2p extends EventEmitter {
249266
log('libp2p has stopped')
250267
}
251268

269+
/**
270+
* Load keychain keys from the datastore.
271+
* Imports the private key as 'self', if needed.
272+
* @async
273+
* @returns {void}
274+
*/
275+
async loadKeychain () {
276+
try {
277+
await this.keychain.findKeyByName('self')
278+
} catch (err) {
279+
await this.keychain.importPeer('self', this.peerId)
280+
}
281+
}
282+
252283
isStarted () {
253284
return this._isStarted
254285
}

‎src/keychain/README.md

-68
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,7 @@
11
# js-libp2p-keychain
22

3-
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai)
4-
[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/)
5-
[![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p)
6-
[![Discourse posts](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg)](https://discuss.libp2p.io)
7-
[![](https://img.shields.io/codecov/c/github/libp2p/js-libp2p-keychain.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-keychain)
8-
[![](https://img.shields.io/travis/libp2p/js-libp2p-keychain.svg?style=flat-square)](https://travis-ci.com/libp2p/js-libp2p-keychain)
9-
[![Dependency Status](https://david-dm.org/libp2p/js-libp2p-keychain.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-keychain)
10-
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
11-
123
> A secure key chain for libp2p in JavaScript
134
14-
## Lead Maintainer
15-
16-
[Vasco Santos](https://github.com/vasco-santos).
17-
185
## Features
196

207
- Manages the lifecycle of a key
@@ -26,49 +13,6 @@
2613
- Uses PKCS 7: CMS (aka RFC 5652) to provide cryptographically protected messages
2714
- Delays reporting errors to slow down brute force attacks
2815

29-
## Table of Contents
30-
31-
## Install
32-
33-
```sh
34-
npm install --save libp2p-keychain
35-
```
36-
37-
### Usage
38-
39-
```js
40-
const Keychain = require('libp2p-keychain')
41-
const FsStore = require('datastore-fs')
42-
43-
const datastore = new FsStore('./a-keystore')
44-
const opts = {
45-
passPhrase: 'some long easily remembered phrase'
46-
}
47-
const keychain = new Keychain(datastore, opts)
48-
```
49-
50-
## API
51-
52-
Managing a key
53-
54-
- `async createKey (name, type, size)`
55-
- `async renameKey (oldName, newName)`
56-
- `async removeKey (name)`
57-
- `async exportKey (name, password)`
58-
- `async importKey (name, pem, password)`
59-
- `async importPeer (name, peer)`
60-
61-
A naming service for a key
62-
63-
- `async listKeys ()`
64-
- `async findKeyById (id)`
65-
- `async findKeyByName (name)`
66-
67-
Cryptographically protected messages
68-
69-
- `async cms.encrypt (name, plain)`
70-
- `async cms.decrypt (cmsData)`
71-
7216
### KeyInfo
7317

7418
The key management and naming service API all return a `KeyInfo` object. The `id` is a universally unique identifier for the key. The `name` is local to the key chain.
@@ -109,15 +53,3 @@ The actual physical storage of an encrypted key is left to implementations of [i
10953
### Cryptographic Message Syntax (CMS)
11054

11155
CMS, aka [PKCS #7](https://en.wikipedia.org/wiki/PKCS) and [RFC 5652](https://tools.ietf.org/html/rfc5652), describes an encapsulation syntax for data protection. It is used to digitally sign, digest, authenticate, or encrypt arbitrary message content. Basically, `cms.encrypt` creates a DER message that can be only be read by someone holding the private key.
112-
113-
## Contribute
114-
115-
Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-keychain/issues)!
116-
117-
This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
118-
119-
[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md)
120-
121-
## License
122-
123-
[MIT](LICENSE)

‎src/keychain/index.js

+467-1
Large diffs are not rendered by default.

‎src/keychain/keychain.js

-469
This file was deleted.

‎test/keychain/browser.js

-27
This file was deleted.

‎test/keychain/cms-interop.js ‎test/keychain/cms-interop.spec.js

+32-24
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,33 @@ const dirtyChai = require('dirty-chai')
77
const expect = chai.expect
88
chai.use(dirtyChai)
99
chai.use(require('chai-string'))
10+
11+
const os = require('os')
12+
const path = require('path')
13+
const { isNode } = require('ipfs-utils/src/env')
14+
const FsStore = require('datastore-fs')
15+
const LevelStore = require('datastore-level')
16+
1017
const Keychain = require('../../src/keychain')
1118

12-
module.exports = (datastore) => {
13-
describe('cms interop', () => {
14-
const passPhrase = 'this is not a secure phrase'
15-
const aliceKeyName = 'cms-interop-alice'
16-
let ks
19+
describe('cms interop', () => {
20+
const passPhrase = 'this is not a secure phrase'
21+
const aliceKeyName = 'cms-interop-alice'
22+
let ks
1723

18-
before(() => {
19-
ks = new Keychain(datastore, { passPhrase: passPhrase })
20-
})
24+
before(() => {
25+
const datastore = isNode
26+
? new FsStore(path.join(os.tmpdir(), 'test-keystore-1-' + Date.now()))
27+
: new LevelStore('test-keystore-1', { db: require('level') })
28+
ks = new Keychain(datastore, { passPhrase: passPhrase })
29+
})
2130

22-
const plainData = Buffer.from('This is a message from Alice to Bob')
31+
const plainData = Buffer.from('This is a message from Alice to Bob')
2332

24-
it('imports openssl key', async function () {
25-
this.timeout(10 * 1000)
26-
const aliceKid = 'QmNzBqPwp42HZJccsLtc4ok6LjZAspckgs2du5tTmjPfFA'
27-
const alice = `-----BEGIN ENCRYPTED PRIVATE KEY-----
33+
it('imports openssl key', async function () {
34+
this.timeout(10 * 1000)
35+
const aliceKid = 'QmNzBqPwp42HZJccsLtc4ok6LjZAspckgs2du5tTmjPfFA'
36+
const alice = `-----BEGIN ENCRYPTED PRIVATE KEY-----
2837
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIMhYqiVoLJMICAggA
2938
MBQGCCqGSIb3DQMHBAhU7J9bcJPLDQSCAoDzi0dP6z97wJBs3jK2hDvZYdoScknG
3039
QMPOnpG1LO3IZ7nFha1dta5liWX+xRFV04nmVYkkNTJAPS0xjJOG9B5Hm7wm8uTd
@@ -42,13 +51,13 @@ igg5jozKCW82JsuWSiW9tu0F/6DuvYiZwHS3OLiJP0CuLfbOaRw8Jia1RTvXEH7m
4251
cn4oisOvxCprs4aM9UVjtZTCjfyNpX8UWwT1W3rySV+KQNhxuMy3RzmL
4352
-----END ENCRYPTED PRIVATE KEY-----
4453
`
45-
const key = await ks.importKey(aliceKeyName, alice, 'mypassword')
46-
expect(key.name).to.equal(aliceKeyName)
47-
expect(key.id).to.equal(aliceKid)
48-
})
54+
const key = await ks.importKey(aliceKeyName, alice, 'mypassword')
55+
expect(key.name).to.equal(aliceKeyName)
56+
expect(key.id).to.equal(aliceKid)
57+
})
4958

50-
it('decrypts node-forge example', async () => {
51-
const example = `
59+
it('decrypts node-forge example', async () => {
60+
const example = `
5261
MIIBcwYJKoZIhvcNAQcDoIIBZDCCAWACAQAxgfowgfcCAQAwYDBbMQ0wCwYDVQQK
5362
EwRpcGZzMREwDwYDVQQLEwhrZXlzdG9yZTE3MDUGA1UEAxMuUW1OekJxUHdwNDJI
5463
WkpjY3NMdGM0b2s2TGpaQXNwY2tnczJkdTV0VG1qUGZGQQIBATANBgkqhkiG9w0B
@@ -58,9 +67,8 @@ knU1yykWGkdlbclCuu0NaAfmb8o0OX50CbEKZB7xmsv8tnqn0H0jMF4GCSqGSIb3
5867
DQEHATAdBglghkgBZQMEASoEEP/PW1JWehQx6/dsLkp/Mf+gMgQwFM9liLTqC56B
5968
nHILFmhac/+a/StQOKuf9dx5qXeGvt9LnwKuGGSfNX4g+dTkoa6N
6069
`
61-
const plain = await ks.cms.decrypt(Buffer.from(example, 'base64'))
62-
expect(plain).to.exist()
63-
expect(plain.toString()).to.equal(plainData.toString())
64-
})
70+
const plain = await ks.cms.decrypt(Buffer.from(example, 'base64'))
71+
expect(plain).to.exist()
72+
expect(plain.toString()).to.equal(plainData.toString())
6573
})
66-
}
74+
})

‎test/keychain/keychain.spec.js

+375-297
Large diffs are not rendered by default.

‎test/keychain/node.js

-31
This file was deleted.
File renamed without changes.

0 commit comments

Comments
 (0)
Please sign in to comment.