diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index ef41d4f..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,2 +0,0 @@
-*.png binary
-* crlf=input
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..0bc3b42
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,11 @@
+version: 2
+updates:
+- package-ecosystem: npm
+ directory: "/"
+ schedule:
+ interval: daily
+ time: "10:00"
+ open-pull-requests-limit: 10
+ commit-message:
+ prefix: "deps"
+ prefix-development: "deps(dev)"
diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml
new file mode 100644
index 0000000..d57c2a0
--- /dev/null
+++ b/.github/workflows/automerge.yml
@@ -0,0 +1,8 @@
+name: Automerge
+on: [ pull_request ]
+
+jobs:
+ automerge:
+ uses: protocol/.github/.github/workflows/automerge.yml@master
+ with:
+ job: 'automerge'
diff --git a/.github/workflows/js-test-and-release.yml b/.github/workflows/js-test-and-release.yml
new file mode 100644
index 0000000..3cb1621
--- /dev/null
+++ b/.github/workflows/js-test-and-release.yml
@@ -0,0 +1,143 @@
+name: test & maybe release
+on:
+ push:
+ branches:
+ - master # with #262 - ${{{ github.default_branch }}}
+ pull_request:
+
+jobs:
+
+ check:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: lts/*
+ - uses: ipfs/aegir/actions/cache-node-modules@master
+ - run: npm run --if-present lint
+ - run: npm run --if-present dep-check
+
+ test-node:
+ needs: check
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [windows-latest, ubuntu-latest, macos-latest]
+ node: [lts/*]
+ fail-fast: true
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: ${{ matrix.node }}
+ - uses: ipfs/aegir/actions/cache-node-modules@master
+ - run: npm run --if-present test:node
+ - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0
+ with:
+ flags: node
+
+ test-chrome:
+ needs: check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: lts/*
+ - uses: ipfs/aegir/actions/cache-node-modules@master
+ - run: npm run --if-present test:chrome
+ - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0
+ with:
+ flags: chrome
+
+ test-chrome-webworker:
+ needs: check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: lts/*
+ - uses: ipfs/aegir/actions/cache-node-modules@master
+ - run: npm run --if-present test:chrome-webworker
+ - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0
+ with:
+ flags: chrome-webworker
+
+ test-firefox:
+ needs: check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: lts/*
+ - uses: ipfs/aegir/actions/cache-node-modules@master
+ - run: npm run --if-present test:firefox
+ - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0
+ with:
+ flags: firefox
+
+ test-firefox-webworker:
+ needs: check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: lts/*
+ - uses: ipfs/aegir/actions/cache-node-modules@master
+ - run: npm run --if-present test:firefox-webworker
+ - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0
+ with:
+ flags: firefox-webworker
+
+ test-electron-main:
+ needs: check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: lts/*
+ - uses: ipfs/aegir/actions/cache-node-modules@master
+ - run: npx xvfb-maybe npm run --if-present test:electron-main
+ - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0
+ with:
+ flags: electron-main
+
+ test-electron-renderer:
+ needs: check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: lts/*
+ - uses: ipfs/aegir/actions/cache-node-modules@master
+ - run: npx xvfb-maybe npm run --if-present test:electron-renderer
+ - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.0
+ with:
+ flags: electron-renderer
+
+ release:
+ needs: [test-node, test-chrome, test-chrome-webworker, test-firefox, test-firefox-webworker, test-electron-main, test-electron-renderer]
+ runs-on: ubuntu-latest
+ if: github.event_name == 'push' && github.ref == 'refs/heads/master' # with #262 - 'refs/heads/${{{ github.default_branch }}}'
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ - uses: actions/setup-node@v3
+ with:
+ node-version: lts/*
+ - uses: ipfs/aegir/actions/cache-node-modules@master
+ - uses: ipfs/aegir/actions/docker-login@master
+ with:
+ docker-token: ${{ secrets.DOCKER_TOKEN }}
+ docker-username: ${{ secrets.DOCKER_USERNAME }}
+ - run: npm run --if-present release
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 0000000..6f6d895
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -0,0 +1,26 @@
+name: Close and mark stale issue
+
+on:
+ schedule:
+ - cron: '0 0 * * *'
+
+jobs:
+ stale:
+
+ runs-on: ubuntu-latest
+ permissions:
+ issues: write
+ pull-requests: write
+
+ steps:
+ - uses: actions/stale@v3
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ stale-issue-message: 'Oops, seems like we needed more information for this issue, please comment with more details or this issue will be closed in 7 days.'
+ close-issue-message: 'This issue was closed because it is missing author input.'
+ stale-issue-label: 'kind/stale'
+ any-of-labels: 'need/author-input'
+ exempt-issue-labels: 'need/triage,need/community-input,need/maintainer-input,need/maintainers-input,need/analysis,status/blocked,status/in-progress,status/ready,status/deferred,status/inactive'
+ days-before-issue-stale: 6
+ days-before-issue-close: 7
+ enable-statistics: true
diff --git a/.gitignore b/.gitignore
index 3da57e8..910f633 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,45 +1,8 @@
-docs
-**/node_modules/
-**/*.log
-test/repo-tests*
-**/bundle.js
-
-# Logs
-logs
-*.log
-
-coverage
-.nyc_output
-
-# Runtime data
-pids
-*.pid
-*.seed
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# node-waf configuration
-.lock-wscript
-
-build
-
-# Dependency directory
-# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
-
-lib
+build
dist
-test/test-data/go-ipfs-repo/LOCK
-test/test-data/go-ipfs-repo/LOG
-test/test-data/go-ipfs-repo/LOG.old
-
-# while testing npm5
+.docs
+.coverage
+node_modules
package-lock.json
-yarn.lock
\ No newline at end of file
+yarn.lock
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 2061bd3..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-language: node_js
-cache: npm
-stages:
- - check
- - test
- - cov
-
-node_js:
- - '10'
- - '12'
-
-os:
- - linux
- - osx
- - windows
-
-script: npx nyc -s npm run test:node -- --bail
-after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov
-
-jobs:
- include:
- - stage: check
- script:
- - npx aegir dep-check
- - npm run lint
-
- - stage: test
- name: chrome
- addons:
- chrome: stable
- script:
- - npx aegir test -t browser -t webworker
-
- - stage: test
- name: firefox
- addons:
- firefox: latest
- script:
- - npx aegir test -t browser -t webworker -- --browsers FirefoxHeadless
-
-notifications:
- email: false
diff --git a/LICENSE b/LICENSE
index bbfffbf..20ce483 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,4 @@
-MIT License
+This project is dual licensed under MIT and Apache-2.0.
-Copyright (c) 2017 libp2p
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+MIT: https://www.opensource.org/licenses/mit
+Apache-2.0: https://www.apache.org/licenses/license-2.0
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644
index 0000000..14478a3
--- /dev/null
+++ b/LICENSE-APACHE
@@ -0,0 +1,5 @@
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..72dc60d
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,19 @@
+The MIT License (MIT)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
index 45d7b43..8ce6664 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,37 @@
-⛔️ DEPRECATED: libp2p-keychain is now in [libp2p/src/keychain](https://github.com/libp2p/js-libp2p/tree/master/src/keychain) per [libp2p@0.28.0](https://github.com/libp2p/js-libp2p/releases/tag/v0.28.0).
-======
+# @libp2p/keychain
-# js-libp2p-keychain
+[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/)
+[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io)
+[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p-keychain.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-keychain)
+[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-keychain/js-test-and-release.yml?branch=master\&style=flat-square)](https://github.com/libp2p/js-libp2p-keychain/actions/workflows/js-test-and-release.yml?query=branch%3Amaster)
-[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai)
-[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/)
-[![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p)
-[![Discourse posts](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg)](https://discuss.libp2p.io)
-[![](https://img.shields.io/codecov/c/github/libp2p/js-libp2p-keychain.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-keychain)
-[![](https://img.shields.io/travis/libp2p/js-libp2p-keychain.svg?style=flat-square)](https://travis-ci.com/libp2p/js-libp2p-keychain)
-[![Dependency Status](https://david-dm.org/libp2p/js-libp2p-keychain.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-keychain)
-[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
+> Key management and cryptographically protected messages
-> A secure key chain for libp2p in JavaScript
+## Table of contents
-## Lead Maintainer
+- [Install](#install)
+ - [Browser `
+```
## Features
@@ -26,52 +41,8 @@
- Uses encrypted PKCS 8 for key storage
- Uses PBKDF2 for a "stetched" key encryption key
- Enforces NIST SP 800-131A and NIST SP 800-132
-- Uses PKCS 7: CMS (aka RFC 5652) to provide cryptographically protected messages
- Delays reporting errors to slow down brute force attacks
-## Table of Contents
-
-## Install
-
-```sh
-npm install --save libp2p-keychain
-```
-
-### Usage
-
-```js
-const Keychain = require('libp2p-keychain')
-const FsStore = require('datastore-fs')
-
-const datastore = new FsStore('./a-keystore')
-const opts = {
- passPhrase: 'some long easily remembered phrase'
-}
-const keychain = new Keychain(datastore, opts)
-```
-
-## API
-
-Managing a key
-
-- `async createKey (name, type, size)`
-- `async renameKey (oldName, newName)`
-- `async removeKey (name)`
-- `async exportKey (name, password)`
-- `async importKey (name, pem, password)`
-- `async importPeer (name, peer)`
-
-A naming service for a key
-
-- `async listKeys ()`
-- `async findKeyById (id)`
-- `async findKeyByName (name)`
-
-Cryptographically protected messages
-
-- `async cms.encrypt (name, plain)`
-- `async cms.decrypt (cmsData)`
-
### KeyInfo
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.
@@ -107,20 +78,19 @@ const defaultOptions = {
### Physical storage
-The actual physical storage of an encrypted key is left to implementations of [interface-datastore](https://github.com/ipfs/interface-datastore/). A key benifit is that now the key chain can be used in browser with the [js-datastore-level](https://github.com/ipfs/js-datastore-level) implementation.
+The actual physical storage of an encrypted key is left to implementations of [interface-datastore](https://github.com/ipfs/interface-datastore/). A key benefit is that now the key chain can be used in browser with the [js-datastore-level](https://github.com/ipfs/js-datastore-level) implementation.
-### Cryptographic Message Syntax (CMS)
+## API Docs
-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.
+-
-## Contribute
-
-Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-keychain/issues)!
+## License
-This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
+Licensed under either of
-[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md)
+- Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / )
+- MIT ([LICENSE-MIT](LICENSE-MIT) / )
-## License
+## Contribution
-[MIT](LICENSE)
+Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
diff --git a/package.json b/package.json
index fcba643..066f8e6 100644
--- a/package.json
+++ b/package.json
@@ -1,76 +1,164 @@
{
- "name": "libp2p-keychain",
- "version": "0.6.1",
+ "name": "@libp2p/keychain",
+ "version": "0.6.2",
"description": "Key management and cryptographically protected messages",
- "leadMaintainer": "Vasco Santos ",
- "main": "src/index.js",
- "scripts": {
- "lint": "aegir lint",
- "build": "aegir build",
- "coverage": "nyc --reporter=text --reporter=lcov npm run test:node",
- "test": "aegir test -t node -t browser",
- "test:node": "aegir test -t node",
- "test:browser": "aegir test -t browser",
- "release": "aegir release",
- "release-minor": "aegir release --type minor",
- "release-major": "aegir release --type major"
- },
- "pre-push": [
- "lint"
- ],
- "engines": {
- "node": ">=10.0.0",
- "npm": ">=3.0.0"
- },
+ "license": "Apache-2.0 OR MIT",
+ "homepage": "https://github.com/libp2p/js-libp2p-keychain#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/libp2p/js-libp2p-keychain.git"
},
+ "bugs": {
+ "url": "https://github.com/libp2p/js-libp2p-keychain/issues"
+ },
"keywords": [
"IPFS",
- "libp2p",
- "keys",
+ "crypto",
"encryption",
- "secure",
- "crypto"
+ "keys",
+ "libp2p",
+ "secure"
],
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/libp2p/js-libp2p-keychain/issues"
+ "engines": {
+ "node": ">=16.0.0",
+ "npm": ">=7.0.0"
+ },
+ "type": "module",
+ "types": "./dist/src/index.d.ts",
+ "files": [
+ "src",
+ "dist",
+ "!dist/test",
+ "!**/*.tsbuildinfo"
+ ],
+ "exports": {
+ ".": {
+ "types": "./src/index.d.ts",
+ "import": "./dist/src/index.js"
+ }
+ },
+ "eslintConfig": {
+ "extends": "ipfs",
+ "parserOptions": {
+ "sourceType": "module"
+ }
+ },
+ "release": {
+ "branches": [
+ "master"
+ ],
+ "plugins": [
+ [
+ "@semantic-release/commit-analyzer",
+ {
+ "preset": "conventionalcommits",
+ "releaseRules": [
+ {
+ "breaking": true,
+ "release": "major"
+ },
+ {
+ "revert": true,
+ "release": "patch"
+ },
+ {
+ "type": "feat",
+ "release": "minor"
+ },
+ {
+ "type": "fix",
+ "release": "patch"
+ },
+ {
+ "type": "docs",
+ "release": "patch"
+ },
+ {
+ "type": "test",
+ "release": "patch"
+ },
+ {
+ "type": "deps",
+ "release": "patch"
+ },
+ {
+ "scope": "no-release",
+ "release": false
+ }
+ ]
+ }
+ ],
+ [
+ "@semantic-release/release-notes-generator",
+ {
+ "preset": "conventionalcommits",
+ "presetConfig": {
+ "types": [
+ {
+ "type": "feat",
+ "section": "Features"
+ },
+ {
+ "type": "fix",
+ "section": "Bug Fixes"
+ },
+ {
+ "type": "chore",
+ "section": "Trivial Changes"
+ },
+ {
+ "type": "docs",
+ "section": "Documentation"
+ },
+ {
+ "type": "deps",
+ "section": "Dependencies"
+ },
+ {
+ "type": "test",
+ "section": "Tests"
+ }
+ ]
+ }
+ }
+ ],
+ "@semantic-release/changelog",
+ "@semantic-release/npm",
+ "@semantic-release/github",
+ "@semantic-release/git"
+ ]
+ },
+ "scripts": {
+ "clean": "aegir clean",
+ "lint": "aegir lint",
+ "dep-check": "aegir dep-check",
+ "build": "aegir build",
+ "test": "aegir test",
+ "test:chrome": "aegir test -t browser --cov",
+ "test:chrome-webworker": "aegir test -t webworker",
+ "test:firefox": "aegir test -t browser -- --browser firefox",
+ "test:firefox-webworker": "aegir test -t webworker -- --browser firefox",
+ "test:node": "aegir test -t node --cov",
+ "test:electron-main": "aegir test -t electron-main",
+ "release": "aegir release",
+ "docs": "aegir docs"
},
- "homepage": "https://github.com/libp2p/js-libp2p-keychain#readme",
"dependencies": {
- "err-code": "^2.0.0",
- "interface-datastore": "^1.0.2",
- "libp2p-crypto": "^0.17.1",
- "merge-options": "^2.0.0",
- "node-forge": "^0.9.1",
- "sanitize-filename": "^1.6.1"
+ "@libp2p/crypto": "^1.0.11",
+ "@libp2p/interface-keychain": "^2.0.3",
+ "@libp2p/interface-peer-id": "^2.0.1",
+ "@libp2p/logger": "^2.0.5",
+ "@libp2p/peer-id": "^2.0.1",
+ "err-code": "^3.0.1",
+ "interface-datastore": "^7.0.3",
+ "merge-options": "^3.0.4",
+ "sanitize-filename": "^1.6.3",
+ "uint8arrays": "^4.0.3"
},
"devDependencies": {
- "aegir": "^22.0.0",
- "chai": "^4.2.0",
- "chai-string": "^1.5.0",
- "datastore-fs": "^1.0.0",
- "datastore-level": "^1.0.0",
- "dirty-chai": "^2.0.1",
- "level": "^6.0.0",
- "multihashes": "^0.4.15",
- "peer-id": "^0.13.5",
- "promisify-es6": "^1.0.3",
- "rimraf": "^3.0.0"
- },
- "contributors": [
- "Vasco Santos ",
- "Richard Schneider ",
- "David Dias ",
- "Alan Shaw ",
- "Alex Potsides ",
- "Alberto Elias ",
- "Masahiro Saito ",
- "Maciej Krüger ",
- "Jacob Heun ",
- "Hugo Dias ",
- "Victor Bjelkholm "
- ]
+ "@libp2p/peer-id-factory": "^2.0.1",
+ "aegir": "^38.1.0",
+ "datastore-core": "^8.0.4",
+ "multiformats": "^11.0.1"
+ }
}
diff --git a/src/cms.js b/src/cms.js
deleted file mode 100644
index 9bec4b9..0000000
--- a/src/cms.js
+++ /dev/null
@@ -1,122 +0,0 @@
-'use strict'
-
-require('node-forge/lib/pkcs7')
-require('node-forge/lib/pbe')
-const forge = require('node-forge/lib/forge')
-const { certificateForKey, findAsync } = require('./util')
-const errcode = require('err-code')
-
-/**
- * Cryptographic Message Syntax (aka PKCS #7)
- *
- * CMS describes an encapsulation syntax for data protection. It
- * is used to digitally sign, digest, authenticate, or encrypt
- * arbitrary message content.
- *
- * See RFC 5652 for all the details.
- */
-class CMS {
- /**
- * Creates a new instance with a keychain
- *
- * @param {Keychain} keychain - the available keys
- */
- constructor (keychain) {
- if (!keychain) {
- throw errcode(new Error('keychain is required'), 'ERR_KEYCHAIN_REQUIRED')
- }
-
- this.keychain = keychain
- }
-
- /**
- * Creates some protected data.
- *
- * The output Buffer contains the PKCS #7 message in DER.
- *
- * @param {string} name - The local key name.
- * @param {Buffer} plain - The data to encrypt.
- * @returns {undefined}
- */
- async encrypt (name, plain) {
- if (!Buffer.isBuffer(plain)) {
- throw errcode(new Error('Plain data must be a Buffer'), 'ERR_INVALID_PARAMS')
- }
-
- const key = await this.keychain.findKeyByName(name)
- const pem = await this.keychain._getPrivateKey(name)
- const privateKey = forge.pki.decryptRsaPrivateKey(pem, this.keychain._())
- const certificate = await certificateForKey(key, privateKey)
-
- // create a p7 enveloped message
- const p7 = forge.pkcs7.createEnvelopedData()
- p7.addRecipient(certificate)
- p7.content = forge.util.createBuffer(plain)
- p7.encrypt()
-
- // convert message to DER
- const der = forge.asn1.toDer(p7.toAsn1()).getBytes()
- return Buffer.from(der, 'binary')
- }
-
- /**
- * Reads some protected data.
- *
- * 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'. It is array of key ids.
- *
- * @param {Buffer} cmsData - The CMS encrypted data to decrypt.
- * @returns {undefined}
- */
- async decrypt (cmsData) {
- if (!Buffer.isBuffer(cmsData)) {
- throw errcode(new Error('CMS data is required'), 'ERR_INVALID_PARAMS')
- }
-
- let cms
- try {
- const buf = forge.util.createBuffer(cmsData.toString('binary'))
- const obj = forge.asn1.fromDer(buf)
- cms = forge.pkcs7.messageFromAsn1(obj)
- } catch (err) {
- throw errcode(new Error('Invalid CMS: ' + err.message), 'ERR_INVALID_CMS')
- }
-
- // Find a recipient whose key we hold. We only deal with recipient certs
- // issued by ipfs (O=ipfs).
- const recipients = cms.recipients
- .filter(r => r.issuer.find(a => a.shortName === 'O' && a.value === 'ipfs'))
- .filter(r => r.issuer.find(a => a.shortName === 'CN'))
- .map(r => {
- return {
- recipient: r,
- keyId: r.issuer.find(a => a.shortName === 'CN').value
- }
- })
-
- const r = await findAsync(recipients, async (recipient) => {
- try {
- const key = await this.keychain.findKeyById(recipient.keyId)
- if (key) return true
- } catch (err) {
- return false
- }
- return false
- })
-
- if (!r) {
- const missingKeys = recipients.map(r => r.keyId)
- throw errcode(new Error('Decryption needs one of the key(s): ' + missingKeys.join(', ')), 'ERR_MISSING_KEYS', {
- missingKeys
- })
- }
-
- const key = await this.keychain.findKeyById(r.keyId)
- const pem = await this.keychain._getPrivateKey(key.name)
- const privateKey = forge.pki.decryptRsaPrivateKey(pem, this.keychain._())
- cms.decrypt(r.recipient, privateKey)
- return Buffer.from(cms.content.getBytes(), 'binary')
- }
-}
-
-module.exports = CMS
diff --git a/src/errors.ts b/src/errors.ts
new file mode 100644
index 0000000..791d87f
--- /dev/null
+++ b/src/errors.ts
@@ -0,0 +1,18 @@
+
+export enum codes {
+ ERR_INVALID_PARAMETERS = 'ERR_INVALID_PARAMETERS',
+ ERR_INVALID_KEY_NAME = 'ERR_INVALID_KEY_NAME',
+ ERR_INVALID_KEY_TYPE = 'ERR_INVALID_KEY_TYPE',
+ ERR_KEY_ALREADY_EXISTS = 'ERR_KEY_ALREADY_EXISTS',
+ ERR_INVALID_KEY_SIZE = 'ERR_INVALID_KEY_SIZE',
+ ERR_KEY_NOT_FOUND = 'ERR_KEY_NOT_FOUND',
+ ERR_OLD_KEY_NAME_INVALID = 'ERR_OLD_KEY_NAME_INVALID',
+ ERR_NEW_KEY_NAME_INVALID = 'ERR_NEW_KEY_NAME_INVALID',
+ ERR_PASSWORD_REQUIRED = 'ERR_PASSWORD_REQUIRED',
+ ERR_PEM_REQUIRED = 'ERR_PEM_REQUIRED',
+ ERR_CANNOT_READ_KEY = 'ERR_CANNOT_READ_KEY',
+ ERR_MISSING_PRIVATE_KEY = 'ERR_MISSING_PRIVATE_KEY',
+ ERR_INVALID_OLD_PASS_TYPE = 'ERR_INVALID_OLD_PASS_TYPE',
+ ERR_INVALID_NEW_PASS_TYPE = 'ERR_INVALID_NEW_PASS_TYPE',
+ ERR_INVALID_PASS_LENGTH = 'ERR_INVALID_PASS_LENGTH'
+}
diff --git a/src/index.js b/src/index.js
deleted file mode 100644
index 2704d62..0000000
--- a/src/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-'use strict'
-
-module.exports = require('./keychain')
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..e21269a
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,577 @@
+/* eslint max-nested-callbacks: ["error", 5] */
+
+import { logger } from '@libp2p/logger'
+import sanitize from 'sanitize-filename'
+import mergeOptions from 'merge-options'
+import { Key } from 'interface-datastore/key'
+import errCode from 'err-code'
+import { codes } from './errors.js'
+import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
+import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
+import { generateKeyPair, importKey, unmarshalPrivateKey } from '@libp2p/crypto/keys'
+import type { PeerId } from '@libp2p/interface-peer-id'
+import { pbkdf2, randomBytes } from '@libp2p/crypto'
+import type { Datastore } from 'interface-datastore'
+import { peerIdFromKeys } from '@libp2p/peer-id'
+import type { KeyChain, KeyInfo, KeyType } from '@libp2p/interface-keychain'
+
+const log = logger('libp2p:keychain')
+
+export interface DEKConfig {
+ hash: string
+ salt: string
+ iterationCount: number
+ keyLength: number
+}
+
+export interface KeyChainInit {
+ pass?: string
+ dek?: DEKConfig
+}
+
+const keyPrefix = '/pkcs8/'
+const infoPrefix = '/info/'
+const privates = new WeakMap