Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
});
});
});

});