Skip to content

Commit

Permalink
FABN-1096 NodeSDK add member_only_read/write
Browse files Browse the repository at this point in the history
SideDB needs to support member_only_read and member_only_write
attributes on collection definitions

Change-Id: Ia79792359b17e13c2c736579ecb262498496e479
Signed-off-by: Bret Harrison <[email protected]>
  • Loading branch information
harrisob committed Jan 24, 2019
1 parent 317ed37 commit b368e5d
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 6 deletions.
12 changes: 11 additions & 1 deletion fabric-client/lib/Channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -2311,7 +2311,17 @@ const Channel = class {
* data expires. For instance if the value is set to 10, a key last modified by block
* number 100 will be purged at block number 111. A zero value is treated same as MaxUint64,
* where the data will not be purged.
* @property {Policy} policy - The
* @property {boolean} member_read_only - The member only read access denotes
* whether only collection member clients can read the private data (if set
* to true), or even non members can read the data (if set to false, for
* example if you want to implement more granular access logic in the
* chaincode)
* @property {boolean} member_write_only - The member only write access denotes
* whether only collection member clients can write the private data (if set
* to true), or even non members can write the data (if set to false, for
* example if you want to implement more granular access logic in the
* chaincode)
* @property {Policy} policy - The "member_orgs_policy" policy
*/

/**
Expand Down
43 changes: 38 additions & 5 deletions fabric-client/lib/SideDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class CollectionConfig {
* @property {number} maxPeerCount integer
* @property {number} requiredPeerCount integer
* @property {!Long|number|string|!{low: number, high: number, unsigned: boolean}} blockToLive param will be converted to unsigned int64 as Long
* @property {boolean} memberOnlyRead denotes whether only collection member clients can read the private data
* @property {boolean} memberOnlyWrite denotes whether only collection member clients can write the private data
*/

/**
Expand Down Expand Up @@ -70,8 +72,11 @@ class CollectionConfig {
* @returns {collectionConfig}
*/
static checkCollectionConfig(collectionConfig) {
const method = 'checkCollectionConfig';
let {
blockToLive
blockToLive,
memberOnlyRead,
memberOnlyWrite
} = collectionConfig;

const {
Expand Down Expand Up @@ -106,19 +111,43 @@ class CollectionConfig {
throw new Error(format('CollectionConfig Requires Param "blockToLive" of type unsigned int64, found %j(type: %s)', blockToLive, typeof blockToLive));
} else {
const test = Long.fromValue(blockToLive, true);
logger.debug('checkCollectionConfig blockToLive parse from %j and parsed to %s)', blockToLive, test);
logger.debug('%s blockToLive parse from %j and parsed to %s)', method, blockToLive, test);

if (test.toString() !== blockToLive.toString()) {
throw new Error(format('CollectionConfig Requires Param "blockToLive" to be a valid unsigned int64, input is %j and parsed to %s)', blockToLive, test));
}
}

if (typeof memberOnlyRead !== 'undefined') {
if (typeof memberOnlyRead === 'boolean') {
logger.debug('%s - memberOnlyRead has value of %s', method, memberOnlyRead);
} else {
throw new Error(format('CollectionConfig Requires Param "memberOnlyRead" to be boolean, input is %s', memberOnlyRead));
}
} else {
logger.debug('%s - memberOnlyRead defaulting to false', method);
memberOnlyRead = false;
}

if (typeof memberOnlyWrite !== 'undefined') {
if (typeof memberOnlyWrite === 'boolean') {
logger.debug('%s - memberOnlyWrite has value of %s', method, memberOnlyWrite);
} else {
throw new Error(format('CollectionConfig Requires Param "memberOnlyWrite" to be boolean, input is %s', memberOnlyWrite));
}
} else {
logger.debug('%s - memberOnlyWrite defaulting to false', method);
memberOnlyWrite = false;
}

return {
name,
policy,
maxPeerCount,
requiredPeerCount,
blockToLive
blockToLive,
memberOnlyRead,
memberOnlyWrite
};
}

Expand All @@ -132,15 +161,19 @@ class CollectionConfig {
policy,
maxPeerCount,
requiredPeerCount,
blockToLive
blockToLive,
memberOnlyRead,
memberOnlyWrite
} = this.checkCollectionConfig(collectionConfig);

const static_collection_config = {
name,
member_orgs_policy: {},
required_peer_count: requiredPeerCount,
maximum_peer_count: maxPeerCount,
block_to_live: blockToLive
block_to_live: blockToLive,
member_only_read: memberOnlyRead,
member_only_write: memberOnlyWrite
};

const principals = [];
Expand Down
66 changes: 66 additions & 0 deletions fabric-client/test/SideDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,72 @@ describe('SideDB', () => {
}).should.throw(/CollectionConfig Requires Param "blockToLive" to be a valid unsigned int64/);
});

it('should throw if passed collectionConfig.memberOnlyRead is not a valid boolean', () => {
(() => {
const checkPolicyStub = sandbox.stub();
const policy = sandbox.stub();
policy.checkPolicy = checkPolicyStub;

revert.push(SideDBRewire.__set__('Policy', policy));
SideDBRewire.checkCollectionConfig({name: 'test', policy: policy, maxPeerCount: 1, requiredPeerCount: 1, blockToLive: '100', memberOnlyRead: 'aa'});
}).should.throw('CollectionConfig Requires Param "memberOnlyRead" to be boolean, input is aa');
});

it('should default `memberOnlyRead` to be false if not passed as a config item', () => {
const checkPolicyStub = sandbox.stub();
const policy = sandbox.stub();
policy.checkPolicy = checkPolicyStub;

revert.push(SideDBRewire.__set__('Policy', policy));

const obj = SideDBRewire.checkCollectionConfig({name: 'test', policy: policy, maxPeerCount: 1, requiredPeerCount: 1});
obj.memberOnlyRead.should.equal(false);
});

it('should `memberOnlyRead` to be true if passed in as true as a config item', () => {
const checkPolicyStub = sandbox.stub();
const policy = sandbox.stub();
policy.checkPolicy = checkPolicyStub;

revert.push(SideDBRewire.__set__('Policy', policy));

const obj = SideDBRewire.checkCollectionConfig({name: 'test', policy: policy, maxPeerCount: 1, requiredPeerCount: 1, memberOnlyRead: true});
obj.memberOnlyRead.should.equal(true);
});

it('should throw if passed collectionConfig.memberOnlyWrite is not a valid boolean', () => {
(() => {
const checkPolicyStub = sandbox.stub();
const policy = sandbox.stub();
policy.checkPolicy = checkPolicyStub;

revert.push(SideDBRewire.__set__('Policy', policy));
SideDBRewire.checkCollectionConfig({name: 'test', policy: policy, maxPeerCount: 1, requiredPeerCount: 1, blockToLive: '100', memberOnlyWrite: 'aa'});
}).should.throw('CollectionConfig Requires Param "memberOnlyWrite" to be boolean, input is aa');
});

it('should default `memberOnlyWrite` to be false if not passed as a config item', () => {
const checkPolicyStub = sandbox.stub();
const policy = sandbox.stub();
policy.checkPolicy = checkPolicyStub;

revert.push(SideDBRewire.__set__('Policy', policy));

const obj = SideDBRewire.checkCollectionConfig({name: 'test', policy: policy, maxPeerCount: 1, requiredPeerCount: 1});
obj.memberOnlyWrite.should.equal(false);
});

it('should `memberOnlyWrite` to be true if passed in as true as a config item', () => {
const checkPolicyStub = sandbox.stub();
const policy = sandbox.stub();
policy.checkPolicy = checkPolicyStub;

revert.push(SideDBRewire.__set__('Policy', policy));

const obj = SideDBRewire.checkCollectionConfig({name: 'test', policy: policy, maxPeerCount: 1, requiredPeerCount: 1, memberOnlyWrite: true});
obj.memberOnlyWrite.should.equal(true);
});

it('should return if passed a correct collectionConfig', () => {
const checkPolicyStub = sandbox.stub();
const Policy = sandbox.stub();
Expand Down
2 changes: 2 additions & 0 deletions fabric-client/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,8 @@ declare namespace Client { // tslint:disable-line:no-namespace
required_peer_count: number;
maximum_peer_count: number;
block_to_live: number;
member_only_read: boolean;
member_only_write: boolean;
}

export interface Response {
Expand Down
4 changes: 4 additions & 0 deletions test/integration/e2e/getCollectionsConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,17 @@ test('getCollectionsConfig from peer', async (t) => {
t.equal(results[0].required_peer_count, 1);
t.equal(results[0].maximum_peer_count, 1);
t.equal(results[0].block_to_live, 100);
t.equal(results[0].member_only_read, false);
t.equal(results[0].member_only_write, false);
t.deepEqual(results[0].policy.identities, [{msp_identifier: 'Org1MSP', role: 'MEMBER'}, {msp_identifier: 'Org2MSP', role: 'MEMBER'}]);

t.equal(results[1].type, 'static_collection_config');
t.equal(results[1].name, 'sensitiveCol');
t.equal(results[1].required_peer_count, 0);
t.equal(results[1].maximum_peer_count, 1);
t.equal(results[1].block_to_live, 100);
t.equal(results[1].member_only_read, false);
t.equal(results[1].member_only_write, false);
t.deepEqual(results[1].policy.identities, [{msp_identifier: 'Org1MSP', role: 'MEMBER'}]);
t.end();
} catch (err) {
Expand Down

0 comments on commit b368e5d

Please sign in to comment.