fix: types from ipfs integration (#832)

This commit is contained in:
Vasco Santos
2020-12-11 17:53:37 +01:00
committed by Vasco Santos
parent 408868655c
commit 9ae1b758e9
4 changed files with 66 additions and 35 deletions

View File

@ -70,7 +70,7 @@
"it-pipe": "^1.1.0", "it-pipe": "^1.1.0",
"it-protocol-buffers": "^0.2.0", "it-protocol-buffers": "^0.2.0",
"libp2p-crypto": "^0.18.0", "libp2p-crypto": "^0.18.0",
"libp2p-interfaces": "^0.8.0", "libp2p-interfaces": "^0.8.1",
"libp2p-utils": "^0.2.2", "libp2p-utils": "^0.2.2",
"mafmt": "^8.0.0", "mafmt": "^8.0.0",
"merge-options": "^2.0.0", "merge-options": "^2.0.0",

View File

@ -1,4 +1,3 @@
// @ts-nocheck
'use strict' 'use strict'
require('node-forge/lib/pkcs7') require('node-forge/lib/pkcs7')
@ -9,6 +8,8 @@ const errcode = require('err-code')
const uint8ArrayFromString = require('uint8arrays/from-string') const uint8ArrayFromString = require('uint8arrays/from-string')
const uint8ArrayToString = require('uint8arrays/to-string') const uint8ArrayToString = require('uint8arrays/to-string')
const privates = new WeakMap()
/** /**
* Cryptographic Message Syntax (aka PKCS #7) * Cryptographic Message Syntax (aka PKCS #7)
* *
@ -23,13 +24,15 @@ class CMS {
* Creates a new instance with a keychain * Creates a new instance with a keychain
* *
* @param {import('./index')} keychain - the available keys * @param {import('./index')} keychain - the available keys
* @param {string} dek
*/ */
constructor (keychain) { constructor (keychain, dek) {
if (!keychain) { if (!keychain) {
throw errcode(new Error('keychain is required'), 'ERR_KEYCHAIN_REQUIRED') throw errcode(new Error('keychain is required'), 'ERR_KEYCHAIN_REQUIRED')
} }
this.keychain = keychain this.keychain = keychain
privates.set(this, { dek })
} }
/** /**
@ -48,7 +51,9 @@ class CMS {
const key = await this.keychain.findKeyByName(name) const key = await this.keychain.findKeyByName(name)
const pem = await this.keychain._getPrivateKey(name) const pem = await this.keychain._getPrivateKey(name)
const privateKey = forge.pki.decryptRsaPrivateKey(pem, this.keychain._()) /** @type {string} */
const dek = privates.get(this).dek
const privateKey = forge.pki.decryptRsaPrivateKey(pem, dek)
const certificate = await certificateForKey(key, privateKey) const certificate = await certificateForKey(key, privateKey)
// create a p7 enveloped message // create a p7 enveloped message
@ -115,8 +120,14 @@ class CMS {
} }
const key = await this.keychain.findKeyById(r.keyId) const key = await this.keychain.findKeyById(r.keyId)
if (!key) {
throw errcode(new Error('No key available to decrypto'), 'ERR_NO_KEY')
}
const pem = await this.keychain._getPrivateKey(key.name) const pem = await this.keychain._getPrivateKey(key.name)
const privateKey = forge.pki.decryptRsaPrivateKey(pem, this.keychain._()) const dek = privates.get(this).dek
const privateKey = forge.pki.decryptRsaPrivateKey(pem, dek)
cms.decrypt(r.recipient, privateKey) cms.decrypt(r.recipient, privateKey)
return uint8ArrayFromString(cms.content.getBytes(), 'ascii') return uint8ArrayFromString(cms.content.getBytes(), 'ascii')
} }

View File

@ -1,11 +1,10 @@
// @ts-nocheck
/* eslint max-nested-callbacks: ["error", 5] */ /* eslint max-nested-callbacks: ["error", 5] */
'use strict' 'use strict'
const sanitize = require('sanitize-filename') const sanitize = require('sanitize-filename')
const mergeOptions = require('merge-options') const mergeOptions = require('merge-options')
const crypto = require('libp2p-crypto') const crypto = require('libp2p-crypto')
const DS = require('interface-datastore') const Datastore = require('interface-datastore')
const CMS = require('./cms') const CMS = require('./cms')
const errcode = require('err-code') const errcode = require('err-code')
const { Number } = require('ipfs-utils/src/globalthis') const { Number } = require('ipfs-utils/src/globalthis')
@ -14,8 +13,14 @@ const uint8ArrayFromString = require('uint8arrays/from-string')
require('node-forge/lib/sha512') require('node-forge/lib/sha512')
/**
* @typedef {import('peer-id')} PeerId
* @typedef {import('interface-datastore/src/key')} Key
*/
const keyPrefix = '/pkcs8/' const keyPrefix = '/pkcs8/'
const infoPrefix = '/info/' const infoPrefix = '/info/'
const privates = new WeakMap()
// NIST SP 800-132 // NIST SP 800-132
const NIST = { const NIST = {
@ -46,7 +51,8 @@ function validateKeyName (name) {
* This assumes than an error indicates that the keychain is under attack. Delay returning an * This assumes than an error indicates that the keychain is under attack. Delay returning an
* error to make brute force attacks harder. * error to make brute force attacks harder.
* *
* @param {string | Error} err - The error * @param {string|Error} err - The error
* @returns {Promise<never>}
* @private * @private
*/ */
async function throwDelayed (err) { async function throwDelayed (err) {
@ -62,29 +68,28 @@ async function throwDelayed (err) {
* Converts a key name into a datastore name. * Converts a key name into a datastore name.
* *
* @param {string} name * @param {string} name
* @returns {DS.Key} * @returns {Key}
* @private * @private
*/ */
function DsName (name) { function DsName (name) {
return new DS.Key(keyPrefix + name) return new Datastore.Key(keyPrefix + name)
} }
/** /**
* Converts a key name into a datastore info name. * Converts a key name into a datastore info name.
* *
* @param {string} name * @param {string} name
* @returns {DS.Key} * @returns {Key}
* @private * @private
*/ */
function DsInfoName (name) { function DsInfoName (name) {
return new DS.Key(infoPrefix + name) return new Datastore.Key(infoPrefix + name)
} }
/** /**
* Information about a key. * Information about a key.
* *
* @typedef {Object} KeyInfo * @typedef {Object} KeyInfo
*
* @property {string} id - The universally unique key id. * @property {string} id - The universally unique key id.
* @property {string} name - The local key name. * @property {string} name - The local key name.
*/ */
@ -101,7 +106,7 @@ class Keychain {
/** /**
* Creates a new instance of a key chain. * Creates a new instance of a key chain.
* *
* @param {DS} store - where the key are. * @param {Datastore} store - where the key are.
* @param {object} options * @param {object} options
* @class * @class
*/ */
@ -134,7 +139,7 @@ class Keychain {
this.opts.dek.keyLength, this.opts.dek.keyLength,
this.opts.dek.hash) : '' this.opts.dek.hash) : ''
Object.defineProperty(this, '_', { value: () => dek }) privates.set(this, { dek })
} }
/** /**
@ -148,13 +153,13 @@ class Keychain {
* @returns {CMS} * @returns {CMS}
*/ */
get cms () { get cms () {
return new CMS(this) return new CMS(this, privates.get(this).dek)
} }
/** /**
* Generates the options for a keychain. A random salt is produced. * Generates the options for a keychain. A random salt is produced.
* *
* @returns {object} * @returns {Object}
*/ */
static generateOptions () { static generateOptions () {
const options = Object.assign({}, defaultOptions) const options = Object.assign({}, defaultOptions)
@ -167,7 +172,7 @@ class Keychain {
* Gets an object that can encrypt/decrypt protected data. * Gets an object that can encrypt/decrypt protected data.
* The default options for a keychain. * The default options for a keychain.
* *
* @returns {object} * @returns {Object}
*/ */
static get options () { static get options () {
return defaultOptions return defaultOptions
@ -178,10 +183,10 @@ class Keychain {
* *
* @param {string} name - The local key name; cannot already exist. * @param {string} name - The local key name; cannot already exist.
* @param {string} type - One of the key types; 'rsa'. * @param {string} type - One of the key types; 'rsa'.
* @param {int} [size] - The key size in bits. Used for rsa keys only. * @param {number} [size = 2048] - The key size in bits. Used for rsa keys only.
* @returns {KeyInfo} * @returns {Promise<KeyInfo>}
*/ */
async createKey (name, type, size) { async createKey (name, type, size = 2048) {
const self = this const self = this
if (!validateKeyName(name) || name === 'self') { if (!validateKeyName(name) || name === 'self') {
@ -208,9 +213,12 @@ class Keychain {
let keyInfo let keyInfo
try { try {
// @ts-ignore Differences between several crypto return types need to be fixed in libp2p-crypto
const keypair = await crypto.keys.generateKeyPair(type, size) const keypair = await crypto.keys.generateKeyPair(type, size)
const kid = await keypair.id() const kid = await keypair.id()
const pem = await keypair.export(this._()) /** @type {string} */
const dek = privates.get(this).dek
const pem = await keypair.export(dek)
keyInfo = { keyInfo = {
name: name, name: name,
id: kid id: kid
@ -230,7 +238,7 @@ class Keychain {
/** /**
* List all the keys. * List all the keys.
* *
* @returns {KeyInfo[]} * @returns {Promise<KeyInfo[]>}
*/ */
async listKeys () { async listKeys () {
const self = this const self = this
@ -250,7 +258,7 @@ class Keychain {
* Find a key by it's id. * Find a key by it's id.
* *
* @param {string} id - The universally unique key identifier. * @param {string} id - The universally unique key identifier.
* @returns {KeyInfo} * @returns {Promise<KeyInfo|undefined>}
*/ */
async findKeyById (id) { async findKeyById (id) {
try { try {
@ -265,7 +273,7 @@ class Keychain {
* Find a key by it's name. * Find a key by it's name.
* *
* @param {string} name - The local key name. * @param {string} name - The local key name.
* @returns {KeyInfo} * @returns {Promise<KeyInfo>}
*/ */
async findKeyByName (name) { async findKeyByName (name) {
if (!validateKeyName(name)) { if (!validateKeyName(name)) {
@ -285,7 +293,7 @@ class Keychain {
* Remove an existing key. * Remove an existing key.
* *
* @param {string} name - The local key name; must already exist. * @param {string} name - The local key name; must already exist.
* @returns {KeyInfo} * @returns {Promise<KeyInfo>}
*/ */
async removeKey (name) { async removeKey (name) {
const self = this const self = this
@ -306,7 +314,7 @@ class Keychain {
* *
* @param {string} oldName - The old local key name; must already exist. * @param {string} oldName - The old local key name; must already exist.
* @param {string} newName - The new local key name; must not already exist. * @param {string} newName - The new local key name; must not already exist.
* @returns {KeyInfo} * @returns {Promise<KeyInfo>}
*/ */
async renameKey (oldName, newName) { async renameKey (oldName, newName) {
const self = this const self = this
@ -347,7 +355,7 @@ class Keychain {
* *
* @param {string} name - The local key name; must already exist. * @param {string} name - The local key name; must already exist.
* @param {string} password - The password * @param {string} password - The password
* @returns {string} * @returns {Promise<string>}
*/ */
async exportKey (name, password) { async exportKey (name, password) {
if (!validateKeyName(name)) { if (!validateKeyName(name)) {
@ -361,7 +369,9 @@ class Keychain {
try { try {
const res = await this.store.get(dsname) const res = await this.store.get(dsname)
const pem = uint8ArrayToString(res) const pem = uint8ArrayToString(res)
const privateKey = await crypto.keys.import(pem, this._()) /** @type {string} */
const dek = privates.get(this).dek
const privateKey = await crypto.keys.import(pem, dek)
return privateKey.export(password) return privateKey.export(password)
} catch (err) { } catch (err) {
return throwDelayed(err) return throwDelayed(err)
@ -374,7 +384,7 @@ class Keychain {
* @param {string} name - The local key name; must not already exist. * @param {string} name - The local key name; must not already exist.
* @param {string} pem - The PEM encoded PKCS #8 string * @param {string} pem - The PEM encoded PKCS #8 string
* @param {string} password - The password. * @param {string} password - The password.
* @returns {KeyInfo} * @returns {Promise<KeyInfo>}
*/ */
async importKey (name, pem, password) { async importKey (name, pem, password) {
const self = this const self = this
@ -398,7 +408,9 @@ class Keychain {
let kid let kid
try { try {
kid = await privateKey.id() kid = await privateKey.id()
pem = await privateKey.export(this._()) /** @type {string} */
const dek = privates.get(this).dek
pem = await privateKey.export(dek)
} catch (err) { } catch (err) {
return throwDelayed(err) return throwDelayed(err)
} }
@ -415,6 +427,13 @@ class Keychain {
return keyInfo return keyInfo
} }
/**
* Import a peer key
*
* @param {string} name - The local key name; must not already exist.
* @param {PeerId} peer - The PEM encoded PKCS #8 string
* @returns {Promise<KeyInfo>}
*/
async importPeer (name, peer) { async importPeer (name, peer) {
const self = this const self = this
if (!validateKeyName(name)) { if (!validateKeyName(name)) {
@ -431,7 +450,9 @@ class Keychain {
try { try {
const kid = await privateKey.id() const kid = await privateKey.id()
const pem = await privateKey.export(this._()) /** @type {string} */
const dek = privates.get(this).dek
const pem = await privateKey.export(dek)
const keyInfo = { const keyInfo = {
name: name, name: name,
id: kid id: kid
@ -450,8 +471,7 @@ class Keychain {
* Gets the private key as PEM encoded PKCS #8 string. * Gets the private key as PEM encoded PKCS #8 string.
* *
* @param {string} name * @param {string} name
* @returns {string} * @returns {Promise<string>}
* @private
*/ */
async _getPrivateKey (name) { async _getPrivateKey (name) {
if (!validateKeyName(name)) { if (!validateKeyName(name)) {

View File

@ -73,7 +73,7 @@ class PeerRouting {
/** /**
* Iterates over all peer routers in series to find the given peer. * Iterates over all peer routers in series to find the given peer.
* *
* @param {string} id - The id of the peer to find * @param {PeerId} id - The id of the peer to find
* @param {object} [options] * @param {object} [options]
* @param {number} [options.timeout] - How long the query should run * @param {number} [options.timeout] - How long the query should run
* @returns {Promise<{ id: PeerId, multiaddrs: Multiaddr[] }>} * @returns {Promise<{ id: PeerId, multiaddrs: Multiaddr[] }>}