diff --git a/build/tasks/test.js b/build/tasks/test.js
index b407dac7c0..cbf0348489 100644
--- a/build/tasks/test.js
+++ b/build/tasks/test.js
@@ -92,8 +92,8 @@ gulp.task('clean-up', () => {
gulp.task('docker-clean', shell.task([
// stop and remove chaincode docker instances
- 'docker kill $(docker ps | grep "dev-" | awk \'{print $1}\')',
- 'docker rm $(docker ps -a | grep "dev-" | awk \'{print $1}\')',
+ 'docker kill $(docker ps -aq)',
+ 'docker rm $(docker ps -aq) -f',
// remove chaincode images so that they get rebuilt during test
'docker rmi $(docker images | grep "^dev-" | awk \'{print $3}\')',
@@ -103,7 +103,7 @@ gulp.task('docker-clean', shell.task([
'docker-compose -f test/fixtures/docker-compose/docker-compose-tls.yaml -p node down'
], {
verbose: true, // so we can see the docker command output
- ignoreErrors: true // kill and rm may fail because the containers may have been cleaned up
+ ignoreErrors: true // kill, rm, and rmi may fail because the containers may have been cleaned up or not exist
}));
gulp.task('docker-ready', ['docker-clean'], shell.task([
@@ -294,10 +294,6 @@ gulp.task('run-tape-e2e', ['docker-ready'],
// Typescript
'test/typescript/test.js',
-
- // Perf
- 'test/integration/perf/orderer.js',
- 'test/integration/perf/peer.js'
]))
.pipe(tape({
reporter: tapColorize()
diff --git a/fabric-ca-client/lib/FabricCAServices.js b/fabric-ca-client/lib/FabricCAServices.js
index b1ea35c1a0..ad228b23cc 100644
--- a/fabric-ca-client/lib/FabricCAServices.js
+++ b/fabric-ca-client/lib/FabricCAServices.js
@@ -198,12 +198,7 @@ const FabricCAServices = class extends BaseClient {
}
}
- let opts;
- if (this.getCryptoSuite()._cryptoKeyStore) {
- opts = {ephemeral: false};
- } else {
- opts = {ephemeral: true};
- }
+ const storeKey = this.getCryptoSuite()._cryptoKeyStore ? true : false;
try {
let csr;
@@ -213,7 +208,11 @@ const FabricCAServices = class extends BaseClient {
csr = req.csr;
} else {
try {
- privateKey = await this.getCryptoSuite().generateKey(opts);
+ if (storeKey) {
+ privateKey = await this.getCryptoSuite().generateKey();
+ } else {
+ privateKey = this.getCryptoSuite().generateEphemeralKey();
+ }
logger.debug('successfully generated key pairs');
} catch (err) {
throw new Error(util.format('Failed to generate key for enrollment due to error [%s]', err));
diff --git a/fabric-ca-client/test/FabricCAServices.js b/fabric-ca-client/test/FabricCAServices.js
index 69cff28358..3315312e2b 100644
--- a/fabric-ca-client/test/FabricCAServices.js
+++ b/fabric-ca-client/test/FabricCAServices.js
@@ -219,6 +219,7 @@ describe('FabricCAServices', () => {
service = new FabricCAServicesRewire('http://penguin.com', null, 'ca_name', cryptoPrimitives);
clientMock = sinon.createStubInstance(FabricCAClient);
service._fabricCAClient = clientMock;
+ cryptoPrimitives._cryptoKeyStore = false;
});
it('should throw if missing required argument "request"', async () => {
@@ -252,7 +253,7 @@ describe('FabricCAServices', () => {
const keyStub = sinon.createStubInstance(ECDSAKey);
keyStub.generateCSR.returns('CN=penguin');
- cryptoPrimitives.generateKey.resolves(keyStub);
+ cryptoPrimitives.generateEphemeralKey.returns(keyStub);
// Take control of the enroll
clientMock.enroll.rejects(new Error('enroll error'));
@@ -271,6 +272,7 @@ describe('FabricCAServices', () => {
const keyStub = sinon.createStubInstance(ECDSAKey);
keyStub.generateCSR.throws(new Error('CSR error'));
cryptoPrimitives.generateKey.resolves(keyStub);
+ cryptoPrimitives.generateEphemeralKey.returns(keyStub);
const atts = [{name: 'penguin'}, {name: 'power'}];
const req = {enrollmentID: 'enrollmentID', enrollmentSecret: 'enrollmentSecret', profile: 'profile', attr_reqs: atts};
@@ -283,7 +285,7 @@ describe('FabricCAServices', () => {
getSubjectCommonNameStub.returns('mr_penguin');
normalizeX509Stub.returns('normal');
- cryptoPrimitives.generateKey.rejects(new Error('Key error'));
+ cryptoPrimitives.generateEphemeralKey.throws(new Error('Key error'));
const atts = [{name: 'penguin'}, {name: 'power'}];
const req = {enrollmentID: 'enrollmentID', enrollmentSecret: 'enrollmentSecret', profile: 'profile', attr_reqs: atts};
@@ -319,9 +321,8 @@ describe('FabricCAServices', () => {
const req = {enrollmentID: 'enrollmentID', enrollmentSecret: 'enrollmentSecret', profile: 'profile', attr_reqs: atts};
await service.enroll(req);
- // Opts should contain false
- const callArgs = newSuite.generateKey.getCall(0);
- callArgs.args[0].should.deep.equal({ephemeral: false});
+ // should call generateKey, not generateEphemeral
+ sinon.assert.called(newSuite.generateKey);
});
@@ -333,6 +334,7 @@ describe('FabricCAServices', () => {
const keyStub = sinon.createStubInstance(ECDSAKey);
keyStub.generateCSR.returns('CN=penguin');
cryptoPrimitives.generateKey.resolves(keyStub);
+ cryptoPrimitives._cryptoKeyStore = true;
// Take control of the enroll
clientMock.enroll.resolves({
@@ -343,9 +345,8 @@ describe('FabricCAServices', () => {
const req = {enrollmentID: 'enrollmentID', enrollmentSecret: 'enrollmentSecret', profile: 'profile', attr_reqs: atts};
await service.enroll(req);
- // generateKey should be called with ephmereal set to true
- const genKeyArgs = cryptoPrimitives.generateKey.getCall(0);
- genKeyArgs.args[0].should.deep.equal({ephemeral: true});
+ // generateKey should be called
+ sinon.assert.calledOnce(cryptoPrimitives.generateKey);
// Enrol should be called with test values
sinon.assert.calledOnce(clientMock.enroll);
@@ -367,6 +368,7 @@ describe('FabricCAServices', () => {
const keyStub = sinon.createStubInstance(ECDSAKey);
keyStub.generateCSR.returns('CN=penguin');
cryptoPrimitives.generateKey.resolves(keyStub);
+ cryptoPrimitives._cryptoKeyStore = true;
// Take control of the enroll
clientMock.enroll.resolves({
diff --git a/fabric-client/lib/BaseClient.js b/fabric-client/lib/BaseClient.js
index c1918fdfee..5d9fc3b371 100644
--- a/fabric-client/lib/BaseClient.js
+++ b/fabric-client/lib/BaseClient.js
@@ -73,12 +73,13 @@ const BaseClient = class {
* This can be overriden with a configuration setting key-value-store
, the value of which is the
* full path of a CommonJS module for the alternative implementation.
*
+ * @async
* @param {Object} options Specific to the implementation, for initializing the instance. For the built-in
* file-based implementation, this requires a single property path
to the top-level folder for the store
* @returns {Promise} A Promise for a {@link module:api.KeyValueStore} instance of the KeyValueStore implementation
*/
- static newDefaultKeyValueStore(options) {
- return sdkUtils.newKeyValueStore(options);
+ static async newDefaultKeyValueStore(options) {
+ return await sdkUtils.newKeyValueStore(options);
}
/**
diff --git a/fabric-client/lib/Channel.js b/fabric-client/lib/Channel.js
index 7418a3747b..c630afd89d 100644
--- a/fabric-client/lib/Channel.js
+++ b/fabric-client/lib/Channel.js
@@ -3704,7 +3704,7 @@ const Channel = class {
* @returns {boolean} A boolean value of true when both the identity and
* the signature are valid, false otherwise.
*/
- verifyProposalResponse(proposal_response) {
+ async verifyProposalResponse(proposal_response) {
logger.debug('verifyProposalResponse - start');
if (!proposal_response) {
throw new Error('Missing proposal response');
@@ -3730,7 +3730,7 @@ const Channel = class {
logger.debug('verifyProposalResponse - found endorser\'s MSP');
try {
- identity = msp.deserializeIdentity(endorsement.endorser, false);
+ identity = await msp.deserializeIdentity(endorsement.endorser, false);
if (!identity) {
throw new Error('Unable to find the endorser identity');
}
diff --git a/fabric-client/lib/Client.js b/fabric-client/lib/Client.js
index 65f5cc59cb..dc3c46f5e4 100644
--- a/fabric-client/lib/Client.js
+++ b/fabric-client/lib/Client.js
@@ -106,12 +106,13 @@ const Client = class extends BaseClient {
/**
* Load a common connection profile object or load a JSON file and return a Client object.
*
+ * @async
* @param {object | string} loadConfig - This may be the config object or a path to the configuration file
* @return {Client} An instance of this class initialized with the network end points.
*/
- static loadFromConfig(loadConfig) {
+ static async loadFromConfig(loadConfig) {
const client = new Client();
- client.loadFromConfig(loadConfig);
+ await client.loadFromConfig(loadConfig);
return client;
}
@@ -119,9 +120,10 @@ const Client = class extends BaseClient {
* Load a common connection profile object or load a JSON file and update this client with
* any values in the config.
*
+ * @async
* @param {object | string} config - This may be the config object or a path to the configuration file
*/
- loadFromConfig(loadConfig) {
+ async loadFromConfig(loadConfig) {
const additional_network_config = _getNetworkConfig(loadConfig, this);
if (!this._network_config) {
this._network_config = additional_network_config;
@@ -129,7 +131,7 @@ const Client = class extends BaseClient {
this._network_config.mergeSettings(additional_network_config);
}
if (this._network_config.hasClient()) {
- this._setAdminFromConfig();
+ await this._setAdminFromConfig();
this._setMspidFromConfig();
this._addConnectionOptionsFromConfig();
}
@@ -889,6 +891,7 @@ const Client = class extends BaseClient {
* Queries the target peer for a list of {@link Peer} objects of all peers
* known by the target peer.
*
+ * @async
* @param {PeerQueryRequest} request - The request parameters.
* @returns {PeerQueryResponse} The list of peer information
*/
@@ -941,6 +944,7 @@ const Client = class extends BaseClient {
* Queries the target peer for the names of all the channels that a
* peer has joined.
*
+ * @async
* @param {Peer} peer - The target peer to send the query
* @param {boolean} useAdmin - Optional. Indicates that the admin credentials
* should be used in making this call to the peer. An administrative
@@ -1015,6 +1019,7 @@ const Client = class extends BaseClient {
/**
* Queries the installed chaincodes on a peer.
*
+ * @async
* @param {Peer} peer - The target peer
* @param {boolean} useAdmin - Optional. Indicates that the admin credentials
* should be used in making this call to the peer. An administrative
@@ -1124,6 +1129,7 @@ const Client = class extends BaseClient {
* performed on a peer-by-peer basis. Only the peer organization's ADMIN
* identities are allowed to perform this operation.
*
+ * @async
* @deprecated
* @param {Deprecated_ChaincodeInstallRequest} request - The request object
* @param {Number} timeout - A number indicating milliseconds to wait on the
@@ -1228,8 +1234,6 @@ const Client = class extends BaseClient {
* from the common connection profile along with the system configuration to build
* instances of the stores and assign them to this client and the crypto suites
* if needed.
- *
- * @returns {Promise} - A promise to build a key value store and crypto store.
*/
async initCredentialStores() {
if (!this._network_config) {
@@ -1241,9 +1245,9 @@ const Client = class extends BaseClient {
this.setStateStore(key_value_store);
const crypto_suite = BaseClient.newCryptoSuite();
// all crypto suites should extends api.CryptoSuite
- crypto_suite.setCryptoKeyStore(BaseClient.newCryptoKeyStore(client_config.credentialStore.cryptoStore));
+ const cryptoStore = BaseClient.newCryptoKeyStore(client_config.credentialStore.cryptoStore);
+ crypto_suite.setCryptoKeyStore(cryptoStore);
this.setCryptoSuite(crypto_suite);
- return true;
} else {
throw new Error('No credentialStore settings found');
}
@@ -1305,11 +1309,13 @@ const Client = class extends BaseClient {
* Set the admin signing identity object. This method will only assign a
* signing identity for use by this client instance and will not persist
* the identity.
+ *
+ * @async
* @param {string} private_key - the private key PEM string
* @param {string} certificate the PEM-encoded string of certificate
* @param {string} mspid The Member Service Provider id for the local signing identity
*/
- setAdminSigningIdentity(private_key, certificate, mspid) {
+ async setAdminSigningIdentity(private_key, certificate, mspid) {
logger.debug('setAdminSigningIdentity - start mspid:%s', mspid);
if (typeof private_key === 'undefined' || private_key === null || private_key === '') {
throw new Error('Invalid parameter. Must have a valid private key.');
@@ -1324,8 +1330,8 @@ const Client = class extends BaseClient {
if (!crypto_suite) {
crypto_suite = BaseClient.newCryptoSuite();
}
- const key = crypto_suite.importKey(private_key, {ephemeral: true});
- const public_key = crypto_suite.importKey(certificate, {ephemeral: true});
+ const key = await crypto_suite.createKeyFromRaw(private_key);
+ const public_key = await crypto_suite.createKeyFromRaw(certificate);
this._adminSigningIdentity = new SigningIdentity(certificate, public_key, mspid, crypto_suite, new Signer(crypto_suite, key));
}
@@ -1336,7 +1342,7 @@ const Client = class extends BaseClient {
* be must loaded that defines an organization for this client and have an
* admin credentials defined.
*/
- _setAdminFromConfig() {
+ async _setAdminFromConfig() {
let admin_key, admin_cert, mspid = null;
if (!this._network_config) {
throw new Error('No common connection profile has been loaded');
@@ -1353,7 +1359,7 @@ const Client = class extends BaseClient {
}
// if we found all we need then set the admin
if (admin_key && admin_cert && mspid) {
- this.setAdminSigningIdentity(admin_key, admin_cert, mspid);
+ await this.setAdminSigningIdentity(admin_key, admin_cert, mspid);
}
}
@@ -1397,6 +1403,7 @@ const Client = class extends BaseClient {
* and the organization in the client section of the common connection profile
* settings.
*
+ * @async
* @param {Object} opts - contains
* - username [required] - username of the user
* - password [optional] - password of the user
@@ -1463,6 +1470,7 @@ const Client = class extends BaseClient {
/**
* Persist the current userContext
to the key value store.
*
+ * @async
* @returns {Promise} A Promise for the userContext object upon successful persistence
*/
async saveUserToStateStore() {
@@ -1508,6 +1516,7 @@ const Client = class extends BaseClient {
* has been set on the Client instance. If no state store has been set, this cache will not be established
* and the application is responsible for setting the user context again if the application crashes and is recovered.
*
+ * @async
* @param {User | UserNamePasswordObject} user - An instance of the User class encapsulating the authenticated
* user’s signing materials (private key and enrollment certificate).
* The parameter may also be a {@link UserNamePasswordObject} that contains the username
@@ -1553,6 +1562,7 @@ const Client = class extends BaseClient {
* (via the KeyValueStore interface). The loaded user object must represent an enrolled user with a valid
* enrollment certificate signed by a trusted CA (such as the CA server).
*
+ * @async
* @param {string} name - Optional. If not specified, will only return the current in-memory user context object, or null
* if none has been set. If "name" is specified, will also attempt to load it from the state store
* if search in memory failed.
@@ -1609,6 +1619,7 @@ const Client = class extends BaseClient {
/**
* Restore the state of the {@link User} by the given name from the key value store (if found). If not found, return null.
*
+ * @async
* @param {string} name - Name of the user
* @returns {Promise} A Promise for a {User} object upon successful restore, or if the user by the name
* does not exist in the state store, returns null without rejecting the promise
@@ -1671,6 +1682,7 @@ const Client = class extends BaseClient {
* Note that upon successful creation of the new user object, it is set to
* the client instance as the current userContext
.
*
+ * @async
* @param {UserOpts} opts - Essential information about the user
* @returns {Promise} Promise for the user object.
*/
@@ -1699,7 +1711,8 @@ const Client = class extends BaseClient {
if (this.getCryptoSuite() === null) {
logger.debug('cryptoSuite is null, creating default cryptoSuite and cryptoKeyStore');
this.setCryptoSuite(sdkUtils.newCryptoSuite());
- this.getCryptoSuite().setCryptoKeyStore(Client.newCryptoKeyStore()); // This is impossible
+ const cryptoStore = Client.newCryptoKeyStore();
+ this.getCryptoSuite().setCryptoKeyStore(cryptoStore);
} else {
if (this.getCryptoSuite()._cryptoKeyStore) {
logger.debug('cryptoSuite has a cryptoKeyStore');
@@ -1727,9 +1740,9 @@ const Client = class extends BaseClient {
if (privateKeyPEM) {
logger.debug('then privateKeyPEM data');
if (opts.skipPersistence) {
- importedKey = await this.getCryptoSuite().importKey(privateKeyPEM.toString(), {ephemeral: true});
+ importedKey = await this.getCryptoSuite().createKeyFromRaw(privateKeyPEM.toString());
} else {
- importedKey = await this.getCryptoSuite().importKey(privateKeyPEM.toString(), {ephemeral: !this.getCryptoSuite()._cryptoKeyStore});
+ importedKey = await this.getCryptoSuite().importKey(privateKeyPEM.toString());
}
} else {
importedKey = opts.cryptoContent.privateKeyObj;
diff --git a/fabric-client/lib/User.js b/fabric-client/lib/User.js
index 1f30c22196..77b4819937 100644
--- a/fabric-client/lib/User.js
+++ b/fabric-client/lib/User.js
@@ -147,6 +147,8 @@ const User = class {
/**
* Set the enrollment object for this User instance
+ *
+ * @async
* @param {module:api.Key} privateKey the private key object
* @param {string} certificate the PEM-encoded string of certificate
* @param {string} mspId The Member Service Provider id for the local signing identity
@@ -179,7 +181,7 @@ const User = class {
if (this._cryptoSuite._cryptoKeyStore && !skipPersistence) {
pubKey = await this._cryptoSuite.importKey(certificate);
} else {
- pubKey = await this._cryptoSuite.importKey(certificate, {ephemeral: true});
+ pubKey = await this._cryptoSuite.createKeyFromRaw(certificate);
}
this._identity = new Identity(certificate, pubKey, mspId, this._cryptoSuite);
@@ -196,11 +198,13 @@ const User = class {
/**
* Set the current state of this member from a string based JSON object
+ *
+ * @async
* @param {string} str - the member state serialized
* @param {boolean} no_save - to indicate that the cryptoSuite should not save
* @return {Member} Promise of the unmarshalled Member object represented by the serialized string
*/
- fromString(str, no_save) {
+ async fromString(str, no_save) {
logger.debug('fromString --start');
const state = JSON.parse(str);
@@ -223,52 +227,36 @@ const User = class {
this._cryptoSuite.setCryptoKeyStore(sdkUtils.newCryptoKeyStore());
}
- const self = this;
let pubKey;
- let import_promise = null;
const opts = {algorithm: CryptoAlgorithms.X509Certificate};
if (no_save) {
- opts.ephemeral = true;
- import_promise = new Promise((resolve, reject) => {
- const key = this._cryptoSuite.importKey(state.enrollment.identity.certificate, opts);
- // construct Promise because importKey does not return Promise when ephemeral is true
- if (key) {
- resolve(key);
- } else {
- reject(new Error('Import of saved user has failed'));
- }
- });
+ pubKey = this._cryptoSuite.createKeyFromRaw(state.enrollment.identity.certificate);
} else {
- import_promise = this._cryptoSuite.importKey(state.enrollment.identity.certificate, opts);
+ pubKey = await this._cryptoSuite.importKey(state.enrollment.identity.certificate, opts);
}
- return import_promise
- .then((key) => {
- pubKey = key;
-
- const identity = new Identity(state.enrollment.identity.certificate, pubKey, self._mspId, this._cryptoSuite);
- self._identity = identity;
-
- // during serialization (see toString() below) only the key's SKI are saved
- // swap out that for the real key from the crypto provider
- return self._cryptoSuite.getKey(state.enrollment.signingIdentity);
- }).then((privateKey) => {
- // the key retrieved from the key store using the SKI could be a public key
- // or a private key, check to make sure it's a private key
- if (privateKey.isPrivate()) {
- self._signingIdentity = new SigningIdentity(
- state.enrollment.identity.certificate,
- pubKey,
- self._mspId,
- self._cryptoSuite,
- new Signer(self._cryptoSuite, privateKey));
-
- return self;
- } else {
- throw new Error(util.format('Private key missing from key store. Can not establish the signing identity for user %s', state.name));
- }
- });
+ const identity = new Identity(state.enrollment.identity.certificate, pubKey, this._mspId, this._cryptoSuite);
+ this._identity = identity;
+
+ // during serialization (see toString() below) only the key's SKI are saved
+ // swap out that for the real key from the crypto provider
+ const privateKey = await this._cryptoSuite.getKey(state.enrollment.signingIdentity);
+
+ // the key retrieved from the key store using the SKI could be a public key
+ // or a private key, check to make sure it's a private key
+ if (privateKey.isPrivate()) {
+ this._signingIdentity = new SigningIdentity(
+ state.enrollment.identity.certificate,
+ pubKey,
+ this._mspId,
+ this._cryptoSuite,
+ new Signer(this._cryptoSuite, privateKey));
+
+ return this;
+ } else {
+ throw new Error(util.format('Private key missing from key store. Can not establish the signing identity for user %s', state.name));
+ }
}
/**
diff --git a/fabric-client/lib/impl/CouchDBKeyValueStore.js b/fabric-client/lib/impl/CouchDBKeyValueStore.js
index dccfbeb789..5310b0abdf 100644
--- a/fabric-client/lib/impl/CouchDBKeyValueStore.js
+++ b/fabric-client/lib/impl/CouchDBKeyValueStore.js
@@ -43,7 +43,6 @@ const CouchDBKeyValueStore = class extends KeyValueStore {
// Create the keyValStore instance
super();
- const self = this;
// url is the database instance url
this._url = options.url;
// Name of the database, optional
@@ -52,125 +51,90 @@ const CouchDBKeyValueStore = class extends KeyValueStore {
} else {
this._name = options.name;
}
+ }
- return new Promise(((resolve, reject) => {
- // Initialize the CouchDB database client
- const dbClient = nano(self._url);
- // Check if the database already exists. If not, create it.
- dbClient.db.get(self._name, (err) => {
- // Check for error
- if (err) {
- // Database doesn't exist
- if (err.error === 'not_found') {
- logger.debug('No %s found, creating %s', self._name, self._name);
-
- dbClient.db.create(self._name, (error) => {
- if (error) {
- return reject(new Error(util.format('Failed to create %s database due to error: %s', self._name, error.stack ? error.stack : error)));
- }
-
- logger.debug('Created %s database', self._name);
- // Specify it as the database to use
- self._database = dbClient.use(self._name);
- resolve(self);
- });
- } else {
- // Other error
- return reject(new Error(util.format('Error creating %s database to store membership data: %s', self._name, err.stack ? err.stack : err)));
- }
- } else {
- // Database exists
- logger.debug('%s already exists', self._name);
+ async initialize() {
+
+ // Initialize the CouchDB database client
+ const dbClient = nano(this._url);
+ const get = util.promisify(dbClient.db.get);
+ try {
+ await get(this._name);
+ // Database exists
+ logger.debug('%s already exists', this._name);
+ // Specify it as the database to use
+ this._database = dbClient.use(this._name);
+ } catch (err) {
+ if (err.error === 'not_found') {
+ logger.debug('No %s found, creating %s', this._name);
+ const create = util.promisify(dbClient.db.create);
+ try {
+ await create(this._name);
+ logger.debug('Created %s database', this._name);
// Specify it as the database to use
- self._database = dbClient.use(self._name);
- resolve(self);
+ this._database = dbClient.use(this._name);
+ } catch (error) {
+ throw new Error(util.format('Failed to create %s database due to error: %s', this._name, error.stack ? error.stack : error.description));
}
- });
- }));
+ } else {
+ // Other error
+ throw new Error(util.format('Error initializing database to store membership data: %s', this._name, err.stack ? err.stack : err.description));
+ }
+ }
}
- getValue(name) {
+ async getValue(name) {
logger.debug('getValue', {key: name});
- const self = this;
- return new Promise(((resolve, reject) => {
- self._database.get(name, (err, body) => {
- // Check for error on retrieving from database
- if (err) {
- if (err.error !== 'not_found') {
- logger.error('getValue: %s, ERROR: [%s.get] - ', name, self._name, err.error);
- return reject(err.error);
- } else {
- logger.debug('getValue: %s, Entry does not exist', name);
- return resolve(null);
- }
- } else {
- logger.debug('getValue: %s, Retrieved message from %s.', name, self._name);
- return resolve(body.member);
- }
- });
- }));
+ const get = util.promisify(this._database.get);
+
+ try {
+ const body = await get(name);
+ return body.member;
+ } catch (err) {
+ if (err.error !== 'not_found') {
+ logger.error('getValue: %s, ERROR: [%s.get] - ', name, this._name, err.error);
+ throw err;
+ } else {
+ logger.debug('getValue: %s, Entry does not exist', name);
+ return null;
+ }
+ }
}
- setValue(name, value) {
+ async setValue(name, value) {
logger.debug('setValue', {key: name});
- const self = this;
-
- return new Promise(((resolve, reject) => {
- // Attempt to retrieve from the database to see if the entry exists
- self._database.get(name, (err, body) => {
- // Check for error on retrieving from database
- if (err) {
- if (err.error !== 'not_found') {
- logger.error('setValue: %s, ERROR: [%s.get] - ', name, self._name, err.error);
- reject(err.error);
- } else {
- // Entry does not exist
- logger.debug('setValue: %s, Entry does not exist, insert it.', name);
- self._dbInsert({_id: name, member: value})
- .then((status) => {
- logger.debug('setValue add: ' + name + ', status: ' + status);
- if (status === true) {
- resolve(value);
- } else {
- reject(new Error('Couch database insert add failed.'));
- }
- });
- }
- } else {
- // Entry already exists and must be updated
- // Update the database entry using the latest rev number
- logger.debug('setValue: %s, Retrieved entry from %s. Latest rev number: %s', name, self._name, body._rev);
-
- self._dbInsert({_id: name, _rev: body._rev, member: value})
- .then((status) => {
- logger.debug('setValue update: ' + name + ', status: ' + status);
- if (status === true) {
- resolve(value);
- } else {
- reject(new Error('Couch database insert update failed.'));
- }
- });
- }
- });
- }));
- }
+ const insert = util.promisify(this._database.insert);
+ const get = util.promisify(this._database.get);
+ let isNew;
+ let body;
+ try {
+ // perform a get to see if the key exists
+ body = await get(name);
+
+ // Didn't error, so it exists
+ isNew = false;
+ } catch (error) {
+ if (error.error !== 'not_found') {
+ logger.error('setValue: %s, key check ERROR: - ', name, error.error);
+ throw error;
+ } else {
+ // Does not exist
+ isNew = true;
+ }
+ }
- _dbInsert(options) {
- logger.debug('setValue, _dbInsert', {options: options});
- const self = this;
- return new Promise(((resolve, reject) => {
- self._database.insert(options, (err) => {
- if (err) {
- logger.error('setValue, _dbInsert, ERROR: [%s.insert] - ', self._name, err.error);
- reject(new Error(err.error));
- } else {
- logger.debug('setValue, _dbInsert, Inserted member into %s.', self._name);
- resolve(true);
- }
- });
- }));
+ // conditionally perform the set/update
+ const opts = isNew ? {_id: name, member: value} : {_id: name, _rev: body._rev, member: value};
+ try {
+ await insert(opts);
+ logger.debug('setValue [add]: ' + name + ', status: SUCCESS');
+ return value;
+ } catch (err) {
+ logger.debug('Couch database insert: ' + name + ', status: FAILED');
+ throw err;
+ }
}
};
diff --git a/fabric-client/lib/impl/CryptoKeyStore.js b/fabric-client/lib/impl/CryptoKeyStore.js
index 5edd6429dc..208e9f4662 100644
--- a/fabric-client/lib/impl/CryptoKeyStore.js
+++ b/fabric-client/lib/impl/CryptoKeyStore.js
@@ -6,7 +6,6 @@
*/
'use strict';
-
const jsrsasign = require('jsrsasign');
const KEYUTIL = jsrsasign.KEYUTIL;
diff --git a/fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js b/fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js
index b6045550a7..37b76ab440 100755
--- a/fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js
+++ b/fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js
@@ -96,23 +96,16 @@ class CryptoSuite_ECDSA_AES extends CryptoSuite {
}
async generateKey(opts) {
- const pair = KEYUTIL.generateKeypair('EC', this._curveName);
-
- if (typeof opts !== 'undefined' && typeof opts.ephemeral !== 'undefined' && opts.ephemeral === true) {
- logger.debug('generateKey, ephemeral true, Promise resolved');
- return new ECDSAKey(pair.prvKeyObj);
- } else {
- if (!this._cryptoKeyStore) {
- throw new Error('generateKey opts.ephemeral is false, which requires CryptoKeyStore to be set.');
- }
- // unless "opts.ephemeral" is explicitly set to "true", default to saving the key
- const key = new ECDSAKey(pair.prvKeyObj);
-
- const store = await this._cryptoKeyStore._getKeyStore();
- logger.debug('generateKey, store.setValue');
- await store.putKey(key);
- return key;
+ if (!this._cryptoKeyStore) {
+ throw new Error('generateKey requires CryptoKeyStore to be set.');
}
+
+ const key = this.generateEphemeralKey();
+
+ const store = await this._cryptoKeyStore._getKeyStore();
+ logger.debug('generateKey, store.setValue');
+ await store.putKey(key);
+ return key;
}
/**
@@ -124,24 +117,11 @@ class CryptoSuite_ECDSA_AES extends CryptoSuite {
}
/**
- * This is an implementation of {@link module:api.CryptoSuite#importKey}
+ * This is an implementation of {@link module:api.CryptoSuite#createKeyFromRaw}
*/
- importKey(pem, opts) {
- logger.debug('importKey - start');
- let store_key = true; // default
- if (typeof opts !== 'undefined' && typeof opts.ephemeral !== 'undefined' && opts.ephemeral === true) {
- store_key = false;
- }
- if (store_key && !this._cryptoKeyStore) {
- throw new Error('importKey opts.ephemeral is false, which requires CryptoKeyStore to be set.');
- }
+ createKeyFromRaw(pem) {
+ logger.debug('createKeyFromRaw - start');
- const self = this;
- // attempt to import the raw content, assuming it's one of the following:
- // X.509v1/v3 PEM certificate (RSA/DSA/ECC)
- // PKCS#8 PEM RSA/DSA/ECC public key
- // PKCS#5 plain PEM DSA/RSA private key
- // PKCS#8 plain PEM RSA/ECDSA private key
// TODO: add support for the following passcode-protected PEM formats
// - PKCS#5 encrypted PEM RSA/DSA private
// - PKCS#8 encrypted PEM RSA/ECDSA private key
@@ -149,43 +129,43 @@ class CryptoSuite_ECDSA_AES extends CryptoSuite {
pemString = makeRealPem(pemString);
let key = null;
let theKey = null;
- let error = null;
+
try {
key = KEYUTIL.getKey(pemString);
} catch (err) {
- error = new Error('Failed to parse key from PEM: ' + err);
+ logger.error('createKeyFromRaw - Failed to parse key from PEM: ', err);
+ throw new Error('Failed to parse key from PEM: ' + err);
}
if (key && key.type && key.type === 'EC') {
theKey = new ECDSAKey(key);
- logger.debug('importKey - have the key %j', theKey);
+ logger.debug('createKeyFromRaw - have the key %j', theKey);
+ return theKey;
} else {
- error = new Error('Does not understand PEM contents other than ECDSA private keys and certificates');
+ logger.error('createKeyFromRaw - Does not understand PEM contents other than ECDSA private keys and certificates');
+ throw new Error('Does not understand PEM contents other than ECDSA private keys and certificates');
}
+ }
- if (!store_key) {
- if (error) {
- logger.error('importKey - %s', error);
- throw error;
- }
- return theKey;
- } else {
- if (error) {
- logger.error('importKey - %j', error);
- return Promise.reject(error);
- }
- return new Promise((resolve, reject) => {
- return self._cryptoKeyStore._getKeyStore()
- .then((store) => {
- return store.putKey(theKey);
- }).then(() => {
- return resolve(theKey);
- }).catch((err) => {
- reject(err);
- });
-
- });
+ /**
+ * This is an implementation of {@link module:api.CryptoSuite#importKey}
+ * Attempt to import the raw content, assuming it's one of the following:
+ * X.509v1/v3 PEM certificate (RSA/DSA/ECC)
+ * PKCS#8 PEM RSA/DSA/ECC public key
+ * PKCS#5 plain PEM DSA/RSA private key
+ * PKCS#8 plain PEM RSA/ECDSA private key
+ */
+ async importKey(pem) {
+
+ if (!this._cryptoKeyStore) {
+ throw new Error('importKey requires CryptoKeyStore to be set.');
}
+
+ // Attempt Key creation from Raw input
+ const key = this.createKeyFromRaw(pem);
+ const store = await this._cryptoKeyStore._getKeyStore();
+ await store.putKey(key);
+ return key;
}
async getKey(ski) {
diff --git a/fabric-client/lib/impl/FileKeyValueStore.js b/fabric-client/lib/impl/FileKeyValueStore.js
index 08724c875f..cd0edb1f30 100644
--- a/fabric-client/lib/impl/FileKeyValueStore.js
+++ b/fabric-client/lib/impl/FileKeyValueStore.js
@@ -39,54 +39,50 @@ const FileKeyValueStore = class extends KeyValueStore {
// Create the keyValStore instance
super();
- const self = this;
this._dir = options.path;
- return new Promise(((resolve, reject) => {
- fs.mkdirs(self._dir, (err) => {
- if (err) {
- logger.error('constructor, error creating directory, code: %s', err.code);
- return reject(err);
- }
- return resolve(self);
- });
- }));
}
- getValue(name) {
+ async initialize() {
+ // Build directories from set path in constructor
+ try {
+ await fs.mkdirs(this._dir);
+ } catch (err) {
+ // Don't throw if it already exists
+ if (err.code !== 'EEXIST') {
+ logger.error('constructor, error creating directory, code: %s', err.code);
+ throw err;
+ }
+ }
+ }
+
+ async getValue(name) {
logger.debug('getValue', {key: name});
- const self = this;
-
- return new Promise(((resolve, reject) => {
- const p = path.join(self._dir, name);
- fs.readFile(p, 'utf8', (err, data) => {
- if (err) {
- if (err.code !== 'ENOENT') {
- return reject(err);
- } else {
- return resolve(null);
- }
- }
- return resolve(data);
- });
- }));
+ try {
+ const p = path.join(this._dir, name);
+ return await fs.readFile(p, 'utf8');
+ } catch (err) {
+ if (err.code !== 'ENOENT') {
+ // reject
+ throw err;
+ } else {
+ // resolve null
+ return null;
+ }
+ }
}
- setValue(name, value) {
+ async setValue(name, value) {
logger.debug('setValue', {key: name});
- const self = this;
-
- return new Promise(((resolve, reject) => {
- const p = path.join(self._dir, name);
- fs.writeFile(p, value, (err) => {
- if (err) {
- reject(err);
- } else {
- return resolve(value);
- }
- });
- }));
+ try {
+ const p = path.join(this._dir, name);
+ return await fs.writeFile(p, value);
+ } catch (err) {
+ // rethrow
+ logger.error('setValue, error for key', name);
+ throw err;
+ }
}
};
diff --git a/fabric-client/lib/impl/bccsp_pkcs11.js b/fabric-client/lib/impl/bccsp_pkcs11.js
index c36cea1778..d62e2555a4 100644
--- a/fabric-client/lib/impl/bccsp_pkcs11.js
+++ b/fabric-client/lib/impl/bccsp_pkcs11.js
@@ -21,7 +21,6 @@ const KEYUTIL = jsrsa.KEYUTIL;
const BN = require('bn.js');
const ecsig = require('elliptic/lib/elliptic/ec/signature.js');
const callsite = require('callsite');
-// const crypto = require('crypto');
const pkcs11js = require('pkcs11js');
const util = require('util');
const ECDSAKey = require('./ecdsa/key.js');
@@ -229,10 +228,12 @@ class CryptoSuite_PKCS11 extends CryptoSuite {
this._pkcs11 = _pkcs11;
this._pkcs11OpenSession(this._pkcs11, pkcs11Lib, pkcs11Slot, pkcs11Pin, pkcs11UserType, pkcs11ReadWrite);
+
/*
* SKI to key cache for getKey(ski) function.
*/
this._skiToKey = {};
+ this.keyToSki = new Map();
}
/** ********************************************************************************
@@ -794,70 +795,78 @@ class CryptoSuite_PKCS11 extends CryptoSuite {
**********************************************************************************/
/**
- * This is an implementation of {@link module:api.CryptoSuite#generateKey}
- * Returns an instance of {@link module.api.Key} representing the private key,
- * which also encapsulates the public key. By default the generated key (keypar)
- * is (are) ephemeral unless opts.ephemeral is set to false, in which case the
- * key (keypair) will be saved across PKCS11 sessions by the HSM hardware.
- *
+ * This is an implementation of {@link module:api.CryptoSuite#generateEphemeralKey}
* @returns {module:api.Key} Promise of an instance of {@link module:PKCS11_ECDSA_KEY}
* containing the private key and the public key.
*/
- generateKey(opts) {
+ generateEphemeralKey(opts) {
if (opts !== null && (typeof opts.algorithm === 'undefined' || opts.algorithm === null)) {
opts.algorithm = 'ECDSA';
}
if (typeof opts === 'undefined' || opts === null ||
typeof opts.algorithm === 'undefined' || opts.algorithm === null ||
typeof opts.algorithm !== 'string') {
- return Promise.reject(Error(__func() + 'opts.algorithm must be String type'));
+ throw new Error(__func() + ' opts.algorithm must be String type');
}
- const token = !opts.ephemeral;
- const self = this;
+ switch (opts.algorithm.toUpperCase()) {
+ case 'AES': {
+ if (this._keySize !== 256) {
+ throw new Error(__func() + ' AES key size must be 256 (bits)');
+ }
+
+ const attributes = this._pkcs11GenerateKey(this._pkcs11, this._pkcs11Session, !!opts.persist);
+ // generateKey will need to know the ski, so set in a map here for use later
+ this.keyToSki.set(key, attributes.ski);
+ const key = new aesKey(attributes, this._keySize);
+ return key;
+ }
+ case 'ECDSA': {
+ const attributes = this._pkcs11GenerateECKeyPair(this._pkcs11, this._pkcs11Session, !!opts.persist);
+ // generateKey will need to know the ski, so set in a map here for use later
+ this.keyToSki.set(key, attributes.ski);
+ const key = new ecdsaKey(attributes, this._keySize);
+ key._cryptoSuite = this;
+ return key;
+ }
+ default:
+ throw new Error(__func() + ' must specify AES or ECDSA key algorithm');
+ }
+ }
+
+ /**
+ * This is an implementation of {@link module:api.CryptoSuite#generateKey}
+ * Returns an instance of {@link module.api.Key} representing the private key,
+ * which also encapsulates the public key. The key (keypair) will be saved
+ * across PKCS11 sessions by the HSM hardware. Use generateEphemeralKey to
+ * retrieve an ephmeral key.
+ *
+ * @returns {module:api.Key} Promise of an instance of {@link module:PKCS11_ECDSA_KEY}
+ * containing the private key and the public key.
+ */
+ generateKey(opts) {
+
+ // Use internal method to get key from passed options (if any)
+ if (!opts) {
+ opts = {};
+ }
+ opts.persist = true;
+ const key = this.generateEphemeralKey(opts);
+
+ // Set array
+ const ski = this.keyToSki.get(key);
switch (opts.algorithm.toUpperCase()) {
case 'AES':
- return new Promise(((resolve, reject) => {
- try {
- if (self._keySize !== 256) {
- throw new Error(
- __func() + 'AES key size must be 256 (bits)');
- }
-
- const attr = self._pkcs11GenerateKey(
- self._pkcs11, self._pkcs11Session, token);
- /*
- * Put key in the session cache and return
- * promise of the key.
- */
- const key = new aesKey(attr, self._keySize);
- self._skiToKey[attr.ski.toString('hex')] = key;
- return resolve(key);
- } catch (e) {
- return reject(e);
- }
- }));
+ this._skiToKey[ski.toString('hex')] = key;
+ return key;
case 'ECDSA':
- return new Promise(((resolve, reject) => {
- try {
- const attr = self._pkcs11GenerateECKeyPair(
- self._pkcs11, self._pkcs11Session, token);
- /*
- * Put key in the session cache and return
- * promise of the key.
- */
- const key = new ecdsaKey(attr, self._keySize);
- self._skiToKey[attr.ski.toString('hex')] = key;
- key._cryptoSuite = self;
- return resolve(key);
- } catch (e) {
- return reject(e);
- }
- }));
+ delete key._cryptoSuite;
+ this._skiToKey[ski.toString('hex')] = key;
+ key._cryptoSuite = this;
+ return key;
default:
- return Promise.reject(Error(
- __func() + 'must specify AES or ECDSA key algorithm'));
+ throw new Error(__func() + ' must specify AES or ECDSA key algorithm');
}
}
@@ -867,7 +876,7 @@ class CryptoSuite_PKCS11 extends CryptoSuite {
*/
getKey(ski) {
if (!ski || !(ski instanceof Buffer || typeof ski === 'string')) {
- return Promise.reject(Error(__func() + 'ski must be Buffer|string type'));
+ return Promise.reject(Error(__func() + ' ski must be Buffer|string type'));
}
/*
* Found the ski in the session key cache.
@@ -893,7 +902,7 @@ class CryptoSuite_PKCS11 extends CryptoSuite {
let key;
if (typeof handle.secretKey !== 'undefined') {
if (self._keySize !== 256) {
- throw new Error(__func() + 'key size mismatch, class: ' + self._keySize + ', ski: 256');
+ throw new Error(__func() + ' key size mismatch, class: ' + self._keySize + ', ski: 256');
}
key = new aesKey({ski, key: handle.secretKey}, self._keySize);
} else { /* ECDSA key. */
@@ -906,7 +915,7 @@ class CryptoSuite_PKCS11 extends CryptoSuite {
toUpperCase()];
if (keySize === undefined ||
keySize !== self._keySize) {
- throw new Error(__func() + 'key size mismatch, class: ' + self._keySize + ', ski: ' + keySize);
+ throw new Error(__func() + ' key size mismatch, class: ' + self._keySize + ', ski: ' + keySize);
}
key = new ecdsaKey({ski, ecpt: attr.ecpt, pub: handle.publicKey, priv: handle.privateKey},
self._keySize);
@@ -931,11 +940,11 @@ class CryptoSuite_PKCS11 extends CryptoSuite {
sign(key, digest) {
if (typeof key === 'undefined' || key === null ||
!(key instanceof ecdsaKey) || !key.isPrivate()) {
- throw new Error(__func() + 'key must be PKCS11_ECDSA_KEY type private key');
+ throw new Error(__func() + ' key must be PKCS11_ECDSA_KEY type private key');
}
if (typeof digest === 'undefined' || digest === null ||
!(digest instanceof Buffer)) {
- throw new Error(__func() + 'digest must be Buffer type');
+ throw new Error(__func() + ' digest must be Buffer type');
}
return this._pkcs11Sign(this._pkcs11, this._pkcs11Session, key, digest);
@@ -948,15 +957,15 @@ class CryptoSuite_PKCS11 extends CryptoSuite {
verify(key, signature, digest) {
if (typeof key === 'undefined' || key === null ||
!(key instanceof ecdsaKey || key instanceof ECDSAKey)) {
- throw new Error(__func() + 'key must be PKCS11_ECDSA_KEY type or ECDSA_KEY type');
+ throw new Error(__func() + ' key must be PKCS11_ECDSA_KEY type or ECDSA_KEY type');
}
if (typeof signature === 'undefined' || signature === null ||
!(signature instanceof Buffer)) {
- throw new Error(__func() + 'signature must be Buffer type');
+ throw new Error(__func() + ' signature must be Buffer type');
}
if (typeof digest === 'undefined' || digest === null ||
!(digest instanceof Buffer)) {
- throw new Error(__func() + 'digest must be Buffer type');
+ throw new Error(__func() + ' digest must be Buffer type');
}
if (key instanceof ECDSAKey) {
@@ -976,11 +985,11 @@ class CryptoSuite_PKCS11 extends CryptoSuite {
*/
encrypt(key, plainText, opts) {
if (typeof key === 'undefined' || key === null || !(key instanceof aesKey)) {
- throw new Error(__func() + 'key must be PKCS11_AES_KEY type');
+ throw new Error(__func() + ' key must be PKCS11_AES_KEY type');
}
if (typeof plainText === 'undefined' || plainText === null ||
!(plainText instanceof Buffer)) {
- throw new Error(__func() + 'plainText must be Buffer type');
+ throw new Error(__func() + ' plainText must be Buffer type');
}
return this._pkcs11Encrypt(this._pkcs11, this._pkcs11Session, key, plainText);
@@ -993,11 +1002,11 @@ class CryptoSuite_PKCS11 extends CryptoSuite {
*/
decrypt(key, cipherText, opts) {
if (typeof key === 'undefined' || key === null || !(key instanceof aesKey)) {
- throw new Error(__func() + 'key must be PKCS11_AES_KEY type');
+ throw new Error(__func() + ' key must be PKCS11_AES_KEY type');
}
if (typeof cipherText === 'undefined' || cipherText === null ||
!(cipherText instanceof Buffer)) {
- throw new Error(__func() + 'cipherText must be Buffer type');
+ throw new Error(__func() + ' cipherText must be Buffer type');
}
return this._pkcs11Decrypt(this._pkcs11, this._pkcs11Session, key, cipherText);
@@ -1007,57 +1016,63 @@ class CryptoSuite_PKCS11 extends CryptoSuite {
* This is an implementation of {@link module:api.CryptoSuite#deriveKey}
*/
deriveKey(key, opts) {
- throw new Error(__func() + 'not yet supported');
+ throw new Error(__func() + ' not yet supported');
+ }
+
+ /**
+ * This is an implementation of {@link module:api.CryptoSuite#createKeyFromRaw}
+ */
+ createKeyFromRaw(pem, opts) {
+ const optsLocal = opts ? opts : {};
+ const token = !optsLocal.ephemeral;
+ switch (optsLocal.algorithm.toUpperCase()) {
+ case 'X509CERTIFICATE':
+ return new ECDSAKey(KEYUTIL.getKey(pem));
+ case 'AES':
+ if (pem.length !== (256 / 8)) {
+ throw new Error(__func() + 'AES key size must be 256 (bits)');
+ } else {
+ const attributes = this._pkcs11CreateObject(this._pkcs11, this._pkcs11Session, pem, token);
+ const key = new aesKey(attributes, pem.length * 8);
+ this.keyToSki.set(key, attributes.ski);
+ return key;
+ }
+ case 'ECDSA':
+ throw new Error(__func() + ' ECDSA key not yet supported');
+ default:
+ throw new Error(__func() + ' only AES or ECDSA key supported');
+ }
}
/**
* This is an implementation of {@link module:api.CryptoSuite#importKey}
*/
- importKey(pem, opts) {
+ async importKey(pem, opts) {
const optsLocal = opts ? opts : {};
const algorithm = optsLocal.algorithm ? optsLocal.algorithm : 'X509Certificate';
if (!pem || !(pem instanceof Buffer || typeof pem === 'string')) {
- return Promise.reject(Error(__func() + 'pem must be Buffer type or String type'));
+ throw new Error(__func() + ' pem must be Buffer type or String type');
}
if (typeof algorithm !== 'string') {
- return Promise.reject(Error(__func() + 'opts.algorithm must be String type'));
+ throw new Error(__func() + ' opts.algorithm must be String type');
}
- const token = !optsLocal.ephemeral;
- const self = this;
+ // Create key
+ const key = this.createKeyFromRaw(pem, optsLocal);
switch (algorithm.toUpperCase()) {
case 'X509CERTIFICATE':
- if (token) {
- return Promise.resolve(new ECDSAKey(KEYUTIL.getKey(pem)));
- } else {
- return new ECDSAKey(KEYUTIL.getKey(pem));
- }
- case 'AES':
- return new Promise(((resolve, reject) => {
- try {
- if (pem.length !== (256 / 8)) {
- throw new Error(__func() + 'AES key size must be 256 (bits)');
- }
-
- const attr = self._pkcs11CreateObject(self._pkcs11, self._pkcs11Session, pem, token);
- /*
- * Put key in the session cache and return
- * promise of the key.
- */
- const key = new aesKey(attr, pem.length * 8);
- self._skiToKey[attr.ski.toString('hex')] = key;
- return resolve(key);
- } catch (e) {
- reject(e);
- }
- }));
- case 'ECDSA':
- return Promise.reject(Error(__func() + 'ECDSA key not yet supported'));
+ return key;
+ case 'AES': {
+ // Store in array cache
+ const ski = this.keyToSki.get(key);
+ this._skiToKey[ski.toString('hex')] = key;
+ return key;
+ }
default:
- return Promise.reject(Error(__func() + 'only AES or ECDSA key supported'));
+ throw new Error(__func() + ' only X509 or AES key supported');
}
}
diff --git a/fabric-client/lib/msp/msp.js b/fabric-client/lib/msp/msp.js
index e8eaf3a841..760c8c8b0b 100755
--- a/fabric-client/lib/msp/msp.js
+++ b/fabric-client/lib/msp/msp.js
@@ -141,7 +141,7 @@ const MSP = class {
* @returns {Promise} Promise for an {@link Identity} instance or
* or the Identity object itself if "storeKey" argument is false
*/
- deserializeIdentity(serializedIdentity, storeKey) {
+ async deserializeIdentity(serializedIdentity, storeKey) {
logger.debug('importKey - start');
let store_key = true; // default
// if storing is not required and therefore a promise will not be returned
@@ -152,15 +152,14 @@ const MSP = class {
const sid = fabprotos.msp.SerializedIdentity.decode(serializedIdentity);
const cert = sid.getIdBytes().toBinary();
logger.debug('Encoded cert from deserialized identity: %s', cert);
+
+ let publicKey;
if (!store_key) {
- const publicKey = this.cryptoSuite.importKey(cert, {algorithm: CryptoAlgorithms.X509Certificate, ephemeral: true});
- return new Identity(cert, publicKey, this.getId(), this.cryptoSuite);
+ publicKey = this.cryptoSuite.createKeyFromRaw(cert, {algorithm: CryptoAlgorithms.X509Certificate});
} else {
- return this.cryptoSuite.importKey(cert, {algorithm: CryptoAlgorithms.X509Certificate})
- .then((publicKey) => {
- return new Identity(cert, publicKey, this.getId(), this.cryptoSuite);
- });
+ publicKey = await this.cryptoSuite.importKey(cert, {algorithm: CryptoAlgorithms.X509Certificate});
}
+ return new Identity(cert, publicKey, this.getId(), this.cryptoSuite);
}
/**
diff --git a/fabric-client/lib/utils.js b/fabric-client/lib/utils.js
index 89fce15ef3..071f14fe9b 100644
--- a/fabric-client/lib/utils.js
+++ b/fabric-client/lib/utils.js
@@ -82,12 +82,14 @@ module.exports.newCryptoSuite = (setting) => {
return new cryptoSuite(keysize, hashAlgo, opts);
};
-// Provide a Promise-based keyValueStore for couchdb, etc.
+// Provide a keyValueStore for couchdb, etc.
module.exports.newKeyValueStore = async (options) => {
// initialize the correct KeyValueStore
const kvsEnv = exports.getConfigSetting('key-value-store');
- const store = require(kvsEnv);
- return new store(options);
+ const Store = require(kvsEnv);
+ const store = new Store(options);
+ await store.initialize();
+ return store;
};
const LOGGING_LEVELS = ['debug', 'info', 'warn', 'error'];
@@ -391,26 +393,23 @@ const CryptoKeyStore = function (KVSImplClass, opts) {
};
- this._getKeyStore = function () {
- const CKS = require('./impl/CryptoKeyStore.js');
-
- const self = this;
- return new Promise((resolve, reject) => {
- if (self._store === null) {
- self.logger.debug(util.format('This class requires a CryptoKeyStore to save keys, using the store: %j', self._storeConfig));
-
- CKS(self._storeConfig.superClass, self._storeConfig.opts).then((ks) => {
- self.logger.debug('_getKeyStore returning ks');
- self._store = ks;
- return resolve(self._store);
- }).catch((err) => {
- reject(err);
- });
- } else {
- self.logger.debug('_getKeyStore resolving store');
- return resolve(self._store);
+ this._getKeyStore = async function () {
+ const CKS = require('fabric-client/lib/impl/CryptoKeyStore');
+
+ if (this._store === null) {
+ this.logger.debug(util.format('This class requires a CryptoKeyStore to save keys, using the store: %j', this._storeConfig));
+
+ try {
+ this._store = await CKS(this._storeConfig.superClass, this._storeConfig.opts);
+ await this._store.initialize();
+ return this._store;
+ } catch (err) {
+ throw err;
}
- });
+ } else {
+ this.logger.debug('_getKeyStore returning store');
+ return this._store;
+ }
};
};
diff --git a/fabric-client/package.json b/fabric-client/package.json
index 46989edddb..8de5b3d54d 100644
--- a/fabric-client/package.json
+++ b/fabric-client/package.json
@@ -40,7 +40,7 @@
"nano": "^6.4.4",
"nconf": "^0.10.0",
"pkcs11js": "^1.0.6",
- "promise-settle": "^0.3.0",
+ "promise-settle": "^0.3.0",
"sjcl": "1.0.7",
"stream-buffers": "3.0.1",
"tar-stream": "1.6.1",
@@ -48,11 +48,12 @@
"winston": "^2.2.0"
},
"devDependencies": {
- "chai": "^4.1.2",
- "chai-as-promised": "^7.1.1",
- "mocha": "^5.2.0",
- "nyc": "^12.0.2",
- "rewire": "^4.0.1",
+ "chai": "^4.1.2",
+ "chai-as-promised": "^7.1.1",
+ "mocha": "^5.2.0",
+ "mock-couch": "^0.1.11",
+ "nyc": "^12.0.2",
+ "rewire": "^4.0.1",
"sinon": "^6.1.3"
},
"license": "Apache-2.0",
diff --git a/fabric-client/test/BaseClient.js b/fabric-client/test/BaseClient.js
index 9d840c9dac..d6ddad4a47 100644
--- a/fabric-client/test/BaseClient.js
+++ b/fabric-client/test/BaseClient.js
@@ -84,13 +84,13 @@ describe('BaseClient', () => {
sandbox.restore();
});
- it('should call `sdkUtils.newKeyValueStore` with passed parameters and return result', () => {
+ it('should call `sdkUtils.newKeyValueStore` with passed parameters and return result', async () => {
const sdkUtilsStub = sandbox.stub();
- const newDefaultKeyValueStoreStub = sandbox.stub().returns('newDefaultKeyValueStore');
+ const newDefaultKeyValueStoreStub = sandbox.stub().resolves('newDefaultKeyValueStore');
sdkUtilsStub.newKeyValueStore = newDefaultKeyValueStoreStub;
BaseClientRewire.__set__('sdkUtils', sdkUtilsStub);
- const result = BaseClientRewire.newDefaultKeyValueStore('setting');
+ const result = await BaseClientRewire.newDefaultKeyValueStore('setting');
result.should.equal('newDefaultKeyValueStore');
sinon.assert.calledOnce(newDefaultKeyValueStoreStub);
diff --git a/fabric-client/test/Channel.js b/fabric-client/test/Channel.js
index 8cae994594..3e816d75cd 100644
--- a/fabric-client/test/Channel.js
+++ b/fabric-client/test/Channel.js
@@ -357,10 +357,10 @@ describe('Channel', () => {
expect(org2PeerNames, 'org2').to.deep.equal([peer2.getName()]);
});
- it('uses org from client if none supplied', () => {
+ it('uses org from client if none supplied', async () => {
const org1 = 'org1';
const org2 = 'org2';
- client.loadFromConfig({
+ await client.loadFromConfig({
version: '1.0',
client: {
organization: 'Org1'
@@ -528,10 +528,10 @@ describe('Channel', () => {
assertChannelEventHubsMatchPeers(eventHubs, [peer1]);
});
- it('returns channel event hubs for channel\'s orgnanization if no organization specified', () => {
+ it('returns channel event hubs for channel\'s orgnanization if no organization specified', async () => {
const org1 = 'org1';
const org2 = 'org2';
- client.loadFromConfig({
+ await client.loadFromConfig({
version: '1.0',
client: {
organization: 'Org1'
@@ -743,70 +743,66 @@ describe('Channel', () => {
});
describe('#verifyProposalResponse', () => {
- it('throws if proposal_response is missing', () => {
- expect(() => channel.verifyProposalResponse(null)).to.throw('Missing proposal response');
+ it('throws if proposal_response is missing', async () => {
+ await channel.verifyProposalResponse(null).should.be.rejectedWith('Missing proposal response');
});
- it('throws if parameter is not a ProposalResponse', () => {
- expect(() => channel.verifyProposalResponse({})).to.throw('ProposalResponse');
+ it('throws if parameter is not a ProposalResponse', async () => {
+ await channel.verifyProposalResponse({}).should.be.rejectedWith('ProposalResponse');
});
- it('throws if parameter is not a ProposalResponse', () => {
- expect(() => channel.verifyProposalResponse([])).to.throw('ProposalResponse');
+ it('throws if parameter is not a ProposalResponse', async () => {
+ await channel.verifyProposalResponse([]).should.be.rejectedWith('ProposalResponse');
});
- it('throws for unknown MSP ID in proposal response', () => {
+ it('throws for unknown MSP ID in proposal response', async () => {
channel.getMSPManager().getMSP.withArgs(mspId).returns(null);
const proposalResponse = createProposalResponse('messsage');
- expect(() => channel.verifyProposalResponse(proposalResponse)).to.throw(mspId);
+ await channel.verifyProposalResponse(proposalResponse).should.be.rejectedWith(mspId);
});
- it('returns false if MSP unable to deserialize identity', () => {
+ it('returns false if MSP unable to deserialize identity', async () => {
stubMsp.deserializeIdentity.returns(null);
const proposalResponse = createProposalResponse('messsage');
- const result = channel.verifyProposalResponse(proposalResponse);
-
+ const result = await channel.verifyProposalResponse(proposalResponse);
expect(result).to.be.false;
});
- it('returns false if identity not valid', () => {
+ it('returns false if identity not valid', async () => {
const proposalResponse = createProposalResponse('messsage');
stubMspIdentity.isValid.returns(false);
- const result = channel.verifyProposalResponse(proposalResponse);
-
+ const result = await channel.verifyProposalResponse(proposalResponse);
expect(result).to.be.false;
});
- it('returns false if signature not valid', () => {
+ it('returns false if signature not valid', async () => {
const proposalResponse = createProposalResponse('messsage');
stubMspIdentity.verify.returns(false);
- const result = channel.verifyProposalResponse(proposalResponse);
-
+ const result = await channel.verifyProposalResponse(proposalResponse);
expect(result).to.be.false;
});
- it('returns false if signature verification errors', () => {
+ it('returns false if signature verification errors', async () => {
const proposalResponse = createProposalResponse('messsage');
stubMspIdentity.verify.throws('VerifyError', 'test');
- const result = channel.verifyProposalResponse(proposalResponse);
-
+ const result = await channel.verifyProposalResponse(proposalResponse);
expect(result).to.be.false;
});
- it('returns true for valid proposal response', () => {
+ it('returns true for valid proposal response', async () => {
const proposalResponse = createProposalResponse('messsage');
- const result = channel.verifyProposalResponse(proposalResponse);
+ const result = await channel.verifyProposalResponse(proposalResponse);
expect(result).to.be.true;
});
- it('returns false if the proposal response is an error', () => {
+ it('returns false if the proposal response is an error', async () => {
const proposalResponse = new Error('sadface');
- const result = channel.verifyProposalResponse(proposalResponse);
+ const result = await channel.verifyProposalResponse(proposalResponse);
expect(result).to.be.false;
});
});
diff --git a/fabric-client/test/Client.js b/fabric-client/test/Client.js
index 307bf074c1..962fafd349 100644
--- a/fabric-client/test/Client.js
+++ b/fabric-client/test/Client.js
@@ -107,10 +107,10 @@ describe('Client', () => {
});
describe('loadFromConfig', () => {
- it('should create a Client instance and call loadFromConfig', () => {
+ it('should create a Client instance and call loadFromConfig', async () => {
const loadConfigStub = sinon.stub();
revert.push(Client.__set__('Client.prototype.loadFromConfig', loadConfigStub));
- const client = Client.loadFromConfig('config');
+ const client = await Client.loadFromConfig('config');
sinon.assert.calledWith(loadConfigStub, 'config');
client.should.be.an.instanceof(Client);
});
@@ -137,27 +137,27 @@ describe('Client', () => {
_addConnectionOptionsFromConfig = sinon.stub(client, '_addConnectionOptionsFromConfig');
});
- it('should get additional network config and set _network_config to it', () => {
+ it('should get additional network config and set _network_config to it', async () => {
mock_network_config.hasClient.returns(false);
client._network_config = null;
- client.loadFromConfig('config');
+ await client.loadFromConfig('config');
sinon.assert.calledWith(_getNetworkConfigStub, 'config', client);
sinon.assert.called(mock_network_config.hasClient);
});
- it('should get additional network config and merge it with the existing config', () => {
+ it('should get additional network config and merge it with the existing config', async () => {
mock_network_config.hasClient.returns(false);
client._network_config = mock_network_config;
- client.loadFromConfig('config');
+ await client.loadFromConfig('config');
sinon.assert.calledWith(_getNetworkConfigStub, 'config', client);
sinon.assert.calledWith(mock_network_config.mergeSettings, mock_network_config);
sinon.assert.called(mock_network_config.hasClient);
});
- it('should get additional network config and set adming and set mspid', () => {
+ it('should get additional network config and set adming and set mspid', async () => {
mock_network_config.hasClient.returns(true);
client._network_config = null;
- client.loadFromConfig('config');
+ await client.loadFromConfig('config');
sinon.assert.calledWith(_getNetworkConfigStub, 'config', client);
sinon.assert.called(mock_network_config.hasClient);
sinon.assert.called(_setAdminFromConfigStub);
@@ -463,11 +463,11 @@ describe('Client', () => {
});
describe('#getPeersForOrg', () => {
- it('returns peers for specified org', () => {
+ it('returns peers for specified org', async () => {
const clientOrg = connectionProfile.client.organization;
const mspId = connectionProfile.organizations[clientOrg].mspid;
const orgPeerNames = connectionProfile.organizations[clientOrg].peers;
- const client = Client.loadFromConfig(connectionProfile);
+ const client = await Client.loadFromConfig(connectionProfile);
const peers = client.getPeersForOrg(mspId);
@@ -475,10 +475,10 @@ describe('Client', () => {
peerNames.should.deep.equal(orgPeerNames);
});
- it('returns peers for client org in connection profile if no org specified', () => {
+ it('returns peers for client org in connection profile if no org specified', async () => {
const clientOrg = connectionProfile.client.organization;
const orgPeerNames = connectionProfile.organizations[clientOrg].peers;
- const client = Client.loadFromConfig(connectionProfile);
+ const client = await Client.loadFromConfig(connectionProfile);
const peers = client.getPeersForOrg();
@@ -492,17 +492,17 @@ describe('Client', () => {
peers.should.be.empty;
});
- it('returns empty list if organisation not in config', () => {
- const client = Client.loadFromConfig(connectionProfile);
+ it('returns empty list if organisation not in config', async () => {
+ const client = await Client.loadFromConfig(connectionProfile);
const peers = client.getPeersForOrg('NON_EXISTENT_MSP_ID');
peers.should.be.empty;
});
- it('returns peers for user context MSP ID if no org specified and no client org in connection profile', () => {
+ it('returns peers for user context MSP ID if no org specified and no client org in connection profile', async () => {
delete connectionProfile.client;
const userOrg = Object.values(connectionProfile.organizations).find((org) => org.mspid === userMspId);
const userPeerNames = userOrg.peers;
- const client = Client.loadFromConfig(connectionProfile);
+ const client = await Client.loadFromConfig(connectionProfile);
client.setUserContext(fakeUser, true);
const peers = client.getPeersForOrg();
@@ -764,11 +764,11 @@ describe('Client', () => {
should.not.exist(actual);
});
- it('MSP ID of the org in the client section of the connection profile if loaded from config', () => {
+ it('MSP ID of the org in the client section of the connection profile if loaded from config', async () => {
const clientOrg = connectionProfile.client.organization;
const expected = connectionProfile.organizations[clientOrg].mspid;
- const client = Client.loadFromConfig(connectionProfile);
+ const client = await Client.loadFromConfig(connectionProfile);
const actual = client.getMspid();
actual.should.equal(expected);
@@ -782,8 +782,8 @@ describe('Client', () => {
actual.should.equal(userMspId);
});
- it('MSP ID of the user context in preference to value from connection profile', () => {
- const client = Client.loadFromConfig(connectionProfile);
+ it('MSP ID of the user context in preference to value from connection profile', async () => {
+ const client = await Client.loadFromConfig(connectionProfile);
client.setUserContext(fakeUser, true);
const actual = client.getMspid();
@@ -1817,11 +1817,15 @@ describe('Client', () => {
let setCryptoKeyStoreStub;
let newCryptoKeyStoreStub;
let setCryptoSuiteStub;
+ let keyValStub;
let client;
beforeEach(() => {
+ keyValStub = {
+ init: sinon.stub()
+ };
getClientConfigStub = sinon.stub();
- newDefaultKeyValueStoreStub = sinon.stub().returns(Promise.resolve('key-val-store'));
+ newDefaultKeyValueStoreStub = sinon.stub().returns(keyValStub);
revert.push(Client.__set__('BaseClient.newDefaultKeyValueStore', newDefaultKeyValueStoreStub));
setStateStoreStub = sinon.stub();
setCryptoKeyStoreStub = sinon.stub();
@@ -1856,20 +1860,18 @@ describe('Client', () => {
}
});
- it('should return true and set the cryptokeystore', async () => {
+ it('should set the cryptokeystore', async () => {
getClientConfigStub.returns({credentialStore: {cryptoStore: 'store'}});
client._network_config = {getClientConfig: getClientConfigStub};
newCryptoKeyStoreStub.returns('new-crypto');
- const success = await client.initCredentialStores();
- success.should.be.true;
+ await client.initCredentialStores();
sinon.assert.called(getClientConfigStub);
sinon.assert.calledWith(newDefaultKeyValueStoreStub, {cryptoStore: 'store'});
- sinon.assert.calledWith(setStateStoreStub, 'key-val-store');
+ sinon.assert.calledWith(setStateStoreStub, keyValStub);
sinon.assert.called(cryptoSuiteStub);
sinon.assert.calledWith(setCryptoKeyStoreStub, 'new-crypto');
sinon.assert.calledWith(newCryptoKeyStoreStub, 'store');
sinon.assert.calledWith(setCryptoSuiteStub, {setCryptoKeyStore: setCryptoKeyStoreStub});
-
});
});
@@ -1933,6 +1935,7 @@ describe('Client', () => {
let getCryptoSuiteStub;
let newCryptoSuiteStub;
let importKeyStub;
+ let createKeyFromRawStub;
let SigningIdentityStub;
let SignerStub;
@@ -1940,7 +1943,11 @@ describe('Client', () => {
beforeEach(() => {
getCryptoSuiteStub = sinon.stub();
importKeyStub = sinon.stub();
- newCryptoSuiteStub = sinon.stub().returns({importKey: importKeyStub});
+ createKeyFromRawStub = sinon.stub();
+ newCryptoSuiteStub = sinon.stub().returns({
+ importKey: importKeyStub,
+ createKeyFromRaw: createKeyFromRawStub
+ });
revert.push(Client.__set__('BaseClient.newCryptoSuite', newCryptoSuiteStub));
SigningIdentityStub = sinon.stub();
revert.push(Client.__set__('SigningIdentity', SigningIdentityStub));
@@ -1951,79 +1958,68 @@ describe('Client', () => {
client.getCryptoSuite = getCryptoSuiteStub;
});
- it('should throw if no private key is given', () => {
- (() => {
- client.setAdminSigningIdentity(undefined, 'certificate', 'mspid');
- }).should.throw('Invalid parameter. Must have a valid private key.');
+ it('should reject if no private key is given', async () => {
+ await client.setAdminSigningIdentity(undefined, 'certificate', 'mspid').should.be.rejectedWith('Invalid parameter. Must have a valid private key.');
});
- it('should throw if private key is null', () => {
- (() => {
- client.setAdminSigningIdentity(null, 'certificate', 'mspid');
- }).should.throw('Invalid parameter. Must have a valid private key.');
+ it('should throw if private key is null', async () => {
+ await client.setAdminSigningIdentity(null, 'certificate', 'mspid').should.be.rejectedWith('Invalid parameter. Must have a valid private key.');
});
- it('should throw if private key is empty string', () => {
- (() => {
- client.setAdminSigningIdentity('', 'certificate', 'mspid');
- }).should.throw('Invalid parameter. Must have a valid private key.');
+ it('should throw if private key is empty string', async () => {
+ await client.setAdminSigningIdentity('', 'certificate', 'mspid').should.be.rejectedWith('Invalid parameter. Must have a valid private key.');
});
- it('should throw if no certificate key is given', () => {
- (() => {
- client.setAdminSigningIdentity('private-key', undefined, 'mspid');
- }).should.throw('Invalid parameter. Must have a valid certificate.');
+ it('should throw if no certificate key is given', async () => {
+ await client.setAdminSigningIdentity('private-key', undefined, 'mspid').should.be.rejectedWith('Invalid parameter. Must have a valid certificate.');
});
- it('should throw if certificate is null', () => {
- (() => {
- client.setAdminSigningIdentity('private-key', null, 'mspid');
- }).should.throw('Invalid parameter. Must have a valid certificate.');
+ it('should throw if certificate is null', async () => {
+ await client.setAdminSigningIdentity('private-key', null, 'mspid').should.be.rejectedWith('Invalid parameter. Must have a valid certificate.');
});
- it('should throw if certificate is empty string', () => {
- (() => {
- client.setAdminSigningIdentity('private-key', '', 'mspid');
- }).should.throw('Invalid parameter. Must have a valid certificate.');
+ it('should throw if certificate is empty string', async () => {
+ await client.setAdminSigningIdentity('private-key', '', 'mspid').should.be.rejectedWith('Invalid parameter. Must have a valid certificate.');
});
- it('should throw if no mspid is given', () => {
- (() => {
- client.setAdminSigningIdentity('private-key', 'certificate', undefined);
- }).should.throw('Invalid parameter. Must have a valid mspid.');
+ it('should throw if no mspid is given', async () => {
+ await client.setAdminSigningIdentity('private-key', 'certificate', undefined).should.be.rejectedWith('Invalid parameter. Must have a valid mspid.');
});
- it('should throw if certificate is null', () => {
- (() => {
- client.setAdminSigningIdentity('private-key', 'certificate', null);
- }).should.throw('Invalid parameter. Must have a valid mspid.');
+ it('should throw if certificate is null', async () => {
+ await client.setAdminSigningIdentity('private-key', 'certificate', null).should.be.rejectedWith('Invalid parameter. Must have a valid mspid.');
});
- it('should throw if certificate is empty string', () => {
- (() => {
- client.setAdminSigningIdentity('private-key', 'certificate', '');
- }).should.throw('Invalid parameter. Must have a valid mspid.');
+ it('should throw if certificate is empty string', async () => {
+ await client.setAdminSigningIdentity('private-key', 'certificate', '').should.be.rejectedWith('Invalid parameter. Must have a valid mspid.');
});
- it('should retrieve CryptoSuite and import the public and private keys before creating an identity', () => {
- getCryptoSuiteStub.returns({importKey: importKeyStub});
- importKeyStub.onCall(0).returns('private_key');
- importKeyStub.onCall(1).returns('public_key');
- client.setAdminSigningIdentity('private-key', 'certificate', 'mspid');
+ it('should retrieve CryptoSuite and import the public and private keys before creating an identity', async () => {
+ getCryptoSuiteStub.returns({
+ importKey: importKeyStub,
+ createKeyFromRaw: createKeyFromRawStub
+ });
+ createKeyFromRawStub.onCall(0).returns('private_key');
+ createKeyFromRawStub.onCall(1).returns('public_key');
+
+ await client.setAdminSigningIdentity('private-key', 'certificate', 'mspid');
+
sinon.assert.called(getCryptoSuiteStub);
- sinon.assert.calledWith(importKeyStub, 'private-key', {ephemeral: true});
- sinon.assert.calledWith(importKeyStub, 'certificate', {ephemeral: true});
+ sinon.assert.calledWith(createKeyFromRawStub, 'private-key');
+ sinon.assert.calledWith(createKeyFromRawStub, 'certificate');
sinon.assert.calledWith(SigningIdentityStub, 'certificate', 'public_key', 'mspid', getCryptoSuiteStub(), new SignerStub());
sinon.assert.calledWith(SignerStub, getCryptoSuiteStub(), 'private_key');
client._adminSigningIdentity.should.deep.equal(new SigningIdentityStub());
});
- it('should create a new CryptoSuite and import the public and private keys before creating an identity', () => {
- importKeyStub.onCall(0).returns('private_key');
- importKeyStub.onCall(1).returns('public_key');
- client.setAdminSigningIdentity('private-key', 'certificate', 'mspid');
- sinon.assert.calledWith(importKeyStub, 'private-key', {ephemeral: true});
- sinon.assert.calledWith(importKeyStub, 'certificate', {ephemeral: true});
+ it('should create a new CryptoSuite and import the public and private keys before creating an identity', async () => {
+ createKeyFromRawStub.onCall(0).returns('private_key');
+ createKeyFromRawStub.onCall(1).returns('public_key');
+
+ await client.setAdminSigningIdentity('private-key', 'certificate', 'mspid');
+
+ sinon.assert.calledWith(createKeyFromRawStub, 'private-key');
+ sinon.assert.calledWith(createKeyFromRawStub, 'certificate');
sinon.assert.calledWith(SigningIdentityStub, 'certificate', 'public_key', 'mspid', newCryptoSuiteStub(), new SignerStub());
sinon.assert.calledWith(SignerStub, newCryptoSuiteStub(), 'private_key');
client._adminSigningIdentity.should.deep.equal(new SigningIdentityStub());
@@ -2055,16 +2051,16 @@ describe('Client', () => {
client.setAdminSigningIdentity = getAdminSigningIdentityStub;
});
- it('should throw an error if no network config is present', () => {
- (() => {
- client._setAdminFromConfig();
- }).should.throw('No common connection profile has been loaded');
+ it('should throw an error if no network config is present', async () => {
+ await client._setAdminFromConfig().should.be.rejectedWith('No common connection profile has been loaded');
});
- it('should not call anything if client config is null', () => {
+ it('should not call anything if client config is null', async () => {
getClientConfigStub.returns(null);
client._network_config = {getClientConfig: getClientConfigStub};
- client._setAdminFromConfig();
+
+ await client._setAdminFromConfig();
+
sinon.assert.notCalled(getOrganizationStub);
sinon.assert.notCalled(getMspidStub);
sinon.assert.notCalled(getAdminPrivateKeyStub);
@@ -2613,6 +2609,7 @@ describe('Client', () => {
let readFileStub;
let getCryptoSuiteStub;
let importKeyStub;
+ let createKeyFromRawStub;
let setCryptoSuiteStub;
let setEnrollmentStub;
let setUserContextStub;
@@ -2629,7 +2626,8 @@ describe('Client', () => {
FakeUser.prototype.setEnrollment = setEnrollmentStub;
readFileStub = sinon.stub().returns(Promise.resolve(1));
getCryptoSuiteStub = sinon.stub();
- importKeyStub = sinon.stub();
+ importKeyStub = sinon.stub().returns(Promise.resolve('imported-key'));
+ createKeyFromRawStub = sinon.stub().returns(Promise.resolve('created-key'));
setUserContextStub = sinon.stub().returns(Promise.resolve());
setCryptoKeyStoreStub = sinon.stub();
@@ -2637,7 +2635,10 @@ describe('Client', () => {
revert.push(Client.__set__('User', FakeUser));
client = new Client();
- client.getCryptoSuite = getCryptoSuiteStub.returns({importKey: importKeyStub.returns(Promise.resolve('imported-key'))});
+ client.getCryptoSuite = getCryptoSuiteStub.returns({
+ importKey: importKeyStub,
+ createKeyFromRaw: createKeyFromRawStub
+ });
client.setUserContext = setUserContextStub;
});
@@ -2698,7 +2699,7 @@ describe('Client', () => {
sinon.assert.calledWith(FakeLogger.debug, 'then signedCertPEM data');
sinon.assert.calledWith(setCryptoSuiteStub, getCryptoSuiteStub());
sinon.assert.called(getCryptoSuiteStub);
- sinon.assert.calledWith(setEnrollmentStub, 'imported-key', 'privateKeyPEM', '1', true);
+ sinon.assert.calledWith(setEnrollmentStub, 'created-key', 'privateKeyPEM', '1', true);
sinon.assert.calledWith(FakeLogger.debug, 'then setUserContext');
sinon.assert.calledWith(setUserContextStub, new FakeUser(), true);
sinon.assert.calledWith(FakeLogger.debug, 'then user');
@@ -2716,7 +2717,7 @@ describe('Client', () => {
sinon.assert.calledWith(FakeLogger.debug, 'then signedCertPEM data');
sinon.assert.calledWith(setCryptoSuiteStub, getCryptoSuiteStub());
sinon.assert.called(getCryptoSuiteStub);
- sinon.assert.calledWith(setEnrollmentStub, 'imported-key', 'privateKeyPEM', '1', true);
+ sinon.assert.calledWith(setEnrollmentStub, 'created-key', 'privateKeyPEM', '1', true);
sinon.assert.calledWith(FakeLogger.debug, 'then setUserContext');
sinon.assert.calledWith(setUserContextStub, new FakeUser(), true);
sinon.assert.calledWith(FakeLogger.debug, 'then user');
@@ -2724,9 +2725,23 @@ describe('Client', () => {
});
it('should return a user if getCryptoSuite does not return null', async () => {
- getCryptoSuiteStub.returns({setCryptoKeyStore: setCryptoKeyStoreStub, importKey: importKeyStub, _cryptoKeyStore: {}});
+ getCryptoSuiteStub.returns({
+ setCryptoKeyStore: setCryptoKeyStoreStub,
+ createKeyFromRaw: createKeyFromRawStub,
+ importKey: importKeyStub,
+ _cryptoKeyStore: {}
+ });
readFileStub.returns(Promise.resolve('privateKeyPEM'));
- const user = await client.createUser({username: 'name', mspid: '1', cryptoContent: {privateKey: 'private-key', signedCert: 'signed-cert', signedCertPEM: 'signed-cert-PEM'}, skipPersistence: true});
+ const user = await client.createUser({
+ username: 'name',
+ mspid: '1',
+ cryptoContent: {
+ privateKey: 'private-key',
+ signedCert: 'signed-cert',
+ signedCertPEM: 'signed-cert-PEM'
+ },
+ skipPersistence: true
+ });
sinon.assert.calledWith(readFileStub, 'private-key');
sinon.assert.calledWith(FakeLogger.debug, 'then privateKeyPEM data');
sinon.assert.calledWith(readFileStub, 'signed-cert');
@@ -2734,7 +2749,7 @@ describe('Client', () => {
sinon.assert.calledWith(setCryptoSuiteStub, getCryptoSuiteStub());
sinon.assert.called(getCryptoSuiteStub);
sinon.assert.calledWith(FakeLogger.debug, 'cryptoSuite has a cryptoKeyStore');
- sinon.assert.calledWith(setEnrollmentStub, 'imported-key', 'privateKeyPEM', '1', true);
+ sinon.assert.calledWith(setEnrollmentStub, 'created-key', 'privateKeyPEM', '1', true);
sinon.assert.calledWith(FakeLogger.debug, 'then setUserContext');
sinon.assert.calledWith(setUserContextStub, new FakeUser(), true);
sinon.assert.calledWith(FakeLogger.debug, 'then user');
diff --git a/fabric-client/test/User.js b/fabric-client/test/User.js
index b9fa8cfac8..c19dfe140d 100644
--- a/fabric-client/test/User.js
+++ b/fabric-client/test/User.js
@@ -189,7 +189,7 @@ describe('User', () => {
const FakeIdentity = sandbox.stub();
const FakeSigningIdentity = sandbox.stub();
- const returnStub = sandbox.stub({setCryptoKeyStore: () => {}, importKey: () => {}});
+ const returnStub = sandbox.stub({setCryptoKeyStore: () => {}, importKey: () => {}, createKeyFromRaw: () => {}});
const newCryptoSuiteStub = sandbox.stub(FakeSdkUtils, 'newCryptoSuite').returns(returnStub);
UserRewire.__set__('sdkUtils', FakeSdkUtils);
@@ -216,6 +216,7 @@ describe('User', () => {
const cryptoSuite = {
setCryptoKeyStore: () => {},
importKey: () => {},
+ createKeyFromRaw: () => {}
};
const FakeSetCryptoKeyStore = sandbox.stub(cryptoSuite, 'setCryptoKeyStore');
@@ -281,9 +282,10 @@ describe('User', () => {
const cryptoSuite = {
setCryptoKeyStore: () => {},
importKey: () => {},
+ createKeyFromRaw: () => {}
};
- const FakeImportKey = sandbox.stub(cryptoSuite, 'importKey');
+ const FakeCreateKey = sandbox.stub(cryptoSuite, 'createKeyFromRaw');
sandbox.stub(FakeSdkUtils, 'newCryptoSuite').returns(cryptoSuite);
sandbox.stub(FakeSdkUtils, 'newCryptoKeyStore').returns('test_cryptoKeyStore');
@@ -296,8 +298,8 @@ describe('User', () => {
const obj = new UserRewire('my_cfg');
await obj.setEnrollment('test_privateKey', 'test_certificate', 'test_mspId', true);
- sinon.assert.calledOnce(FakeImportKey);
- sinon.assert.calledWith(FakeImportKey, 'test_certificate', {ephemeral: true});
+ sinon.assert.calledOnce(FakeCreateKey);
+ sinon.assert.calledWith(FakeCreateKey, 'test_certificate');
});
it('should set the users identity', async() => {
@@ -313,12 +315,14 @@ describe('User', () => {
const FakeCryptoSuite = {
setCryptoKeyStore: () => {},
importKey: () => {},
+ createKeyFromRaw: () => {},
+ _cryptoKeyStore: true
};
sandbox.stub(FakeSdkUtils, 'newCryptoSuite').returns(FakeCryptoSuite);
sandbox.stub(FakeSdkUtils, 'newCryptoKeyStore').returns('test_cryptoKeyStore');
- sandbox.stub(FakeCryptoSuite, 'importKey').returns('test_key');
-
+ sandbox.stub(FakeCryptoSuite, 'importKey').returns('import_key');
+ sandbox.stub(FakeCryptoSuite, 'createKeyFromRaw').returns('raw_key');
UserRewire.__set__('sdkUtils', FakeSdkUtils);
UserRewire.__set__('Identity', FakeIdentity);
@@ -328,7 +332,7 @@ describe('User', () => {
await obj.setEnrollment('test_privateKey', 'test_certificate', 'test_mspId', false);
sinon.assert.calledOnce(FakeIdentity);
- sinon.assert.calledWith(FakeIdentity, 'test_certificate', 'test_key', 'test_mspId', FakeCryptoSuite);
+ sinon.assert.calledWith(FakeIdentity, 'test_certificate', 'import_key', 'test_mspId', FakeCryptoSuite);
});
it('should set the users signingIdentity', async() => {
@@ -344,11 +348,13 @@ describe('User', () => {
const FakeCryptoSuite = {
setCryptoKeyStore: () => {},
importKey: () => {},
+ createKeyFromRaw: () => {}
};
sandbox.stub(FakeSdkUtils, 'newCryptoSuite').returns(FakeCryptoSuite);
sandbox.stub(FakeSdkUtils, 'newCryptoKeyStore').returns('test_cryptoKeyStore');
- sandbox.stub(FakeCryptoSuite, 'importKey').returns('test_key');
+ sandbox.stub(FakeCryptoSuite, 'importKey').returns('import_key');
+ sandbox.stub(FakeCryptoSuite, 'createKeyFromRaw').returns('raw_key');
UserRewire.__set__('sdkUtils', FakeSdkUtils);
@@ -359,7 +365,7 @@ describe('User', () => {
await obj.setEnrollment('test_privateKey', 'test_certificate', 'test_mspId', false);
sinon.assert.calledOnce(FakeSigningIdentity);
- sinon.assert.calledWith(FakeIdentity, 'test_certificate', 'test_key', 'test_mspId', FakeCryptoSuite);
+ sinon.assert.calledWith(FakeIdentity, 'test_certificate', 'raw_key', 'test_mspId', FakeCryptoSuite);
});
});
@@ -396,7 +402,7 @@ describe('User', () => {
sandbox.restore();
});
- it('should log and set the users state, name, roles, afilliation and enrollmentSecret', () => {
+ it('should log and set the users state, name, roles, afilliation and enrollmentSecret', async () => {
const FakeLogger = {
debug: () => {}
};
@@ -406,26 +412,31 @@ describe('User', () => {
newCryptoKeyStore: () => {},
};
+ const privateStub = {
+ isPrivate: () => {
+ return true;
+ }
+ };
+
const FakeCryptoSuite = {
setCryptoKeyStore: () => {},
- importKey: () => {},
- getKey: () => {}
+ importKey: () => sinon.stub().resolves(),
+ getKey: sinon.stub().returns(privateStub),
+ createKeyFromRaw: () => {}
};
const debugStub = sandbox.stub(FakeLogger, 'debug');
const FakeIdentity = sandbox.stub();
- const promise = new Promise(() => {});
sandbox.stub(FakeSdkUtils, 'newCryptoSuite').returns(FakeCryptoSuite);
sandbox.stub(FakeSdkUtils, 'newCryptoKeyStore').returns('test_cryptoKeyStore');
- sandbox.stub(FakeCryptoSuite, 'importKey').returns(promise);
UserRewire.__set__('logger', FakeLogger);
UserRewire.__set__('sdkUtils', FakeSdkUtils);
UserRewire.__set__('Identity', FakeIdentity);
const obj = new UserRewire('cfg');
- obj.fromString('{ "name":"cfg", "roles":"test_role", "affiliation":"test_affiliation", "enrollmentSecret":"test_enrollmentSecret", "mspid":"test_mspId", "enrollment":{"identity":{"certificate":"test_certificate"}}}', false);
+ await obj.fromString('{ "name":"cfg", "roles":"test_role", "affiliation":"test_affiliation", "enrollmentSecret":"test_enrollmentSecret", "mspid":"test_mspId", "enrollment":{"identity":{"certificate":"test_certificate"}}}', false);
sinon.assert.calledOnce(debugStub);
sinon.assert.calledWith(debugStub, 'fromString --start');
@@ -435,70 +446,33 @@ describe('User', () => {
obj._enrollmentSecret.should.equal('test_enrollmentSecret');
});
- it('should throw error if state name is not the same as user name', () => {
- (() => {
- const FakeLogger = {
- debug: () => {}
- };
-
- sandbox.stub(FakeLogger, 'debug');
-
- UserRewire.__set__('logger', FakeLogger);
-
- const obj = new UserRewire('cfg');
- obj.fromString('{ "name":"wrong_name", "roles":"test_role", "affiliation":"test_affiliation", "enrollmentSecret":"test_enrollmentSecret", "mspid":"test_mspid", "enrollment":{"identity":{"certificate":"test_certificate"}}}', false);
- }).should.throw(/name mismatch: 'wrong_name' does not equal 'cfg'/);
- });
-
- it('should throw error if the state has no mspid', () => {
- (() => {
- const FakeLogger = {
- debug: () => {}
- };
+ it('should throw error if state name is not the same as user name', async () => {
+ const FakeLogger = {
+ debug: () => {}
+ };
- sandbox.stub(FakeLogger, 'debug');
+ sandbox.stub(FakeLogger, 'debug');
- UserRewire.__set__('logger', FakeLogger);
+ UserRewire.__set__('logger', FakeLogger);
- const obj = new UserRewire('cfg');
- obj.fromString('{ "name":"cfg", "roles":"test_role", "affiliation":"test_affiliation", "enrollmentSecret":"test_enrollmentSecret", "mspid":"", "enrollment":{"identity":{"certificate":"test_certificate"}}}', false);
- }).should.throw(/Failed to find "mspid" in the deserialized state object for the user. Likely due to an outdated state store./);
+ const obj = new UserRewire('cfg');
+ await obj.fromString('{ "name":"wrong_name", "roles":"test_role", "affiliation":"test_affiliation", "enrollmentSecret":"test_enrollmentSecret", "mspid":"test_mspid", "enrollment":{"identity":{"certificate":"test_certificate"}}}', false).should.be.rejectedWith(/name mismatch: 'wrong_name' does not equal 'cfg'/);
});
- it('should set the users mspid to the state mspid', () => {
+ it('should throw error if the state has no mspid', async () => {
const FakeLogger = {
debug: () => {}
};
- const FakeSdkUtils = {
- newCryptoSuite: () => {},
- newCryptoKeyStore: () => {},
- };
-
- const FakeCryptoSuite = {
- setCryptoKeyStore: () => {},
- importKey: () => {},
- getKey: () => {}
- };
-
- const FakeIdentity = sandbox.stub();
- const promise = new Promise(() => {});
-
- sandbox.stub(FakeSdkUtils, 'newCryptoSuite').returns(FakeCryptoSuite);
- sandbox.stub(FakeSdkUtils, 'newCryptoKeyStore').returns('test_cryptoKeyStore');
- sandbox.stub(FakeCryptoSuite, 'importKey').returns(promise);
+ sandbox.stub(FakeLogger, 'debug');
UserRewire.__set__('logger', FakeLogger);
- UserRewire.__set__('sdkUtils', FakeSdkUtils);
- UserRewire.__set__('Identity', FakeIdentity);
const obj = new UserRewire('cfg');
- obj.fromString('{ "name":"cfg", "roles":"test_role", "affiliation":"test_affiliation", "enrollmentSecret":"test_enrollmentSecret", "mspid":"test_mspId", "enrollment":{"identity":{"certificate":"test_certificate"}}}', true);
-
- obj._mspId.should.equal('test_mspId');
+ await obj.fromString('{ "name":"cfg", "roles":"test_role", "affiliation":"test_affiliation", "enrollmentSecret":"test_enrollmentSecret", "mspid":"", "enrollment":{"identity":{"certificate":"test_certificate"}}}', false).should.be.rejectedWith(/Failed to find "mspid" in the deserialized state object for the user. Likely due to an outdated state store./);
});
- it('should set import_promise if no_save is true', async () => {
+ it('should set the users mspid to the state mspid', async () => {
const FakeLogger = {
debug: () => {}
};
@@ -508,41 +482,39 @@ describe('User', () => {
newCryptoKeyStore: () => {},
};
+ const privateStub = {
+ isPrivate: () => {
+ return true;
+ }
+ };
+
const FakeCryptoSuite = {
setCryptoKeyStore: () => {},
importKey: () => {},
- getKey: () => {}
- };
-
- const FakeCryptoAlgorithms = {
- X509Certificate: 'X509Certificate',
+ getKey: sinon.stub().returns(privateStub),
+ createKeyFromRaw: () => {}
};
const FakeIdentity = sandbox.stub();
- const FakeImportKey = sandbox.stub(FakeCryptoSuite, 'importKey').returns('key');
- const promise = new Promise((resolve) => {
- resolve({isPrivate() {
- return true;
- }});
- });
+ const promise = new Promise(() => {});
sandbox.stub(FakeSdkUtils, 'newCryptoSuite').returns(FakeCryptoSuite);
sandbox.stub(FakeSdkUtils, 'newCryptoKeyStore').returns('test_cryptoKeyStore');
- sandbox.stub(FakeCryptoSuite, 'getKey').returns(promise);
+ sandbox.stub(FakeCryptoSuite, 'importKey').returns(promise);
+ sandbox.stub(FakeCryptoSuite, 'createKeyFromRaw').returns('create_pem');
UserRewire.__set__('logger', FakeLogger);
UserRewire.__set__('sdkUtils', FakeSdkUtils);
UserRewire.__set__('Identity', FakeIdentity);
- UserRewire.__set__('CryptoAlgorithms', FakeCryptoAlgorithms);
const obj = new UserRewire('cfg');
await obj.fromString('{ "name":"cfg", "roles":"test_role", "affiliation":"test_affiliation", "enrollmentSecret":"test_enrollmentSecret", "mspid":"test_mspId", "enrollment":{"identity":{"certificate":"test_certificate"}}}', true);
- sinon.assert.calledOnce(FakeImportKey);
- sinon.assert.calledWith(FakeImportKey, 'test_certificate', {algorithm: 'X509Certificate', ephemeral: true});
+ obj._mspId.should.equal('test_mspId');
});
- it('should throw an error if key is not set if no_save is true', async () => {
+
+ it('should throw an error if resulting key is not private', async () => {
const FakeLogger = {
debug: () => {}
};
@@ -552,35 +524,33 @@ describe('User', () => {
newCryptoKeyStore: () => {},
};
+ const privateStub = {
+ isPrivate: () => {
+ return false;
+ }
+ };
+
const FakeCryptoSuite = {
setCryptoKeyStore: () => {},
importKey: () => {},
- getKey: () => {}
- };
-
- const FakeCryptoAlgorithms = {
- X509Certificate: 'X509Certificate',
+ getKey: sinon.stub().returns(privateStub),
+ createKeyFromRaw: () => {}
};
const FakeIdentity = sandbox.stub();
- sandbox.stub(FakeCryptoSuite, 'importKey').returns(null);
- const promise = new Promise((resolve) => {
- resolve({isPrivate() {
- return true;
- }});
- });
+ const promise = new Promise(() => {});
sandbox.stub(FakeSdkUtils, 'newCryptoSuite').returns(FakeCryptoSuite);
sandbox.stub(FakeSdkUtils, 'newCryptoKeyStore').returns('test_cryptoKeyStore');
- sandbox.stub(FakeCryptoSuite, 'getKey').returns(promise);
+ sandbox.stub(FakeCryptoSuite, 'importKey').returns(promise);
+ sandbox.stub(FakeCryptoSuite, 'createKeyFromRaw').returns('create_pem');
UserRewire.__set__('logger', FakeLogger);
UserRewire.__set__('sdkUtils', FakeSdkUtils);
UserRewire.__set__('Identity', FakeIdentity);
- UserRewire.__set__('CryptoAlgorithms', FakeCryptoAlgorithms);
const obj = new UserRewire('cfg');
- await obj.fromString('{ "name":"cfg", "roles":"test_role", "affiliation":"test_affiliation", "enrollmentSecret":"test_enrollmentSecret", "mspid":"test_mspId", "enrollment":{"identity":{"certificate":"test_certificate"}}}', true).should.be.rejectedWith(/Import of saved user has failed/);
+ await obj.fromString('{ "name":"cfg", "roles":"test_role", "affiliation":"test_affiliation", "enrollmentSecret":"test_enrollmentSecret", "mspid":"test_mspId", "enrollment":{"identity":{"certificate":"test_certificate"}}}', true).should.be.rejectedWith(/Private key missing from key store. Can not establish the signing identity for user/);
});
it('should set import_promise if no_save is false', async () => {
@@ -596,7 +566,8 @@ describe('User', () => {
const FakeCryptoSuite = {
setCryptoKeyStore: () => {},
importKey: () => {},
- getKey: () => {}
+ getKey: () => {},
+ createKeyFromRaw: () => {}
};
const FakeCryptoAlgorithms = {
@@ -640,7 +611,8 @@ describe('User', () => {
const FakeCryptoSuite = {
setCryptoKeyStore: () => {},
importKey: () => {},
- getKey: () => {}
+ getKey: () => {},
+ createKeyFromRaw: () => {}
};
const FakeCryptoAlgorithms = {
@@ -686,7 +658,8 @@ describe('User', () => {
const FakeCryptoSuite = {
setCryptoKeyStore: () => {},
importKey: () => {},
- getKey: () => {}
+ getKey: () => {},
+ createKeyFromRaw: () => {}
};
const FakeKey = {
@@ -732,7 +705,8 @@ describe('User', () => {
const FakeCryptoSuite = {
setCryptoKeyStore: () => {},
importKey: () => {},
- getKey: () => {}
+ getKey: () => {},
+ createKeyFromRaw: () => {}
};
const FakeIdentity = sandbox.stub();
diff --git a/fabric-client/test/impl/CouchDBKeyValueStore.js b/fabric-client/test/impl/CouchDBKeyValueStore.js
new file mode 100644
index 0000000000..c047360ac9
--- /dev/null
+++ b/fabric-client/test/impl/CouchDBKeyValueStore.js
@@ -0,0 +1,200 @@
+/**
+ * Copyright 2019 IBM All Rights Reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+'use strict';
+
+const rewire = require('rewire');
+const CouchDBKeyValueStoreRW = rewire('../../lib/impl/CouchDBKeyValueStore');
+const CouchDBKeyValueStore = require('../../lib/impl/CouchDBKeyValueStore');
+const CouchdbMock = require('mock-couch');
+
+const chai = require('chai');
+const should = chai.should();
+const sinon = require('sinon');
+
+describe('CouchDBKeyValueStore', () => {
+
+ let couchDB;
+ const listenPort = 5489;
+ const badPort = 9999;
+ const baseURL = 'http://localhost:';
+
+ beforeEach(() => {
+ couchDB = CouchdbMock.createServer();
+ couchDB.listen(listenPort);
+ });
+
+ afterEach(() => {
+ couchDB.close();
+ });
+
+ describe('#constructor', () => {
+
+ it('should throw if instantiated without options', () => {
+ (() => {
+ new CouchDBKeyValueStore();
+ }).should.throw(/Must provide the CouchDB database url to store membership data/);
+ });
+
+ it('should throw if instantiated with incorrect options', () => {
+ (() => {
+ new CouchDBKeyValueStore({droids: 'not the ones looked for'});
+ }).should.throw(/Must provide the CouchDB database url to store membership data/);
+ });
+
+ it('should set a default member_db name if not passed', () => {
+ const myStore = new CouchDBKeyValueStore({url: 'anything'});
+ myStore._name.should.equal('member_db');
+ });
+
+ it('should set the member_db name if not passed', () => {
+ const myStore = new CouchDBKeyValueStore({url: 'anything', name: 'pingu'});
+ myStore._name.should.equal('pingu');
+ });
+ });
+
+ describe('#init', () => {
+
+ let revert;
+ const errorStub = sinon.stub();
+ const debugStub = sinon.stub();
+ const fakeLogger = {
+ debug: debugStub,
+ error: errorStub
+ };
+
+ beforeEach(() => {
+ errorStub.resetHistory();
+ debugStub.resetHistory();
+
+ revert = CouchDBKeyValueStoreRW.__set__('logger', fakeLogger);
+ });
+
+ afterEach(() => {
+ revert();
+ });
+
+ it('should throw if unable to connect to URL', async () => {
+ const store = new CouchDBKeyValueStoreRW({url: baseURL + badPort});
+ await store.initialize().should.be.rejectedWith(/Error initializing database to store membership data: member_db Error: connect ECONNREFUSED 127.0.0.1:9999/);
+ });
+
+ it('should connect to and create a store if one does not exist', async () => {
+ const store = new CouchDBKeyValueStoreRW({url: baseURL + listenPort});
+ await store.initialize();
+
+ sinon.assert.calledWith(debugStub, 'Created %s database', 'member_db');
+ });
+
+ it('should connect to a store if one does exist', async () => {
+ const store = new CouchDBKeyValueStoreRW({url: baseURL + listenPort});
+ await store.initialize();
+
+ debugStub.resetHistory();
+
+ await store.initialize();
+ sinon.assert.calledWith(debugStub, '%s already exists', 'member_db');
+ });
+
+ });
+
+
+ describe('#getValue', () => {
+
+ const myFakeError = function(a, b) {
+ throw new Error('Forced Test Error');
+ };
+
+ const myFakeReturn = function(a, b) {
+ b(null, {member: 'Fake Test Value'});
+ };
+
+ it('should return an error', async() => {
+ const store = new CouchDBKeyValueStore({url: baseURL + listenPort});
+ await store.initialize();
+
+ const fakeGet = {
+ get: sinon.stub().callsFake(myFakeError)
+ };
+ store._database = fakeGet;
+
+ await store.getValue('bert').should.be.rejectedWith(/Forced Test Error/);
+ });
+
+ it('should return null if item not found', async () => {
+ const store = new CouchDBKeyValueStore({url: baseURL + listenPort});
+ await store.initialize();
+ const val = await store.getValue('bert');
+ should.not.exist(val);
+ });
+
+ it('should return the item value if item found', async () => {
+ const store = new CouchDBKeyValueStore({url: baseURL + listenPort});
+ await store.initialize();
+
+ const fakeGet = {
+ get: sinon.stub().callsFake(myFakeReturn)
+ };
+ store._database = fakeGet;
+
+ const value = await store.getValue('test');
+ value.should.equal('Fake Test Value');
+ });
+ });
+
+ describe('#setValue', () => {
+
+ const myGetError = function(a, b) {
+ const error = new Error('Forced Error');
+ error.error = 'not_found';
+ b(error, null);
+ };
+ const myGet = function(a, b) {
+ b(null, {_rev: 101});
+ };
+
+ const myInsert = function(a, b) {
+ b(null, 'Success');
+ };
+
+ it('should create a value if it does not exist already', async () => {
+ const store = new CouchDBKeyValueStore({url: baseURL + listenPort});
+ await store.initialize();
+
+ const insertStub = sinon.stub().callsFake(myInsert);
+ const fakeDB = {
+ get: sinon.stub().callsFake(myGet),
+ insert: insertStub
+ };
+ store._database = fakeDB;
+
+ await store.setValue('myKey', 'myValue');
+
+ // insert should have been called once with known value
+ sinon.assert.calledOnce(insertStub);
+ sinon.assert.calledWith(insertStub, {_id: 'myKey', _rev: 101, member: 'myValue'});
+
+ });
+
+ it('should update the revision number if it already exists', async () => {
+ const store = new CouchDBKeyValueStore({url: baseURL + listenPort});
+ await store.initialize();
+
+ const insertStub = sinon.stub().callsFake(myInsert);
+ const fakeDB = {
+ get: sinon.stub().callsFake(myGetError),
+ insert: insertStub
+ };
+ store._database = fakeDB;
+
+ await store.setValue('myKey', 'myValue');
+
+ // insert should ah e been called once with known value
+ sinon.assert.calledOnce(insertStub);
+ sinon.assert.calledWith(insertStub, {_id: 'myKey', member: 'myValue'});
+ });
+ });
+});
diff --git a/fabric-client/test/impl/FileKeyValueStore.js b/fabric-client/test/impl/FileKeyValueStore.js
new file mode 100644
index 0000000000..2c8f0e3bc7
--- /dev/null
+++ b/fabric-client/test/impl/FileKeyValueStore.js
@@ -0,0 +1,183 @@
+/**
+ * Copyright 2019 IBM All Rights Reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+'use strict';
+
+const rewire = require('rewire');
+const FileKeyValueStoreRW = rewire('../../lib/impl/FileKeyValueStore');
+
+const chai = require('chai');
+const should = chai.should();
+const sinon = require('sinon');
+
+describe('FileKeyValueStore', () => {
+
+ let revert;
+ let mkDirsStub;
+ let readFileStub;
+ let writeFileStub;
+ let fsStub;
+ let errorStub;
+ let debugStub;
+ let fakeLogger;
+
+
+ beforeEach(() => {
+ revert = [];
+ mkDirsStub = sinon.stub().returns();
+ readFileStub = sinon.stub().resolves();
+ writeFileStub = sinon.stub().resolves();
+ fsStub = {
+ mkdirs: mkDirsStub,
+ readFile: readFileStub,
+ writeFile: writeFileStub
+ };
+
+ errorStub = sinon.stub();
+ debugStub = sinon.stub();
+ fakeLogger = {
+ debug: debugStub,
+ error: errorStub
+ };
+
+ revert.push(FileKeyValueStoreRW.__set__('fs', fsStub));
+ revert.push(FileKeyValueStoreRW.__set__('logger', fakeLogger));
+ });
+
+ afterEach(() => {
+ if (revert.length) {
+ revert.forEach(Function.prototype.call, Function.prototype.call);
+ }
+ });
+
+ describe('Constructor', () => {
+
+ it('should throw when no options are given', () => {
+ (() => {
+ new FileKeyValueStoreRW();
+ }).should.throw(/Must provide the path to the directory to hold files for the store./);
+ });
+
+ it('should throw when no required options are given', () => {
+ (() => {
+ new FileKeyValueStoreRW({penguin: 'unrequired'});
+ }).should.throw(/Must provide the path to the directory to hold files for the store./);
+ });
+
+
+ it('should set the file path from the passed options', () => {
+ const store = new FileKeyValueStoreRW({path: '/my/path/is/amazing'});
+ store._dir.should.equal('/my/path/is/amazing');
+ });
+ });
+
+ describe('#init', () => {
+ it('should throw on error when creating dir', async () => {
+
+ const err = new Error('fake error');
+ err.code = 42;
+ mkDirsStub.throws(err);
+ const store = new FileKeyValueStoreRW({path: '/such_path'});
+ await store.initialize().should.be.rejectedWith(/fake error/);
+ sinon.assert.calledOnce(errorStub);
+ sinon.assert.calledWith(errorStub, 'constructor, error creating directory, code: %s', 42);
+ });
+
+ it('should not throw on error when creating dir that exists', async () => {
+ const err = new Error('fake error');
+ err.code = 'EEXIST';
+ mkDirsStub.throws(err);
+ const store = new FileKeyValueStoreRW({path: '/such_path'});
+ const response = await store.initialize();
+ should.not.exist(response);
+ });
+
+ it('should call fs.mkdirs with constructor directory', () => {
+ const store = new FileKeyValueStoreRW({path: '/such_path'});
+ store.initialize();
+
+ // Check correct calls
+ sinon.assert.calledOnce(mkDirsStub);
+ sinon.assert.notCalled(readFileStub);
+ sinon.assert.notCalled(writeFileStub);
+
+ // check passed args
+ mkDirsStub.getCall(0).args[0].should.equal('/such_path');
+
+ // debug logging
+ sinon.assert.calledOnce(debugStub);
+ sinon.assert.calledWith(debugStub, 'constructor', {options: {path: '/such_path'}});
+
+ });
+ });
+
+ describe('#getValue()', () => {
+ it('should call fs.readFile with passed directory key and utf8 opts', async () => {
+ const store = await new FileKeyValueStoreRW({path: '/such_path'});
+ store.initialize();
+ store.getValue('myKey');
+
+ // Check correct calls
+ sinon.assert.calledOnce(mkDirsStub);
+ sinon.assert.calledOnce(readFileStub);
+ sinon.assert.notCalled(writeFileStub);
+
+ // check passed args
+ readFileStub.getCall(0).args[0].should.equal('/such_path/myKey');
+ readFileStub.getCall(0).args[1].should.equal('utf8');
+
+ // debug logging
+ sinon.assert.calledWith(debugStub, 'getValue', {key: 'myKey'});
+ });
+
+ it('should resolve null if the error returned is ENOENT', async () => {
+ const err = new Error('fake error');
+ err.code = 'ENOENT';
+ readFileStub.rejects(err);
+
+ const myKeys = await new FileKeyValueStoreRW({path: '/such_path'});
+ const resp = await myKeys.getValue('myKey');
+ should.not.exist(resp);
+ });
+
+ it('should reject if the error returned is not ENOENT', async () => {
+ const err = new Error('fake rethrow error');
+ err.code = 'NOT ENOENT';
+ readFileStub.rejects(err);
+ const myKeys = await new FileKeyValueStoreRW({path: '/such_path'});
+ await myKeys.getValue('myKey').should.be.rejectedWith(/fake rethrow error/);
+ });
+ });
+
+ describe('#setValue()', () => {
+
+ it('should call fs.writeFile with default path and passed value', async () => {
+ const store = await new FileKeyValueStoreRW({path: '/such_path'});
+ store.initialize();
+ await store.setValue('myKey', 'myValue');
+
+ // Check correct calls
+ sinon.assert.calledOnce(mkDirsStub);
+ sinon.assert.notCalled(readFileStub);
+ sinon.assert.calledOnce(writeFileStub);
+
+ // check passed args
+ writeFileStub.getCall(0).args[0].should.equal('/such_path/myKey');
+ writeFileStub.getCall(0).args[1].should.equal('myValue');
+
+ // debug logging
+ sinon.assert.calledWith(debugStub, 'setValue', {key: 'myKey'});
+ });
+
+ it('should reject if the error returned is not ENOENT', async () => {
+ const err = new Error('fake rethrow error');
+ writeFileStub.rejects(err);
+ const myKeys = await new FileKeyValueStoreRW({path: '/such_path'});
+ await myKeys.setValue('myKey').should.be.rejectedWith(/fake rethrow error/);
+ });
+ });
+
+});
diff --git a/fabric-client/test/msp/msp.js b/fabric-client/test/msp/msp.js
index 3be599d989..a7a0d6a424 100644
--- a/fabric-client/test/msp/msp.js
+++ b/fabric-client/test/msp/msp.js
@@ -13,9 +13,8 @@ const utils = require('../../lib/utils');
const path = require('path');
const fs = require('fs');
-const chai = require('chai');
+require('chai');
const sinon = require('sinon');
-const should = chai.should();
const rewire = require('rewire');
const MspRewire = rewire('../../lib/msp/msp');
@@ -286,11 +285,11 @@ describe('MSP', () => {
}
});
- it('should call cryptoSuite.importKey with ephemeral: true if passed a false flag', () => {
+ it('should call cryptoSuite.createKeyFromRaw if passed a false flag', () => {
const importStub = sinon.stub();
const cryptoStub = {
- importKey: importStub
+ createKeyFromRaw: importStub
};
const decoded = {
@@ -318,10 +317,9 @@ describe('MSP', () => {
const args = importStub.getCall(0).args;
args[0].should.equal('binary');
args[1].algorithm.should.equal('X509Certificate');
- args[1].ephemeral.should.equal(true);
});
- it('should not call cryptoSuite.importKey with ephemeral: true if not passed a false flag', async () => {
+ it('should call cryptoSuite.importKey if not passed a false flag', async () => {
const importStub = sinon.stub().resolves('key');
const cryptoStub = {
importKey: importStub
@@ -352,7 +350,6 @@ describe('MSP', () => {
const args = importStub.getCall(0).args;
args[0].should.equal('binary');
args[1].algorithm.should.equal('X509Certificate');
- should.not.exist(args[1].ephemeral);
});
it('should deserialise a serialized identity', async () => {
@@ -378,7 +375,7 @@ describe('MSP', () => {
const serializedID = identity.serialize();
// Verify non-promise based route
- let deserializedID = msp.deserializeIdentity(serializedID, false);
+ let deserializedID = await msp.deserializeIdentity(serializedID, false);
deserializedID.getMSPId().should.equal('testMSP');
deserializedID = await msp.deserializeIdentity(serializedID);
diff --git a/fabric-client/test/utils.js b/fabric-client/test/utils.js
index 07d4ba1ed9..277c9eb14b 100644
--- a/fabric-client/test/utils.js
+++ b/fabric-client/test/utils.js
@@ -113,7 +113,7 @@ describe('Utils', () => {
describe('#newKeyValueStore', () => {
it('should create a new key value store', async() => {
- const MockKeyValStore = sandbox.stub().returns(new Object({'value': 1}));
+ const MockKeyValStore = sandbox.stub().returns(new Object({'value': 1, initialize: sinon.stub().resolves}));
requireStub = sandbox.stub().returns(MockKeyValStore);
const getConfigSettingStub = sandbox.stub().returns('kvs');
revert.push(Utils.__set__('exports.getConfigSetting', getConfigSettingStub));
@@ -122,7 +122,7 @@ describe('Utils', () => {
const kvs = await Utils.newKeyValueStore('options');
sinon.assert.calledWith(requireStub, 'kvs');
sinon.assert.calledWith(MockKeyValStore, 'options');
- kvs.should.deep.equal({value: 1});
+ kvs.value.should.equal(1);
});
});
@@ -408,10 +408,11 @@ describe('Utils', () => {
keyStore = new CryptoKeyStore((value) => value);
});
- it('should return a promise to the this._store', async() => {
- requireStub.returns(() => Promise.resolve('keystore'));
+ it('should return a store to the this._store', async() => {
+ const fakeKeystore = new Object({name:'keystore', initialize: sinon.stub()});
+ requireStub.returns(() => Promise.resolve(fakeKeystore));
const result = await keyStore._getKeyStore();
- result.should.equal('keystore');
+ result.name.should.equal('keystore');
});
it('should return a promise to the this._store if this._store is set', async() => {
diff --git a/fabric-common/lib/CryptoSuite.js b/fabric-common/lib/CryptoSuite.js
index fd9e406f7a..48f98e9450 100644
--- a/fabric-common/lib/CryptoSuite.js
+++ b/fabric-common/lib/CryptoSuite.js
@@ -29,16 +29,16 @@
class CryptoSuite {
/**
- * Generate a key using the options in opts
. If the opts.ephemeral
- * parameter is false, the method, in addition to returning the imported {@link Key}
- * instance, also persists the generated key in the key store as PEM files that can be
+ * Generate a key using the options in opts
and persist it in the key store as PEM files that can be
* retrieved using the getKey()
method
*
+ * @async
* @param {KeyOpts} opts Optional
- * @returns {module:api.Key} Promise for an instance of the Key class
+ * @returns {Promise} Promise for an instance of the Key class
* @throws Will throw an error if not implemented
*/
generateKey(opts) {
+ throw new Error('Unimplemented abstract method');
}
/**
@@ -48,6 +48,7 @@ class CryptoSuite {
* @throws Will throw an error if not implemented
*/
generateEphemeralKey() {
+ throw new Error('Unimplemented abstract method');
}
/**
@@ -62,18 +63,26 @@ class CryptoSuite {
}
/**
- * Imports a {@link Key} from its raw representation using opts
. If the opts.ephemeral
- * parameter is false, the method, in addition to returning the imported {@link Key}
- * instance, also saves the imported key in the key store as PEM files that can be
+ * Creates a {@link Key} from its raw representation
+ * @param {*} pem PEM string of the key to create
+ * @param {KeyOpts} opts Options for the concrete implementation
+ * @returns {module:api.Key} The created key
+ */
+ createKeyFromRaw(pem, opts) {
+ throw new Error('Unimplemented abstract method');
+ }
+
+ /**
+ * Imports a {@link Key} from its raw representation using opts
to the key store as PEM files that can be
* retrieved using the 'getKey()' method
*
+ * @async
* @param {string} pem PEM string of the key to import
- * @param {KeyOpts} opts Optional
- * @returns {Key | Promise} If "opts.ephemeral" is true, returns the Key class synchronously.
- * If "opts.ephemeral" not set or false, returns a Promise of an instance of the
- * Key class.
+ * @param {KeyOpts} opts Options for the concrete implementation
+ * @returns {Promise} returns an instance of the Key class that was persisted.
*/
importKey(pem, opts) {
+ throw new Error('Unimplemented abstract method');
}
/**
diff --git a/fabric-common/lib/KeyValueStore.js b/fabric-common/lib/KeyValueStore.js
index 9729901bc5..7732d7478d 100644
--- a/fabric-common/lib/KeyValueStore.js
+++ b/fabric-common/lib/KeyValueStore.js
@@ -27,6 +27,14 @@
*/
class KeyValueStore {
+ /**
+ * Initialize the store
+ *
+ * @async
+ */
+ initialize() {
+ }
+
/**
* Get the value associated with name
.
*
diff --git a/fabric-common/test/CryptoSuite.js b/fabric-common/test/CryptoSuite.js
index 7de1a00ef8..9a3bfcc69c 100644
--- a/fabric-common/test/CryptoSuite.js
+++ b/fabric-common/test/CryptoSuite.js
@@ -27,15 +27,18 @@ describe('CryptoSuite', () => {
});
describe('#generateKey', () => {
- it('should return undefined', () => {
- should.equal(cryptoSuite.generateKey(), undefined);
- should.equal(cryptoSuite.generateKey({}), undefined);
+ it('should throw if unimplemented', () => {
+ (() => {
+ cryptoSuite.generateKey();
+ }).should.throw(/Unimplemented abstract method/);
});
});
describe('#generateEphemeralKey', () => {
- it('should return undefined', () => {
- should.equal(cryptoSuite.generateEphemeralKey(), undefined);
+ it('should throw if unimplemented', () => {
+ (() => {
+ cryptoSuite.generateEphemeralKey();
+ }).should.throw(/Unimplemented abstract method/);
});
});
@@ -48,10 +51,19 @@ describe('CryptoSuite', () => {
});
describe('#importKey', () => {
- it('should return undefined', () => {
- should.equal(cryptoSuite.importKey(), undefined);
- should.equal(cryptoSuite.importKey('name'), undefined);
- should.equal(cryptoSuite.importKey('name', {}), undefined);
+
+ it('should throw if unimplemented', () => {
+ (() => {
+ cryptoSuite.importKey();
+ }).should.throw(/Unimplemented abstract method/);
+ });
+ });
+
+ describe('#createKeyFromRaw', () => {
+ it('should throw if unimplemented', () => {
+ (() => {
+ cryptoSuite.createKeyFromRaw();
+ }).should.throw(/Unimplemented abstract method/);
});
});
diff --git a/fabric-common/test/KeyValueStore.js b/fabric-common/test/KeyValueStore.js
index 4fb2d7ba69..1ec9a59fc2 100644
--- a/fabric-common/test/KeyValueStore.js
+++ b/fabric-common/test/KeyValueStore.js
@@ -26,6 +26,13 @@ describe('KeyValueStore', () => {
keyValueStore = new KeyValueStore();
});
+ describe('#initialize', () => {
+ it('should return undefined', async () => {
+ const result = await keyValueStore.initialize();
+ should.equal(result, undefined);
+ });
+ });
+
describe('#getName', () => {
it('should return undefined', () => {
const value1 = keyValueStore.getValue('name');
diff --git a/fabric-network/lib/gateway.js b/fabric-network/lib/gateway.js
index 013e1e81da..cb0af3ef14 100644
--- a/fabric-network/lib/gateway.js
+++ b/fabric-network/lib/gateway.js
@@ -168,7 +168,7 @@ class Gateway {
if (!(config && config.constructor && config.constructor.name === 'Client')) {
// still use a ccp for the discovery peer and ca information
logger.debug('%s - loading client from ccp', method);
- this.client = Client.loadFromConfig(config);
+ this.client = await Client.loadFromConfig(config);
} else {
// initialize from an existing Client object instance
logger.debug('%s - using existing client object', method);
diff --git a/fabric-network/lib/impl/wallet/couchdbwallet.js b/fabric-network/lib/impl/wallet/couchdbwallet.js
index af3a71f325..245e9144c2 100644
--- a/fabric-network/lib/impl/wallet/couchdbwallet.js
+++ b/fabric-network/lib/impl/wallet/couchdbwallet.js
@@ -57,6 +57,7 @@ class CouchDBWallet extends BaseWallet {
const method = 'getStateStore';
logger.debug('in %s, label = %s', method, label);
const store = new CouchDBWalletKeyValueStore(this._createOptions());
+ await store.initialize();
return store;
}
diff --git a/fabric-network/lib/impl/wallet/filesystemwallet.js b/fabric-network/lib/impl/wallet/filesystemwallet.js
index eb068d61f3..2d6d2e8cf4 100644
--- a/fabric-network/lib/impl/wallet/filesystemwallet.js
+++ b/fabric-network/lib/impl/wallet/filesystemwallet.js
@@ -26,11 +26,11 @@ class FileSystemWallet extends BaseWallet {
*
* @static
* @param {string} path the root path of the key value store
- * @returns {Promise} a promise that is resolved when a new File KVS instance is recreated.
+ * @returns {FileKVS} a new File KVS instance.
* @private
*/
- static async _createFileKVS(path) {
- return await new FileKVS({path});
+ static _createFileKVS(path) {
+ return new FileKVS({path});
}
/**
@@ -84,7 +84,9 @@ class FileSystemWallet extends BaseWallet {
async getStateStore(label) {
const partitionedPath = this._getPartitionedPath(label);
- return FileSystemWallet._createFileKVS(partitionedPath);
+ const store = FileSystemWallet._createFileKVS(partitionedPath);
+ await store.initialize();
+ return store;
}
async getCryptoSuite(label) {
diff --git a/fabric-network/lib/impl/wallet/inmemorywallet.js b/fabric-network/lib/impl/wallet/inmemorywallet.js
index 7c09009774..f75ad1bb4f 100644
--- a/fabric-network/lib/impl/wallet/inmemorywallet.js
+++ b/fabric-network/lib/impl/wallet/inmemorywallet.js
@@ -33,11 +33,10 @@ class InMemoryWallet extends BaseWallet {
logger.debug('in InMemoryWallet constructor');
}
- async getStateStore(label) {
+ getStateStore(label) {
logger.debug('in getStateStore, label = %s', label);
label = this.normalizeLabel(label);
- const store = await new InMemoryKVS(label);
- return store;
+ return new InMemoryKVS(label);
}
async getCryptoSuite(label) {
@@ -89,7 +88,6 @@ class InMemoryKVS extends KeyValueStore {
super();
logger.debug('in InMemoryKVS constructor, prefix = ' + prefix);
this.partitionKey = prefix;
- return Promise.resolve(this);
}
async getValue(name) {
diff --git a/fabric-network/test/impl/wallet/couchdbwallet.js b/fabric-network/test/impl/wallet/couchdbwallet.js
index 87d8fa3ea8..af50ab961d 100644
--- a/fabric-network/test/impl/wallet/couchdbwallet.js
+++ b/fabric-network/test/impl/wallet/couchdbwallet.js
@@ -26,11 +26,13 @@ describe('CouchDBWallet', () => {
let deleteStub;
let existsStub;
let getAllLabelsStub;
+ let initStub;
const CouchDBKeyValueStoreMock = class {
constructor() {
this.delete = deleteStub;
this.exists = existsStub;
this.getAllLabels = getAllLabelsStub;
+ this.initialize = initStub;
}
};
let FakeLogger;
@@ -58,6 +60,7 @@ describe('CouchDBWallet', () => {
getStub = sandbox.stub();
destroyStub = sandbox.stub();
getAllLabelsStub = sandbox.stub();
+ initStub = sandbox.stub();
nanoStub.returns({db: {
destroy: destroyStub,
get: getStub,
diff --git a/fabric-network/test/impl/wallet/filesystemwallet.js b/fabric-network/test/impl/wallet/filesystemwallet.js
index 77b8a15fed..c6355c200a 100644
--- a/fabric-network/test/impl/wallet/filesystemwallet.js
+++ b/fabric-network/test/impl/wallet/filesystemwallet.js
@@ -14,7 +14,7 @@ const rewire = require('rewire');
const FileSystemWallet = rewire('../../../lib/impl/wallet/filesystemwallet');
const X509WalletMixin = require('../../../lib/impl/wallet/x509walletmixin');
const Client = require('fabric-client');
-const {CryptoSuite, KeyValueStore} = require('fabric-common');
+const {CryptoSuite} = require('fabric-common');
const fs = require('fs-extra');
const Path = require('path');
const rimraf = require('rimraf');
@@ -51,10 +51,22 @@ describe('FileSystemWallet', () => {
});
describe('#_createFileKVS', () => {
+ let revert;
+ let instanceStub;
+
+ beforeEach(() => {
+ instanceStub = sinon.stub();
+ revert = FileSystemWallet.__set__('FileKVS', instanceStub);
+ });
+
+ afterEach(() => {
+ revert();
+ });
+
it('should create a File Key Value Store', async () => {
- sandbox.stub(fs, 'mkdirs').callsArg(1);
- const store = await FileSystemWallet._createFileKVS('test');
- store.should.be.an.instanceof(KeyValueStore);
+ await FileSystemWallet._createFileKVS('test');
+ sinon.assert.calledWithNew(instanceStub);
+ sinon.assert.calledWith(instanceStub, {path: 'test'});
});
});
@@ -108,12 +120,12 @@ describe('FileSystemWallet', () => {
describe('#getStateStore', () => {
it('should create a KV store', async () => {
// use Error as a class to be detected
- sandbox.stub(FileSystemWallet, '_createFileKVS').resolves(new Error());
+ sandbox.stub(FileSystemWallet, '_createFileKVS').returns(new Object({'value': 1, initialize: sinon.stub().resolves}));
sinon.stub(testwallet, '_getPartitionedPath').returns('/partitioned/path');
const store = await testwallet.getStateStore('test');
sinon.assert.calledOnce(FileSystemWallet._createFileKVS);
sinon.assert.calledWith(FileSystemWallet._createFileKVS, '/partitioned/path');
- store.should.be.an.instanceof(Error);
+ store.value.should.equal(1);
});
});
diff --git a/package.json b/package.json
index 8ebeb8e4b3..c96664c17b 100644
--- a/package.json
+++ b/package.json
@@ -63,7 +63,7 @@
"jsrsasign": "^7.2.2",
"log4js": "^2.6.1",
"mocha": "5.2.0",
- "mock-couch": "git+https://github.com/jimthematrix/mock-couch.git",
+ "mock-couch": "^0.1.11",
"mockery": "^2.1.0",
"nano": "^6.4.4",
"nyc": "^12.0.2",
diff --git a/release_notes/v2.0.0.txt b/release_notes/v2.0.0.txt
new file mode 100644
index 0000000000..dfafb3215c
--- /dev/null
+++ b/release_notes/v2.0.0.txt
@@ -0,0 +1,30 @@
+Release Notes
+-------------
+
+
+Bug fixes and documentation improvements.
+
+Breaking Changes
+---------------------
+
+CR https://gerrit.hyperledger.org/r/#/c/29360/ delivers breaking changes to the key-value stores and Cryptosuite classes:
+ - Key-value stores no longer initialize the store within the constructor; there is a seperate (async) `initialize` method that contains the initialize logic.
+ - Cryptosuite interface is now strictly followed. The `generateKey` method within implementations no longer accepts `ephemeral: true` as an option; the `generateEphemeralKey` method should be used to retrive an ephemeral key.
+
+
+Known Vulnerabilities
+---------------------
+none
+
+
+Resolved Vulnerabilities
+------------------------
+none
+
+
+Known Issues & Workarounds
+--------------------------
+
+
+Change Log
+----------
diff --git a/test/fixtures/chaincode/goLang/src/github.com/example_cc/example_cc.go b/test/fixtures/chaincode/goLang/src/github.com/example_cc/example_cc.go
index 6e12fc00cc..15656f2e9f 100644
--- a/test/fixtures/chaincode/goLang/src/github.com/example_cc/example_cc.go
+++ b/test/fixtures/chaincode/goLang/src/github.com/example_cc/example_cc.go
@@ -77,6 +77,9 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
function, args := stub.GetFunctionAndParameters()
+ logger.Info("function: ", function)
+ logger.Info("args: ", args)
+
if function == "delete" {
// Deletes an entity from its state
return t.delete(stub, args)
diff --git a/test/fixtures/chaincode/node_cc/example_cc/chaincode.js b/test/fixtures/chaincode/node_cc/example_cc/chaincode.js
index be0e972d75..666704591a 100644
--- a/test/fixtures/chaincode/node_cc/example_cc/chaincode.js
+++ b/test/fixtures/chaincode/node_cc/example_cc/chaincode.js
@@ -67,6 +67,7 @@ const Chaincode = class {
const fcn = ret.fcn;
const args = ret.params;
+ logger.info('-stub.getFunctionAndParameters(): ', JSON.stringify(ret));
try {
if (fcn === 'delete') {
return this.delete(stub, args);
diff --git a/test/fixtures/docker-compose/docker-compose.yaml b/test/fixtures/docker-compose/docker-compose.yaml
index cfcb75177d..c173164568 100644
--- a/test/fixtures/docker-compose/docker-compose.yaml
+++ b/test/fixtures/docker-compose/docker-compose.yaml
@@ -40,6 +40,8 @@ services:
service: peer
container_name: peer0.org1.example.com
environment:
+ - CORE_LOGGING_LEVEL=debug
+ - CORE_CHAINCODE_LOGGING_LEVEL=debug
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer0.org1.example.com
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
@@ -78,6 +80,8 @@ services:
container_name: peer0.org2.example.com
environment:
+ - CORE_LOGGING_LEVEL=debug
+ - CORE_CHAINCODE_LOGGING_LEVEL=debug
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer0.org2.example.com
- CORE_PEER_ADDRESS=peer0.org2.example.com:8051
diff --git a/test/integration/e2e/e2eUtils.js b/test/integration/e2e/e2eUtils.js
index 92cf3edd59..21d2160ea9 100644
--- a/test/integration/e2e/e2eUtils.js
+++ b/test/integration/e2e/e2eUtils.js
@@ -577,7 +577,7 @@ function invokeChaincode(userOrg, version, chaincodeId, t, useStore, fcn, args,
t.comment('stop and start the peer event hub ---- N O W ----- you have ' + sleep_time + ' millis ' + (new Date()).toString());
t.comment('*****************************************************************************');
return exports.sleep(sleep_time);
- }).then(() => {
+ }).then(async() => {
const proposalResponses = pass_results[0];
const proposal = pass_results[1];
@@ -594,7 +594,7 @@ function invokeChaincode(userOrg, version, chaincodeId, t, useStore, fcn, args,
logger.debug('invoke chaincode, proposal response: ' + util.inspect(proposal_response, {depth: null}));
if (proposal_response.response && proposal_response.response.status === 200) {
t.pass('transaction proposal has response status of good');
- one_good = channel.verifyProposalResponse(proposal_response);
+ one_good = await channel.verifyProposalResponse(proposal_response);
if (one_good) {
t.pass('transaction proposal signature and endorser are valid');
}
diff --git a/test/integration/grpc.js b/test/integration/grpc.js
index 5434718c7b..3662ef67c8 100644
--- a/test/integration/grpc.js
+++ b/test/integration/grpc.js
@@ -193,7 +193,7 @@ async function send(client, channel, url, cc, opts, megs, grpc_send_max, grpc_re
}
async function sendToConnectionProfile(client, channel, config, cc, megs) {
- client.loadFromConfig(config);
+ await client.loadFromConfig(config);
const peer = client.getPeersForOrg('Org1MSP')[0]; // will only be one
const request = {
diff --git a/test/integration/invoke.js b/test/integration/invoke.js
index 77b91bcfcb..77afe70023 100644
--- a/test/integration/invoke.js
+++ b/test/integration/invoke.js
@@ -170,7 +170,7 @@ function invokeChaincode(userOrg, version, t, shouldFail, peersArray) {
t.fail('Failed to enroll user \'admin\'. ' + err);
throw new Error('Failed to enroll user \'admin\'. ' + err);
- }).then((results) => {
+ }).then(async (results) => {
const proposalResponses = results[0];
const proposal = results[1];
let all_good = true;
@@ -180,7 +180,7 @@ function invokeChaincode(userOrg, version, t, shouldFail, peersArray) {
const proposal_response = proposalResponses[i];
if (proposal_response.response && proposal_response.response.status === 200) {
t.pass('transaction proposal has response status of good');
- one_good = channel.verifyProposalResponse(proposal_response);
+ one_good = await channel.verifyProposalResponse(proposal_response);
if (one_good) {
t.pass(' transaction proposal signature and endorser are valid');
}
diff --git a/test/integration/memory.js b/test/integration/memory.js
index 77e8bd5eef..1f50c887b1 100644
--- a/test/integration/memory.js
+++ b/test/integration/memory.js
@@ -99,7 +99,7 @@ async function createChannel(t) {
// this network config does not have the client information, we will
// load that later so that we can switch this client to be in a different
// organization
- const client = Client.loadFromConfig('test/fixtures/profiles/network.yaml');
+ const client = await Client.loadFromConfig('test/fixtures/profiles/network.yaml');
t.pass('Successfully loaded a Common connection profile');
const channel_name = 'mychannel';
@@ -115,7 +115,7 @@ async function createChannel(t) {
try {
// lets load the client information for this organization
// the file only has the client section
- client.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ await client.loadFromConfig('test/fixtures/profiles/org1.yaml');
t.pass('Successfully loaded client section of network config');
// tell this client instance where the state and key stores are located
@@ -229,7 +229,7 @@ async function createChannel(t) {
/*
* switch to organization org1
*/
- client.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ await client.loadFromConfig('test/fixtures/profiles/org1.yaml');
t.pass('Successfully loaded \'admin\' for org1');
await client.initCredentialStores();
@@ -280,7 +280,7 @@ async function createChannel(t) {
* switch to organization org2
*/
- client.loadFromConfig('test/fixtures/profiles/org2.yaml');
+ await client.loadFromConfig('test/fixtures/profiles/org2.yaml');
await client.initCredentialStores();
t.pass('Successfully created the key value store and crypto store based on the config and network config');
@@ -367,7 +367,7 @@ async function actions(t) {
// this network config does not have the client information, we will
// load that later so that we can switch this client to be in a different
// organization
- const client = Client.loadFromConfig('test/fixtures/profiles/network.yaml');
+ const client = await Client.loadFromConfig('test/fixtures/profiles/network.yaml');
t.pass('Successfully loaded a common connection profile');
const channel_name = 'mychannel';
@@ -381,7 +381,7 @@ async function actions(t) {
try {
// lets load the client information for this organization
// the file only has the client section
- client.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ await client.loadFromConfig('test/fixtures/profiles/org1.yaml');
// tell this client instance where the state and key stores are located
await client.initCredentialStores();
t.pass('Successfully created the key value store and crypto store based on the config and network config');
diff --git a/test/integration/network-config.js b/test/integration/network-config.js
index 3308cac063..4d956978e2 100644
--- a/test/integration/network-config.js
+++ b/test/integration/network-config.js
@@ -22,12 +22,12 @@ const path = require('path');
const testUtil = require('../unit/util.js');
-test('\n\n***** clean up the connection profile testing stores *****\n\n', (t) => {
+test('\n\n***** clean up the connection profile testing stores *****\n\n', async (t) => {
/*
* The following is just testing housekeeping... cleanup from the last time
* this test was run, a real application would not do this.
*/
- const client = Client.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ const client = await Client.loadFromConfig('test/fixtures/profiles/org1.yaml');
let client_config = client.getClientConfig();
let store_path = client_config.credentialStore.path;
@@ -38,7 +38,7 @@ test('\n\n***** clean up the connection profile testing stores *****\n\n', (t)
logger.debug('removing org1 cryptoStore %s', crypto_path);
fsx.removeSync(crypto_path);
- client.loadFromConfig('test/fixtures/profiles/org2.yaml');
+ await client.loadFromConfig('test/fixtures/profiles/org2.yaml');
client_config = client.getClientConfig();
store_path = client_config.credentialStore.path;
@@ -62,8 +62,8 @@ test('\n\n***** use the connection profile file *****\n\n', async (t) => {
// this connection profile does not have the client information, we will
// load that later so that we can switch this client to be in a different
// organization.
- const client_org1 = Client.loadFromConfig('test/fixtures/profiles/network2.yaml');
- const client_org2 = Client.loadFromConfig('test/fixtures/profiles/network2.yaml');
+ const client_org1 = await Client.loadFromConfig('test/fixtures/profiles/network2.yaml');
+ const client_org2 = await Client.loadFromConfig('test/fixtures/profiles/network2.yaml');
t.pass('Successfully loaded a connection profile');
let config = null;
@@ -77,8 +77,8 @@ test('\n\n***** use the connection profile file *****\n\n', async (t) => {
// Load the client information for an organization.
// The file only has the client section.
// A real application might do this when a new user logs in.
- client_org1.loadFromConfig('test/fixtures/profiles/org1.yaml');
- client_org2.loadFromConfig('test/fixtures/profiles/org2.yaml');
+ await client_org1.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ await client_org2.loadFromConfig('test/fixtures/profiles/org2.yaml');
try {
// tell this client instance where the state and key stores are located
@@ -672,8 +672,8 @@ test('\n\n***** Enroll user and set user context using a specified caName *****\
// Build a 'Client' instance that knows the network
// then load org1.yaml to the same instance
- const client_org1 = Client.loadFromConfig('test/fixtures/profiles/network.yaml');
- client_org1.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ const client_org1 = await Client.loadFromConfig('test/fixtures/profiles/network.yaml');
+ await client_org1.loadFromConfig('test/fixtures/profiles/org1.yaml');
t.pass('Successfully loaded client section of network config');
// tell this client instance where the state and key stores are located
@@ -736,8 +736,8 @@ test('\n\n***** Enroll user and set user context using a bad caName *****\n\n',
// Build a 'Client' instance that knows the network
// then load org1.yaml to the same instance
- const client_org1 = Client.loadFromConfig('test/fixtures/profiles/network.yaml');
- client_org1.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ const client_org1 = await Client.loadFromConfig('test/fixtures/profiles/network.yaml');
+ await client_org1.loadFromConfig('test/fixtures/profiles/org1.yaml');
t.pass('Successfully loaded client section of network config');
// tell this client instance where the state and key stores are located
diff --git a/test/integration/network-e2e/idmanager.js b/test/integration/network-e2e/idmanager.js
index 2563e18aad..bed714322f 100644
--- a/test/integration/network-e2e/idmanager.js
+++ b/test/integration/network-e2e/idmanager.js
@@ -10,8 +10,8 @@ const User = require('fabric-client/lib/User');
class IDManager {
- initialize(ccp) {
- this.client = Client.loadFromConfig(ccp);
+ async initialize(ccp) {
+ this.client = await Client.loadFromConfig(ccp);
}
async registerUser(userID, options, issuerWallet, issuerId) {
diff --git a/test/integration/only-admin.js b/test/integration/only-admin.js
index 7259ec4c74..43963534e0 100644
--- a/test/integration/only-admin.js
+++ b/test/integration/only-admin.js
@@ -55,7 +55,7 @@ async function manually(t, client) {
const pem = Buffer.from(data).toString();
t.pass('Successfully read all crypto material');
- client.setAdminSigningIdentity(key, cert, 'OrdererMSP');
+ await client.setAdminSigningIdentity(key, cert, 'OrdererMSP');
t.pass('Successfully set the client with admin signing identity');
const sys_channel = client.newChannel('testchainid');
diff --git a/test/integration/orderer-channel-tests.js b/test/integration/orderer-channel-tests.js
index 581d61b5ac..1aa85d6bec 100644
--- a/test/integration/orderer-channel-tests.js
+++ b/test/integration/orderer-channel-tests.js
@@ -33,7 +33,7 @@ const org = 'org1';
// before the orderer URL was set. Verify that an error is reported when tying
// to send the request.
//
-test('\n\n** TEST ** orderer via member missing orderer', (t) => {
+test('\n\n** TEST ** orderer via member missing orderer', async (t) => {
testUtil.resetDefaults();
utils.setConfigSetting('key-value-store', 'fabric-ca-client/lib/impl/FileKeyValueStore.js');// force for 'gulp test'
Client.addConfigFile(path.join(__dirname, 'e2e', 'config.json'));
@@ -48,12 +48,12 @@ test('\n\n** TEST ** orderer via member missing orderer', (t) => {
cryptoSuite.setCryptoKeyStore(Client.newCryptoKeyStore({path: testUtil.storePathForOrg(orgName)}));
client.setCryptoSuite(cryptoSuite);
- Client.newDefaultKeyValueStore({
+ const store = await Client.newDefaultKeyValueStore({
path: testUtil.KVS
- }).then((store) => {
- client.setStateStore(store);
- return testUtil.getSubmitter(client, t, org);
- }).then(
+ });
+
+ client.setStateStore(store);
+ testUtil.getSubmitter(client, t, org).then(
() => {
t.pass('Successfully enrolled user \'admin\'');
diff --git a/test/scenario/features/lib/channel.js b/test/scenario/features/lib/channel.js
index 2f8a455759..5c260a8d7b 100644
--- a/test/scenario/features/lib/channel.js
+++ b/test/scenario/features/lib/channel.js
@@ -138,7 +138,7 @@ async function existing_channels(ccp, tls) {
cryptoSuite.setCryptoKeyStore(Client.newCryptoKeyStore({path: testUtil.storePathForOrg(org)}));
client.setCryptoSuite(cryptoSuite);
- client.loadFromConfig(ccp.getProfile());
+ await client.loadFromConfig(ccp.getProfile());
// Run this to set the required identity on the client object
await testUtil.getSubmitter(client, true, orgName, ccp);
diff --git a/test/typescript/test.ts b/test/typescript/test.ts
index e0f0ce9883..367a3eec0c 100644
--- a/test/typescript/test.ts
+++ b/test/typescript/test.ts
@@ -86,11 +86,11 @@ test('test-crypto-key-store', (t: any) => {
t.end();
});
-test('use the connection profile file', (t: any) => {
- let client = Client.loadFromConfig(configNetwork);
+test('use the connection profile file', async (t: any) => {
+ let client = await Client.loadFromConfig(configNetwork);
t.pass('Successfully load config from network.yaml');
- client.loadFromConfig(configOrg1);
+ await client.loadFromConfig(configOrg1);
let config: Buffer;
const signatures: any[] = [];
@@ -182,7 +182,7 @@ test('use the connection profile file', (t: any) => {
txId,
};
return channel.joinChannel(request); //admin from org2
- }).then((results: ProposalResponse[]) => {
+ }).then(async (results: ProposalResponse[]) => {
// first of the results should not have good status as submitter does not have permission
if (results && results[0] && results[0].response && results[0].response.status === 200) {
t.fail('Successfully had peer in organization org1 join the channel');
@@ -202,9 +202,9 @@ test('use the connection profile file', (t: any) => {
/*
* switch to organization org1 (recreate client)
*/
- client = Client.loadFromConfig(configNetwork);
+ client = await Client.loadFromConfig(configNetwork);
- client.loadFromConfig(configOrg1);
+ await client.loadFromConfig(configOrg1);
t.pass('Successfully loaded \'admin\' for org1');
return client.initCredentialStores();
}).then(() => {
@@ -258,7 +258,7 @@ test('use the connection profile file', (t: any) => {
};
return client.installChaincode(request);
- }).then((results: ProposalResponseObject) => {
+ }).then(async (results: ProposalResponseObject) => {
const firstResponse = results[0][0];
if (firstResponse instanceof Error || firstResponse.response.status !== 200) {
t.fail(' Failed to install chaincode on org1');
@@ -267,7 +267,7 @@ test('use the connection profile file', (t: any) => {
}
t.pass('Successfully installed chain code on org1');
- client.loadFromConfig(configOrg2);
+ await client.loadFromConfig(configOrg2);
t.pass('Successfully loaded \'admin\' for org2');
return client.initCredentialStores();
}).then(() => {
@@ -284,7 +284,7 @@ test('use the connection profile file', (t: any) => {
};
return client.installChaincode(request);
- }).then((results: ProposalResponseObject) => {
+ }).then(async (results: ProposalResponseObject) => {
const firstResponse = results[0][0];
if (firstResponse instanceof Error || firstResponse.response.status !== 200) {
t.fail(' Failed to install chaincode on org2');
@@ -294,7 +294,7 @@ test('use the connection profile file', (t: any) => {
t.pass('Successfully installed chain code on org2');
// Back to org1 for instantiation
- client.loadFromConfig(configOrg1);
+ await client.loadFromConfig(configOrg1);
t.pass('Successfully loaded \'admin\' for org1');
return client.initCredentialStores();
}).then(() => {
@@ -340,7 +340,7 @@ test('use the connection profile file', (t: any) => {
t.fail('Failed to order the transaction to instantiate the chaincode. Error code: ' + response.status);
throw new Error('Failed to order the transaction to instantiate the chaincode. Error code: ' + response.status);
}
- }).then(() => {
+ }).then(async () => {
t.pass('Successfully waited for chaincode to startup');
/*
@@ -350,10 +350,10 @@ test('use the connection profile file', (t: any) => {
* switch to organization org2
*/
- client.loadFromConfig('test/fixtures/profiles/org2.yaml');
+ await client.loadFromConfig('test/fixtures/profiles/org2.yaml');
return client.initCredentialStores();
- }).then(() => {
+ }).then(async () => {
t.pass('Successfully created the key value store and crypto store based on the config and connection profile');
const ca: FabricCAServices = client.getCertificateAuthority();
@@ -366,7 +366,7 @@ test('use the connection profile file', (t: any) => {
/*
* switch to organization org1
*/
- client.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ await client.loadFromConfig('test/fixtures/profiles/org1.yaml');
t.pass('Successfully loaded config for org1');
return client.initCredentialStores();
diff --git a/test/unit/couchdb-key-value-store.js b/test/unit/couchdb-key-value-store.js
deleted file mode 100644
index 29ad3fda83..0000000000
--- a/test/unit/couchdb-key-value-store.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * Copyright 2017 IBM All Rights Reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-'use strict';
-
-const tape = require('tape');
-const _test = require('tape-promise').default;
-const test = _test(tape);
-const CouchdbMock = require('mock-couch');
-
-const CDBKVS = require('fabric-client/lib/impl/CouchDBKeyValueStore.js');
-
-test('\n\n** CouchDBKeyValueStore tests', (t) => {
- t.throws(
- () => {
- new CDBKVS();
- },
- /Must provide the CouchDB database url to store membership data/,
- 'Error checking in the constructor: missing opts'
- );
-
- t.throws(
- () => {
- new CDBKVS({dummy: 'value'});
- },
- /Must provide the CouchDB database url to store membership data/,
- 'Error checking in the constructor: opts object missing required "url"'
- );
-
- let store;
-
- new CDBKVS({url: 'http://localhost:9999'})
- .then(() => {
- t.fail('Should not have been able to successfully construct a store from an invalid URL');
- throw new Error('Failed');
- }, (err) => {
- if (err.message && err.message.indexOf('ECONNREFUSED') > 0) {
- t.pass('Successfully rejected the construction request due to invalid URL');
- } else {
- t.fail('Store construction failed for unknown reason: ' + err.stack ? err.stack : err);
- throw new Error('Failed');
- }
-
- const couchdb = CouchdbMock.createServer();
- couchdb.listen(5985);
-
- // override t.end function so it'll always disconnect the event hub
- t.end = ((context, mockdb, f) => {
- return function() {
- if (mockdb) {
- t.comment('Disconnecting the mock couchdb server');
- mockdb.close();
- }
-
- f.apply(context, arguments);
- };
- })(t, couchdb, t.end);
-
- return new CDBKVS({url: 'http://localhost:5985'});
- }).then((st) => {
- store = st;
- t.pass('Successfully connected the key value store to couchdb at localhost:5985');
-
- t.notEqual(store._database, undefined, 'Check "_database" value of the constructed store object');
-
- return store.setValue('someKey', 'someValue');
- }).then((value) => {
- t.equal(value, 'someValue', 'Check result of setValue()');
-
- return store.getValue('someKey');
- }).then((value) => {
- t.equal(value, 'someValue', 'Check result of getValue()');
- t.end();
- }).catch((err) => {
- t.fail(err.stack ? err.stack : err);
- t.end();
- });
-});
diff --git a/test/unit/crypto-key-store.js b/test/unit/crypto-key-store.js
index 655d24723c..007ec57fb7 100644
--- a/test/unit/crypto-key-store.js
+++ b/test/unit/crypto-key-store.js
@@ -63,28 +63,9 @@ test('\n\n** CryptoKeyStore tests **\n\n', (t) => {
const keystorePath = path.join(testutil.getTempDir(), 'crypto-key-store');
- t.throws(
- () => {
- CKS();
- },
- /Must provide the path to the directory to hold files for the store/,
- 'Test invalid constructor calls: missing options parameter'
- );
-
- t.throws(
- () => {
- CKS({something: 'useless'});
- },
- /Must provide the path to the directory to hold files for the store/,
- 'Test invalid constructor calls: missing "path" property in the "options" parameter'
- );
-
- let store;
- CKS({path: keystorePath})
- .then((st) => {
- store = st;
- return store.putKey(testPrivKey);
- }).then(() => {
+ const store = CKS({path: keystorePath});
+ return store.initialize().then(() => {
+ store.putKey(testPrivKey).then(() => {
t.pass('Successfully saved private key in store');
t.equal(fs.existsSync(path.join(keystorePath, testPrivKey.getSKI() + '-priv')), true,
@@ -116,6 +97,7 @@ test('\n\n** CryptoKeyStore tests **\n\n', (t) => {
t.fail(err.stack ? err.stack : err);
t.end();
});
+ });
});
@@ -137,8 +119,9 @@ test('\n\n** CryptoKeyStore tests - couchdb based store tests - use configSettin
};
})(t, couchdb, t.end);
- CKS({name: dbname, url: 'http://localhost:5985'})
- .then((store) => {
+ const store = CKS({name: dbname, url: 'http://localhost:5985'});
+ store.initialize()
+ .then(() => {
return testKeyStore(store, t);
}).catch((err) => {
t.fail(err.stack ? err.stack : err);
@@ -164,8 +147,9 @@ test('\n\n** CryptoKeyStore tests - couchdb based store tests - use constructor
};
})(t, couchdb, t.end);
- CKS(CouchDBKeyValueStore, {name: dbname, url: 'http://localhost:5985'})
- .then((store) => {
+ const store = CKS(CouchDBKeyValueStore, {name: dbname, url: 'http://localhost:5985'});
+ store.initialize()
+ .then(() => {
return testKeyStore(store, t);
}).catch((err) => {
t.fail(err.stack ? err.stack : err);
diff --git a/test/unit/cryptosuite-ecdsa-aes.js b/test/unit/cryptosuite-ecdsa-aes.js
index 0cb7c431a0..e6ba633bc1 100644
--- a/test/unit/cryptosuite-ecdsa-aes.js
+++ b/test/unit/cryptosuite-ecdsa-aes.js
@@ -95,24 +95,29 @@ test('\n\n** utils.newCryptoSuite tests **\n\n', (t) => {
t.end();
});
-test('\n\n ** CryptoSuite_ECDSA_AES - error tests **\n\n', (t) => {
+test('\n\n ** CryptoSuite_ECDSA_AES - error tests **\n\n', async (t) => {
testutil.resetDefaults();
const cryptoUtils = utils.newCryptoSuite();
- t.throws(
- () => {
- cryptoUtils.importKey(TEST_CERT_PEM);
- },
- /importKey opts.ephemeral is false, which requires CryptoKeyStore to be set./,
- 'Test missing cryptoKeyStore: cryptoSuite.importKey'
- );
- cryptoUtils.generateKey().catch(err => {
+
+ try {
+ await cryptoUtils.importKey(TEST_CERT_PEM);
+ t.fail('Import key did not fail when testing missing cryptoKeyStore');
+ } catch (err) {
t.ok(err.toString()
- .includes('generateKey opts.ephemeral is false, which requires CryptoKeyStore to be set.'),
- 'Test missing cryptoKeyStore: cryptoSuite.generateKey');
+ .includes('importKey requires CryptoKeyStore to be set.'),
+ 'Test missing cryptoKeyStore: cryptoSuite.importKey');
+ }
- t.end();
- });
+ try {
+ await cryptoUtils.generateKey();
+ t.fail('generateKey did not fail when testing missing cryptoKeyStore');
+ } catch (err) {
+ t.ok(err.toString()
+ .includes('generateKey requires CryptoKeyStore to be set.'),
+ 'Test missing cryptoKeyStore: cryptoSuite.generateKey');
+ }
+ t.end();
});
test('\n\n ** CryptoSuite_ECDSA_AES - generateEphemeralKey tests **\n\n', (t) => {
@@ -129,29 +134,15 @@ test('\n\n ** CryptoSuite_ECDSA_AES - generateEphemeralKey tests **\n\n', (t) =>
});
-test('\n\n ** CryptoSuite_ECDSA_AES - ephemeral true tests **\n\n', (t) => {
+test('\n\n ** CryptoSuite_ECDSA_AES - createKeyFromRaw **\n\n', async (t) => {
testutil.resetDefaults();
const cryptoUtils = utils.newCryptoSuite();
- const key = cryptoUtils.importKey(TEST_KEY_PRIVATE_PEM, {ephemeral: true});
+ const key = cryptoUtils.createKeyFromRaw(TEST_KEY_PRIVATE_PEM);
if (key && key._key && key._key.type === 'EC') {
t.pass('importKey returned key using ephemeral true');
} else {
t.fail('importKey did not return key using ephemeral true');
}
-
- return cryptoUtils.generateKey({ephemeral: true})
- .then((generatedKey) => {
- if (generatedKey && generatedKey._key && generatedKey._key.type === 'EC') {
- t.pass('generateKey returned key using ephemeral true');
- t.end();
- } else {
- t.fail('generateKey did not return key using ephemeral true');
- t.end();
- }
- }, (err) => {
- t.fail('Failed to generateKey. Can not progress any further. Exiting. ' + err.stack ? err.stack : err);
- t.end();
- });
});
test('\n\n ** CryptoSuite_ECDSA_AES - function tests **\n\n', (t) => {
@@ -432,31 +423,3 @@ test('\n\n ** CryptoSuite_ECDSA_AES - function tests **\n\n', (t) => {
t.end();
});
});
-
-// function cleanupFileKeyValueStore(keyValStorePath) {
-// var absPath = getAbsolutePath(keyValStorePath);
-// var exists = testutil.existsSync(absPath);
-// if (exists) {
-// fs.removeSync(absPath);
-// }
-// }
-
-// prepend absolute path where this test is running, then join to the relative path
-// function getAbsolutePath(dir) {
-// return path.join(process.cwd(), getRelativePath(dir));
-// }
-
-// get relative file path for either Unix or Windows
-// unix relative path does not start with '/'
-// windows relative path starts with '/'
-// function getRelativePath(dir /*string*/) {
-// if (/^win/.test(process.platform)) {
-// if (!(dir.toString().substr(0, 1) === '/')) dir = '/' + dir;
-// dir = path.resolve(dir);
-// dir = dir.replace(/([A-Z]:[\\\/]).*?/gi, '');
-// return dir;
-// } else {
-// if (dir.toString().substr(0, 1) === '/') dir = dir.substr(1);
-// return dir;
-// }
-// }
diff --git a/test/unit/file-key-value-store.js b/test/unit/file-key-value-store.js
deleted file mode 100644
index c5c1540b54..0000000000
--- a/test/unit/file-key-value-store.js
+++ /dev/null
@@ -1,143 +0,0 @@
-/**
- * Copyright 2016 IBM All Rights Reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-'use strict';
-
-const tape = require('tape');
-const _test = require('tape-promise').default;
-const test = _test(tape);
-
-const path = require('path');
-const testUtil = require('./util.js');
-const fs = require('fs-extra');
-const utils = require('fabric-client/lib/utils.js');
-
-const FileKeyValueStore = require('fabric-client/lib/impl/FileKeyValueStore.js');
-
-const keyValStorePath = path.join(testUtil.getTempDir(), 'kvsTemp');
-const testKey = 'keyValFileStoreName';
-const testValue = 'secretKeyValue';
-let store1 = '';
-
-test('\n\n ** FileKeyValueStore - read and write test **\n\n', (t) => {
- testUtil.resetDefaults();
-
- // clean up
- if (testUtil.existsSync(keyValStorePath)) {
- fs.removeSync(keyValStorePath);
- }
- utils.newKeyValueStore({
- path: keyValStorePath
- })
- .then(
- (store) => {
- if (testUtil.existsSync(keyValStorePath)) {
- t.pass('FileKeyValueStore read and write test: Successfully created new directory for testValueStore');
- } else {
- t.fail('FileKeyValueStore read and write test: failed to create new directory for testValueStore');
- t.end();
- }
- store1 = store;
- return store.setValue(testKey, testValue);
- }
- ).then(
- (result) => {
- if (result === testValue) {
- t.pass('FileKeyValueStore read and write test: Successfully set value');
- } else {
- t.fail('FileKeyValueStore read and write test: set value ' + result + 'does not match testValue ' + testValue);
- t.end();
- }
- if (testUtil.existsSync(path.join(keyValStorePath, testKey))) {
- t.pass('FileKeyValueStore read and write test: Verified the file for key ' + testKey + ' does exist');
-
- return store1.getValue(testKey);
- } else {
- t.fail('FileKeyValueStore read and write test: Failed to create file for key ' + testKey);
- t.end();
- }
- },
- (reason) => {
- t.fail('FileKeyValueStore read and write test: Failed to set value, reason: ' + reason);
- t.end();
- }
- ).then(
- // Log the fulfillment value
- (val) => {
- if (val !== testValue) {
- t.fail('FileKeyValueStore read and write test: get value ' + val + ' does not equal testValue of ' + testValue);
- } else {
- t.pass('FileKeyValueStore read and write test: Successfully retrieved value');
- }
-
- // now test getValue() when the underlying directory get deleted
- fs.removeSync(keyValStorePath);
- return store1.getValue(testKey);
- },
- // Log the rejection reason
- (reason) => {
- t.fail('FileKeyValueStore read and write test: Failed getValue, reason: ' + reason);
- t.end();
- }
- ).then(
- // Log the fulfillment value
- (val) => {
- if (val === null) {
- t.pass('FileKeyValueStore error check tests: Delete store & getValue test. getValue() returns null as expected');
- } else {
- t.fail('FileKeyValueStore error check tests: Delete store & getValue test. getValue() should not have returned value: ' + val);
- }
-
- return new FileKeyValueStore({path: keyValStorePath});
- },
- (reason) => {
- t.fail('FileKeyValueStore error check tests: Delete store & getValue test. getValue caught unexpected error: ' + reason);
- }
- )
- .then(
- (store) => {
- // now test setValue() when the underlying directory get deleted
- fs.removeSync(keyValStorePath);
- return store.setValue(testKey, testValue);
- })
- .then(
- () => {
- t.fail('FileKeyValueStore error check tests: Delete store & setValue test. setValue() should have failed.');
- t.end();
- },
- (reason) => {
- t.pass('FileKeyValueStore error check tests: Delete store & setValue test. setValue() failed as expected: ' + reason);
- t.end();
- })
- .catch(
- (err) => {
- t.fail('Failed with unexpected error: ' + err.stack ? err.stack : err);
- t.end();
- });
-});
-
-test('\n\n** FileKeyValueStore error check tests **\n\n', (t) => {
-
- t.throws(
- () => {
- new FileKeyValueStore();
- },
- /^Error: Must provide the path/,
- 'FileKeyValueStore error check tests: new FileKeyValueStore with no options should throw ' +
- '"Must provide the path to the directory to hold files for the store."'
- );
-
- t.throws(
- () => {
- new FileKeyValueStore({dir: keyValStorePath});
- },
- /^Error: Must provide the path/,
- 'FileKeyValueStore error check tests: new FileKeyValueStore with no options.path should throw ' +
- '"Must provide the path to the directory to hold files for the store."'
- );
-
- t.end();
-});
diff --git a/test/unit/network-config.js b/test/unit/network-config.js
index a4ff73a868..a0aa6c47fc 100644
--- a/test/unit/network-config.js
+++ b/test/unit/network-config.js
@@ -27,18 +27,18 @@ const NetworkConfig = require('fabric-client/lib/impl/NetworkConfig_1_0.js');
const testutil = require('./util.js');
-test('\n\n ** configuration testing **\n\n', (t) => {
+test('\n\n ** configuration testing **\n\n', async (t) => {
testutil.resetDefaults();
t.doesNotThrow(
- () => {
+ async () => {
const config_loc = path.resolve('test/fixtures/profiles/network.yaml');
const file_data = fs.readFileSync(config_loc);
const network_data = yaml.safeLoad(file_data);
- const client = Client.loadFromConfig(network_data);
+ const client = await Client.loadFromConfig(network_data);
client.setCryptoSuite(Client.newCryptoSuite());
client.setUserContext(new User('testUser'), true);
- client.loadFromConfig(network_data);
+ await client.loadFromConfig(network_data);
const channel = client.getChannel('mychannel');
t.equals(channel.getPeers()[0].getUrl(), 'grpcs://localhost:7051', ' check to see that the peer has been added to the channel');
t.equals(channel.getPeers()[1].getUrl(), 'grpcs://localhost:8051', ' check to see that the peer has been added to the channel');
@@ -63,16 +63,16 @@ test('\n\n ** configuration testing **\n\n', (t) => {
}
};
- t.doesNotThrow(
- () => {
- const client = new Client();
- client.setCryptoSuite(Client.newCryptoSuite());
- client.setUserContext(new User('testUser'), true);
- client._network_config = new NetworkConfig(network_config, client);
- const channel = client.newChannel('mychannel');
- t.equals('mychannel', channel.getName(), 'Channel should be named');
- },
- 'Should be able to instantiate a new instance of "Channel" with an empty channel definition in the common connection profile'
+ await testutil.tapeAsyncNoThrow(t, async () => {
+ const client = new Client();
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
+ client.setUserContext(new User('testUser'), true);
+ client._network_config = new NetworkConfig(network_config, client);
+ const channel = client.newChannel('mychannel');
+ t.equals('mychannel', channel.getName(), 'Channel should be named');
+ },
+ 'able to instantiate a new instance of "Channel" with an empty channel definition in the common connection profile'
);
network_config.channels = {
@@ -90,23 +90,23 @@ test('\n\n ** configuration testing **\n\n', (t) => {
}
};
- t.doesNotThrow(
- () => {
- const client = new Client();
- client.setCryptoSuite(Client.newCryptoSuite());
- client.setUserContext(new User('testUser'), true);
- client._network_config = new NetworkConfig(network_config, client);
- const channel = client.getChannel('mychannel');
- t.equals('mychannel', channel.getName(), 'Channel should be named');
- const orderer = channel.getOrderers()[0];
- if (orderer instanceof Orderer) {
- t.pass('Successfully got an orderer');
- } else {
- t.fail('Failed to get an orderer');
- }
- t.equals('orderer0', orderer.getName(), 'Orderer should be named');
- },
- 'Should be able to instantiate a new instance of "Channel" with only orderer definition in the common connection profile'
+ await testutil.tapeAsyncNoThrow(t, async () => {
+ const client = new Client();
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
+ client.setUserContext(new User('testUser'), true);
+ client._network_config = new NetworkConfig(network_config, client);
+ const channel = client.getChannel('mychannel');
+ t.equals('mychannel', channel.getName(), 'Channel should be named');
+ const orderer = channel.getOrderers()[0];
+ if (orderer instanceof Orderer) {
+ t.pass('Successfully got an orderer');
+ } else {
+ t.fail('Failed to get an orderer');
+ }
+ t.equals('orderer0', orderer.getName(), 'Orderer should be named');
+ },
+ 'able to instantiate a new instance of "Channel" with only orderer definition in the common connection profile'
);
network_config.channels = {
@@ -122,23 +122,23 @@ test('\n\n ** configuration testing **\n\n', (t) => {
};
network_config.orgainizations = {'org1': {}};
- t.doesNotThrow(
- () => {
- const client = new Client();
- client.setCryptoSuite(Client.newCryptoSuite());
- client.setUserContext(new User('testUser'), true);
- client._network_config = new NetworkConfig(network_config, client);
- const channel = client.getChannel('mychannel');
- t.equals('mychannel', channel.getName(), 'Channel should be named');
- t.equals(channel.getPeers().length, 0, 'Peers should be empty');
- const orderer = channel.getOrderers()[0];
- if (orderer instanceof Orderer) {
- t.pass('Successfully got an orderer');
- } else {
- t.fail('Failed to get an orderer');
- }
- },
- 'Should be able to instantiate a new instance of "Channel" with org that does not exist in the common connection profile'
+ await testutil.tapeAsyncNoThrow(t, async () => {
+ const client = new Client();
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
+ await client.setUserContext(new User('testUser'), true);
+ client._network_config = new NetworkConfig(network_config, client);
+ const channel = client.getChannel('mychannel');
+ t.equals('mychannel', channel.getName(), 'Channel should be named');
+ t.equals(channel.getPeers().length, 0, 'Peers should be empty');
+ const orderer = channel.getOrderers()[0];
+ if (orderer instanceof Orderer) {
+ t.pass('Successfully got an orderer');
+ } else {
+ t.fail('Failed to get an orderer');
+ }
+ },
+ 'able to instantiate a new instance of "Channel" with org that does not exist in the common connection profile'
);
network_config.organizations = {
@@ -154,23 +154,23 @@ test('\n\n ** configuration testing **\n\n', (t) => {
}
};
- t.doesNotThrow(
- () => {
- const client = new Client();
- client.setCryptoSuite(Client.newCryptoSuite());
- client.setUserContext(new User('testUser'), true);
- client._network_config = new NetworkConfig(network_config, client);
- const channel = client.getChannel('mychannel');
- t.equals('mychannel', channel.getName(), 'Channel should be named');
- t.equals(channel.getPeers().length, 0, 'Peers should be empty');
- const orderer = channel.getOrderers()[0];
- if (orderer instanceof Orderer) {
- t.pass('Successfully got an orderer');
- } else {
- t.fail('Failed to get an orderer');
- }
- },
- 'Should be able to instantiate a new instance of "Channel" with a peer in the org that does not exist in the common connection profile'
+ await testutil.tapeAsyncNoThrow(t, async () => {
+ const client = new Client();
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
+ await client.setUserContext(new User('testUser'), true);
+ client._network_config = new NetworkConfig(network_config, client);
+ const channel = client.getChannel('mychannel');
+ t.equals('mychannel', channel.getName(), 'Channel should be named');
+ t.equals(channel.getPeers().length, 0, 'Peers should be empty');
+ const orderer = channel.getOrderers()[0];
+ if (orderer instanceof Orderer) {
+ t.pass('Successfully got an orderer');
+ } else {
+ t.fail('Failed to get an orderer');
+ }
+ },
+ 'able to instantiate a new instance of "Channel" with a peer in the org that does not exist in the common connection profile'
);
network_config.peers = {
@@ -218,84 +218,85 @@ test('\n\n ** configuration testing **\n\n', (t) => {
registrar: {enrollId: 'admin2', enrollSecret: 'adminpw2'}
}
};
- t.doesNotThrow(
- () => {
- const client = new Client();
- client.setCryptoSuite(Client.newCryptoSuite());
- client.setUserContext(new User('testUser'), true);
- client._network_config = new NetworkConfig(network_config, client);
- const channel = client.getChannel('mychannel');
- t.equals('mychannel', channel.getName(), 'Channel should be named');
- t.equals(channel.getPeers().length, 4, 'Peers should be four');
- const peer = channel.getPeers()[0];
- if (peer && peer.constructor && peer.constructor.name === 'ChannelPeer') {
- t.pass('Successfully got a channel peer');
- } else {
- t.fail('Failed to get a channel peer');
- }
- },
- 'Should be able to instantiate a new instance of "Channel" with orderer, org and peer defined in the common connection profile'
+
+ await testutil.tapeAsyncNoThrow(t, async () => {
+ const client = new Client();
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
+ client.setUserContext(new User('testUser'), true);
+ client._network_config = new NetworkConfig(network_config, client);
+ const channel = client.getChannel('mychannel');
+ t.equals('mychannel', channel.getName(), 'Channel should be named');
+ t.equals(channel.getPeers().length, 4, 'Peers should be four');
+ const peer = channel.getPeers()[0];
+ if (peer && peer.constructor && peer.constructor.name === 'ChannelPeer') {
+ t.pass('Successfully got a channel peer');
+ } else {
+ t.fail('Failed to get a channel peer');
+ }
+ },
+ 'able to instantiate a new instance of "Channel" with orderer, org and peer defined in the common connection profile'
);
const peer1 = new Peer('grpcs://localhost:9999', {pem: '-----BEGIN CERTIFICATE-----MIIB8TCC5l-----END CERTIFICATE-----'});
- t.doesNotThrow(
- () => {
- const client = new Client();
- client.setCryptoSuite(Client.newCryptoSuite());
- client.setUserContext(new User('testUser'), true);
- client._network_config = new NetworkConfig(network_config, client);
+ await testutil.tapeAsyncNoThrow(t, async () => {
+ const client = new Client();
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
+ client.setUserContext(new User('testUser'), true);
+ client._network_config = new NetworkConfig(network_config, client);
- let targets = client.getTargetPeers('peer1', client);
- if (Array.isArray(targets)) {
- t.pass('targets is an array');
- } else {
- t.fail('targets is not an array');
- }
- if (targets[0] instanceof Peer) {
- t.pass('targets has a peer ');
- } else {
- t.fail('targets does not have a peer');
- }
+ let targets = client.getTargetPeers('peer1', client);
+ if (Array.isArray(targets)) {
+ t.pass('targets is an array');
+ } else {
+ t.fail('targets is not an array');
+ }
+ if (targets[0] instanceof Peer) {
+ t.pass('targets has a peer ');
+ } else {
+ t.fail('targets does not have a peer');
+ }
- targets = client.getTargetPeers(['peer1'], client);
- if (Array.isArray(targets)) {
- t.pass('targets is an array');
- } else {
- t.fail('targets is not an array');
- }
- if (targets[0] instanceof Peer) {
- t.pass('targets has a peer ');
- } else {
- t.fail('targets does not have a peer');
- }
+ targets = client.getTargetPeers(['peer1'], client);
+ if (Array.isArray(targets)) {
+ t.pass('targets is an array');
+ } else {
+ t.fail('targets is not an array');
+ }
+ if (targets[0] instanceof Peer) {
+ t.pass('targets has a peer ');
+ } else {
+ t.fail('targets does not have a peer');
+ }
- targets = client.getTargetPeers(peer1, client);
- if (Array.isArray(targets)) {
- t.pass('targets is an array');
- } else {
- t.fail('targets is not an array');
- }
- if (targets[0] instanceof Peer) {
- t.pass('targets has a peer ');
- } else {
- t.fail('targets does not have a peer');
- }
+ targets = client.getTargetPeers(peer1, client);
+ if (Array.isArray(targets)) {
+ t.pass('targets is an array');
+ } else {
+ t.fail('targets is not an array');
+ }
+ if (targets[0] instanceof Peer) {
+ t.pass('targets has a peer ');
+ } else {
+ t.fail('targets does not have a peer');
+ }
- targets = client.getTargetPeers([peer1], client);
- if (Array.isArray(targets)) {
- t.pass('targets is an array');
- } else {
- t.fail('targets is not an array');
- }
- if (targets[0] instanceof Peer) {
- t.pass('targets has a peer ');
- } else {
- t.fail('targets does not have a peer');
- }
+ targets = client.getTargetPeers([peer1], client);
+ if (Array.isArray(targets)) {
+ t.pass('targets is an array');
+ } else {
+ t.fail('targets is not an array');
+ }
+ if (targets[0] instanceof Peer) {
+ t.pass('targets has a peer ');
+ } else {
+ t.fail('targets does not have a peer');
+ }
- },
- 'Should be able to get targets for peer'
+ },
+ 'able to get targets for peer'
);
t.doesNotThrow(
@@ -358,37 +359,37 @@ test('\n\n ** configuration testing **\n\n', (t) => {
'Should not get an error when working with credentialStore settings'
);
- t.doesNotThrow(
- () => {
- const client = new Client();
- client.setCryptoSuite(Client.newCryptoSuite());
- client.setUserContext(new User('testUser'), true);
- client._network_config = new NetworkConfig(network_config, client);
- const organizations = client._network_config.getOrganizations();
- if (Array.isArray(organizations)) {
- t.pass('organizations is an array');
- } else {
- t.fail('organizations is not an array');
- }
- if (organizations[0] instanceof Organization) {
- t.pass('organizations has a organization ');
- } else {
- t.fail('organizations does not have a organization');
- }
+ await testutil.tapeAsyncNoThrow(t, async () => {
+ const client = new Client();
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
+ client.setUserContext(new User('testUser'), true);
+ client._network_config = new NetworkConfig(network_config, client);
+ const organizations = client._network_config.getOrganizations();
+ if (Array.isArray(organizations)) {
+ t.pass('organizations is an array');
+ } else {
+ t.fail('organizations is not an array');
+ }
+ if (organizations[0] instanceof Organization) {
+ t.pass('organizations has a organization ');
+ } else {
+ t.fail('organizations does not have a organization');
+ }
- let organization = client._network_config.getOrganization(organizations[0].getName());
- let ca = organization.getCertificateAuthorities()[0];
- t.equals('ca1', ca.getName(), 'check the ca name');
+ let organization = client._network_config.getOrganization(organizations[0].getName());
+ let ca = organization.getCertificateAuthorities()[0];
+ t.equals('ca1', ca.getName(), 'check the ca name');
- organization = client._network_config.getOrganization(organizations[1].getName());
- ca = organization.getCertificateAuthorities()[0];
- t.equals('ca2', ca.getName(), 'check the ca name');
+ organization = client._network_config.getOrganization(organizations[1].getName());
+ ca = organization.getCertificateAuthorities()[0];
+ t.equals('ca2', ca.getName(), 'check the ca name');
- organization = client._network_config.getOrganizationByMspId(organizations[0].getMspid());
- ca = organization.getCertificateAuthorities()[0];
- t.equals('ca1', ca.getName(), 'check the ca name');
- },
- 'Should be able to get organizations'
+ organization = client._network_config.getOrganizationByMspId(organizations[0].getMspid());
+ ca = organization.getCertificateAuthorities()[0];
+ t.equals('ca1', ca.getName(), 'check the ca name');
+ },
+ 'able to get organizations'
);
network_config.channels = {
@@ -403,33 +404,33 @@ test('\n\n ** configuration testing **\n\n', (t) => {
}
};
- t.doesNotThrow(
- () => {
- let client = Client.loadFromConfig(network_config);
- client.setCryptoSuite(Client.newCryptoSuite());
- client.setUserContext(new User('testUser'), true);
- let channel = client.getChannel('mychannel');
-
- checkTarget(channel._getTargetForQuery(), '7053', 'finding a default ledger query', t);
- checkTarget(channel._getTargets(null, 'ledgerQuery'), '7053', 'finding a default ledger query', t);
- checkTarget(channel._getTargetForQuery('peer1'), '7051', 'finding a string target for ledger query', t);
- checkTarget(channel._getTargets('peer1'), '7051', 'finding a string target', t);
- checkTarget(channel._getTargetForQuery(peer1), '9999', 'should get back the same target if a good peer', t);
- checkTarget(channel._getTargets(peer1), '9999', 'should get back the same target if a good peer', t);
- client = new Client();
- channel = client.newChannel('mychannel');
- channel.addPeer(peer1);
- checkTarget(channel._getTargetForQuery(), '9999', 'finding a default ledger query without networkconfig', t);
- checkTarget(channel._getTargets(undefined, 'ANY'), '9999', 'finding a default targets without networkconfig', t);
- },
- 'Should be able to run channel target methods'
+ await testutil.tapeAsyncNoThrow(t, async () => {
+ let client = await Client.loadFromConfig(network_config);
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
+ client.setUserContext(new User('testUser'), true);
+ let channel = client.getChannel('mychannel');
+
+ checkTarget(channel._getTargetForQuery(), '7053', 'finding a default ledger query', t);
+ checkTarget(channel._getTargets(null, 'ledgerQuery'), '7053', 'finding a default ledger query', t);
+ checkTarget(channel._getTargetForQuery('peer1'), '7051', 'finding a string target for ledger query', t);
+ checkTarget(channel._getTargets('peer1'), '7051', 'finding a string target', t);
+ checkTarget(channel._getTargetForQuery(peer1), '9999', 'should get back the same target if a good peer', t);
+ checkTarget(channel._getTargets(peer1), '9999', 'should get back the same target if a good peer', t);
+ client = new Client();
+ channel = client.newChannel('mychannel');
+ channel.addPeer(peer1);
+ checkTarget(channel._getTargetForQuery(), '9999', 'finding a default ledger query without networkconfig', t);
+ checkTarget(channel._getTargets(undefined, 'ANY'), '9999', 'finding a default targets without networkconfig', t);
+ },
+ 'able to run channel target methods'
);
-
- t.throws(
- () => {
- const client = Client.loadFromConfig(network_config);
- client.setCryptoSuite(Client.newCryptoSuite());
+ await testutil.tapeAsyncThrow(t,
+ async () => {
+ const client = await Client.loadFromConfig(network_config);
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
client.setUserContext(new User('testUser'), true);
const channel = client.getChannel('mychannel');
channel._getTargetForQuery(['peer1']);
@@ -438,10 +439,11 @@ test('\n\n ** configuration testing **\n\n', (t) => {
'Should get an error back when passing an array'
);
- t.throws(
- () => {
- const client = Client.loadFromConfig(network_config);
- client.setCryptoSuite(Client.newCryptoSuite());
+ await testutil.tapeAsyncThrow(t,
+ async () => {
+ const client = await Client.loadFromConfig(network_config);
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
client.setUserContext(new User('testUser'), true);
const channel = client.getChannel('mychannel');
channel._getTargets('bad');
@@ -480,63 +482,63 @@ test('\n\n ** configuration testing **\n\n', (t) => {
'Should get an error when the request orderer is not defined and the channel does not have any orderers'
);
- t.doesNotThrow(
- () => {
- const client = new Client();
- client.setCryptoSuite(Client.newCryptoSuite());
- client.setUserContext(new User('testUser'), true);
- client._network_config = new NetworkConfig(network_config, client);
+ await testutil.tapeAsyncNoThrow(t, async () => {
+ const client = new Client();
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
+ client.setUserContext(new User('testUser'), true);
+ client._network_config = new NetworkConfig(network_config, client);
- let orderer = client.getTargetOrderer('orderer0');
- if (orderer instanceof Orderer) {
- t.pass('orderer has a orderer ');
- } else {
- t.fail('orderer does not have a orderer');
- }
+ let orderer = client.getTargetOrderer('orderer0');
+ if (orderer instanceof Orderer) {
+ t.pass('orderer has a orderer ');
+ } else {
+ t.fail('orderer does not have a orderer');
+ }
- const orderer1 = new Orderer('grpcs://localhost:9999', {pem: '-----BEGIN CERTIFICATE-----MIIB8TCC5l-----END CERTIFICATE-----'});
+ const orderer1 = new Orderer('grpcs://localhost:9999', {pem: '-----BEGIN CERTIFICATE-----MIIB8TCC5l-----END CERTIFICATE-----'});
- orderer = client.getTargetOrderer(orderer1);
- if (orderer instanceof Orderer) {
- t.pass('orderer has a orderer ');
- } else {
- t.fail('orderer does not have a orderer');
- }
+ orderer = client.getTargetOrderer(orderer1);
+ if (orderer instanceof Orderer) {
+ t.pass('orderer has a orderer ');
+ } else {
+ t.fail('orderer does not have a orderer');
+ }
- orderer = client.getTargetOrderer(null, null, 'mychannel');
- if (orderer instanceof Orderer) {
- t.pass('orderer has a orderer ');
- } else {
- t.fail('orderer does not have a orderer');
- }
+ orderer = client.getTargetOrderer(null, null, 'mychannel');
+ if (orderer instanceof Orderer) {
+ t.pass('orderer has a orderer ');
+ } else {
+ t.fail('orderer does not have a orderer');
+ }
- orderer = client.getTargetOrderer(null, [orderer1]);
- if (orderer instanceof Orderer) {
- t.pass('orderer has a orderer ');
- } else {
- t.fail('orderer does not have a orderer');
- }
- },
- 'Should be able to get orderer'
+ orderer = client.getTargetOrderer(null, [orderer1]);
+ if (orderer instanceof Orderer) {
+ t.pass('orderer has a orderer ');
+ } else {
+ t.fail('orderer does not have a orderer');
+ }
+ },
+ 'able to get orderer'
);
- t.doesNotThrow(
- () => {
- const client = Client.loadFromConfig(network_config);
- client.setCryptoSuite(Client.newCryptoSuite());
- client.setUserContext(new User('testUser'), true);
- client.getChannel('mychannel');
- client.loadFromConfig({
- version: '1.0.0',
- channels: {
- 'otherchannel': {
- orderers: ['orderer0']
- }
+ await testutil.tapeAsyncNoThrow(t, async () => {
+ const client = await Client.loadFromConfig(network_config);
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
+ client.setUserContext(new User('testUser'), true);
+ client.getChannel('mychannel');
+ await client.loadFromConfig({
+ version: '1.0.0',
+ channels: {
+ 'otherchannel': {
+ orderers: ['orderer0']
}
- });
- client.getChannel('otherchannel');
- },
- 'Should be able to load additional configurations'
+ }
+ });
+ client.getChannel('otherchannel');
+ },
+ 'able to load additional configurations'
);
t.doesNotThrow(
@@ -590,40 +592,36 @@ test('\n\n ** configuration testing **\n\n', (t) => {
}
);
- t.throws(
- () => {
- const client = new Client();
- client._setAdminFromConfig();
- },
- /No common connection profile has been loaded/,
- 'Should get an error No common connection profile has been loaded'
+ await testutil.tapeAsyncThrow(t, async () => {
+ const client = new Client();
+ await client._setAdminFromConfig();
+ },
+ /No common connection profile has been loaded/,
+ 'Should get an error No common connection profile has been loaded'
);
- t.throws(
- () => {
- const client = new Client();
- client.setAdminSigningIdentity();
- },
- /Invalid parameter. Must have a valid private key./,
- 'Should get an error Invalid parameter. Must have a valid private key.'
+ await testutil.tapeAsyncThrow(t, async () => {
+ const client = new Client();
+ await client.setAdminSigningIdentity();
+ },
+ /Invalid parameter. Must have a valid private key./,
+ 'Should get an error Invalid parameter. Must have a valid private key.'
);
- t.throws(
- () => {
- const client = new Client();
- client.setAdminSigningIdentity('privateKey');
- },
- /Invalid parameter. Must have a valid certificate./,
- 'Should get an error Invalid parameter. Must have a valid certificate.'
+ await testutil.tapeAsyncThrow(t, async () => {
+ const client = new Client();
+ await client.setAdminSigningIdentity('privateKey');
+ },
+ /Invalid parameter. Must have a valid certificate./,
+ 'Should get an error Invalid parameter. Must have a valid certificate.'
);
- t.throws(
- () => {
- const client = new Client();
- client.setAdminSigningIdentity('privateKey', 'cert');
- },
- /Invalid parameter. Must have a valid mspid./,
- 'Should get an error Invalid parameter. Must have a valid mspid.'
+ await testutil.tapeAsyncThrow(t, async () => {
+ const client = new Client();
+ await client.setAdminSigningIdentity('privateKey', 'cert');
+ },
+ /Invalid parameter. Must have a valid mspid./,
+ 'Should get an error Invalid parameter. Must have a valid mspid.'
);
t.throws(
@@ -636,11 +634,11 @@ test('\n\n ** configuration testing **\n\n', (t) => {
);
try {
- const client = Client.loadFromConfig('test/fixtures/profiles/network.yaml');
+ const client = await Client.loadFromConfig('test/fixtures/profiles/network.yaml');
t.pass('Successfully loaded a common connection profile');
t.pass('Should be able to try to load an admin from the config');
- client.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ await client.loadFromConfig('test/fixtures/profiles/org1.yaml');
t.pass('Should be able to load an additional config ...this one has the client section');
t.pass('Should be able to try to load an admin from the config');
// check to see if we were able to load a setting from the yaml into
@@ -650,14 +648,14 @@ test('\n\n ** configuration testing **\n\n', (t) => {
t.fail('Fail - caught an error while trying to load a config and run the set admin');
}
- const clientp1 = Client.loadFromConfig('test/fixtures/profiles/network.yaml');
+ const clientp1 = await Client.loadFromConfig('test/fixtures/profiles/network.yaml');
t.pass('Successfully loaded a common connection profile');
- clientp1.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ await clientp1.loadFromConfig('test/fixtures/profiles/org1.yaml');
t.pass('Should be able to load an additional config ...this one has the client section');
- const p1 = clientp1.initCredentialStores().then(() => {
+ const p1 = clientp1.initCredentialStores().then(async() => {
t.pass('Should be able to load the stores from the config');
- clientp1._setAdminFromConfig();
+ await clientp1._setAdminFromConfig();
t.pass('Should be able to load an admin from the config');
clientp1._getSigningIdentity(true);
t.pass('Should be able to get the loaded admin identity');
@@ -665,9 +663,9 @@ test('\n\n ** configuration testing **\n\n', (t) => {
t.fail(util.format('Should not get an error when doing get signer: %O', err));
});
- const clientp2 = Client.loadFromConfig('test/fixtures/profiles/network.yaml');
+ const clientp2 = await Client.loadFromConfig('test/fixtures/profiles/network.yaml');
t.pass('Successfully loaded a common connection profile');
- clientp2.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ await clientp2.loadFromConfig('test/fixtures/profiles/org1.yaml');
t.pass('Should be able to load an additional config ...this one has the client section');
const p2 = clientp2.initCredentialStores().then(() => {
t.pass('Should be able to load the stores from the config');
@@ -684,9 +682,9 @@ test('\n\n ** configuration testing **\n\n', (t) => {
}
});
- const clientp3 = Client.loadFromConfig('test/fixtures/profiles/network.yaml');
+ const clientp3 = await Client.loadFromConfig('test/fixtures/profiles/network.yaml');
t.pass('Successfully loaded a common connection profile');
- clientp3.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ await clientp3.loadFromConfig('test/fixtures/profiles/org1.yaml');
t.pass('Should be able to load an additional config ...this one has the client section');
const p3 = clientp3.initCredentialStores().then(() => {
t.pass('Should be able to load the stores from the config');
@@ -703,7 +701,7 @@ test('\n\n ** configuration testing **\n\n', (t) => {
}
});
- const clientp4 = Client.loadFromConfig('test/fixtures/profiles/network.yaml');
+ const clientp4 = await Client.loadFromConfig('test/fixtures/profiles/network.yaml');
t.pass('Successfully loaded a common connection profile');
const p4 = clientp4._setUserFromConfig({username: 'username', password: 'password'}).then(() => {
t.fail('Should not be able to load an user based on the config');
@@ -732,18 +730,19 @@ test('\n\n ** configuration testing **\n\n', (t) => {
t.end();
});
-test('\n\n ** channel testing **\n\n', (t) => {
+test('\n\n ** channel testing **\n\n', async (t) => {
const client = new Client();
- client.setCryptoSuite(Client.newCryptoSuite());
+ const suite = await Client.newCryptoSuite();
+ client.setCryptoSuite(suite);
client.setUserContext(new User('testUser'), true);
- client.loadFromConfig('test/fixtures/profiles/network.yaml');
+ await client.loadFromConfig('test/fixtures/profiles/network.yaml');
const channel = client.getChannel('mychannel');
let channelEventHubs = channel.getChannelEventHubsForOrg('bad');
t.equals(channelEventHubs.length, 0, 'Checking that we got the correct number of peers in the list');
channelEventHubs = channel.getChannelEventHubsForOrg('Org2MSP');
t.equals(channelEventHubs[0].getName(), 'peer0.org2.example.com', 'Checking that we got the correct peer in the list');
- client.loadFromConfig('test/fixtures/profiles/org1.yaml');
+ await client.loadFromConfig('test/fixtures/profiles/org1.yaml');
channelEventHubs = channel.getChannelEventHubsForOrg();
t.equals(channelEventHubs[0].getName(), 'peer0.org1.example.com', 'Checking that we got the correct peer in the list');
diff --git a/test/unit/util.js b/test/unit/util.js
index dac3f1b8e2..c28017c5f0 100644
--- a/test/unit/util.js
+++ b/test/unit/util.js
@@ -317,12 +317,12 @@ module.exports.getClientForOrg = async function(t, org) {
// this network config does not have the client information, we will
// load that later so that we can switch this client to be in a different
// organization
- const client = Client.loadFromConfig('test/fixtures/profiles/network-ad.yaml');
+ const client = await Client.loadFromConfig('test/fixtures/profiles/network-ad.yaml');
t.pass('Successfully loaded a common connection profile');
// load the client information for this organization
// this file only has the client section
- client.loadFromConfig('test/fixtures/profiles/' + org + '.yaml');
+ await client.loadFromConfig('test/fixtures/profiles/' + org + '.yaml');
t.pass('Successfully loaded client section of network config for organization:' + org);
if (client._adminSigningIdentity) {
t.pass('Successfully assigned an admin idenity to this client');
@@ -757,6 +757,7 @@ module.exports.queryClientAsAdmin = async function(t, client, channel, peer) {
module.exports.sleep = function(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
};
+
exports.tapeAsyncThrow = async (t, asyncFun, regx, message) => {
try {
await asyncFun();
@@ -770,3 +771,12 @@ exports.tapeAsyncThrow = async (t, asyncFun, regx, message) => {
}
}
};
+
+exports.tapeAsyncNoThrow = async (t, asyncFun, msg) => {
+ try {
+ await asyncFun();
+ t.pass('Successfully ' + msg);
+ } catch (err) {
+ t.fail('Should be ' + msg);
+ }
+};