Skip to content

Commit

Permalink
Add IdCard.toArchive function (hyperledger-archives#1719)
Browse files Browse the repository at this point in the history
Signed-off-by: Mark S. Lewis <[email protected]>
  • Loading branch information
bestbeforetoday authored and jt-nti committed Aug 1, 2017
1 parent f624c4e commit 4333bce
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 35 deletions.
3 changes: 2 additions & 1 deletion packages/composer-common/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ class IdCard {
+ Object getCredentials()
+ Object getEnrollmentCredentials()
+ String[] getRoles()
+ Promise fromArchive(Buffer)
+ Promise fromArchive()
+ Promise toArchive(Object,String)
}
class IllegalModelException extends BaseFileException {
+ void constructor(String,ModelFile,Object,String,String,String,String)
Expand Down
3 changes: 2 additions & 1 deletion packages/composer-common/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
#
# Note that the latest public API is documented using JSDocs and is available in api.txt.
#
Version 0.10.2 {e07efe48c4f431525388c10979b4289b} 2017-07-27
Version 0.10.2 {04641978245bd4326e314f0afb758b67} 2017-07-27
- Added IdCard.getRoles function
- Added IdCard.toArchive function

Version 0.10.1 {d1fd512551ff5bb30b31f05f6817966e} 2017-07-24
- Added InvalidQueryException, BaseFileException
Expand Down
65 changes: 52 additions & 13 deletions packages/composer-common/lib/idcard.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ const JSZip = require('jszip');
const Logger = require('./log/logger');
const LOG = Logger.getLog('IdCard');

const CONNECTION_FILENAME = 'connection.json';
const METADATA_FILENAME = 'metadata.json';
const CREDENTIALS_DIRNAME = 'credentials';

/**
* An ID card. Encapsulates credentials and other information required to connect to a specific business network
* as a specific user.
Expand Down Expand Up @@ -140,24 +144,26 @@ class IdCard {

/**
* Create an IdCard from a card archive.
* @param {Buffer} buffer - the Buffer to a zip archive
* @return {Promise} Promise to the instantiated IdCard
* <p>
* Valid types for <em>zipData</em> are any of the types supported by JSZip.
* @param {String|ArrayBuffer|Uint8Array|Buffer|Blob|Promise} zipData - card archive data.
* @return {Promise} Promise to the instantiated IdCard.
*/
static fromArchive(buffer) {
static fromArchive(zipData) {
const method = 'fromArchive';
LOG.entry(method, buffer.length);
LOG.entry(method, zipData.length);

return JSZip.loadAsync(buffer).then((zip) => {
return JSZip.loadAsync(zipData).then((zip) => {
let promise = Promise.resolve();

let metadata;
let connection;
let credentials = Object.create(null);

LOG.debug(method, 'Loading connection.json');
const connectionFile = zip.file('connection.json');
LOG.debug(method, 'Loading ' + CONNECTION_FILENAME);
const connectionFile = zip.file(CONNECTION_FILENAME);
if (!connectionFile) {
throw Error('Required file not found: connection.json');
throw Error('Required file not found: ' + CONNECTION_FILENAME);
}

promise = promise.then(() => {
Expand All @@ -166,10 +172,10 @@ class IdCard {
connection = JSON.parse(connectionContent);
});

LOG.debug(method, 'Loading metadata.json');
const metadataFile = zip.file('metadata.json');
LOG.debug(method, 'Loading ' + METADATA_FILENAME);
const metadataFile = zip.file(METADATA_FILENAME);
if (!metadataFile) {
throw Error('Required file not found: metadata.json');
throw Error('Required file not found: ' + METADATA_FILENAME);
}

promise = promise.then(() => {
Expand All @@ -193,8 +199,8 @@ class IdCard {
});
};

LOG.debug(method, 'Loading credentials');
loadDirectoryToObject('credentials', credentials);
LOG.debug(method, 'Loading ' + CREDENTIALS_DIRNAME);
loadDirectoryToObject(CREDENTIALS_DIRNAME, credentials);

return promise.then(() => {
const idCard = new IdCard(metadata, connection, credentials);
Expand All @@ -204,6 +210,39 @@ class IdCard {
});
}

/**
* Generate a card archive representing this ID card.
* <p>
* The default value for the <em>options.type</em> parameter is <em>arraybuffer</em>. See JSZip documentation
* for other valid values.
* @param {Object} [options] - JSZip generation options.
* @param {String} [options.type] - type of the resulting ZIP file data.
* @return {Promise} Promise of the generated ZIP file; by default an {@link ArrayBuffer}.
*/
toArchive(options) {
const method = 'fromArchive';
LOG.entry(method, options);

const zipOptions = Object.assign({ type: 'arraybuffer' }, options);
const zip = new JSZip();

const connectionContents = JSON.stringify(this.connectionProfile);
zip.file(CONNECTION_FILENAME, connectionContents);

const metadataContents = JSON.stringify(this.metadata);
zip.file(METADATA_FILENAME, metadataContents);

Object.keys(this.credentials).forEach(credentialName => {
const filename = CREDENTIALS_DIRNAME + '/' + credentialName;
const credentialData = this.credentials[credentialName];
zip.file(filename, credentialData);
});

const result = zip.generateAsync(zipOptions);
LOG.exit(method, result);
return result;
}

}

module.exports = IdCard;
82 changes: 62 additions & 20 deletions packages/composer-common/test/idcard.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,41 +83,41 @@ describe('IdCard', function() {

it('should throw error on missing connection.json', function() {
return readIdCardAsync('missing-connection').then((readBuffer) => {
return IdCard.fromArchive(readBuffer).then(function resolved(card) {
throw Error('Card loaded without error');
}, function rejected(error) {
error.message.should.include('connection.json');
});
return IdCard.fromArchive(readBuffer);
}).then(function resolved(card) {
throw Error('Card loaded without error');
}, function rejected(error) {
error.message.should.include('connection.json');
});
});

it('should throw error on missing name field in connection.json', function() {
return readIdCardAsync('missing-connection-name').then((readBuffer) => {
return IdCard.fromArchive(readBuffer).then(function resolved(card) {
throw Error('Card loaded without error');
}, function rejected(error) {
error.message.should.include('name');
});
return IdCard.fromArchive(readBuffer);
}).then(function resolved(card) {
throw Error('Card loaded without error');
}, function rejected(error) {
error.message.should.include('name');
});
});

it('should throw error on missing metadata.json', function() {
return readIdCardAsync('missing-metadata').then((readBuffer) => {
return IdCard.fromArchive(readBuffer).then(function resolved(card) {
throw Error('Card loaded without error');
}, function rejected(error) {
error.message.should.include('metadata.json');
});
return IdCard.fromArchive(readBuffer);
}).then(function resolved(card) {
throw Error('Card loaded without error');
}, function rejected(error) {
error.message.should.include('metadata.json');
});
});

it('should throw error on missing name field in metadata', function() {
return readIdCardAsync('missing-metadata-name').then((readBuffer) => {
return IdCard.fromArchive(readBuffer).then(function resolved(card) {
throw Error('Card loaded without error');
}, function rejected(error) {
error.message.should.include('name');
});
return IdCard.fromArchive(readBuffer);
}).then(function resolved(card) {
throw Error('Card loaded without error');
}, function rejected(error) {
error.message.should.include('name');
});
});

Expand Down Expand Up @@ -223,6 +223,48 @@ describe('IdCard', function() {
roles.should.be.empty;
});
});
});

describe('#toArchive', function() {
const minimalMetadata = { name: 'minimal'};
const minimalConnectionProfile = { name: 'minimal' };
const emptyCredentials = { };
const validCredentials = {
public: 'public-key-data',
private: 'private-key-data'
};

const minimalCard = new IdCard(minimalMetadata, minimalConnectionProfile, emptyCredentials);
const credentialsCard = new IdCard(minimalMetadata, minimalConnectionProfile, validCredentials);

it('should export a valid minimal ID card', function() {
return minimalCard.toArchive().then(cardArchive => {
return IdCard.fromArchive(cardArchive);
}).then(card => {
card.should.deep.equal(minimalCard);
});
});

it('should export credentials', function() {
return credentialsCard.toArchive().then(cardArchive => {
return IdCard.fromArchive(cardArchive);
}).then(card => {
card.should.deep.equal(credentialsCard);
});
});

it('should export to an ArrayBuffer by default', function() {
return minimalCard.toArchive().then(cardArchive => {
cardArchive.should.be.an.instanceof(ArrayBuffer);
});
});

it('should export to a Node Buffer if requested', function() {
const options = { type: 'nodebuffer' };
return minimalCard.toArchive(options).then(cardArchive => {
cardArchive.should.be.an.instanceof(Buffer);
});
});
});

});

0 comments on commit 4333bce

Please sign in to comment.