diff --git a/Chapter03/README.md b/Chapter03/README.md index e8bd5de..76aa997 100644 --- a/Chapter03/README.md +++ b/Chapter03/README.md @@ -227,3 +227,20 @@ If github is new to you, please use the following process: - press the enter key. This will make a local copy of the tutorial on your computer and, because you cloned from your personal copy of the tutorial, will allow you to save your work up to github.com and, if you choose, share your work with others. +# Check out the network + + - Open a Terminal Window and change to Chapter03 + - Issue the command ```buildAndDeploy``` and press enter, which will create a file called zerotoblockchain-network.bna in the Chapter03/network/dist folder. + - Open HyperLedger Composer [Playground](https://composer-playground.mybluemix.net) and then click on the web page to select the option to use your own business network + - You may get the following message. If so, congrats! You've used playground before. Click on ```Clear local Storage``` + ![Invalid Storage](../assets/IBMCloud_playground_invalid.png) + - You may see this message. If so, click on ```Let's Blockchain!``` + ![Let's Blockchain!](../assets/IBMCloud_playground_lets.png) + - You should then see this page. Click on the right hand icon - deploy a new business network + ![Deploy new network](../assets/IBMCloud_playground_deploy1.png) + - which takes you to this page: + ![Drag your file here](../assets/IBMCloud_playground_drag.png) + - navigate in Finder (OSX) or the Ubuntu File Explorer to Chapter03/network/dist + - and then drag the ```zerotoblockchain-network.bna``` file to the highlighted icon in the playground + - The right hand side of the screen will now activate. Press the ```Deploy``` button + ![Deploy](../assets/IBMCloud_playground_deploy2.png) \ No newline at end of file diff --git a/Chapter03/README.pdf b/Chapter03/README.pdf index 559b88e..dd7d83d 100644 Binary files a/Chapter03/README.pdf and b/Chapter03/README.pdf differ diff --git a/Chapter03/deployNetwork.sh b/Chapter03/deployNetwork.sh index f2b5305..9c13a36 100755 --- a/Chapter03/deployNetwork.sh +++ b/Chapter03/deployNetwork.sh @@ -76,5 +76,16 @@ echo "Parameters:" echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "deploying network" -cd network/dist -composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString \ No newline at end of file +# original - V0.13 +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString +# +# what the documentation implies is required +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString +# +# what really works +composer identity request -p hlfv1 -i admin -s adminpw +composer identity import -p hlfv1 -u admin -c ~/.identityCredentials/admin-pub.pem -k ~/.identityCredentials/admin-priv.pem +cd network/dist +composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString diff --git a/Chapter03/network/package.json b/Chapter03/network/package.json index 02c2226..be89bc0 100644 --- a/Chapter03/network/package.json +++ b/Chapter03/network/package.json @@ -1,9 +1,9 @@ { "engines": { - "composer": "^0.10.0" + "composer": "" }, "name": "zerotoblockchain-network", - "version": "0.1.6", + "version": "0.1.5", "description": "Zero to Blockchain tutorial network", "networkImage": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimage.svg", "networkImageanimated": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimageanimated.svg", @@ -36,11 +36,11 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-admin": "^0.9.0", - "composer-cli": "^0.9.0", - "composer-client": "^0.9.0", - "composer-connector-embedded": "^0.9.0", - "composer-cucumber-steps": "^0.9.0", + "composer-admin": "^0.14.0", + "composer-cli": "^0.14.0", + "composer-client": "^0.14.0", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter03/network/permissions.acl b/Chapter03/network/permissions.acl index 2ee49bf..fd1f3e6 100644 --- a/Chapter03/network/permissions.acl +++ b/Chapter03/network/permissions.acl @@ -7,4 +7,24 @@ rule Default { operation: ALL resource: "org.acme.Z2BTestNetwork.*" action: ALLOW +} +/** +* Added to support V0.14 breaking changes +* +*/ + +rule NetworkAdminUser { + description: "Grant business network administrators full access to user resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "**" + action: ALLOW +} + +rule NetworkAdminSystem { + description: "Grant business network administrators full access to system resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "org.hyperledger.composer.system.**" + action: ALLOW } \ No newline at end of file diff --git a/Chapter03/package.json b/Chapter03/package.json index 9964083..01578b9 100644 --- a/Chapter03/package.json +++ b/Chapter03/package.json @@ -1,6 +1,6 @@ { "engines": { - "composer": "" + "composer": "^0.10.0" }, "name": "zerotoblockchain-network", "version": "0.1.6", @@ -33,31 +33,15 @@ "author": "Bob Dill, IBM Distinguished Engineer", "license": "Apache-2.0", "devDependencies": { - "http": "", - "https": "", - "fs": "", - "mime": "", - "path": "", - "body-parser": "", - "cfenv": "", - "cookie-parser": "", - "express-session": "", - "vcap_services": "", - "uuid": "", - "connect-busboy": "", - "ejs": "", - "date-format": "", - "extend": "", "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-admin": "", - "composer-cli": "", - "composer-client": "", + "composer-admin": "^0.14.0", + "composer-cli": "^0.14.0", + "composer-client": "^0.14.0", "composer-common": "", - "composer-connector-embedded": "", - "composer-connector-hlf": "", - "composer-cucumber-steps": "", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", @@ -99,10 +83,5 @@ "branches": 100, "functions": 100, "lines": 100 - }, - "dependencies": { - "express": "^4.15.4", - "http": "0.0.0", - "sleep": "^5.1.1" } } diff --git a/Chapter03/start_rest_server.sh b/Chapter03/start_rest_server.sh index 4249418..61d94ed 100755 --- a/Chapter03/start_rest_server.sh +++ b/Chapter03/start_rest_server.sh @@ -77,4 +77,7 @@ echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "testing rest server \n when this completes, \n go to your favorite browser \n and enter localhost:3000/explorer " -composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# original (pre V0.14) +# composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# V0.14 +composer-rest-server -p hlfv1 -n zerotoblockchain-network -i admin -s adminPW diff --git a/Chapter04/Documentation/answers/lib/sample_complete.js b/Chapter04/Documentation/answers/lib/sample_complete.js index aa819dc..1036514 100644 --- a/Chapter04/Documentation/answers/lib/sample_complete.js +++ b/Chapter04/Documentation/answers/lib/sample_complete.js @@ -12,6 +12,24 @@ * limitations under the License. */ +var orderStatus = { + Created: {code: 1, text: 'Order Created'}, + Bought: {code: 2, text: 'Order Purchased'}, + Cancelled: {code: 3, text: 'Order Cancelled'}, + Ordered: {code: 4, text: 'Order Submitted to Provider'}, + ShipRequest: {code: 5, text: 'Shipping Requested'}, + Delivered: {code: 6, text: 'Order Delivered'}, + Delivering: {code: 15, text: 'Order being Delivered'}, + Backordered: {code: 7, text: 'Order Backordered'}, + Dispute: {code: 8, text: 'Order Disputed'}, + Resolve: {code: 9, text: 'Order Dispute Resolved'}, + PayRequest: {code: 10, text: 'Payment Requested'}, + Authorize: {code: 11, text: 'Payment Approved'}, + Paid: {code: 14, text: 'Payment Processed'}, + Refund: {code: 12, text: 'Order Refund Requested'}, + Refunded: {code: 13, text: 'Order Refunded'} +}; + /** * create an order to purchase * @param {org.acme.Z2BTestNetwork.CreateOrder} purchase - the order to be processed @@ -20,8 +38,9 @@ function CreateOrder(purchase) { purchase.order.buyer = purchase.buyer; purchase.order.amount = purchase.amount; + purchase.order.financeCo = purchase.financeCo; purchase.order.created = new Date().toISOString(); - purchase.order.status = "Order Created"; + purchase.order.status = JSON.stringify(orderStatus.Created); return getAssetRegistry('org.acme.Z2BTestNetwork.Order') .then(function (assetRegistry) { return assetRegistry.update(purchase.order); @@ -33,14 +52,35 @@ function CreateOrder(purchase) { * @transaction */ function Buy(purchase) { - purchase.order.buyer = purchase.buyer; - purchase.order.seller = purchase.seller; - purchase.order.bought = new Date().toISOString(); - purchase.order.status = "Purchased"; - return getAssetRegistry('org.acme.Z2BTestNetwork.Order') - .then(function (assetRegistry) { - return assetRegistry.update(purchase.order); - }); + if (purchase.order.status = JSON.stringify(orderStatus.Created)) + { + purchase.order.buyer = purchase.buyer; + purchase.order.seller = purchase.seller; + purchase.order.bought = new Date().toISOString(); + purchase.order.status = JSON.stringify(orderStatus.Bought); + return getAssetRegistry('org.acme.Z2BTestNetwork.Order') + .then(function (assetRegistry) { + return assetRegistry.update(purchase.order); + }); + } +} +/** + * Record a request to cancel an order + * @param {org.acme.Z2BTestNetwork.OrderCancel} purchase - the order to be processed + * @transaction + */ +function OrderCancel(purchase) { + if ((purchase.order.status = JSON.stringify(orderStatus.Created)) || (purchase.order.status = JSON.stringify(orderStatus.Bought))) + { + purchase.order.buyer = purchase.buyer; + purchase.order.seller = purchase.seller; + purchase.order.cancelled = new Date().toISOString(); + purchase.order.status = JSON.stringify(orderStatus.Cancelled); + return getAssetRegistry('org.acme.Z2BTestNetwork.Order') + .then(function (assetRegistry) { + return assetRegistry.update(purchase.order); + }); + } } /** * Record a request to order by seller from supplier @@ -48,14 +88,16 @@ function Buy(purchase) { * @transaction */ function OrderFromSupplier(purchase) { - var supplier = '{"supplier": "'+purchase.provider.$identifier+'"}'; - purchase.order.vendors.push(supplier); - purchase.order.ordered = new Date().toISOString(); - purchase.order.status = "Ordered From Supplier"; - return getAssetRegistry('org.acme.Z2BTestNetwork.Order') - .then(function (assetRegistry) { - return assetRegistry.update(purchase.order); - }); + if (purchase.order.status = JSON.stringify(orderStatus.Bought)) + { + purchase.order.provider = purchase.provider; + purchase.order.ordered = new Date().toISOString(); + purchase.order.status = JSON.stringify(orderStatus.Ordered); + return getAssetRegistry('org.acme.Z2BTestNetwork.Order') + .then(function (assetRegistry) { + return assetRegistry.update(purchase.order); + }); + } } /** * Record a request to ship by supplier to shipper @@ -63,14 +105,34 @@ function OrderFromSupplier(purchase) { * @transaction */ function RequestShipping(purchase) { - var shipper = '{"shipper": "'+purchase.shipper.$identifier+'"}'; - purchase.order.vendors.push(shipper); - purchase.order.requestShipment = new Date().toISOString(); - purchase.order.status = "Shipment Requested"; - return getAssetRegistry('org.acme.Z2BTestNetwork.Order') - .then(function (assetRegistry) { - return assetRegistry.update(purchase.order); - }); + if (purchase.order.status = JSON.stringify(orderStatus.Ordered)) + { + purchase.order.shipper = purchase.shipper; + purchase.order.requestShipment = new Date().toISOString(); + purchase.order.status = JSON.stringify(orderStatus.ShipRequest); + return getAssetRegistry('org.acme.Z2BTestNetwork.Order') + .then(function (assetRegistry) { + return assetRegistry.update(purchase.order); + }); + } +} +/** + * Record a delivery by shipper + * @param {org.acme.Z2BTestNetwork.Delivering} purchase - the order to be processed + * @transaction + */ +function Delivering(purchase) { + if ((purchase.order.status = JSON.stringify(orderStatus.ShipRequest)) || (JSON.parse(purchase.order.status).code = orderStatus.Delivering.code)) + { + purchase.order.delivering = new Date().toISOString(); + var _status = orderStatus.Delivering; + _status.text += ' '+purchase.deliveryStatus; + purchase.order.status = JSON.stringify(_status); + return getAssetRegistry('org.acme.Z2BTestNetwork.Order') + .then(function (assetRegistry) { + return assetRegistry.update(purchase.order); + }); + } } /** * Record a delivery by shipper @@ -78,12 +140,15 @@ function RequestShipping(purchase) { * @transaction */ function Deliver(purchase) { - purchase.order.delivered = new Date().toISOString(); - purchase.order.status = "Delivered"; - return getAssetRegistry('org.acme.Z2BTestNetwork.Order') - .then(function (assetRegistry) { - return assetRegistry.update(purchase.order); - }); + if ((purchase.order.status = JSON.stringify(orderStatus.ShipRequest)) || (JSON.parse(purchase.order.status).code = orderStatus.Delivering.code)) + { + purchase.order.delivered = new Date().toISOString(); + purchase.order.status = JSON.stringify(orderStatus.Delivered); + return getAssetRegistry('org.acme.Z2BTestNetwork.Order') + .then(function (assetRegistry) { + return assetRegistry.update(purchase.order); + }); + } } /** * Record a request for payment by the seller @@ -91,16 +156,30 @@ function Deliver(purchase) { * @transaction */ function RequestPayment(purchase) { - if ((purchase.order.status == "Delivered") || (purchase.order.status == "Resolved")) - {purchase.order.status = "Payment Requested"; - var payer = '{"financeCo": "'+purchase.financeCo.$identifier+'"}'; - purchase.order.vendors.push(payer); + if ((JSON.parse(purchase.order.status).text == orderStatus.Delivered.text) || (JSON.parse(purchase.order.status).text == orderStatus.Resolve.text)) + {purchase.order.status = JSON.stringify(orderStatus.PayRequest); + purchase.order.financeCo = purchase.financeCo; purchase.order.paymentRequested = new Date().toISOString(); } return getAssetRegistry('org.acme.Z2BTestNetwork.Order') .then(function (assetRegistry) { return assetRegistry.update(purchase.order); }); +} + /** + * Record a payment to the seller + * @param {org.acme.Z2BTestNetwork.AuthorizePayment} purchase - the order to be processed + * @transaction + */ +function AuthorizePayment(purchase) { + if ((JSON.parse(purchase.order.status).text == orderStatus.PayRequest.text ) || (JSON.parse(purchase.order.status).text == orderStatus.Resolve.text )) + {purchase.order.status = JSON.stringify(orderStatus.Authorize); + purchase.order.approved = new Date().toISOString(); + } + return getAssetRegistry('org.acme.Z2BTestNetwork.Order') + .then(function (assetRegistry) { + return assetRegistry.update(purchase.order); + }); } /** * Record a payment to the seller @@ -108,8 +187,8 @@ function RequestPayment(purchase) { * @transaction */ function Pay(purchase) { - if (purchase.order.status == "Payment Requested") - {purchase.order.status = "Paid"; + if (JSON.parse(purchase.order.status).text == orderStatus.Authorize.text ) + {purchase.order.status = JSON.stringify(orderStatus.Paid); purchase.order.paid = new Date().toISOString(); } return getAssetRegistry('org.acme.Z2BTestNetwork.Order') @@ -123,7 +202,7 @@ function Pay(purchase) { * @transaction */ function Dispute(purchase) { - purchase.order.status = "In Dispute"; + purchase.order.status = JSON.stringify(orderStatus.Dispute); purchase.order.dispute = purchase.dispute; purchase.order.disputeOpened = new Date().toISOString(); return getAssetRegistry('org.acme.Z2BTestNetwork.Order') @@ -137,7 +216,7 @@ function Dispute(purchase) { * @transaction */ function Resolve(purchase) { - purchase.order.status = "Resolved"; + purchase.order.status = JSON.stringify(orderStatus.Resolve); purchase.order.resolve = purchase.resolve; purchase.order.disputeResolved = new Date().toISOString(); return getAssetRegistry('org.acme.Z2BTestNetwork.Order') @@ -151,7 +230,7 @@ function Resolve(purchase) { * @transaction */ function Refund(purchase) { - purchase.order.status = "Refunded"; + purchase.order.status = JSON.stringify(orderStatus.Refund); purchase.order.refund = purchase.refund; purchase.order.orderRefunded = new Date().toISOString(); return getAssetRegistry('org.acme.Z2BTestNetwork.Order') @@ -165,24 +244,25 @@ function Refund(purchase) { * @transaction */ function BackOrder(purchase) { - purchase.order.status = "Backordered"; + purchase.order.status = JSON.stringify(orderStatus.Backordered); purchase.order.backorder = purchase.backorder; purchase.order.dateBackordered = new Date().toISOString(); - return getAssetRegistry('org.acme.Z2BTestNetwork.Order') + purchase.order.provider = purchase.provider; + return getAssetRegistry('org.acme.Z2BTestNetwork.Order') .then(function (assetRegistry) { return assetRegistry.update(purchase.order); }); } - /** + +/** * display using console.log the properties of each property in the inbound object * @param {displayObjectProperties} _string - string name of object * @param {displayObjectProperties} _object - the object to be parsed * @utility */ - function displayObjectValues (_string, _object) { for (var prop in _object){ console.log(_string+'-->'+prop+':\t '+(((typeof(_object[prop]) === 'object') || (typeof(_object[prop]) === 'function')) ? typeof(_object[prop]) : _object[prop])); } -} +} \ No newline at end of file diff --git a/Chapter04/Documentation/answers/models/sample_complete.cto b/Chapter04/Documentation/answers/models/sample_complete.cto index b3ffb61..a803085 100644 --- a/Chapter04/Documentation/answers/models/sample_complete.cto +++ b/Chapter04/Documentation/answers/models/sample_complete.cto @@ -25,25 +25,30 @@ asset Order identified by orderNumber { o String orderNumber o String[] items o String status + o String dispute + o String resolve + o String backorder + o String refund o Integer amount o String created o String bought + o String cancelled o String ordered o String dateBackordered o String requestShipment o String delivered + o String delivering o String disputeOpened o String disputeResolved o String paymentRequested o String orderRefunded + o String approved o String paid - o String[] vendors - o String dispute - o String resolve - o String backorder - o String refund + --> Provider provider + --> Shipper shipper --> Buyer buyer --> Seller seller + --> FinanceCo financeCo } transaction CreateOrder { @@ -51,6 +56,12 @@ asset Order identified by orderNumber { --> Order order --> Buyer buyer --> Seller seller + --> FinanceCo financeCo +} + transaction OrderCancel { + --> Order order + --> Buyer buyer + --> Seller seller } transaction Buy { --> Order order @@ -60,14 +71,21 @@ asset Order identified by orderNumber { transaction OrderFromSupplier { --> Order order --> Provider provider + --> Seller seller } transaction RequestShipping { --> Order order --> Shipper shipper + --> Provider provider } transaction Deliver { --> Order order --> Shipper shipper +} + transaction Delivering { + o String deliveryStatus + --> Order order + --> Shipper shipper } transaction BackOrder { o String backorder @@ -86,13 +104,19 @@ asset Order identified by orderNumber { --> Order order --> Buyer buyer --> Seller seller + --> Shipper shipper + --> Provider provider --> FinanceCo financeCo } transaction RequestPayment { --> Order order - --> Buyer buyer --> Seller seller --> FinanceCo financeCo +} + transaction AuthorizePayment { + --> Order order + --> Buyer buyer + --> FinanceCo financeCo } transaction Pay { --> Order order @@ -102,7 +126,6 @@ asset Order identified by orderNumber { transaction Refund { o String refund --> Order order - --> Buyer buyer --> Seller seller --> FinanceCo financeCo } diff --git a/Chapter04/Documentation/answers/test/sample_complete.js b/Chapter04/Documentation/answers/test/sample_complete.js index 0ea5df1..1c3e3e6 100644 --- a/Chapter04/Documentation/answers/test/sample_complete.js +++ b/Chapter04/Documentation/answers/test/sample_complete.js @@ -36,7 +36,27 @@ const financeCoID = 'GlobalFinancier'; const dispute = 'ordered products received but defective'; const resolve = 'defective products will be refunded'; const backorder = 'order received, products on backorder. Will be shipped in 2 weeks.'; +let shipper; +let provider; +let financeCo; let orderAmount = 0; +let orderStatus = { + 'Created': {'code': 1, 'text': 'Order Created'}, + 'Bought': {'code': 2, 'text': 'Order Purchased'}, + 'Cancelled': {'code': 3, 'text': 'Order Cancelled'}, + 'Ordered': {'code': 4, 'text': 'Order Submitted to Provider'}, + 'ShipRequest': {'code': 5, 'text': 'Shipping Requested'}, + 'Delivered': {'code': 6, 'text': 'Order Delivered'}, + 'Delivering': {'code': 15, 'text': 'Order being Delivered'}, + 'Backordered': {'code': 7, 'text': 'Order Backordered'}, + 'Dispute': {'code': 8, 'text': 'Order Disputed'}, + 'Resolve': {'code': 9, 'text': 'Order Dispute Resolved'}, + 'PayRequest': {'code': 10, 'text': 'Payment Requested'}, + 'Authorize': {'code': 11, 'text': 'Payment Approved'}, + 'Paid': {'code': 14, 'text': 'Payment Processed'}, + 'Refund': {'code': 12, 'text': 'Order Refund Requested'}, + 'Refunded': {'code': 13, 'text': 'Order Refunded'} +}; /** * create an empty order @@ -49,23 +69,25 @@ function createOrderTemplate (_inbound) _inbound.orderNumber = ''; _inbound.amount = 0; _inbound.items = []; - _inbound.status = 'Order Created'; + _inbound.status = JSON.stringify(orderStatus.Created); _inbound.created = new Date().toISOString(); + _inbound.cancelled = ''; _inbound.ordered = ''; _inbound.bought = ''; _inbound.dateBackordered = ''; _inbound.requestShipment = ''; _inbound.delivered = ''; + _inbound.delivering = ''; _inbound.disputeOpened = ''; _inbound.disputeResolved = ''; _inbound.orderRefunded = ''; _inbound.paymentRequested = ''; + _inbound.approved = ''; _inbound.paid = ''; _inbound.dispute = ''; _inbound.resolve = ''; _inbound.backorder = ''; _inbound.refund = ''; - _inbound.vendors = []; return(_inbound); } /** @@ -87,20 +109,6 @@ function addItems (_inbound) orderAmount= _inbound.amount; return (_inbound); } -/** - * find a vendor in an array - * @param {vendor_type} _string - type of vendor to find (e.g. 'supplier', 'shipper', etc.) - * @param {vendor_array} _vendorArray - vendor array from order - * @returns {$identifier} - returns the identifier if found else -1 - * @utility - */ -function getVendor(_string, _vendorArray) -{ - for (let each in _vendorArray) - {for (let _prop in JSON.parse(_vendorArray[each])) - {if (_prop === _string){return (JSON.parse(_vendorArray[each])[_string]);}}} - return(-1); -} describe('Finance Network', () => { @@ -132,7 +140,6 @@ describe('Finance Network', () => { it('should be able to create an order', () => { const factory = businessNetworkConnection.getBusinessNetwork().getFactory(); - // create the buyer const buyer = factory.newResource(NS, 'Buyer', buyerID); buyer.companyName = 'billybob computing'; @@ -141,6 +148,18 @@ describe('Finance Network', () => { const seller = factory.newResource(NS, 'Seller', sellerID); seller.companyName = 'Simon PC Hardware, Inc'; + // create the provider + provider = factory.newResource(NS, 'Provider', providerID); + provider.companyName = 'Ginsu Knife Specialists'; + + // create the shipper + shipper = factory.newResource(NS, 'Shipper', shipperID); + shipper.companyName = 'Fastest Ever Shippers'; + + // create the financeCo + financeCo = factory.newResource(NS, 'FinanceCo', financeCoID); + financeCo.companyName = 'The Global Financier'; + // create the order let order = factory.newResource(NS, 'Order', orderNo); order = createOrderTemplate(order); @@ -152,13 +171,17 @@ describe('Finance Network', () => { order.buyer = factory.newRelationship(NS, 'Buyer', buyer.$identifier); order.seller = factory.newRelationship(NS, 'Seller', seller.$identifier); + order.provider = factory.newRelationship(NS, 'Provider', provider.$identifier); + order.shipper = factory.newRelationship(NS, 'Shipper', shipper.$identifier); + order.financeCo = factory.newRelationship(NS, 'FinanceCo', financeCo.$identifier); + createNew.financeCo = factory.newRelationship(NS, 'FinanceCo', financeCo.$identifier); createNew.order = factory.newRelationship(NS, 'Order', order.$identifier); createNew.buyer = factory.newRelationship(NS, 'Buyer', buyer.$identifier); createNew.seller = factory.newRelationship(NS, 'Seller', seller.$identifier); createNew.amount = order.amount; // the buyer should of the commodity should be buyer //order.buyer.$identifier.should.equal(buyer.$identifier); - order.status.should.equal('Order Created'); + JSON.parse(order.status).text.should.equal(orderStatus.Created.text); order.amount.should.equal(orderAmount); createNew.amount.should.equal(orderAmount); createNew.order.$identifier.should.equal(orderNo); @@ -174,7 +197,7 @@ describe('Finance Network', () => { }) .then((participantRegistry) => { // add the buyer and seller - return participantRegistry.addAll([buyer, seller]); + return participantRegistry.addAll([buyer, seller, shipper, provider]); }) .then(() => { // submit the transaction @@ -226,7 +249,7 @@ describe('Finance Network', () => { .then((newOrder) => { // the owner of the commodity should be buyer newOrder.buyer.$identifier.should.equal(buyerID); - newOrder.status.should.equal('Purchased'); + JSON.parse(newOrder.status).text.should.equal(orderStatus.Bought.text); }); }); @@ -238,18 +261,10 @@ describe('Finance Network', () => { it('should be able to issue a supplier order', () => { const factory = businessNetworkConnection.getBusinessNetwork().getFactory(); - // create the provider - const provider = factory.newResource(NS, 'Provider', providerID); - provider.companyName = 'Ginsu Knife Specialists'; - // create the buy transaction const orderNow = factory.newTransaction(NS, 'OrderFromSupplier'); return businessNetworkConnection.getParticipantRegistry(NS + '.Provider') - .then((participantRegistry) => { - // add the provider - return participantRegistry.addAll([provider]); - }) .then(() => { return businessNetworkConnection.getAssetRegistry(NS + '.Order'); }) @@ -263,6 +278,7 @@ describe('Finance Network', () => { orderNow.order = factory.newRelationship(NS, 'Order', newOrder.$identifier); orderNow.provider = factory.newRelationship(NS, 'Provider', providerID); + orderNow.seller = factory.newRelationship(NS, 'Seller', sellerID); // submit the transaction return businessNetworkConnection.submitTransaction(orderNow) .then(() => { @@ -274,9 +290,7 @@ describe('Finance Network', () => { }) .then((newOrder) => { // the owner of the commodity should be buyer - let vendor = getVendor('supplier', newOrder.vendors); - vendor.should.equal(providerID); - newOrder.status.should.equal('Ordered From Supplier'); + JSON.parse(newOrder.status).text.should.equal(orderStatus.Ordered.text); }); }); @@ -287,10 +301,6 @@ describe('Finance Network', () => { it('should be able to issue a request to ship product', () => { const factory = businessNetworkConnection.getBusinessNetwork().getFactory(); - // create the shipper - const shipper = factory.newResource(NS, 'Shipper', shipperID); - shipper.companyName = 'Fastest Ever Shippers'; - // create the buy transaction const orderNow = factory.newTransaction(NS, 'RequestShipping'); @@ -311,6 +321,7 @@ describe('Finance Network', () => { newOrder.$identifier.should.equal(orderNo); orderNow.order = factory.newRelationship(NS, 'Order', newOrder.$identifier); + orderNow.provider = factory.newRelationship(NS, 'Provider', providerID); orderNow.shipper = factory.newRelationship(NS, 'Shipper', shipperID); // submit the transaction return businessNetworkConnection.submitTransaction(orderNow) @@ -323,9 +334,7 @@ describe('Finance Network', () => { }) .then((newOrder) => { // the owner of the commodity should be buyer - let vendor = getVendor('shipper', newOrder.vendors); - vendor.should.equal(shipperID); - newOrder.status.should.equal('Shipment Requested'); + JSON.parse(newOrder.status).text.should.equal(orderStatus.ShipRequest.text); }); }); @@ -361,9 +370,7 @@ describe('Finance Network', () => { }) .then((newOrder) => { // the owner of the commodity should be buyer - let vendor = getVendor('shipper', newOrder.vendors); - vendor.should.equal(shipperID); - newOrder.status.should.equal('Delivered'); + JSON.parse(newOrder.status).text.should.equal(orderStatus.Delivered.text); }); }); @@ -375,10 +382,6 @@ describe('Finance Network', () => { it('should be able to issue a request to request payment for a product', () => { const factory = businessNetworkConnection.getBusinessNetwork().getFactory(); - // create the financeCo - const financeCo = factory.newResource(NS, 'FinanceCo', financeCoID); - financeCo.companyName = 'The Global Financier'; - // create the buy transaction const orderNow = factory.newTransaction(NS, 'RequestPayment'); @@ -400,7 +403,6 @@ describe('Finance Network', () => { orderNow.order = factory.newRelationship(NS, 'Order', newOrder.$identifier); orderNow.financeCo = factory.newRelationship(NS, 'FinanceCo', financeCoID); - orderNow.buyer = factory.newRelationship(NS, 'Buyer', newOrder.buyer.$identifier); orderNow.seller = factory.newRelationship(NS, 'Seller', newOrder.seller.$identifier); // submit the transaction return businessNetworkConnection.submitTransaction(orderNow) @@ -413,17 +415,53 @@ describe('Finance Network', () => { }) .then((newOrder) => { // the owner of the commodity should be buyer - let vendor = getVendor('financeCo', newOrder.vendors); - vendor.should.equal(financeCoID); - newOrder.status.should.equal('Payment Requested'); + JSON.parse(newOrder.status).text.should.equal(orderStatus.PayRequest.text); + }); + }); + }); + }); + + describe('#authorizePayment', () => { + + it('should be able to record a approval for order payment', () => { + const factory = businessNetworkConnection.getBusinessNetwork().getFactory(); + + // create the Deliver transaction + const orderNow = factory.newTransaction(NS, 'AuthorizePayment'); + + return businessNetworkConnection.getAssetRegistry(NS + '.Order') + .then((assetRegistry) => { + // re-get the commodity + return assetRegistry.get(orderNo); + }) + .then((newOrder) => { + newOrder.buyer.$identifier.should.equal(buyerID); + newOrder.$identifier.should.equal(orderNo); + + orderNow.order = factory.newRelationship(NS, 'Order', newOrder.$identifier); + orderNow.financeCo = factory.newRelationship(NS, 'FinanceCo', financeCoID); + orderNow.buyer = factory.newRelationship(NS, 'Buyer', newOrder.buyer.$identifier); + // submit the transaction + return businessNetworkConnection.submitTransaction(orderNow) + .then(() => { + return businessNetworkConnection.getAssetRegistry(NS + '.Order'); + }) + .then((assetRegistry) => { + // re-get the commodity + return assetRegistry.get(orderNo); + }) + .then((newOrder) => { + // the owner of the commodity should be buyer + JSON.parse(newOrder.status).text.should.equal(orderStatus.Authorize.text); }); + }); }); }); - describe('#issuePayment', () => { + describe('#Pay', () => { - it('should be able to record a product payment', () => { + it('should be able to record an order payment', () => { const factory = businessNetworkConnection.getBusinessNetwork().getFactory(); // create the Deliver transaction @@ -452,9 +490,7 @@ describe('Finance Network', () => { }) .then((newOrder) => { // the owner of the commodity should be buyer - let vendor = getVendor('financeCo', newOrder.vendors); - vendor.should.equal(financeCoID); - newOrder.status.should.equal('Paid'); + JSON.parse(newOrder.status).text.should.equal(orderStatus.Paid.text); }); }); @@ -495,7 +531,7 @@ describe('Finance Network', () => { .then((newOrder) => { // the owner of the commodity should be buyer newOrder.dispute.should.equal(dispute); - newOrder.status.should.equal('In Dispute'); + JSON.parse(newOrder.status).text.should.equal(orderStatus.Dispute.text); }); }); @@ -523,6 +559,8 @@ describe('Finance Network', () => { orderNow.order = factory.newRelationship(NS, 'Order', newOrder.$identifier); orderNow.financeCo = factory.newRelationship(NS, 'FinanceCo', financeCoID); orderNow.seller = factory.newRelationship(NS, 'Seller', newOrder.seller.$identifier); + orderNow.shipper = factory.newRelationship(NS, 'Shipper', newOrder.shipper.$identifier); + orderNow.provider = factory.newRelationship(NS, 'Provider', provider.$identifier); orderNow.buyer = factory.newRelationship(NS, 'Buyer', newOrder.buyer.$identifier); // submit the transaction return businessNetworkConnection.submitTransaction(orderNow) @@ -536,7 +574,7 @@ describe('Finance Network', () => { .then((newOrder) => { // the owner of the commodity should be buyer newOrder.resolve.should.equal(resolve); - newOrder.status.should.equal('Resolved'); + JSON.parse(newOrder.status).text.should.equal(orderStatus.Resolve.text); }); }); @@ -562,7 +600,7 @@ describe('Finance Network', () => { orderNow.backorder = backorder; orderNow.order = factory.newRelationship(NS, 'Order', newOrder.$identifier); - orderNow.provider = factory.newRelationship(NS, 'Provider', JSON.parse(newOrder.vendors[0]).supplier); + orderNow.provider = factory.newRelationship(NS, 'Provider', providerID); // submit the transaction return businessNetworkConnection.submitTransaction(orderNow) .then(() => { @@ -575,7 +613,44 @@ describe('Finance Network', () => { .then((newOrder) => { // the owner of the commodity should be buyer newOrder.backorder.should.equal(backorder); - newOrder.status.should.equal('Backordered'); + JSON.parse(newOrder.status).text.should.equal(orderStatus.Backordered.text); + }); + + }); + }); + }); + describe('#issueCancel', () => { + + it('should be able to record an order cancellation', () => { + const factory = businessNetworkConnection.getBusinessNetwork().getFactory(); + + // create the Deliver transaction + const orderNow = factory.newTransaction(NS, 'OrderCancel'); + + return businessNetworkConnection.getAssetRegistry(NS + '.Order') + .then((assetRegistry) => { + // re-get the commodity + return assetRegistry.get(orderNo); + }) + .then((newOrder) => { + newOrder.buyer.$identifier.should.equal(buyerID); + newOrder.$identifier.should.equal(orderNo); + + orderNow.order = factory.newRelationship(NS, 'Order', newOrder.$identifier); + orderNow.seller = factory.newRelationship(NS, 'Seller', newOrder.seller.$identifier); + orderNow.buyer = factory.newRelationship(NS, 'Buyer', newOrder.buyer.$identifier); + // submit the transaction + return businessNetworkConnection.submitTransaction(orderNow) + .then(() => { + return businessNetworkConnection.getAssetRegistry(NS + '.Order'); + }) + .then((assetRegistry) => { + // re-get the commodity + return assetRegistry.get(orderNo); + }) + .then((newOrder) => { + // the owner of the commodity should be buyer + JSON.parse(newOrder.status).text.should.equal(orderStatus.Cancelled.text); }); }); diff --git a/Chapter04/README.md b/Chapter04/README.md index 582f8ac..e6581bc 100644 --- a/Chapter04/README.md +++ b/Chapter04/README.md @@ -28,7 +28,30 @@ Key files: ## Installing the code: - run this command from a terminal window: ```npm install``` - - then run ```buildAndDeploy`` (yes, case is important) + - when you run ```npm install``` command, you will get the following error, which you can ignore. The error is caused by the installation process for the SDK tooling, which searches for all instances of files ending in ```.cto``` . Because we have those files in the answers folder, as well as in the (correctly placed) network/models folder, npm install gets confused. It's ok, the process will still work correctly. + ``` + Looking for package.json of Business Network Definition + Input directory: /Users/robertdill/Documents/GitHub/Z2B_Master/Chapter04 + Error: namespace already exists + at ModelManager.addModelFiles (/usr/local/lib/node_modules/composer-cli/node_modules/composer-common/lib/modelmanager.js:241:31) + at Function._processModelFiles (/usr/local/lib/node_modules/composer-cli/node_modules/composer-common/lib/businessnetworkdefinition.js:457:43) + at Promise.resolve.then (/usr/local/lib/node_modules/composer-cli/node_modules/composer-common/lib/businessnetworkdefinition.js:620:18) + at process._tickCallback (internal/process/next_tick.js:109:7) + at Module.runMain (module.js:606:11) + at run (bootstrap_node.js:383:7) + at startup (bootstrap_node.js:149:9) + at bootstrap_node.js:496:3 + Error: namespace already exists + at ModelManager.addModelFiles (/usr/local/lib/node_modules/composer-cli/node_modules/composer-common/lib/modelmanager.js:241:31) + at Function._processModelFiles (/usr/local/lib/node_modules/composer-cli/node_modules/composer-common/lib/businessnetworkdefinition.js:457:43) + at Promise.resolve.then (/usr/local/lib/node_modules/composer-cli/node_modules/composer-common/lib/businessnetworkdefinition.js:620:18) + at process._tickCallback (internal/process/next_tick.js:109:7) + at Module.runMain (module.js:606:11) + at run (bootstrap_node.js:383:7) + at startup (bootstrap_node.js:149:9) + at bootstrap_node.js:496:3 ``` + + - then run ```buildAndDeploy``` (yes, case is important) - then run ```npm run test``` - this should deliver the following result: ``` diff --git a/Chapter04/README.pdf b/Chapter04/README.pdf index 8e72601..431fd7f 100644 Binary files a/Chapter04/README.pdf and b/Chapter04/README.pdf differ diff --git a/Chapter04/deployNetwork.sh b/Chapter04/deployNetwork.sh index f2b5305..9c13a36 100755 --- a/Chapter04/deployNetwork.sh +++ b/Chapter04/deployNetwork.sh @@ -76,5 +76,16 @@ echo "Parameters:" echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "deploying network" -cd network/dist -composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString \ No newline at end of file +# original - V0.13 +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString +# +# what the documentation implies is required +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString +# +# what really works +composer identity request -p hlfv1 -i admin -s adminpw +composer identity import -p hlfv1 -u admin -c ~/.identityCredentials/admin-pub.pem -k ~/.identityCredentials/admin-priv.pem +cd network/dist +composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString diff --git a/Chapter04/network/package.json b/Chapter04/network/package.json index 02c2226..be89bc0 100644 --- a/Chapter04/network/package.json +++ b/Chapter04/network/package.json @@ -1,9 +1,9 @@ { "engines": { - "composer": "^0.10.0" + "composer": "" }, "name": "zerotoblockchain-network", - "version": "0.1.6", + "version": "0.1.5", "description": "Zero to Blockchain tutorial network", "networkImage": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimage.svg", "networkImageanimated": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimageanimated.svg", @@ -36,11 +36,11 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-admin": "^0.9.0", - "composer-cli": "^0.9.0", - "composer-client": "^0.9.0", - "composer-connector-embedded": "^0.9.0", - "composer-cucumber-steps": "^0.9.0", + "composer-admin": "^0.14.0", + "composer-cli": "^0.14.0", + "composer-client": "^0.14.0", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter04/network/permissions.acl b/Chapter04/network/permissions.acl index 2ee49bf..5d16047 100644 --- a/Chapter04/network/permissions.acl +++ b/Chapter04/network/permissions.acl @@ -7,4 +7,27 @@ rule Default { operation: ALL resource: "org.acme.Z2BTestNetwork.*" action: ALLOW -} \ No newline at end of file +} + +/** +* Added to support V0.14 breaking changes +* +*/ +rule NetworkAdminUser { + description: "Grant business network administrators full access to user resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "**" + action: ALLOW +} + +rule NetworkAdminSystem { + description: "Grant business network administrators full access to system resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} +/** +* end of V0.14 additions +*/ diff --git a/Chapter04/package.json b/Chapter04/package.json index dfd50fe..1d086ff 100644 --- a/Chapter04/package.json +++ b/Chapter04/package.json @@ -37,13 +37,13 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-connector-embedded": "0.13.2", - "composer-cucumber-steps": "0.13.2", - "composer-admin": "0.13.2", - "composer-client": "0.13.2", - "composer-common": "0.13.2", - "composer-runtime": "0.13.2", - "composer-runtime-hlfv1": "0.13.2", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", + "composer-admin": "^0.14.0", + "composer-client": "^0.14.0", + "composer-common": "^0.14.0", + "composer-runtime": "^0.14.0", + "composer-runtime-hlfv1": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter04/start_rest_server.sh b/Chapter04/start_rest_server.sh index 4249418..61d94ed 100755 --- a/Chapter04/start_rest_server.sh +++ b/Chapter04/start_rest_server.sh @@ -77,4 +77,7 @@ echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "testing rest server \n when this completes, \n go to your favorite browser \n and enter localhost:3000/explorer " -composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# original (pre V0.14) +# composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# V0.14 +composer-rest-server -p hlfv1 -n zerotoblockchain-network -i admin -s adminPW diff --git a/Chapter05/Documentation/answers/composer/hlcAdmin_complete.js b/Chapter05/Documentation/answers/composer/hlcAdmin_complete.js index 3ff2256..7190361 100644 --- a/Chapter05/Documentation/answers/composer/hlcAdmin_complete.js +++ b/Chapter05/Documentation/answers/composer/hlcAdmin_complete.js @@ -56,7 +56,7 @@ exports.adminNew = function() { */ exports.adminConnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ console.log('create connection successful '); res.send({connection: 'succeeded'}); @@ -91,7 +91,7 @@ exports.createProfile = function(req, res, next) { peers: [{eventURL: req.body.peers.eventURL, requestURL: req.body.peers.requestRUL}] }; let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.createProfile(req.body.profileName, adminOptions) .then(function(result){ @@ -115,7 +115,7 @@ exports.createProfile = function(req, res, next) { */ exports.deleteProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deleteProfile(req.body.profileName) .then(function(result){ @@ -146,7 +146,7 @@ exports.deploy = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deploy(archive) .then(function(){ @@ -177,7 +177,7 @@ exports.networkInstall = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); return BusinessNetworkDefinition.fromArchive(archiveFile) .then((businessNetworkDefinition) => { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { return adminConnection.install(businessNetworkDefinition.getName()) .then(() => { @@ -213,7 +213,7 @@ exports.networkStart = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.start(archive) .then(function(){ @@ -238,7 +238,7 @@ exports.networkStart = function(req, res, next) { */ exports.disconnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.disconnect() .then(function(result){ @@ -261,7 +261,7 @@ exports.disconnect = function(req, res, next) { */ exports.getAllProfiles = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getAllProfiles() .then((profiles) => { @@ -284,7 +284,7 @@ exports.getAllProfiles = function(req, res, next) { */ exports.getProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getProfile(req.body.connectionProfile) .then((profile) => { @@ -308,7 +308,7 @@ exports.getProfile = function(req, res, next) { exports.listAsAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); util.displayObjectValuesRecursive(adminConnection); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -335,7 +335,7 @@ exports.listAsAdmin = function(req, res, next) { */ exports.listAsPeerAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.peerAdmin, config.composer.secret) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -362,7 +362,7 @@ exports.listAsPeerAdmin = function(req, res, next) { */ exports.ping = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.ping() .then(function(result){ @@ -387,7 +387,7 @@ exports.ping = function(req, res, next) { */ exports.undeploy = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.undeploy(req.body.businessNetwork) .then(function(result){ @@ -419,7 +419,7 @@ exports.update = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, netName) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, netName) .then(function(){ adminConnection.update(archive) .then(function(){ @@ -451,10 +451,10 @@ exports.getRegistries = function(req, res, next) let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getAllParticipantRegistries() .then(function(participantRegistries){ @@ -488,10 +488,10 @@ exports.getMembers = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) .then(function(registry){ @@ -526,13 +526,17 @@ exports.getMembers = function(req, res, next) { } res.send({'result': 'success', 'members': allMembers}); }) - .catch((error) => {console.log('error with getAllMembers', error)}); + .catch((error) => {console.log('error with getAllMembers', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with getRegistry', error)}); + .catch((error) => {console.log('error with getRegistry', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with business network Connect', error)}); + .catch((error) => {console.log('error with business network Connect', error.message); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with admin network Connect', error)}); + .catch((error) => {console.log('error with admin network Connect', error); + res.send({'result': 'failed '+error.message, 'members': []});}); } @@ -554,10 +558,10 @@ exports.getAssets = function(req, res, next) { let factory; let serializer; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { // let bnd = new BusinessNetworkDefinition(config.composer.network+'@0.1.6', config.composer.description, packageJSON); // retry this with fromArchive when time allows @@ -640,10 +644,10 @@ exports.addMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.type) @@ -680,10 +684,10 @@ exports.removeMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) @@ -725,10 +729,10 @@ exports.getHistory = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then((bnd) => { ser = bnd.getSerializer(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getRegistry('org.hyperledger.composer.system.HistorianRecord') .then(function(registry){ diff --git a/Chapter05/Documentation/answers/js/z2b-admin_complete.js b/Chapter05/Documentation/answers/js/z2b-admin_complete.js index 2fe8d5c..c716cb8 100644 --- a/Chapter05/Documentation/answers/js/z2b-admin_complete.js +++ b/Chapter05/Documentation/answers/js/z2b-admin_complete.js @@ -76,6 +76,7 @@ function displayProfileForm () $.when($.get(toLoad)).done(function (page) {$('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("createConnectionProfile"); var _cancel = $('#cancel'); var _submit = $('#submit'); _cancel.on('click', function (){$('#admin-forms').empty();}); @@ -154,6 +155,7 @@ function listProfiles(_state) { $('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("deleteConnectionProfile"); $('#connection_profiles').on('change',function() { var name = $('#connection_profiles').find(':selected').text(); var profile = connection_profiles[name]; @@ -449,6 +451,7 @@ function addMember() { $('#admin-forms').empty(); $('#admin-forms').append(_page); + updatePage("createMember"); var _cancel = $('#cancel'); var _submit = $('#submit'); $('#messages').empty(); @@ -481,6 +484,7 @@ function removeMember() { $('#admin-forms').append(_page[0]); $('#member_type').append(options.registry); + updatePage("removeMember"); member_list = _results[0].members; for (each in _results[0].members) {(function(_idx, _arr){ @@ -521,6 +525,7 @@ function getSecret() $.when($.post('/composer/admin/getMembers', options),$.get('getMemberSecret.html')).done(function (_results, _page) { $('#admin-forms').append(_page[0]); + updatePage("getMemberSecret"); $('#member_type').append(options.registry); member_list = _results[0].members; for (each in _results[0].members) diff --git a/Chapter05/controller/restapi/features/composer/creds/admin-priv.pem b/Chapter05/controller/restapi/features/composer/creds/admin-priv.pem new file mode 100644 index 0000000..11b9fd4 --- /dev/null +++ b/Chapter05/controller/restapi/features/composer/creds/admin-priv.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg00IwLLBKoi/9ikb6 +ZOAV0S1XeNGWllvlFDeczRKQn2uhRANCAARrvCsQUNRpMUkzFaC7+zV4mClo+beg +4VkUyQR5y5Fle5UVH2GigChWnUoouTO2e2acA/DUuyLDHT0emeBMhoMC +-----END PRIVATE KEY----- diff --git a/Chapter05/controller/restapi/features/composer/creds/admin-pub.pem b/Chapter05/controller/restapi/features/composer/creds/admin-pub.pem new file mode 100644 index 0000000..8c2855f --- /dev/null +++ b/Chapter05/controller/restapi/features/composer/creds/admin-pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEa7wrEFDUaTFJMxWgu/s1eJgpaPm3 +oOFZFMkEecuRZXuVFR9hooAoVp1KKLkztntmnAPw1Lsiwx09HpngTIaDAg== +-----END PUBLIC KEY----- diff --git a/Chapter05/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem b/Chapter05/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem similarity index 100% rename from Chapter05/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem rename to Chapter05/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem diff --git a/Chapter05/controller/restapi/features/composer/hlcAdmin.js b/Chapter05/controller/restapi/features/composer/hlcAdmin.js index 3ff2256..7190361 100644 --- a/Chapter05/controller/restapi/features/composer/hlcAdmin.js +++ b/Chapter05/controller/restapi/features/composer/hlcAdmin.js @@ -56,7 +56,7 @@ exports.adminNew = function() { */ exports.adminConnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ console.log('create connection successful '); res.send({connection: 'succeeded'}); @@ -91,7 +91,7 @@ exports.createProfile = function(req, res, next) { peers: [{eventURL: req.body.peers.eventURL, requestURL: req.body.peers.requestRUL}] }; let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.createProfile(req.body.profileName, adminOptions) .then(function(result){ @@ -115,7 +115,7 @@ exports.createProfile = function(req, res, next) { */ exports.deleteProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deleteProfile(req.body.profileName) .then(function(result){ @@ -146,7 +146,7 @@ exports.deploy = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deploy(archive) .then(function(){ @@ -177,7 +177,7 @@ exports.networkInstall = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); return BusinessNetworkDefinition.fromArchive(archiveFile) .then((businessNetworkDefinition) => { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { return adminConnection.install(businessNetworkDefinition.getName()) .then(() => { @@ -213,7 +213,7 @@ exports.networkStart = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.start(archive) .then(function(){ @@ -238,7 +238,7 @@ exports.networkStart = function(req, res, next) { */ exports.disconnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.disconnect() .then(function(result){ @@ -261,7 +261,7 @@ exports.disconnect = function(req, res, next) { */ exports.getAllProfiles = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getAllProfiles() .then((profiles) => { @@ -284,7 +284,7 @@ exports.getAllProfiles = function(req, res, next) { */ exports.getProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getProfile(req.body.connectionProfile) .then((profile) => { @@ -308,7 +308,7 @@ exports.getProfile = function(req, res, next) { exports.listAsAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); util.displayObjectValuesRecursive(adminConnection); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -335,7 +335,7 @@ exports.listAsAdmin = function(req, res, next) { */ exports.listAsPeerAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.peerAdmin, config.composer.secret) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -362,7 +362,7 @@ exports.listAsPeerAdmin = function(req, res, next) { */ exports.ping = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.ping() .then(function(result){ @@ -387,7 +387,7 @@ exports.ping = function(req, res, next) { */ exports.undeploy = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.undeploy(req.body.businessNetwork) .then(function(result){ @@ -419,7 +419,7 @@ exports.update = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, netName) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, netName) .then(function(){ adminConnection.update(archive) .then(function(){ @@ -451,10 +451,10 @@ exports.getRegistries = function(req, res, next) let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getAllParticipantRegistries() .then(function(participantRegistries){ @@ -488,10 +488,10 @@ exports.getMembers = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) .then(function(registry){ @@ -526,13 +526,17 @@ exports.getMembers = function(req, res, next) { } res.send({'result': 'success', 'members': allMembers}); }) - .catch((error) => {console.log('error with getAllMembers', error)}); + .catch((error) => {console.log('error with getAllMembers', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with getRegistry', error)}); + .catch((error) => {console.log('error with getRegistry', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with business network Connect', error)}); + .catch((error) => {console.log('error with business network Connect', error.message); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with admin network Connect', error)}); + .catch((error) => {console.log('error with admin network Connect', error); + res.send({'result': 'failed '+error.message, 'members': []});}); } @@ -554,10 +558,10 @@ exports.getAssets = function(req, res, next) { let factory; let serializer; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { // let bnd = new BusinessNetworkDefinition(config.composer.network+'@0.1.6', config.composer.description, packageJSON); // retry this with fromArchive when time allows @@ -640,10 +644,10 @@ exports.addMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.type) @@ -680,10 +684,10 @@ exports.removeMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) @@ -725,10 +729,10 @@ exports.getHistory = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then((bnd) => { ser = bnd.getSerializer(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getRegistry('org.hyperledger.composer.system.HistorianRecord') .then(function(registry){ diff --git a/Chapter05/controller/restapi/features/composer/queryBlockChain.js b/Chapter05/controller/restapi/features/composer/queryBlockChain.js index 4a61c7d..a0b0b57 100644 --- a/Chapter05/controller/restapi/features/composer/queryBlockChain.js +++ b/Chapter05/controller/restapi/features/composer/queryBlockChain.js @@ -58,6 +58,7 @@ exports.getChainInfo = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -103,6 +104,7 @@ exports.getChainEvents = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -110,7 +112,8 @@ exports.getChainEvents = function(req, res, next) { channel = client.newChannel(config.fabric.channelName); channel.addPeer(client.newPeer(config.fabric.peerRequestURL)); channel.addOrderer(client.newOrderer(config.fabric.ordererURL)); - var pemPath = path.join(__dirname,'creds','Admin@org1.example.com-cert.pem'); + // change Admin in following line to admin + var pemPath = path.join(__dirname,'creds','admin@org.hyperledger.composer.system-cert.pem'); var adminPEM = fs.readFileSync(pemPath); var bcEvents = new hfcEH(client); bcEvents.setPeerAddr(config.fabric.peerEventURL, {pem: adminPEM}); diff --git a/Chapter05/deployNetwork.sh b/Chapter05/deployNetwork.sh index e4782a1..9c13a36 100755 --- a/Chapter05/deployNetwork.sh +++ b/Chapter05/deployNetwork.sh @@ -1,6 +1,35 @@ #!/bin/bash -. ../common_OSX.sh + YELLOW='\033[1;33m' + RED='\033[1;31m' + GREEN='\033[1;32m' + RESET='\033[0m' + +# indent text on echo +function indent() { + c='s/^/ /' + case $(uname) in + Darwin) sed -l "$c";; + *) sed -u "$c";; + esac +} + +# Grab the current directory +function getCurrent() + { + showStep "getting current directory" + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + THIS_SCRIPT=`basename "$0"` + showStep "Running '${THIS_SCRIPT}'" + } + +# displays where we are, uses the indent function (above) to indent each line +function showStep () + { + echo -e "${YELLOW}=====================================================" | indent + echo -e "${RESET}-----> $*" | indent + echo -e "${YELLOW}=====================================================${RESET}" | indent + } function printHelp () { @@ -19,7 +48,7 @@ function printHeader () { echo "" echo -e "${YELLOW}network deploy script for the Zero To Blockchain Series" | indent - echo -e "${RED}This is for Mac OSX ONLY" | indent + echo -e "${RED}This has been successfully tested on OSX Sierra and Ubuntu 16.04" | indent echo -e "${YELLOW}This script will create your Composer archive" | indent echo "" } @@ -47,5 +76,16 @@ echo "Parameters:" echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "deploying network" +# original - V0.13 +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString +# +# what the documentation implies is required +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString +# +# what really works +composer identity request -p hlfv1 -i admin -s adminpw +composer identity import -p hlfv1 -u admin -c ~/.identityCredentials/admin-pub.pem -k ~/.identityCredentials/admin-priv.pem cd network/dist -composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString \ No newline at end of file +composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString diff --git a/Chapter05/network/package.json b/Chapter05/network/package.json index 7b20679..be89bc0 100644 --- a/Chapter05/network/package.json +++ b/Chapter05/network/package.json @@ -36,11 +36,11 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-admin": "^0.9.0", - "composer-cli": "^0.9.0", - "composer-client": "^0.9.0", - "composer-connector-embedded": "^0.9.0", - "composer-cucumber-steps": "^0.9.0", + "composer-admin": "^0.14.0", + "composer-cli": "^0.14.0", + "composer-client": "^0.14.0", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter05/network/permissions.acl b/Chapter05/network/permissions.acl index 2ee49bf..5d16047 100644 --- a/Chapter05/network/permissions.acl +++ b/Chapter05/network/permissions.acl @@ -7,4 +7,27 @@ rule Default { operation: ALL resource: "org.acme.Z2BTestNetwork.*" action: ALLOW -} \ No newline at end of file +} + +/** +* Added to support V0.14 breaking changes +* +*/ +rule NetworkAdminUser { + description: "Grant business network administrators full access to user resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "**" + action: ALLOW +} + +rule NetworkAdminSystem { + description: "Grant business network administrators full access to system resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} +/** +* end of V0.14 additions +*/ diff --git a/Chapter05/package.json b/Chapter05/package.json index dfd50fe..1d086ff 100644 --- a/Chapter05/package.json +++ b/Chapter05/package.json @@ -37,13 +37,13 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-connector-embedded": "0.13.2", - "composer-cucumber-steps": "0.13.2", - "composer-admin": "0.13.2", - "composer-client": "0.13.2", - "composer-common": "0.13.2", - "composer-runtime": "0.13.2", - "composer-runtime-hlfv1": "0.13.2", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", + "composer-admin": "^0.14.0", + "composer-client": "^0.14.0", + "composer-common": "^0.14.0", + "composer-runtime": "^0.14.0", + "composer-runtime-hlfv1": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter05/start_rest_server.sh b/Chapter05/start_rest_server.sh index 4249418..61d94ed 100755 --- a/Chapter05/start_rest_server.sh +++ b/Chapter05/start_rest_server.sh @@ -77,4 +77,7 @@ echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "testing rest server \n when this completes, \n go to your favorite browser \n and enter localhost:3000/explorer " -composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# original (pre V0.14) +# composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# V0.14 +composer-rest-server -p hlfv1 -n zerotoblockchain-network -i admin -s adminPW diff --git a/Chapter06/HTML/js/z2b-admin.js b/Chapter06/HTML/js/z2b-admin.js index 2fe8d5c..c716cb8 100644 --- a/Chapter06/HTML/js/z2b-admin.js +++ b/Chapter06/HTML/js/z2b-admin.js @@ -76,6 +76,7 @@ function displayProfileForm () $.when($.get(toLoad)).done(function (page) {$('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("createConnectionProfile"); var _cancel = $('#cancel'); var _submit = $('#submit'); _cancel.on('click', function (){$('#admin-forms').empty();}); @@ -154,6 +155,7 @@ function listProfiles(_state) { $('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("deleteConnectionProfile"); $('#connection_profiles').on('change',function() { var name = $('#connection_profiles').find(':selected').text(); var profile = connection_profiles[name]; @@ -449,6 +451,7 @@ function addMember() { $('#admin-forms').empty(); $('#admin-forms').append(_page); + updatePage("createMember"); var _cancel = $('#cancel'); var _submit = $('#submit'); $('#messages').empty(); @@ -481,6 +484,7 @@ function removeMember() { $('#admin-forms').append(_page[0]); $('#member_type').append(options.registry); + updatePage("removeMember"); member_list = _results[0].members; for (each in _results[0].members) {(function(_idx, _arr){ @@ -521,6 +525,7 @@ function getSecret() $.when($.post('/composer/admin/getMembers', options),$.get('getMemberSecret.html')).done(function (_results, _page) { $('#admin-forms').append(_page[0]); + updatePage("getMemberSecret"); $('#member_type').append(options.registry); member_list = _results[0].members; for (each in _results[0].members) diff --git a/Chapter06/controller/restapi/features/composer/creds/admin-priv.pem b/Chapter06/controller/restapi/features/composer/creds/admin-priv.pem new file mode 100644 index 0000000..11b9fd4 --- /dev/null +++ b/Chapter06/controller/restapi/features/composer/creds/admin-priv.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg00IwLLBKoi/9ikb6 +ZOAV0S1XeNGWllvlFDeczRKQn2uhRANCAARrvCsQUNRpMUkzFaC7+zV4mClo+beg +4VkUyQR5y5Fle5UVH2GigChWnUoouTO2e2acA/DUuyLDHT0emeBMhoMC +-----END PRIVATE KEY----- diff --git a/Chapter06/controller/restapi/features/composer/creds/admin-pub.pem b/Chapter06/controller/restapi/features/composer/creds/admin-pub.pem new file mode 100644 index 0000000..8c2855f --- /dev/null +++ b/Chapter06/controller/restapi/features/composer/creds/admin-pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEa7wrEFDUaTFJMxWgu/s1eJgpaPm3 +oOFZFMkEecuRZXuVFR9hooAoVp1KKLkztntmnAPw1Lsiwx09HpngTIaDAg== +-----END PUBLIC KEY----- diff --git a/Chapter06/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem b/Chapter06/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem similarity index 100% rename from Chapter06/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem rename to Chapter06/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem diff --git a/Chapter06/controller/restapi/features/composer/hlcAdmin.js b/Chapter06/controller/restapi/features/composer/hlcAdmin.js index 3ff2256..7190361 100644 --- a/Chapter06/controller/restapi/features/composer/hlcAdmin.js +++ b/Chapter06/controller/restapi/features/composer/hlcAdmin.js @@ -56,7 +56,7 @@ exports.adminNew = function() { */ exports.adminConnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ console.log('create connection successful '); res.send({connection: 'succeeded'}); @@ -91,7 +91,7 @@ exports.createProfile = function(req, res, next) { peers: [{eventURL: req.body.peers.eventURL, requestURL: req.body.peers.requestRUL}] }; let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.createProfile(req.body.profileName, adminOptions) .then(function(result){ @@ -115,7 +115,7 @@ exports.createProfile = function(req, res, next) { */ exports.deleteProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deleteProfile(req.body.profileName) .then(function(result){ @@ -146,7 +146,7 @@ exports.deploy = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deploy(archive) .then(function(){ @@ -177,7 +177,7 @@ exports.networkInstall = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); return BusinessNetworkDefinition.fromArchive(archiveFile) .then((businessNetworkDefinition) => { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { return adminConnection.install(businessNetworkDefinition.getName()) .then(() => { @@ -213,7 +213,7 @@ exports.networkStart = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.start(archive) .then(function(){ @@ -238,7 +238,7 @@ exports.networkStart = function(req, res, next) { */ exports.disconnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.disconnect() .then(function(result){ @@ -261,7 +261,7 @@ exports.disconnect = function(req, res, next) { */ exports.getAllProfiles = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getAllProfiles() .then((profiles) => { @@ -284,7 +284,7 @@ exports.getAllProfiles = function(req, res, next) { */ exports.getProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getProfile(req.body.connectionProfile) .then((profile) => { @@ -308,7 +308,7 @@ exports.getProfile = function(req, res, next) { exports.listAsAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); util.displayObjectValuesRecursive(adminConnection); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -335,7 +335,7 @@ exports.listAsAdmin = function(req, res, next) { */ exports.listAsPeerAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.peerAdmin, config.composer.secret) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -362,7 +362,7 @@ exports.listAsPeerAdmin = function(req, res, next) { */ exports.ping = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.ping() .then(function(result){ @@ -387,7 +387,7 @@ exports.ping = function(req, res, next) { */ exports.undeploy = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.undeploy(req.body.businessNetwork) .then(function(result){ @@ -419,7 +419,7 @@ exports.update = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, netName) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, netName) .then(function(){ adminConnection.update(archive) .then(function(){ @@ -451,10 +451,10 @@ exports.getRegistries = function(req, res, next) let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getAllParticipantRegistries() .then(function(participantRegistries){ @@ -488,10 +488,10 @@ exports.getMembers = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) .then(function(registry){ @@ -526,13 +526,17 @@ exports.getMembers = function(req, res, next) { } res.send({'result': 'success', 'members': allMembers}); }) - .catch((error) => {console.log('error with getAllMembers', error)}); + .catch((error) => {console.log('error with getAllMembers', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with getRegistry', error)}); + .catch((error) => {console.log('error with getRegistry', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with business network Connect', error)}); + .catch((error) => {console.log('error with business network Connect', error.message); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with admin network Connect', error)}); + .catch((error) => {console.log('error with admin network Connect', error); + res.send({'result': 'failed '+error.message, 'members': []});}); } @@ -554,10 +558,10 @@ exports.getAssets = function(req, res, next) { let factory; let serializer; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { // let bnd = new BusinessNetworkDefinition(config.composer.network+'@0.1.6', config.composer.description, packageJSON); // retry this with fromArchive when time allows @@ -640,10 +644,10 @@ exports.addMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.type) @@ -680,10 +684,10 @@ exports.removeMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) @@ -725,10 +729,10 @@ exports.getHistory = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then((bnd) => { ser = bnd.getSerializer(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getRegistry('org.hyperledger.composer.system.HistorianRecord') .then(function(registry){ diff --git a/Chapter06/controller/restapi/features/composer/queryBlockChain.js b/Chapter06/controller/restapi/features/composer/queryBlockChain.js index 4a61c7d..a0b0b57 100644 --- a/Chapter06/controller/restapi/features/composer/queryBlockChain.js +++ b/Chapter06/controller/restapi/features/composer/queryBlockChain.js @@ -58,6 +58,7 @@ exports.getChainInfo = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -103,6 +104,7 @@ exports.getChainEvents = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -110,7 +112,8 @@ exports.getChainEvents = function(req, res, next) { channel = client.newChannel(config.fabric.channelName); channel.addPeer(client.newPeer(config.fabric.peerRequestURL)); channel.addOrderer(client.newOrderer(config.fabric.ordererURL)); - var pemPath = path.join(__dirname,'creds','Admin@org1.example.com-cert.pem'); + // change Admin in following line to admin + var pemPath = path.join(__dirname,'creds','admin@org.hyperledger.composer.system-cert.pem'); var adminPEM = fs.readFileSync(pemPath); var bcEvents = new hfcEH(client); bcEvents.setPeerAddr(config.fabric.peerEventURL, {pem: adminPEM}); diff --git a/Chapter06/deployNetwork.sh b/Chapter06/deployNetwork.sh index e4782a1..9c13a36 100755 --- a/Chapter06/deployNetwork.sh +++ b/Chapter06/deployNetwork.sh @@ -1,6 +1,35 @@ #!/bin/bash -. ../common_OSX.sh + YELLOW='\033[1;33m' + RED='\033[1;31m' + GREEN='\033[1;32m' + RESET='\033[0m' + +# indent text on echo +function indent() { + c='s/^/ /' + case $(uname) in + Darwin) sed -l "$c";; + *) sed -u "$c";; + esac +} + +# Grab the current directory +function getCurrent() + { + showStep "getting current directory" + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + THIS_SCRIPT=`basename "$0"` + showStep "Running '${THIS_SCRIPT}'" + } + +# displays where we are, uses the indent function (above) to indent each line +function showStep () + { + echo -e "${YELLOW}=====================================================" | indent + echo -e "${RESET}-----> $*" | indent + echo -e "${YELLOW}=====================================================${RESET}" | indent + } function printHelp () { @@ -19,7 +48,7 @@ function printHeader () { echo "" echo -e "${YELLOW}network deploy script for the Zero To Blockchain Series" | indent - echo -e "${RED}This is for Mac OSX ONLY" | indent + echo -e "${RED}This has been successfully tested on OSX Sierra and Ubuntu 16.04" | indent echo -e "${YELLOW}This script will create your Composer archive" | indent echo "" } @@ -47,5 +76,16 @@ echo "Parameters:" echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "deploying network" +# original - V0.13 +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString +# +# what the documentation implies is required +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString +# +# what really works +composer identity request -p hlfv1 -i admin -s adminpw +composer identity import -p hlfv1 -u admin -c ~/.identityCredentials/admin-pub.pem -k ~/.identityCredentials/admin-priv.pem cd network/dist -composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString \ No newline at end of file +composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString diff --git a/Chapter06/network/package.json b/Chapter06/network/package.json index 6e58707..be89bc0 100644 --- a/Chapter06/network/package.json +++ b/Chapter06/network/package.json @@ -3,11 +3,12 @@ "composer": "" }, "name": "zerotoblockchain-network", - "version": "0.1.6", + "version": "0.1.5", "description": "Zero to Blockchain tutorial network", "networkImage": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimage.svg", "networkImageanimated": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimageanimated.svg", "scripts": { + "prepublish": "mkdirp ./network/dist && composer archive create --sourceType dir --sourceName . -a ./network/dist/zerotoblockchain-network.bna", "pretest": "npm run lint", "lint": "eslint ./network", "postlint": "npm run licchk", @@ -35,12 +36,11 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-admin": "", - "composer-cli": "", - "composer-client": "", - "composer-connector-embedded": "", - "composer-connector-hlf": "", - "composer-cucumber-steps": "", + "composer-admin": "^0.14.0", + "composer-cli": "^0.14.0", + "composer-client": "^0.14.0", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter06/network/permissions.acl b/Chapter06/network/permissions.acl index 7893db9..c51b93f 100644 --- a/Chapter06/network/permissions.acl +++ b/Chapter06/network/permissions.acl @@ -9,6 +9,28 @@ rule AllAccess { } */ +/** +* Added to support V0.14 breaking changes +* +*/ +rule NetworkAdminUser { + description: "Grant business network administrators full access to user resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "**" + action: ALLOW +} + +rule NetworkAdminSystem { + description: "Grant business network administrators full access to system resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} +/** +* end of V0.14 additions +*/ /** * diff --git a/Chapter06/package.json b/Chapter06/package.json index dfd50fe..1d086ff 100644 --- a/Chapter06/package.json +++ b/Chapter06/package.json @@ -37,13 +37,13 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-connector-embedded": "0.13.2", - "composer-cucumber-steps": "0.13.2", - "composer-admin": "0.13.2", - "composer-client": "0.13.2", - "composer-common": "0.13.2", - "composer-runtime": "0.13.2", - "composer-runtime-hlfv1": "0.13.2", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", + "composer-admin": "^0.14.0", + "composer-client": "^0.14.0", + "composer-common": "^0.14.0", + "composer-runtime": "^0.14.0", + "composer-runtime-hlfv1": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter06/start_rest_server.sh b/Chapter06/start_rest_server.sh index 4249418..61d94ed 100755 --- a/Chapter06/start_rest_server.sh +++ b/Chapter06/start_rest_server.sh @@ -77,4 +77,7 @@ echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "testing rest server \n when this completes, \n go to your favorite browser \n and enter localhost:3000/explorer " -composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# original (pre V0.14) +# composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# V0.14 +composer-rest-server -p hlfv1 -n zerotoblockchain-network -i admin -s adminPW diff --git a/Chapter07/Documentation/answers/composer/hlcClient_complete.js b/Chapter07/Documentation/answers/composer/hlcClient_complete.js index 80f2e10..1c43f70 100644 --- a/Chapter07/Documentation/answers/composer/hlcClient_complete.js +++ b/Chapter07/Documentation/answers/composer/hlcClient_complete.js @@ -144,9 +144,7 @@ exports.orderAction = function (req, res, next) { { case 'Pay': console.log('Pay entered'); - updateOrder = factory.newTransaction(NS, 'Pay'); - updateOrder.financeCo = factory.newRelationship(NS, 'FinanceCo', financeCoID); - updateOrder.seller = factory.newRelationship(NS, 'Seller', order.seller.$identifier); + break; case 'Dispute': console.log('Dispute entered'); @@ -164,15 +162,22 @@ exports.orderAction = function (req, res, next) { break; case 'Order From Supplier': console.log('Order from Supplier entered for '+order.orderNumber+ ' inbound id: '+ _userID+' with order.seller as: '+order.seller.$identifier); - + updateOrder = factory.newTransaction(NS, 'OrderFromSupplier'); + updateOrder.provider = factory.newRelationship(NS, 'Provider', req.body.provider); + updateOrder.seller = factory.newRelationship(NS, 'Seller', order.seller.$identifier); break; case 'Request Payment': console.log('Request Payment entered'); - + updateOrder = factory.newTransaction(NS, 'RequestPayment'); + updateOrder.seller = factory.newRelationship(NS, 'Seller', order.seller.$identifier); + updateOrder.financeCo = factory.newRelationship(NS, 'FinanceCo', financeCoID); break; case 'Refund': console.log('Refund Payment entered'); - + updateOrder = factory.newTransaction(NS, 'Refund'); + updateOrder.seller = factory.newRelationship(NS, 'Seller', order.seller.$identifier); + updateOrder.financeCo = factory.newRelationship(NS, 'FinanceCo', financeCoID); + updateOrder.refund = req.body.reason; break; case 'Resolve': console.log('Resolve entered'); @@ -183,6 +188,22 @@ exports.orderAction = function (req, res, next) { updateOrder.seller = factory.newRelationship(NS, 'Seller', order.seller.$identifier); updateOrder.financeCo = factory.newRelationship(NS, 'FinanceCo', financeCoID); updateOrder.resolve = req.body.reason; + break; + case 'Request Shipping': + console.log('Request Shipping entered'); + + break; + case 'Update Delivery Status': + console.log('Update Delivery Status'); + + break; + case 'Delivered': + console.log('Delivered entered'); + + break; + case 'BackOrder': + console.log('BackOrder entered'); + break; case 'Authorize Payment': console.log('Authorize Payment entered'); diff --git a/Chapter07/Documentation/answers/network/permissions_complete.acl b/Chapter07/Documentation/answers/network/permissions_complete.acl index 9e5cac4..9382d8d 100644 --- a/Chapter07/Documentation/answers/network/permissions_complete.acl +++ b/Chapter07/Documentation/answers/network/permissions_complete.acl @@ -9,6 +9,29 @@ rule AllAccess { } */ +/** +* Added to support V0.14 breaking changes +* +*/ +rule NetworkAdminUser { + description: "Grant business network administrators full access to user resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "**" + action: ALLOW +} + +rule NetworkAdminSystem { + description: "Grant business network administrators full access to system resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} +/** +* end of V0.14 additions +*/ + /** * **/ diff --git a/Chapter07/HTML/js/z2b-admin.js b/Chapter07/HTML/js/z2b-admin.js index 2fe8d5c..c716cb8 100644 --- a/Chapter07/HTML/js/z2b-admin.js +++ b/Chapter07/HTML/js/z2b-admin.js @@ -76,6 +76,7 @@ function displayProfileForm () $.when($.get(toLoad)).done(function (page) {$('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("createConnectionProfile"); var _cancel = $('#cancel'); var _submit = $('#submit'); _cancel.on('click', function (){$('#admin-forms').empty();}); @@ -154,6 +155,7 @@ function listProfiles(_state) { $('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("deleteConnectionProfile"); $('#connection_profiles').on('change',function() { var name = $('#connection_profiles').find(':selected').text(); var profile = connection_profiles[name]; @@ -449,6 +451,7 @@ function addMember() { $('#admin-forms').empty(); $('#admin-forms').append(_page); + updatePage("createMember"); var _cancel = $('#cancel'); var _submit = $('#submit'); $('#messages').empty(); @@ -481,6 +484,7 @@ function removeMember() { $('#admin-forms').append(_page[0]); $('#member_type').append(options.registry); + updatePage("removeMember"); member_list = _results[0].members; for (each in _results[0].members) {(function(_idx, _arr){ @@ -521,6 +525,7 @@ function getSecret() $.when($.post('/composer/admin/getMembers', options),$.get('getMemberSecret.html')).done(function (_results, _page) { $('#admin-forms').append(_page[0]); + updatePage("getMemberSecret"); $('#member_type').append(options.registry); member_list = _results[0].members; for (each in _results[0].members) diff --git a/Chapter07/controller/restapi/features/composer/creds/admin-priv.pem b/Chapter07/controller/restapi/features/composer/creds/admin-priv.pem new file mode 100644 index 0000000..11b9fd4 --- /dev/null +++ b/Chapter07/controller/restapi/features/composer/creds/admin-priv.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg00IwLLBKoi/9ikb6 +ZOAV0S1XeNGWllvlFDeczRKQn2uhRANCAARrvCsQUNRpMUkzFaC7+zV4mClo+beg +4VkUyQR5y5Fle5UVH2GigChWnUoouTO2e2acA/DUuyLDHT0emeBMhoMC +-----END PRIVATE KEY----- diff --git a/Chapter07/controller/restapi/features/composer/creds/admin-pub.pem b/Chapter07/controller/restapi/features/composer/creds/admin-pub.pem new file mode 100644 index 0000000..8c2855f --- /dev/null +++ b/Chapter07/controller/restapi/features/composer/creds/admin-pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEa7wrEFDUaTFJMxWgu/s1eJgpaPm3 +oOFZFMkEecuRZXuVFR9hooAoVp1KKLkztntmnAPw1Lsiwx09HpngTIaDAg== +-----END PUBLIC KEY----- diff --git a/Chapter07/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem b/Chapter07/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem similarity index 100% rename from Chapter07/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem rename to Chapter07/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem diff --git a/Chapter07/controller/restapi/features/composer/hlcAdmin.js b/Chapter07/controller/restapi/features/composer/hlcAdmin.js index 3ff2256..7190361 100644 --- a/Chapter07/controller/restapi/features/composer/hlcAdmin.js +++ b/Chapter07/controller/restapi/features/composer/hlcAdmin.js @@ -56,7 +56,7 @@ exports.adminNew = function() { */ exports.adminConnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ console.log('create connection successful '); res.send({connection: 'succeeded'}); @@ -91,7 +91,7 @@ exports.createProfile = function(req, res, next) { peers: [{eventURL: req.body.peers.eventURL, requestURL: req.body.peers.requestRUL}] }; let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.createProfile(req.body.profileName, adminOptions) .then(function(result){ @@ -115,7 +115,7 @@ exports.createProfile = function(req, res, next) { */ exports.deleteProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deleteProfile(req.body.profileName) .then(function(result){ @@ -146,7 +146,7 @@ exports.deploy = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deploy(archive) .then(function(){ @@ -177,7 +177,7 @@ exports.networkInstall = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); return BusinessNetworkDefinition.fromArchive(archiveFile) .then((businessNetworkDefinition) => { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { return adminConnection.install(businessNetworkDefinition.getName()) .then(() => { @@ -213,7 +213,7 @@ exports.networkStart = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.start(archive) .then(function(){ @@ -238,7 +238,7 @@ exports.networkStart = function(req, res, next) { */ exports.disconnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.disconnect() .then(function(result){ @@ -261,7 +261,7 @@ exports.disconnect = function(req, res, next) { */ exports.getAllProfiles = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getAllProfiles() .then((profiles) => { @@ -284,7 +284,7 @@ exports.getAllProfiles = function(req, res, next) { */ exports.getProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getProfile(req.body.connectionProfile) .then((profile) => { @@ -308,7 +308,7 @@ exports.getProfile = function(req, res, next) { exports.listAsAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); util.displayObjectValuesRecursive(adminConnection); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -335,7 +335,7 @@ exports.listAsAdmin = function(req, res, next) { */ exports.listAsPeerAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.peerAdmin, config.composer.secret) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -362,7 +362,7 @@ exports.listAsPeerAdmin = function(req, res, next) { */ exports.ping = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.ping() .then(function(result){ @@ -387,7 +387,7 @@ exports.ping = function(req, res, next) { */ exports.undeploy = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.undeploy(req.body.businessNetwork) .then(function(result){ @@ -419,7 +419,7 @@ exports.update = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, netName) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, netName) .then(function(){ adminConnection.update(archive) .then(function(){ @@ -451,10 +451,10 @@ exports.getRegistries = function(req, res, next) let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getAllParticipantRegistries() .then(function(participantRegistries){ @@ -488,10 +488,10 @@ exports.getMembers = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) .then(function(registry){ @@ -526,13 +526,17 @@ exports.getMembers = function(req, res, next) { } res.send({'result': 'success', 'members': allMembers}); }) - .catch((error) => {console.log('error with getAllMembers', error)}); + .catch((error) => {console.log('error with getAllMembers', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with getRegistry', error)}); + .catch((error) => {console.log('error with getRegistry', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with business network Connect', error)}); + .catch((error) => {console.log('error with business network Connect', error.message); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with admin network Connect', error)}); + .catch((error) => {console.log('error with admin network Connect', error); + res.send({'result': 'failed '+error.message, 'members': []});}); } @@ -554,10 +558,10 @@ exports.getAssets = function(req, res, next) { let factory; let serializer; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { // let bnd = new BusinessNetworkDefinition(config.composer.network+'@0.1.6', config.composer.description, packageJSON); // retry this with fromArchive when time allows @@ -640,10 +644,10 @@ exports.addMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.type) @@ -680,10 +684,10 @@ exports.removeMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) @@ -725,10 +729,10 @@ exports.getHistory = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then((bnd) => { ser = bnd.getSerializer(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getRegistry('org.hyperledger.composer.system.HistorianRecord') .then(function(registry){ diff --git a/Chapter07/controller/restapi/features/composer/queryBlockChain.js b/Chapter07/controller/restapi/features/composer/queryBlockChain.js index 4a61c7d..a0b0b57 100644 --- a/Chapter07/controller/restapi/features/composer/queryBlockChain.js +++ b/Chapter07/controller/restapi/features/composer/queryBlockChain.js @@ -58,6 +58,7 @@ exports.getChainInfo = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -103,6 +104,7 @@ exports.getChainEvents = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -110,7 +112,8 @@ exports.getChainEvents = function(req, res, next) { channel = client.newChannel(config.fabric.channelName); channel.addPeer(client.newPeer(config.fabric.peerRequestURL)); channel.addOrderer(client.newOrderer(config.fabric.ordererURL)); - var pemPath = path.join(__dirname,'creds','Admin@org1.example.com-cert.pem'); + // change Admin in following line to admin + var pemPath = path.join(__dirname,'creds','admin@org.hyperledger.composer.system-cert.pem'); var adminPEM = fs.readFileSync(pemPath); var bcEvents = new hfcEH(client); bcEvents.setPeerAddr(config.fabric.peerEventURL, {pem: adminPEM}); diff --git a/Chapter07/deployNetwork.sh b/Chapter07/deployNetwork.sh index e4782a1..9c13a36 100755 --- a/Chapter07/deployNetwork.sh +++ b/Chapter07/deployNetwork.sh @@ -1,6 +1,35 @@ #!/bin/bash -. ../common_OSX.sh + YELLOW='\033[1;33m' + RED='\033[1;31m' + GREEN='\033[1;32m' + RESET='\033[0m' + +# indent text on echo +function indent() { + c='s/^/ /' + case $(uname) in + Darwin) sed -l "$c";; + *) sed -u "$c";; + esac +} + +# Grab the current directory +function getCurrent() + { + showStep "getting current directory" + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + THIS_SCRIPT=`basename "$0"` + showStep "Running '${THIS_SCRIPT}'" + } + +# displays where we are, uses the indent function (above) to indent each line +function showStep () + { + echo -e "${YELLOW}=====================================================" | indent + echo -e "${RESET}-----> $*" | indent + echo -e "${YELLOW}=====================================================${RESET}" | indent + } function printHelp () { @@ -19,7 +48,7 @@ function printHeader () { echo "" echo -e "${YELLOW}network deploy script for the Zero To Blockchain Series" | indent - echo -e "${RED}This is for Mac OSX ONLY" | indent + echo -e "${RED}This has been successfully tested on OSX Sierra and Ubuntu 16.04" | indent echo -e "${YELLOW}This script will create your Composer archive" | indent echo "" } @@ -47,5 +76,16 @@ echo "Parameters:" echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "deploying network" +# original - V0.13 +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString +# +# what the documentation implies is required +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString +# +# what really works +composer identity request -p hlfv1 -i admin -s adminpw +composer identity import -p hlfv1 -u admin -c ~/.identityCredentials/admin-pub.pem -k ~/.identityCredentials/admin-priv.pem cd network/dist -composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString \ No newline at end of file +composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString diff --git a/Chapter07/network/dist/placeholder.txt b/Chapter07/network/dist/placeholder.txt new file mode 100644 index 0000000..b3a4252 --- /dev/null +++ b/Chapter07/network/dist/placeholder.txt @@ -0,0 +1 @@ +placeholder \ No newline at end of file diff --git a/Chapter07/network/package.json b/Chapter07/network/package.json index 6e58707..be89bc0 100644 --- a/Chapter07/network/package.json +++ b/Chapter07/network/package.json @@ -3,11 +3,12 @@ "composer": "" }, "name": "zerotoblockchain-network", - "version": "0.1.6", + "version": "0.1.5", "description": "Zero to Blockchain tutorial network", "networkImage": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimage.svg", "networkImageanimated": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimageanimated.svg", "scripts": { + "prepublish": "mkdirp ./network/dist && composer archive create --sourceType dir --sourceName . -a ./network/dist/zerotoblockchain-network.bna", "pretest": "npm run lint", "lint": "eslint ./network", "postlint": "npm run licchk", @@ -35,12 +36,11 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-admin": "", - "composer-cli": "", - "composer-client": "", - "composer-connector-embedded": "", - "composer-connector-hlf": "", - "composer-cucumber-steps": "", + "composer-admin": "^0.14.0", + "composer-cli": "^0.14.0", + "composer-client": "^0.14.0", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter07/network/permissions.acl b/Chapter07/network/permissions.acl index 0e80b04..9382d8d 100644 --- a/Chapter07/network/permissions.acl +++ b/Chapter07/network/permissions.acl @@ -9,6 +9,29 @@ rule AllAccess { } */ +/** +* Added to support V0.14 breaking changes +* +*/ +rule NetworkAdminUser { + description: "Grant business network administrators full access to user resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "**" + action: ALLOW +} + +rule NetworkAdminSystem { + description: "Grant business network administrators full access to system resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} +/** +* end of V0.14 additions +*/ + /** * **/ @@ -115,42 +138,75 @@ rule netAccessBuyer { * **/ rule SellerOrderFromSupplier { - + description: "Enable a Seller to Submit an Order to a third party for fulfillment" + participant(m): "org.acme.Z2BTestNetwork.Seller" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.OrderFromSupplier" + condition: (v.seller.sellerID == m.getIdentifier()) + action: ALLOW } /** * **/ rule SellerRequestPayment { - + description: "Enable a Seller to request payment for a fulfilled order" + participant(m): "org.acme.Z2BTestNetwork.Seller" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.RequestPayment" + condition: (v.seller.sellerID == m.getIdentifier()) + action: ALLOW } /** * **/ rule SellerResolve { - + description: "Enable a Seller to resolve a dispute" + participant(m): "org.acme.Z2BTestNetwork.Seller" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.Resolve" + condition: (v.seller.sellerID == m.getIdentifier()) + action: ALLOW } /** * **/ rule SellerRefund { - + description: "Enable a Seller to refund payment for a disputed order" + participant(m): "org.acme.Z2BTestNetwork.Seller" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.Refund" + condition: (v.seller.sellerID == m.getIdentifier()) + action: ALLOW } /** * **/ rule SellerACL { - + description: "Allow Seller full access to order where they are listed as seller and the order has been Submitted for Purchase" + participant(m): "org.acme.Z2BTestNetwork.Seller" + operation: READ, UPDATE + resource(v): "org.acme.Z2BTestNetwork.Order" + condition: ((v.seller.sellerID == m.getIdentifier()) && (v.bought != '')) + action: ALLOW } /** * */ rule netAccessSeller { - + description: "Allow Sellers access to the network" + participant: "org.acme.Z2BTestNetwork.Seller" + operation: READ, CREATE, UPDATE, DELETE + resource: "org.hyperledger.composer.system.**" + action: ALLOW } /** diff --git a/Chapter07/package.json b/Chapter07/package.json index dfd50fe..1d086ff 100644 --- a/Chapter07/package.json +++ b/Chapter07/package.json @@ -37,13 +37,13 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-connector-embedded": "0.13.2", - "composer-cucumber-steps": "0.13.2", - "composer-admin": "0.13.2", - "composer-client": "0.13.2", - "composer-common": "0.13.2", - "composer-runtime": "0.13.2", - "composer-runtime-hlfv1": "0.13.2", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", + "composer-admin": "^0.14.0", + "composer-client": "^0.14.0", + "composer-common": "^0.14.0", + "composer-runtime": "^0.14.0", + "composer-runtime-hlfv1": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter07/start_rest_server.sh b/Chapter07/start_rest_server.sh index 4249418..61d94ed 100755 --- a/Chapter07/start_rest_server.sh +++ b/Chapter07/start_rest_server.sh @@ -77,4 +77,7 @@ echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "testing rest server \n when this completes, \n go to your favorite browser \n and enter localhost:3000/explorer " -composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# original (pre V0.14) +# composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# V0.14 +composer-rest-server -p hlfv1 -n zerotoblockchain-network -i admin -s adminPW diff --git a/Chapter08/Documentation/answers/composer/hlcClient_complete.js b/Chapter08/Documentation/answers/composer/hlcClient_complete.js index cbc465e..ea8464c 100644 --- a/Chapter08/Documentation/answers/composer/hlcClient_complete.js +++ b/Chapter08/Documentation/answers/composer/hlcClient_complete.js @@ -142,6 +142,10 @@ exports.orderAction = function (req, res, next) { order.status = req.body.action; switch (req.body.action) { + case 'Pay': + console.log('Pay entered'); + + break; case 'Dispute': console.log('Dispute entered'); updateOrder = factory.newTransaction(NS, 'Dispute'); @@ -190,6 +194,14 @@ exports.orderAction = function (req, res, next) { updateOrder = factory.newTransaction(NS, 'RequestShipping'); updateOrder.shipper = factory.newRelationship(NS, 'Shipper', req.body.shipper); updateOrder.provider = factory.newRelationship(NS, 'Provider', order.provider.$identifier); + break; + case 'Update Delivery Status': + console.log('Update Delivery Status'); + + break; + case 'Delivered': + console.log('Delivered entered'); + break; case 'BackOrder': console.log('BackOrder entered'); diff --git a/Chapter08/Documentation/answers/network/permissions_complete.acl b/Chapter08/Documentation/answers/network/permissions_complete.acl index 290800c..03e3e96 100644 --- a/Chapter08/Documentation/answers/network/permissions_complete.acl +++ b/Chapter08/Documentation/answers/network/permissions_complete.acl @@ -9,6 +9,29 @@ rule AllAccess { } */ +/** +* Added to support V0.14 breaking changes +* +*/ +rule NetworkAdminUser { + description: "Grant business network administrators full access to user resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "**" + action: ALLOW +} + +rule NetworkAdminSystem { + description: "Grant business network administrators full access to system resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} +/** +* end of V0.14 additions +*/ + /** * **/ @@ -274,6 +297,28 @@ rule netAccessProvider { action: ALLOW } +/** +* +**/ +rule ShipperACL { + description: "Allow Shipper read, update access to order where they are listed as shiper and the order has been Submitted for delivery" + participant(m): "org.acme.Z2BTestNetwork.Shipper" + operation: READ, UPDATE + resource(v): "org.acme.Z2BTestNetwork.Order" + condition: ((v.shipper.shipperID == m.getIdentifier()) && (v.requestShipment != '')) + action: ALLOW +} + +/** +* +*/ +rule netAccessShipper { + description: "Allow Sellers access to the network" + participant: "org.acme.Z2BTestNetwork.Shipper" + operation: READ, CREATE, UPDATE, DELETE + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} /** * diff --git a/Chapter08/HTML/js/z2b-admin.js b/Chapter08/HTML/js/z2b-admin.js index 25354c0..c716cb8 100644 --- a/Chapter08/HTML/js/z2b-admin.js +++ b/Chapter08/HTML/js/z2b-admin.js @@ -31,7 +31,7 @@ function loadAdminUX () $.when($.get(toLoad)).done(function (page) {$('#body').empty(); $('#body').append(page); - goMultiLingual("US_English", "admin"); + updatePage("admin"); listMemRegistries(); }); } @@ -76,6 +76,7 @@ function displayProfileForm () $.when($.get(toLoad)).done(function (page) {$('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("createConnectionProfile"); var _cancel = $('#cancel'); var _submit = $('#submit'); _cancel.on('click', function (){$('#admin-forms').empty();}); @@ -154,6 +155,7 @@ function listProfiles(_state) { $('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("deleteConnectionProfile"); $('#connection_profiles').on('change',function() { var name = $('#connection_profiles').find(':selected').text(); var profile = connection_profiles[name]; @@ -449,6 +451,7 @@ function addMember() { $('#admin-forms').empty(); $('#admin-forms').append(_page); + updatePage("createMember"); var _cancel = $('#cancel'); var _submit = $('#submit'); $('#messages').empty(); @@ -481,6 +484,7 @@ function removeMember() { $('#admin-forms').append(_page[0]); $('#member_type').append(options.registry); + updatePage("removeMember"); member_list = _results[0].members; for (each in _results[0].members) {(function(_idx, _arr){ @@ -521,6 +525,7 @@ function getSecret() $.when($.post('/composer/admin/getMembers', options),$.get('getMemberSecret.html')).done(function (_results, _page) { $('#admin-forms').append(_page[0]); + updatePage("getMemberSecret"); $('#member_type').append(options.registry); member_list = _results[0].members; for (each in _results[0].members) diff --git a/Chapter08/controller/restapi/features/composer/creds/admin-priv.pem b/Chapter08/controller/restapi/features/composer/creds/admin-priv.pem new file mode 100644 index 0000000..11b9fd4 --- /dev/null +++ b/Chapter08/controller/restapi/features/composer/creds/admin-priv.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg00IwLLBKoi/9ikb6 +ZOAV0S1XeNGWllvlFDeczRKQn2uhRANCAARrvCsQUNRpMUkzFaC7+zV4mClo+beg +4VkUyQR5y5Fle5UVH2GigChWnUoouTO2e2acA/DUuyLDHT0emeBMhoMC +-----END PRIVATE KEY----- diff --git a/Chapter08/controller/restapi/features/composer/creds/admin-pub.pem b/Chapter08/controller/restapi/features/composer/creds/admin-pub.pem new file mode 100644 index 0000000..8c2855f --- /dev/null +++ b/Chapter08/controller/restapi/features/composer/creds/admin-pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEa7wrEFDUaTFJMxWgu/s1eJgpaPm3 +oOFZFMkEecuRZXuVFR9hooAoVp1KKLkztntmnAPw1Lsiwx09HpngTIaDAg== +-----END PUBLIC KEY----- diff --git a/Chapter08/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem b/Chapter08/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem similarity index 100% rename from Chapter08/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem rename to Chapter08/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem diff --git a/Chapter08/controller/restapi/features/composer/hlcAdmin.js b/Chapter08/controller/restapi/features/composer/hlcAdmin.js index 3ff2256..7190361 100644 --- a/Chapter08/controller/restapi/features/composer/hlcAdmin.js +++ b/Chapter08/controller/restapi/features/composer/hlcAdmin.js @@ -56,7 +56,7 @@ exports.adminNew = function() { */ exports.adminConnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ console.log('create connection successful '); res.send({connection: 'succeeded'}); @@ -91,7 +91,7 @@ exports.createProfile = function(req, res, next) { peers: [{eventURL: req.body.peers.eventURL, requestURL: req.body.peers.requestRUL}] }; let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.createProfile(req.body.profileName, adminOptions) .then(function(result){ @@ -115,7 +115,7 @@ exports.createProfile = function(req, res, next) { */ exports.deleteProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deleteProfile(req.body.profileName) .then(function(result){ @@ -146,7 +146,7 @@ exports.deploy = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deploy(archive) .then(function(){ @@ -177,7 +177,7 @@ exports.networkInstall = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); return BusinessNetworkDefinition.fromArchive(archiveFile) .then((businessNetworkDefinition) => { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { return adminConnection.install(businessNetworkDefinition.getName()) .then(() => { @@ -213,7 +213,7 @@ exports.networkStart = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.start(archive) .then(function(){ @@ -238,7 +238,7 @@ exports.networkStart = function(req, res, next) { */ exports.disconnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.disconnect() .then(function(result){ @@ -261,7 +261,7 @@ exports.disconnect = function(req, res, next) { */ exports.getAllProfiles = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getAllProfiles() .then((profiles) => { @@ -284,7 +284,7 @@ exports.getAllProfiles = function(req, res, next) { */ exports.getProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getProfile(req.body.connectionProfile) .then((profile) => { @@ -308,7 +308,7 @@ exports.getProfile = function(req, res, next) { exports.listAsAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); util.displayObjectValuesRecursive(adminConnection); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -335,7 +335,7 @@ exports.listAsAdmin = function(req, res, next) { */ exports.listAsPeerAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.peerAdmin, config.composer.secret) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -362,7 +362,7 @@ exports.listAsPeerAdmin = function(req, res, next) { */ exports.ping = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.ping() .then(function(result){ @@ -387,7 +387,7 @@ exports.ping = function(req, res, next) { */ exports.undeploy = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.undeploy(req.body.businessNetwork) .then(function(result){ @@ -419,7 +419,7 @@ exports.update = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, netName) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, netName) .then(function(){ adminConnection.update(archive) .then(function(){ @@ -451,10 +451,10 @@ exports.getRegistries = function(req, res, next) let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getAllParticipantRegistries() .then(function(participantRegistries){ @@ -488,10 +488,10 @@ exports.getMembers = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) .then(function(registry){ @@ -526,13 +526,17 @@ exports.getMembers = function(req, res, next) { } res.send({'result': 'success', 'members': allMembers}); }) - .catch((error) => {console.log('error with getAllMembers', error)}); + .catch((error) => {console.log('error with getAllMembers', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with getRegistry', error)}); + .catch((error) => {console.log('error with getRegistry', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with business network Connect', error)}); + .catch((error) => {console.log('error with business network Connect', error.message); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with admin network Connect', error)}); + .catch((error) => {console.log('error with admin network Connect', error); + res.send({'result': 'failed '+error.message, 'members': []});}); } @@ -554,10 +558,10 @@ exports.getAssets = function(req, res, next) { let factory; let serializer; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { // let bnd = new BusinessNetworkDefinition(config.composer.network+'@0.1.6', config.composer.description, packageJSON); // retry this with fromArchive when time allows @@ -640,10 +644,10 @@ exports.addMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.type) @@ -680,10 +684,10 @@ exports.removeMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) @@ -725,10 +729,10 @@ exports.getHistory = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then((bnd) => { ser = bnd.getSerializer(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getRegistry('org.hyperledger.composer.system.HistorianRecord') .then(function(registry){ diff --git a/Chapter08/controller/restapi/features/composer/queryBlockChain.js b/Chapter08/controller/restapi/features/composer/queryBlockChain.js index 4a61c7d..a0b0b57 100644 --- a/Chapter08/controller/restapi/features/composer/queryBlockChain.js +++ b/Chapter08/controller/restapi/features/composer/queryBlockChain.js @@ -58,6 +58,7 @@ exports.getChainInfo = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -103,6 +104,7 @@ exports.getChainEvents = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -110,7 +112,8 @@ exports.getChainEvents = function(req, res, next) { channel = client.newChannel(config.fabric.channelName); channel.addPeer(client.newPeer(config.fabric.peerRequestURL)); channel.addOrderer(client.newOrderer(config.fabric.ordererURL)); - var pemPath = path.join(__dirname,'creds','Admin@org1.example.com-cert.pem'); + // change Admin in following line to admin + var pemPath = path.join(__dirname,'creds','admin@org.hyperledger.composer.system-cert.pem'); var adminPEM = fs.readFileSync(pemPath); var bcEvents = new hfcEH(client); bcEvents.setPeerAddr(config.fabric.peerEventURL, {pem: adminPEM}); diff --git a/Chapter08/deployNetwork.sh b/Chapter08/deployNetwork.sh index e4782a1..9c13a36 100755 --- a/Chapter08/deployNetwork.sh +++ b/Chapter08/deployNetwork.sh @@ -1,6 +1,35 @@ #!/bin/bash -. ../common_OSX.sh + YELLOW='\033[1;33m' + RED='\033[1;31m' + GREEN='\033[1;32m' + RESET='\033[0m' + +# indent text on echo +function indent() { + c='s/^/ /' + case $(uname) in + Darwin) sed -l "$c";; + *) sed -u "$c";; + esac +} + +# Grab the current directory +function getCurrent() + { + showStep "getting current directory" + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + THIS_SCRIPT=`basename "$0"` + showStep "Running '${THIS_SCRIPT}'" + } + +# displays where we are, uses the indent function (above) to indent each line +function showStep () + { + echo -e "${YELLOW}=====================================================" | indent + echo -e "${RESET}-----> $*" | indent + echo -e "${YELLOW}=====================================================${RESET}" | indent + } function printHelp () { @@ -19,7 +48,7 @@ function printHeader () { echo "" echo -e "${YELLOW}network deploy script for the Zero To Blockchain Series" | indent - echo -e "${RED}This is for Mac OSX ONLY" | indent + echo -e "${RED}This has been successfully tested on OSX Sierra and Ubuntu 16.04" | indent echo -e "${YELLOW}This script will create your Composer archive" | indent echo "" } @@ -47,5 +76,16 @@ echo "Parameters:" echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "deploying network" +# original - V0.13 +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString +# +# what the documentation implies is required +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString +# +# what really works +composer identity request -p hlfv1 -i admin -s adminpw +composer identity import -p hlfv1 -u admin -c ~/.identityCredentials/admin-pub.pem -k ~/.identityCredentials/admin-priv.pem cd network/dist -composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString \ No newline at end of file +composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString diff --git a/Chapter08/network/package.json b/Chapter08/network/package.json index 6e58707..be89bc0 100644 --- a/Chapter08/network/package.json +++ b/Chapter08/network/package.json @@ -3,11 +3,12 @@ "composer": "" }, "name": "zerotoblockchain-network", - "version": "0.1.6", + "version": "0.1.5", "description": "Zero to Blockchain tutorial network", "networkImage": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimage.svg", "networkImageanimated": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimageanimated.svg", "scripts": { + "prepublish": "mkdirp ./network/dist && composer archive create --sourceType dir --sourceName . -a ./network/dist/zerotoblockchain-network.bna", "pretest": "npm run lint", "lint": "eslint ./network", "postlint": "npm run licchk", @@ -35,12 +36,11 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-admin": "", - "composer-cli": "", - "composer-client": "", - "composer-connector-embedded": "", - "composer-connector-hlf": "", - "composer-cucumber-steps": "", + "composer-admin": "^0.14.0", + "composer-cli": "^0.14.0", + "composer-client": "^0.14.0", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter08/network/permissions.acl b/Chapter08/network/permissions.acl index 31348d7..03e3e96 100644 --- a/Chapter08/network/permissions.acl +++ b/Chapter08/network/permissions.acl @@ -9,6 +9,29 @@ rule AllAccess { } */ +/** +* Added to support V0.14 breaking changes +* +*/ +rule NetworkAdminUser { + description: "Grant business network administrators full access to user resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "**" + action: ALLOW +} + +rule NetworkAdminSystem { + description: "Grant business network administrators full access to system resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} +/** +* end of V0.14 additions +*/ + /** * **/ @@ -190,48 +213,111 @@ rule netAccessSeller { * **/ rule ProviderRequestShipping { - + description: "Enable a Provider to initiate a shipping request for an order" + participant(m): "org.acme.Z2BTestNetwork.Provider" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.RequestShipping" + condition: (v.provider.providerID == m.getIdentifier()) + action: ALLOW } /** * **/ rule ProviderBackorder { - + description: "Enable a Provider to issue a backorder status for an order" + participant(m): "org.acme.Z2BTestNetwork.Provider" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.BackOrder" + condition: (v.provider.providerID == m.getIdentifier()) + action: ALLOW } + /** * **/ rule ProviderPayRequest { - + description: "Enable a Provider to issue a request for payment" + participant(m): "org.acme.Z2BTestNetwork.Provider" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.RequestPayment" + condition: (v.provider.providerID == m.getIdentifier()) + action: ALLOW } /** * **/ rule ProviderResolve { - + description: "Enable a Provider to resolve a disputed order" + participant(m): "org.acme.Z2BTestNetwork.Provider" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.Resolve" + condition: (v.provider.providerID == m.getIdentifier()) + action: ALLOW } /** * **/ rule ProviderRefund { - + description: "Enable a Provider to refund payment for a disputed order" + participant(m): "org.acme.Z2BTestNetwork.Provider" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.Refund" + condition: (v.provider.providerID == m.getIdentifier()) + action: ALLOW } /** * **/ rule ProviderACL { - + description: "Allow Provider read and update access to order where they are listed as seller and the order has been submitted to them to provide (Seller issues OrderFromSupplier transaction" + participant(m): "org.acme.Z2BTestNetwork.Provider" + operation: READ, UPDATE + resource(v): "org.acme.Z2BTestNetwork.Order" + condition: ((v.provider.providerID == m.getIdentifier()) && (v.ordered != '')) + action: ALLOW } /** * */ rule netAccessProvider { + description: "Allow Sellers access to the network" + participant: "org.acme.Z2BTestNetwork.Provider" + operation: READ, CREATE, UPDATE, DELETE + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} +/** +* +**/ +rule ShipperACL { + description: "Allow Shipper read, update access to order where they are listed as shiper and the order has been Submitted for delivery" + participant(m): "org.acme.Z2BTestNetwork.Shipper" + operation: READ, UPDATE + resource(v): "org.acme.Z2BTestNetwork.Order" + condition: ((v.shipper.shipperID == m.getIdentifier()) && (v.requestShipment != '')) + action: ALLOW +} + +/** +* +*/ +rule netAccessShipper { + description: "Allow Sellers access to the network" + participant: "org.acme.Z2BTestNetwork.Shipper" + operation: READ, CREATE, UPDATE, DELETE + resource: "org.hyperledger.composer.system.**" + action: ALLOW } /** diff --git a/Chapter08/package.json b/Chapter08/package.json index dfd50fe..1d086ff 100644 --- a/Chapter08/package.json +++ b/Chapter08/package.json @@ -37,13 +37,13 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-connector-embedded": "0.13.2", - "composer-cucumber-steps": "0.13.2", - "composer-admin": "0.13.2", - "composer-client": "0.13.2", - "composer-common": "0.13.2", - "composer-runtime": "0.13.2", - "composer-runtime-hlfv1": "0.13.2", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", + "composer-admin": "^0.14.0", + "composer-client": "^0.14.0", + "composer-common": "^0.14.0", + "composer-runtime": "^0.14.0", + "composer-runtime-hlfv1": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter08/start_rest_server.sh b/Chapter08/start_rest_server.sh index 4249418..61d94ed 100755 --- a/Chapter08/start_rest_server.sh +++ b/Chapter08/start_rest_server.sh @@ -77,4 +77,7 @@ echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "testing rest server \n when this completes, \n go to your favorite browser \n and enter localhost:3000/explorer " -composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# original (pre V0.14) +# composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# V0.14 +composer-rest-server -p hlfv1 -n zerotoblockchain-network -i admin -s adminPW diff --git a/Chapter09/Documentation/answers/composer/hlcClient_complete.js b/Chapter09/Documentation/answers/composer/hlcClient_complete.js index 04b523f..6d7ffab 100644 --- a/Chapter09/Documentation/answers/composer/hlcClient_complete.js +++ b/Chapter09/Documentation/answers/composer/hlcClient_complete.js @@ -142,6 +142,10 @@ exports.orderAction = function (req, res, next) { order.status = req.body.action; switch (req.body.action) { + case 'Pay': + console.log('Pay entered'); + + break; case 'Dispute': console.log('Dispute entered'); updateOrder = factory.newTransaction(NS, 'Dispute'); diff --git a/Chapter09/Documentation/answers/network/permissions_complete.acl b/Chapter09/Documentation/answers/network/permissions_complete.acl index 6c0c98f..742aed3 100644 --- a/Chapter09/Documentation/answers/network/permissions_complete.acl +++ b/Chapter09/Documentation/answers/network/permissions_complete.acl @@ -9,6 +9,29 @@ rule AllAccess { } */ +/** +* Added to support V0.14 breaking changes +* +*/ +rule NetworkAdminUser { + description: "Grant business network administrators full access to user resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "**" + action: ALLOW +} + +rule NetworkAdminSystem { + description: "Grant business network administrators full access to system resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} +/** +* end of V0.14 additions +*/ + /** * **/ diff --git a/Chapter09/HTML/js/z2b-admin.js b/Chapter09/HTML/js/z2b-admin.js index 25354c0..c716cb8 100644 --- a/Chapter09/HTML/js/z2b-admin.js +++ b/Chapter09/HTML/js/z2b-admin.js @@ -31,7 +31,7 @@ function loadAdminUX () $.when($.get(toLoad)).done(function (page) {$('#body').empty(); $('#body').append(page); - goMultiLingual("US_English", "admin"); + updatePage("admin"); listMemRegistries(); }); } @@ -76,6 +76,7 @@ function displayProfileForm () $.when($.get(toLoad)).done(function (page) {$('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("createConnectionProfile"); var _cancel = $('#cancel'); var _submit = $('#submit'); _cancel.on('click', function (){$('#admin-forms').empty();}); @@ -154,6 +155,7 @@ function listProfiles(_state) { $('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("deleteConnectionProfile"); $('#connection_profiles').on('change',function() { var name = $('#connection_profiles').find(':selected').text(); var profile = connection_profiles[name]; @@ -449,6 +451,7 @@ function addMember() { $('#admin-forms').empty(); $('#admin-forms').append(_page); + updatePage("createMember"); var _cancel = $('#cancel'); var _submit = $('#submit'); $('#messages').empty(); @@ -481,6 +484,7 @@ function removeMember() { $('#admin-forms').append(_page[0]); $('#member_type').append(options.registry); + updatePage("removeMember"); member_list = _results[0].members; for (each in _results[0].members) {(function(_idx, _arr){ @@ -521,6 +525,7 @@ function getSecret() $.when($.post('/composer/admin/getMembers', options),$.get('getMemberSecret.html')).done(function (_results, _page) { $('#admin-forms').append(_page[0]); + updatePage("getMemberSecret"); $('#member_type').append(options.registry); member_list = _results[0].members; for (each in _results[0].members) diff --git a/Chapter09/controller/restapi/features/composer/creds/admin-priv.pem b/Chapter09/controller/restapi/features/composer/creds/admin-priv.pem new file mode 100644 index 0000000..11b9fd4 --- /dev/null +++ b/Chapter09/controller/restapi/features/composer/creds/admin-priv.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg00IwLLBKoi/9ikb6 +ZOAV0S1XeNGWllvlFDeczRKQn2uhRANCAARrvCsQUNRpMUkzFaC7+zV4mClo+beg +4VkUyQR5y5Fle5UVH2GigChWnUoouTO2e2acA/DUuyLDHT0emeBMhoMC +-----END PRIVATE KEY----- diff --git a/Chapter09/controller/restapi/features/composer/creds/admin-pub.pem b/Chapter09/controller/restapi/features/composer/creds/admin-pub.pem new file mode 100644 index 0000000..8c2855f --- /dev/null +++ b/Chapter09/controller/restapi/features/composer/creds/admin-pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEa7wrEFDUaTFJMxWgu/s1eJgpaPm3 +oOFZFMkEecuRZXuVFR9hooAoVp1KKLkztntmnAPw1Lsiwx09HpngTIaDAg== +-----END PUBLIC KEY----- diff --git a/Chapter09/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem b/Chapter09/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem similarity index 100% rename from Chapter09/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem rename to Chapter09/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem diff --git a/Chapter09/controller/restapi/features/composer/hlcAdmin.js b/Chapter09/controller/restapi/features/composer/hlcAdmin.js index 3ff2256..7190361 100644 --- a/Chapter09/controller/restapi/features/composer/hlcAdmin.js +++ b/Chapter09/controller/restapi/features/composer/hlcAdmin.js @@ -56,7 +56,7 @@ exports.adminNew = function() { */ exports.adminConnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ console.log('create connection successful '); res.send({connection: 'succeeded'}); @@ -91,7 +91,7 @@ exports.createProfile = function(req, res, next) { peers: [{eventURL: req.body.peers.eventURL, requestURL: req.body.peers.requestRUL}] }; let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.createProfile(req.body.profileName, adminOptions) .then(function(result){ @@ -115,7 +115,7 @@ exports.createProfile = function(req, res, next) { */ exports.deleteProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deleteProfile(req.body.profileName) .then(function(result){ @@ -146,7 +146,7 @@ exports.deploy = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deploy(archive) .then(function(){ @@ -177,7 +177,7 @@ exports.networkInstall = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); return BusinessNetworkDefinition.fromArchive(archiveFile) .then((businessNetworkDefinition) => { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { return adminConnection.install(businessNetworkDefinition.getName()) .then(() => { @@ -213,7 +213,7 @@ exports.networkStart = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.start(archive) .then(function(){ @@ -238,7 +238,7 @@ exports.networkStart = function(req, res, next) { */ exports.disconnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.disconnect() .then(function(result){ @@ -261,7 +261,7 @@ exports.disconnect = function(req, res, next) { */ exports.getAllProfiles = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getAllProfiles() .then((profiles) => { @@ -284,7 +284,7 @@ exports.getAllProfiles = function(req, res, next) { */ exports.getProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getProfile(req.body.connectionProfile) .then((profile) => { @@ -308,7 +308,7 @@ exports.getProfile = function(req, res, next) { exports.listAsAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); util.displayObjectValuesRecursive(adminConnection); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -335,7 +335,7 @@ exports.listAsAdmin = function(req, res, next) { */ exports.listAsPeerAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.peerAdmin, config.composer.secret) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -362,7 +362,7 @@ exports.listAsPeerAdmin = function(req, res, next) { */ exports.ping = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.ping() .then(function(result){ @@ -387,7 +387,7 @@ exports.ping = function(req, res, next) { */ exports.undeploy = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.undeploy(req.body.businessNetwork) .then(function(result){ @@ -419,7 +419,7 @@ exports.update = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, netName) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, netName) .then(function(){ adminConnection.update(archive) .then(function(){ @@ -451,10 +451,10 @@ exports.getRegistries = function(req, res, next) let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getAllParticipantRegistries() .then(function(participantRegistries){ @@ -488,10 +488,10 @@ exports.getMembers = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) .then(function(registry){ @@ -526,13 +526,17 @@ exports.getMembers = function(req, res, next) { } res.send({'result': 'success', 'members': allMembers}); }) - .catch((error) => {console.log('error with getAllMembers', error)}); + .catch((error) => {console.log('error with getAllMembers', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with getRegistry', error)}); + .catch((error) => {console.log('error with getRegistry', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with business network Connect', error)}); + .catch((error) => {console.log('error with business network Connect', error.message); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with admin network Connect', error)}); + .catch((error) => {console.log('error with admin network Connect', error); + res.send({'result': 'failed '+error.message, 'members': []});}); } @@ -554,10 +558,10 @@ exports.getAssets = function(req, res, next) { let factory; let serializer; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { // let bnd = new BusinessNetworkDefinition(config.composer.network+'@0.1.6', config.composer.description, packageJSON); // retry this with fromArchive when time allows @@ -640,10 +644,10 @@ exports.addMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.type) @@ -680,10 +684,10 @@ exports.removeMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) @@ -725,10 +729,10 @@ exports.getHistory = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then((bnd) => { ser = bnd.getSerializer(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getRegistry('org.hyperledger.composer.system.HistorianRecord') .then(function(registry){ diff --git a/Chapter09/controller/restapi/features/composer/queryBlockChain.js b/Chapter09/controller/restapi/features/composer/queryBlockChain.js index 4a61c7d..a0b0b57 100644 --- a/Chapter09/controller/restapi/features/composer/queryBlockChain.js +++ b/Chapter09/controller/restapi/features/composer/queryBlockChain.js @@ -58,6 +58,7 @@ exports.getChainInfo = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -103,6 +104,7 @@ exports.getChainEvents = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -110,7 +112,8 @@ exports.getChainEvents = function(req, res, next) { channel = client.newChannel(config.fabric.channelName); channel.addPeer(client.newPeer(config.fabric.peerRequestURL)); channel.addOrderer(client.newOrderer(config.fabric.ordererURL)); - var pemPath = path.join(__dirname,'creds','Admin@org1.example.com-cert.pem'); + // change Admin in following line to admin + var pemPath = path.join(__dirname,'creds','admin@org.hyperledger.composer.system-cert.pem'); var adminPEM = fs.readFileSync(pemPath); var bcEvents = new hfcEH(client); bcEvents.setPeerAddr(config.fabric.peerEventURL, {pem: adminPEM}); diff --git a/Chapter09/deployNetwork.sh b/Chapter09/deployNetwork.sh index e4782a1..9c13a36 100755 --- a/Chapter09/deployNetwork.sh +++ b/Chapter09/deployNetwork.sh @@ -1,6 +1,35 @@ #!/bin/bash -. ../common_OSX.sh + YELLOW='\033[1;33m' + RED='\033[1;31m' + GREEN='\033[1;32m' + RESET='\033[0m' + +# indent text on echo +function indent() { + c='s/^/ /' + case $(uname) in + Darwin) sed -l "$c";; + *) sed -u "$c";; + esac +} + +# Grab the current directory +function getCurrent() + { + showStep "getting current directory" + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + THIS_SCRIPT=`basename "$0"` + showStep "Running '${THIS_SCRIPT}'" + } + +# displays where we are, uses the indent function (above) to indent each line +function showStep () + { + echo -e "${YELLOW}=====================================================" | indent + echo -e "${RESET}-----> $*" | indent + echo -e "${YELLOW}=====================================================${RESET}" | indent + } function printHelp () { @@ -19,7 +48,7 @@ function printHeader () { echo "" echo -e "${YELLOW}network deploy script for the Zero To Blockchain Series" | indent - echo -e "${RED}This is for Mac OSX ONLY" | indent + echo -e "${RED}This has been successfully tested on OSX Sierra and Ubuntu 16.04" | indent echo -e "${YELLOW}This script will create your Composer archive" | indent echo "" } @@ -47,5 +76,16 @@ echo "Parameters:" echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "deploying network" +# original - V0.13 +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString +# +# what the documentation implies is required +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString +# +# what really works +composer identity request -p hlfv1 -i admin -s adminpw +composer identity import -p hlfv1 -u admin -c ~/.identityCredentials/admin-pub.pem -k ~/.identityCredentials/admin-priv.pem cd network/dist -composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString \ No newline at end of file +composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString diff --git a/Chapter09/network/package.json b/Chapter09/network/package.json index 6e58707..be89bc0 100644 --- a/Chapter09/network/package.json +++ b/Chapter09/network/package.json @@ -3,11 +3,12 @@ "composer": "" }, "name": "zerotoblockchain-network", - "version": "0.1.6", + "version": "0.1.5", "description": "Zero to Blockchain tutorial network", "networkImage": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimage.svg", "networkImageanimated": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimageanimated.svg", "scripts": { + "prepublish": "mkdirp ./network/dist && composer archive create --sourceType dir --sourceName . -a ./network/dist/zerotoblockchain-network.bna", "pretest": "npm run lint", "lint": "eslint ./network", "postlint": "npm run licchk", @@ -35,12 +36,11 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-admin": "", - "composer-cli": "", - "composer-client": "", - "composer-connector-embedded": "", - "composer-connector-hlf": "", - "composer-cucumber-steps": "", + "composer-admin": "^0.14.0", + "composer-cli": "^0.14.0", + "composer-client": "^0.14.0", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter09/network/permissions.acl b/Chapter09/network/permissions.acl index efcc275..742aed3 100644 --- a/Chapter09/network/permissions.acl +++ b/Chapter09/network/permissions.acl @@ -9,6 +9,29 @@ rule AllAccess { } */ +/** +* Added to support V0.14 breaking changes +* +*/ +rule NetworkAdminUser { + description: "Grant business network administrators full access to user resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "**" + action: ALLOW +} + +rule NetworkAdminSystem { + description: "Grant business network administrators full access to system resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} +/** +* end of V0.14 additions +*/ + /** * **/ @@ -278,42 +301,75 @@ rule netAccessProvider { * **/ rule ShipperRefund { - + description: "Enable a Shipper to refund payment for a disputed order" + participant(m): "org.acme.Z2BTestNetwork.Shipper" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.Refund" + condition: (v.shipper.shipperID == m.getIdentifier()) + action: ALLOW } /** * **/ rule ShipperResolve { - + description: "Enable a Shipper to resolve a disputed order" + participant(m): "org.acme.Z2BTestNetwork.Shipper" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.Resolve" + condition: (v.shipper.shipperID == m.getIdentifier()) + action: ALLOW } /** * **/ rule ShipperDelivering { - + description: "Enable a Shipper to update delivery status on an order" + participant(m): "org.acme.Z2BTestNetwork.Shipper" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.Delivering" + condition: (v.shipper.shipperID == m.getIdentifier()) + action: ALLOW } /** * **/ rule ShipperDelivered { - + description: "Enable a Shipper to mark an order as delivered" + participant(m): "org.acme.Z2BTestNetwork.Shipper" + operation: READ, CREATE, UPDATE + resource(v): "org.acme.Z2BTestNetwork.**" + transaction(tx): "org.acme.Z2BTestNetwork.Deliver" + condition: (v.shipper.shipperID == m.getIdentifier()) + action: ALLOW } /** * **/ rule ShipperACL { - + description: "Allow Shipper read, update access to order where they are listed as shiper and the order has been Submitted for delivery" + participant(m): "org.acme.Z2BTestNetwork.Shipper" + operation: READ, UPDATE + resource(v): "org.acme.Z2BTestNetwork.Order" + condition: ((v.shipper.shipperID == m.getIdentifier()) && (v.requestShipment != '')) + action: ALLOW } /** * */ rule netAccessShipper { - + description: "Allow Sellers access to the network" + participant: "org.acme.Z2BTestNetwork.Shipper" + operation: READ, CREATE, UPDATE, DELETE + resource: "org.hyperledger.composer.system.**" + action: ALLOW } /** diff --git a/Chapter09/package.json b/Chapter09/package.json index dfd50fe..1d086ff 100644 --- a/Chapter09/package.json +++ b/Chapter09/package.json @@ -37,13 +37,13 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-connector-embedded": "0.13.2", - "composer-cucumber-steps": "0.13.2", - "composer-admin": "0.13.2", - "composer-client": "0.13.2", - "composer-common": "0.13.2", - "composer-runtime": "0.13.2", - "composer-runtime-hlfv1": "0.13.2", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", + "composer-admin": "^0.14.0", + "composer-client": "^0.14.0", + "composer-common": "^0.14.0", + "composer-runtime": "^0.14.0", + "composer-runtime-hlfv1": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter09/start_rest_server.sh b/Chapter09/start_rest_server.sh index 4249418..61d94ed 100755 --- a/Chapter09/start_rest_server.sh +++ b/Chapter09/start_rest_server.sh @@ -77,4 +77,7 @@ echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "testing rest server \n when this completes, \n go to your favorite browser \n and enter localhost:3000/explorer " -composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# original (pre V0.14) +# composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# V0.14 +composer-rest-server -p hlfv1 -n zerotoblockchain-network -i admin -s adminPW diff --git a/Chapter10/Documentation/answers/network/permissions_complete.acl b/Chapter10/Documentation/answers/network/permissions_complete.acl index 83614dc..1457cc5 100644 --- a/Chapter10/Documentation/answers/network/permissions_complete.acl +++ b/Chapter10/Documentation/answers/network/permissions_complete.acl @@ -9,6 +9,28 @@ rule AllAccess { } */ +/** +* Added to support V0.14 breaking changes +* +*/ +rule NetworkAdminUser { + description: "Grant business network administrators full access to user resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "**" + action: ALLOW +} + +rule NetworkAdminSystem { + description: "Grant business network administrators full access to system resources" + participant: "org.hyperledger.composer.system.NetworkAdmin" + operation: ALL + resource: "org.hyperledger.composer.system.**" + action: ALLOW +} +/** +* end of V0.14 additions +*/ /** * diff --git a/Chapter10/HTML/js/z2b-admin.js b/Chapter10/HTML/js/z2b-admin.js index 25354c0..c716cb8 100644 --- a/Chapter10/HTML/js/z2b-admin.js +++ b/Chapter10/HTML/js/z2b-admin.js @@ -31,7 +31,7 @@ function loadAdminUX () $.when($.get(toLoad)).done(function (page) {$('#body').empty(); $('#body').append(page); - goMultiLingual("US_English", "admin"); + updatePage("admin"); listMemRegistries(); }); } @@ -76,6 +76,7 @@ function displayProfileForm () $.when($.get(toLoad)).done(function (page) {$('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("createConnectionProfile"); var _cancel = $('#cancel'); var _submit = $('#submit'); _cancel.on('click', function (){$('#admin-forms').empty();}); @@ -154,6 +155,7 @@ function listProfiles(_state) { $('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("deleteConnectionProfile"); $('#connection_profiles').on('change',function() { var name = $('#connection_profiles').find(':selected').text(); var profile = connection_profiles[name]; @@ -449,6 +451,7 @@ function addMember() { $('#admin-forms').empty(); $('#admin-forms').append(_page); + updatePage("createMember"); var _cancel = $('#cancel'); var _submit = $('#submit'); $('#messages').empty(); @@ -481,6 +484,7 @@ function removeMember() { $('#admin-forms').append(_page[0]); $('#member_type').append(options.registry); + updatePage("removeMember"); member_list = _results[0].members; for (each in _results[0].members) {(function(_idx, _arr){ @@ -521,6 +525,7 @@ function getSecret() $.when($.post('/composer/admin/getMembers', options),$.get('getMemberSecret.html')).done(function (_results, _page) { $('#admin-forms').append(_page[0]); + updatePage("getMemberSecret"); $('#member_type').append(options.registry); member_list = _results[0].members; for (each in _results[0].members) diff --git a/Chapter10/controller/restapi/features/composer/creds/admin-priv.pem b/Chapter10/controller/restapi/features/composer/creds/admin-priv.pem new file mode 100644 index 0000000..11b9fd4 --- /dev/null +++ b/Chapter10/controller/restapi/features/composer/creds/admin-priv.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg00IwLLBKoi/9ikb6 +ZOAV0S1XeNGWllvlFDeczRKQn2uhRANCAARrvCsQUNRpMUkzFaC7+zV4mClo+beg +4VkUyQR5y5Fle5UVH2GigChWnUoouTO2e2acA/DUuyLDHT0emeBMhoMC +-----END PRIVATE KEY----- diff --git a/Chapter10/controller/restapi/features/composer/creds/admin-pub.pem b/Chapter10/controller/restapi/features/composer/creds/admin-pub.pem new file mode 100644 index 0000000..8c2855f --- /dev/null +++ b/Chapter10/controller/restapi/features/composer/creds/admin-pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEa7wrEFDUaTFJMxWgu/s1eJgpaPm3 +oOFZFMkEecuRZXuVFR9hooAoVp1KKLkztntmnAPw1Lsiwx09HpngTIaDAg== +-----END PUBLIC KEY----- diff --git a/Chapter10/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem b/Chapter10/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem similarity index 100% rename from Chapter10/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem rename to Chapter10/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem diff --git a/Chapter10/controller/restapi/features/composer/hlcAdmin.js b/Chapter10/controller/restapi/features/composer/hlcAdmin.js index 3ff2256..7190361 100644 --- a/Chapter10/controller/restapi/features/composer/hlcAdmin.js +++ b/Chapter10/controller/restapi/features/composer/hlcAdmin.js @@ -56,7 +56,7 @@ exports.adminNew = function() { */ exports.adminConnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ console.log('create connection successful '); res.send({connection: 'succeeded'}); @@ -91,7 +91,7 @@ exports.createProfile = function(req, res, next) { peers: [{eventURL: req.body.peers.eventURL, requestURL: req.body.peers.requestRUL}] }; let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.createProfile(req.body.profileName, adminOptions) .then(function(result){ @@ -115,7 +115,7 @@ exports.createProfile = function(req, res, next) { */ exports.deleteProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deleteProfile(req.body.profileName) .then(function(result){ @@ -146,7 +146,7 @@ exports.deploy = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deploy(archive) .then(function(){ @@ -177,7 +177,7 @@ exports.networkInstall = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); return BusinessNetworkDefinition.fromArchive(archiveFile) .then((businessNetworkDefinition) => { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { return adminConnection.install(businessNetworkDefinition.getName()) .then(() => { @@ -213,7 +213,7 @@ exports.networkStart = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.start(archive) .then(function(){ @@ -238,7 +238,7 @@ exports.networkStart = function(req, res, next) { */ exports.disconnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.disconnect() .then(function(result){ @@ -261,7 +261,7 @@ exports.disconnect = function(req, res, next) { */ exports.getAllProfiles = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getAllProfiles() .then((profiles) => { @@ -284,7 +284,7 @@ exports.getAllProfiles = function(req, res, next) { */ exports.getProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getProfile(req.body.connectionProfile) .then((profile) => { @@ -308,7 +308,7 @@ exports.getProfile = function(req, res, next) { exports.listAsAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); util.displayObjectValuesRecursive(adminConnection); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -335,7 +335,7 @@ exports.listAsAdmin = function(req, res, next) { */ exports.listAsPeerAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.peerAdmin, config.composer.secret) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -362,7 +362,7 @@ exports.listAsPeerAdmin = function(req, res, next) { */ exports.ping = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.ping() .then(function(result){ @@ -387,7 +387,7 @@ exports.ping = function(req, res, next) { */ exports.undeploy = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.undeploy(req.body.businessNetwork) .then(function(result){ @@ -419,7 +419,7 @@ exports.update = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, netName) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, netName) .then(function(){ adminConnection.update(archive) .then(function(){ @@ -451,10 +451,10 @@ exports.getRegistries = function(req, res, next) let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getAllParticipantRegistries() .then(function(participantRegistries){ @@ -488,10 +488,10 @@ exports.getMembers = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) .then(function(registry){ @@ -526,13 +526,17 @@ exports.getMembers = function(req, res, next) { } res.send({'result': 'success', 'members': allMembers}); }) - .catch((error) => {console.log('error with getAllMembers', error)}); + .catch((error) => {console.log('error with getAllMembers', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with getRegistry', error)}); + .catch((error) => {console.log('error with getRegistry', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with business network Connect', error)}); + .catch((error) => {console.log('error with business network Connect', error.message); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with admin network Connect', error)}); + .catch((error) => {console.log('error with admin network Connect', error); + res.send({'result': 'failed '+error.message, 'members': []});}); } @@ -554,10 +558,10 @@ exports.getAssets = function(req, res, next) { let factory; let serializer; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { // let bnd = new BusinessNetworkDefinition(config.composer.network+'@0.1.6', config.composer.description, packageJSON); // retry this with fromArchive when time allows @@ -640,10 +644,10 @@ exports.addMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.type) @@ -680,10 +684,10 @@ exports.removeMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) @@ -725,10 +729,10 @@ exports.getHistory = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then((bnd) => { ser = bnd.getSerializer(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getRegistry('org.hyperledger.composer.system.HistorianRecord') .then(function(registry){ diff --git a/Chapter10/controller/restapi/features/composer/queryBlockChain.js b/Chapter10/controller/restapi/features/composer/queryBlockChain.js index 4a61c7d..a0b0b57 100644 --- a/Chapter10/controller/restapi/features/composer/queryBlockChain.js +++ b/Chapter10/controller/restapi/features/composer/queryBlockChain.js @@ -58,6 +58,7 @@ exports.getChainInfo = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -103,6 +104,7 @@ exports.getChainEvents = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -110,7 +112,8 @@ exports.getChainEvents = function(req, res, next) { channel = client.newChannel(config.fabric.channelName); channel.addPeer(client.newPeer(config.fabric.peerRequestURL)); channel.addOrderer(client.newOrderer(config.fabric.ordererURL)); - var pemPath = path.join(__dirname,'creds','Admin@org1.example.com-cert.pem'); + // change Admin in following line to admin + var pemPath = path.join(__dirname,'creds','admin@org.hyperledger.composer.system-cert.pem'); var adminPEM = fs.readFileSync(pemPath); var bcEvents = new hfcEH(client); bcEvents.setPeerAddr(config.fabric.peerEventURL, {pem: adminPEM}); diff --git a/Chapter10/deployNetwork.sh b/Chapter10/deployNetwork.sh index 78943ff..9c13a36 100755 --- a/Chapter10/deployNetwork.sh +++ b/Chapter10/deployNetwork.sh @@ -1,6 +1,35 @@ #!/bin/bash -. ../common_OSX.sh + YELLOW='\033[1;33m' + RED='\033[1;31m' + GREEN='\033[1;32m' + RESET='\033[0m' + +# indent text on echo +function indent() { + c='s/^/ /' + case $(uname) in + Darwin) sed -l "$c";; + *) sed -u "$c";; + esac +} + +# Grab the current directory +function getCurrent() + { + showStep "getting current directory" + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + THIS_SCRIPT=`basename "$0"` + showStep "Running '${THIS_SCRIPT}'" + } + +# displays where we are, uses the indent function (above) to indent each line +function showStep () + { + echo -e "${YELLOW}=====================================================" | indent + echo -e "${RESET}-----> $*" | indent + echo -e "${YELLOW}=====================================================${RESET}" | indent + } function printHelp () { @@ -19,7 +48,7 @@ function printHeader () { echo "" echo -e "${YELLOW}network deploy script for the Zero To Blockchain Series" | indent - echo -e "${GREEN}This has been tested on Mac OSX thru High Sierra and Ubuntu V16 LTS" | indent + echo -e "${RED}This has been successfully tested on OSX Sierra and Ubuntu 16.04" | indent echo -e "${YELLOW}This script will create your Composer archive" | indent echo "" } @@ -47,5 +76,16 @@ echo "Parameters:" echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "deploying network" +# original - V0.13 +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString +# +# what the documentation implies is required +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString +# +# what really works +composer identity request -p hlfv1 -i admin -s adminpw +composer identity import -p hlfv1 -u admin -c ~/.identityCredentials/admin-pub.pem -k ~/.identityCredentials/admin-priv.pem cd network/dist -composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString \ No newline at end of file +composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString diff --git a/Chapter10/network/package.json b/Chapter10/network/package.json index 6e58707..be89bc0 100644 --- a/Chapter10/network/package.json +++ b/Chapter10/network/package.json @@ -3,11 +3,12 @@ "composer": "" }, "name": "zerotoblockchain-network", - "version": "0.1.6", + "version": "0.1.5", "description": "Zero to Blockchain tutorial network", "networkImage": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimage.svg", "networkImageanimated": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimageanimated.svg", "scripts": { + "prepublish": "mkdirp ./network/dist && composer archive create --sourceType dir --sourceName . -a ./network/dist/zerotoblockchain-network.bna", "pretest": "npm run lint", "lint": "eslint ./network", "postlint": "npm run licchk", @@ -35,12 +36,11 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-admin": "", - "composer-cli": "", - "composer-client": "", - "composer-connector-embedded": "", - "composer-connector-hlf": "", - "composer-cucumber-steps": "", + "composer-admin": "^0.14.0", + "composer-cli": "^0.14.0", + "composer-client": "^0.14.0", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter10/package.json b/Chapter10/package.json index dfd50fe..1d086ff 100644 --- a/Chapter10/package.json +++ b/Chapter10/package.json @@ -37,13 +37,13 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-connector-embedded": "0.13.2", - "composer-cucumber-steps": "0.13.2", - "composer-admin": "0.13.2", - "composer-client": "0.13.2", - "composer-common": "0.13.2", - "composer-runtime": "0.13.2", - "composer-runtime-hlfv1": "0.13.2", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", + "composer-admin": "^0.14.0", + "composer-client": "^0.14.0", + "composer-common": "^0.14.0", + "composer-runtime": "^0.14.0", + "composer-runtime-hlfv1": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter10/start_rest_server.sh b/Chapter10/start_rest_server.sh index 4249418..61d94ed 100755 --- a/Chapter10/start_rest_server.sh +++ b/Chapter10/start_rest_server.sh @@ -77,4 +77,7 @@ echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "testing rest server \n when this completes, \n go to your favorite browser \n and enter localhost:3000/explorer " -composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# original (pre V0.14) +# composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# V0.14 +composer-rest-server -p hlfv1 -n zerotoblockchain-network -i admin -s adminPW diff --git a/Chapter11/Documentation/answers/js/z2b-events_complete.js b/Chapter11/Documentation/answers/js/z2b-events_complete.js index 13f1c7e..f0cfc7f 100644 --- a/Chapter11/Documentation/answers/js/z2b-events_complete.js +++ b/Chapter11/Documentation/answers/js/z2b-events_complete.js @@ -43,12 +43,11 @@ function singleUX () }); } } - /** * load all of the members in the network for use in the different user experiences. This is a synchronous routine and is executed autormatically on web app start. * However, if this is a newly created network, then there are no members to retrieve and this will create four empty arrays */ -function memberLoad() +function memberLoad () { var options = {}; options.registry = 'Seller'; @@ -61,7 +60,13 @@ function memberLoad() $.when($.post('/composer/admin/getMembers', options), $.post('/composer/admin/getMembers', options2), $.post('/composer/admin/getMembers', options3), $.post('/composer/admin/getMembers', options4)).done(function (_sellers, _buyers, _providers, _shippers) { - + buyers = _buyers[0].members; + sellers = _sellers[0].members; + s_string = _getMembers(sellers); + providers = _providers[0].members + p_string = _getMembers(providers); + shippers = _shippers[0].members + sh_string = _getMembers(shippers); }); } /** diff --git a/Chapter11/HTML/js/z2b-admin.js b/Chapter11/HTML/js/z2b-admin.js index 2fe8d5c..c716cb8 100644 --- a/Chapter11/HTML/js/z2b-admin.js +++ b/Chapter11/HTML/js/z2b-admin.js @@ -76,6 +76,7 @@ function displayProfileForm () $.when($.get(toLoad)).done(function (page) {$('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("createConnectionProfile"); var _cancel = $('#cancel'); var _submit = $('#submit'); _cancel.on('click', function (){$('#admin-forms').empty();}); @@ -154,6 +155,7 @@ function listProfiles(_state) { $('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("deleteConnectionProfile"); $('#connection_profiles').on('change',function() { var name = $('#connection_profiles').find(':selected').text(); var profile = connection_profiles[name]; @@ -449,6 +451,7 @@ function addMember() { $('#admin-forms').empty(); $('#admin-forms').append(_page); + updatePage("createMember"); var _cancel = $('#cancel'); var _submit = $('#submit'); $('#messages').empty(); @@ -481,6 +484,7 @@ function removeMember() { $('#admin-forms').append(_page[0]); $('#member_type').append(options.registry); + updatePage("removeMember"); member_list = _results[0].members; for (each in _results[0].members) {(function(_idx, _arr){ @@ -521,6 +525,7 @@ function getSecret() $.when($.post('/composer/admin/getMembers', options),$.get('getMemberSecret.html')).done(function (_results, _page) { $('#admin-forms').append(_page[0]); + updatePage("getMemberSecret"); $('#member_type').append(options.registry); member_list = _results[0].members; for (each in _results[0].members) diff --git a/Chapter11/HTML/js/z2b-buyer.js b/Chapter11/HTML/js/z2b-buyer.js index c5d61b0..409979a 100644 --- a/Chapter11/HTML/js/z2b-buyer.js +++ b/Chapter11/HTML/js/z2b-buyer.js @@ -87,7 +87,7 @@ $.when($.get(toLoad), $.get('/composer/client/getItemTable')).done(function (pag // update the page with the appropriate text for the selected language updatePage('createOrder'); $('#seller').empty(); - // populate the seller HTML select object. This string was built during the memberLoad or deferredMemberLoad function call + // populate the seller HTML select object. This string was built during the MemberLoad or deferredMemberLoad function call $('#seller').append(s_string); $('#seller').val($("#seller option:first").val()); $('#orderNo').append('xxx'); diff --git a/Chapter11/HTML/js/z2b-initiate.js b/Chapter11/HTML/js/z2b-initiate.js index 1734b57..290ef03 100644 --- a/Chapter11/HTML/js/z2b-initiate.js +++ b/Chapter11/HTML/js/z2b-initiate.js @@ -47,7 +47,7 @@ var orderStatus = { // goMultiLingual() establishes what languages are available for this web app, populates the header with available languages and sets the default language to US_English goMultiLingual("US_English", "index"); // singleUX loads the members already present in the network - loadMembers(); + memberLoad(); // goChainEvents creates a web socket connection with the server and initiates blockchain event monitoring getChainEvents(); } diff --git a/Chapter11/controller/restapi/features/composer/creds/admin-priv.pem b/Chapter11/controller/restapi/features/composer/creds/admin-priv.pem new file mode 100644 index 0000000..11b9fd4 --- /dev/null +++ b/Chapter11/controller/restapi/features/composer/creds/admin-priv.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg00IwLLBKoi/9ikb6 +ZOAV0S1XeNGWllvlFDeczRKQn2uhRANCAARrvCsQUNRpMUkzFaC7+zV4mClo+beg +4VkUyQR5y5Fle5UVH2GigChWnUoouTO2e2acA/DUuyLDHT0emeBMhoMC +-----END PRIVATE KEY----- diff --git a/Chapter11/controller/restapi/features/composer/creds/admin-pub.pem b/Chapter11/controller/restapi/features/composer/creds/admin-pub.pem new file mode 100644 index 0000000..8c2855f --- /dev/null +++ b/Chapter11/controller/restapi/features/composer/creds/admin-pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEa7wrEFDUaTFJMxWgu/s1eJgpaPm3 +oOFZFMkEecuRZXuVFR9hooAoVp1KKLkztntmnAPw1Lsiwx09HpngTIaDAg== +-----END PUBLIC KEY----- diff --git a/Chapter11/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem b/Chapter11/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem similarity index 100% rename from Chapter11/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem rename to Chapter11/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem diff --git a/Chapter11/controller/restapi/features/composer/hlcAdmin.js b/Chapter11/controller/restapi/features/composer/hlcAdmin.js index 3ff2256..7190361 100644 --- a/Chapter11/controller/restapi/features/composer/hlcAdmin.js +++ b/Chapter11/controller/restapi/features/composer/hlcAdmin.js @@ -56,7 +56,7 @@ exports.adminNew = function() { */ exports.adminConnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ console.log('create connection successful '); res.send({connection: 'succeeded'}); @@ -91,7 +91,7 @@ exports.createProfile = function(req, res, next) { peers: [{eventURL: req.body.peers.eventURL, requestURL: req.body.peers.requestRUL}] }; let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.createProfile(req.body.profileName, adminOptions) .then(function(result){ @@ -115,7 +115,7 @@ exports.createProfile = function(req, res, next) { */ exports.deleteProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deleteProfile(req.body.profileName) .then(function(result){ @@ -146,7 +146,7 @@ exports.deploy = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deploy(archive) .then(function(){ @@ -177,7 +177,7 @@ exports.networkInstall = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); return BusinessNetworkDefinition.fromArchive(archiveFile) .then((businessNetworkDefinition) => { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { return adminConnection.install(businessNetworkDefinition.getName()) .then(() => { @@ -213,7 +213,7 @@ exports.networkStart = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.start(archive) .then(function(){ @@ -238,7 +238,7 @@ exports.networkStart = function(req, res, next) { */ exports.disconnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.disconnect() .then(function(result){ @@ -261,7 +261,7 @@ exports.disconnect = function(req, res, next) { */ exports.getAllProfiles = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getAllProfiles() .then((profiles) => { @@ -284,7 +284,7 @@ exports.getAllProfiles = function(req, res, next) { */ exports.getProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getProfile(req.body.connectionProfile) .then((profile) => { @@ -308,7 +308,7 @@ exports.getProfile = function(req, res, next) { exports.listAsAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); util.displayObjectValuesRecursive(adminConnection); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -335,7 +335,7 @@ exports.listAsAdmin = function(req, res, next) { */ exports.listAsPeerAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.peerAdmin, config.composer.secret) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -362,7 +362,7 @@ exports.listAsPeerAdmin = function(req, res, next) { */ exports.ping = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.ping() .then(function(result){ @@ -387,7 +387,7 @@ exports.ping = function(req, res, next) { */ exports.undeploy = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.undeploy(req.body.businessNetwork) .then(function(result){ @@ -419,7 +419,7 @@ exports.update = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, netName) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, netName) .then(function(){ adminConnection.update(archive) .then(function(){ @@ -451,10 +451,10 @@ exports.getRegistries = function(req, res, next) let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getAllParticipantRegistries() .then(function(participantRegistries){ @@ -488,10 +488,10 @@ exports.getMembers = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) .then(function(registry){ @@ -526,13 +526,17 @@ exports.getMembers = function(req, res, next) { } res.send({'result': 'success', 'members': allMembers}); }) - .catch((error) => {console.log('error with getAllMembers', error)}); + .catch((error) => {console.log('error with getAllMembers', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with getRegistry', error)}); + .catch((error) => {console.log('error with getRegistry', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with business network Connect', error)}); + .catch((error) => {console.log('error with business network Connect', error.message); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with admin network Connect', error)}); + .catch((error) => {console.log('error with admin network Connect', error); + res.send({'result': 'failed '+error.message, 'members': []});}); } @@ -554,10 +558,10 @@ exports.getAssets = function(req, res, next) { let factory; let serializer; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { // let bnd = new BusinessNetworkDefinition(config.composer.network+'@0.1.6', config.composer.description, packageJSON); // retry this with fromArchive when time allows @@ -640,10 +644,10 @@ exports.addMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.type) @@ -680,10 +684,10 @@ exports.removeMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) @@ -725,10 +729,10 @@ exports.getHistory = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then((bnd) => { ser = bnd.getSerializer(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getRegistry('org.hyperledger.composer.system.HistorianRecord') .then(function(registry){ diff --git a/Chapter11/controller/restapi/features/composer/queryBlockChain.js b/Chapter11/controller/restapi/features/composer/queryBlockChain.js index 4a61c7d..a0b0b57 100644 --- a/Chapter11/controller/restapi/features/composer/queryBlockChain.js +++ b/Chapter11/controller/restapi/features/composer/queryBlockChain.js @@ -58,6 +58,7 @@ exports.getChainInfo = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -103,6 +104,7 @@ exports.getChainEvents = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -110,7 +112,8 @@ exports.getChainEvents = function(req, res, next) { channel = client.newChannel(config.fabric.channelName); channel.addPeer(client.newPeer(config.fabric.peerRequestURL)); channel.addOrderer(client.newOrderer(config.fabric.ordererURL)); - var pemPath = path.join(__dirname,'creds','Admin@org1.example.com-cert.pem'); + // change Admin in following line to admin + var pemPath = path.join(__dirname,'creds','admin@org.hyperledger.composer.system-cert.pem'); var adminPEM = fs.readFileSync(pemPath); var bcEvents = new hfcEH(client); bcEvents.setPeerAddr(config.fabric.peerEventURL, {pem: adminPEM}); diff --git a/Chapter11/deployNetwork.sh b/Chapter11/deployNetwork.sh index 78943ff..9c13a36 100755 --- a/Chapter11/deployNetwork.sh +++ b/Chapter11/deployNetwork.sh @@ -1,6 +1,35 @@ #!/bin/bash -. ../common_OSX.sh + YELLOW='\033[1;33m' + RED='\033[1;31m' + GREEN='\033[1;32m' + RESET='\033[0m' + +# indent text on echo +function indent() { + c='s/^/ /' + case $(uname) in + Darwin) sed -l "$c";; + *) sed -u "$c";; + esac +} + +# Grab the current directory +function getCurrent() + { + showStep "getting current directory" + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + THIS_SCRIPT=`basename "$0"` + showStep "Running '${THIS_SCRIPT}'" + } + +# displays where we are, uses the indent function (above) to indent each line +function showStep () + { + echo -e "${YELLOW}=====================================================" | indent + echo -e "${RESET}-----> $*" | indent + echo -e "${YELLOW}=====================================================${RESET}" | indent + } function printHelp () { @@ -19,7 +48,7 @@ function printHeader () { echo "" echo -e "${YELLOW}network deploy script for the Zero To Blockchain Series" | indent - echo -e "${GREEN}This has been tested on Mac OSX thru High Sierra and Ubuntu V16 LTS" | indent + echo -e "${RED}This has been successfully tested on OSX Sierra and Ubuntu 16.04" | indent echo -e "${YELLOW}This script will create your Composer archive" | indent echo "" } @@ -47,5 +76,16 @@ echo "Parameters:" echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "deploying network" +# original - V0.13 +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString +# +# what the documentation implies is required +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString +# +# what really works +composer identity request -p hlfv1 -i admin -s adminpw +composer identity import -p hlfv1 -u admin -c ~/.identityCredentials/admin-pub.pem -k ~/.identityCredentials/admin-priv.pem cd network/dist -composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString \ No newline at end of file +composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString diff --git a/Chapter11/network/package.json b/Chapter11/network/package.json index 6e58707..be89bc0 100644 --- a/Chapter11/network/package.json +++ b/Chapter11/network/package.json @@ -3,11 +3,12 @@ "composer": "" }, "name": "zerotoblockchain-network", - "version": "0.1.6", + "version": "0.1.5", "description": "Zero to Blockchain tutorial network", "networkImage": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimage.svg", "networkImageanimated": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimageanimated.svg", "scripts": { + "prepublish": "mkdirp ./network/dist && composer archive create --sourceType dir --sourceName . -a ./network/dist/zerotoblockchain-network.bna", "pretest": "npm run lint", "lint": "eslint ./network", "postlint": "npm run licchk", @@ -35,12 +36,11 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-admin": "", - "composer-cli": "", - "composer-client": "", - "composer-connector-embedded": "", - "composer-connector-hlf": "", - "composer-cucumber-steps": "", + "composer-admin": "^0.14.0", + "composer-cli": "^0.14.0", + "composer-client": "^0.14.0", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter11/network/permissions.acl b/Chapter11/network/permissions.acl index 0a57f6a..1457cc5 100644 --- a/Chapter11/network/permissions.acl +++ b/Chapter11/network/permissions.acl @@ -8,8 +8,11 @@ rule AllAccess { action: ALLOW } */ + /** -* added to support composer V0.14 +* Added to support V0.14 breaking changes +* +*/ rule NetworkAdminUser { description: "Grant business network administrators full access to user resources" participant: "org.hyperledger.composer.system.NetworkAdmin" @@ -17,9 +20,7 @@ rule NetworkAdminUser { resource: "**" action: ALLOW } -*/ -/** -* added to support composer V0.14 + rule NetworkAdminSystem { description: "Grant business network administrators full access to system resources" participant: "org.hyperledger.composer.system.NetworkAdmin" @@ -27,7 +28,10 @@ rule NetworkAdminSystem { resource: "org.hyperledger.composer.system.**" action: ALLOW } +/** +* end of V0.14 additions */ + /** * **/ diff --git a/Chapter11/package.json b/Chapter11/package.json index dfd50fe..1d086ff 100644 --- a/Chapter11/package.json +++ b/Chapter11/package.json @@ -37,13 +37,13 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-connector-embedded": "0.13.2", - "composer-cucumber-steps": "0.13.2", - "composer-admin": "0.13.2", - "composer-client": "0.13.2", - "composer-common": "0.13.2", - "composer-runtime": "0.13.2", - "composer-runtime-hlfv1": "0.13.2", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", + "composer-admin": "^0.14.0", + "composer-client": "^0.14.0", + "composer-common": "^0.14.0", + "composer-runtime": "^0.14.0", + "composer-runtime-hlfv1": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter11/start_rest_server.sh b/Chapter11/start_rest_server.sh index 4249418..61d94ed 100755 --- a/Chapter11/start_rest_server.sh +++ b/Chapter11/start_rest_server.sh @@ -77,4 +77,7 @@ echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "testing rest server \n when this completes, \n go to your favorite browser \n and enter localhost:3000/explorer " -composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# original (pre V0.14) +# composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# V0.14 +composer-rest-server -p hlfv1 -n zerotoblockchain-network -i admin -s adminPW diff --git a/Chapter12/Documentation/answers/CSS/pageStyles_complete.css b/Chapter12/Documentation/answers/CSS/pageStyles_complete.css index 3058288..3bc804f 100755 --- a/Chapter12/Documentation/answers/CSS/pageStyles_complete.css +++ b/Chapter12/Documentation/answers/CSS/pageStyles_complete.css @@ -18,7 +18,7 @@ body {height: 100%} overflow: auto; } .button-wide { - width: 30%; + width: 15%; color: blue; font-size: 1em; text-align: center; diff --git a/Chapter12/Documentation/answers/HTML/buyer_complete.html b/Chapter12/Documentation/answers/HTML/buyer_complete.html index 34b35c9..8e9b8aa 100644 --- a/Chapter12/Documentation/answers/HTML/buyer_complete.html +++ b/Chapter12/Documentation/answers/HTML/buyer_complete.html @@ -1,10 +1,10 @@

- -
1
-
-
-
-
-
-
+ +
1
+
+
+
+
+
+
diff --git a/Chapter12/Documentation/answers/HTML/financeCo_complete.html b/Chapter12/Documentation/answers/HTML/financeCo_complete.html index 4003b2a..0a8834b 100644 --- a/Chapter12/Documentation/answers/HTML/financeCo_complete.html +++ b/Chapter12/Documentation/answers/HTML/financeCo_complete.html @@ -1,10 +1,10 @@

-
1
-
-
-
-
-
-
-
+
1
+
+
+
+
+
+
+
diff --git a/Chapter12/Documentation/answers/composer/hlcClient_complete.js b/Chapter12/Documentation/answers/composer/hlcClient_complete.js index e3efe47..dcce523 100644 --- a/Chapter12/Documentation/answers/composer/hlcClient_complete.js +++ b/Chapter12/Documentation/answers/composer/hlcClient_complete.js @@ -364,25 +364,18 @@ exports.addOrder = function (req, res, next) { exports.init_z2bEvents = function (req, res, next) { var method = 'init_z2bEvents'; - // check to see if we're already registered. Don't want to overload the system with duplicate event monitoring if (bRegistered) {res.send('Already Registered');} else{ bRegistered = true; - // create an alert socket using the capability in Z2B_Services let _conn = svc.createAlertSocket(); - // create a new business network connection let businessNetworkConnection; businessNetworkConnection = new BusinessNetworkConnection(); businessNetworkConnection.setMaxListeners(50); - // connect to the business network using the data and admin id and password from the env.json file return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { - // monitor for events and call the _monitor function when an event is received businessNetworkConnection.on('event', (event) => {_monitor(svc.al_connection, svc.f_connection, event); }); - // we're only listening for 1 event. Send a message back to the browser on success. res.send('event registration complete'); }).catch((error) => { - // if the monitor request failed, log it and send a failed message back to the browser console.log(method+' business network connection failed'+error.message); res.send(method+' business network connection failed'+error.message); }); @@ -395,26 +388,20 @@ exports.init_z2bEvents = function (req, res, next) */ function _monitor(_conn, _f_conn, _event) { - // let's log each received event var method = '_monitor'; console.log(method+ ' _event received: '+_event.$type+' for Order: '+_event.orderID); - // create an event object and populate it with everything needed for an Order Creation event - // hint, look in the sample.cto and sample.js files to know what to use here. var event = {}; event.type = _event.$type; event.orderID = _event.orderID; event.ID = _event.buyerID; + _conn.sendUTF(JSON.stringify(event)); switch (_event.$type) { case 'Created': - // send an event back to the browser - _conn.sendUTF(JSON.stringify(event)); break; case 'Bought': case 'PaymentRequested': - // these events send notifications to the same users - // the finance ID uses a different connector, so that you can open it in a different window and still receive alerts. event.ID = _event.sellerID; _conn.sendUTF(JSON.stringify(event)); event.ID = _event.financeCoID; @@ -423,7 +410,6 @@ function _monitor(_conn, _f_conn, _event) case 'Ordered': case 'Cancelled': case 'Backordered': - // these events send notifications to the same users event.ID = _event.sellerID; _conn.sendUTF(JSON.stringify(event)); event.ID = _event.providerID; @@ -432,7 +418,6 @@ function _monitor(_conn, _f_conn, _event) case 'ShipRequest': case 'DeliveryStarted': case 'DeliveryCompleted': - // these events send notifications to the same users event.ID = _event.sellerID; _conn.sendUTF(JSON.stringify(event)); event.ID = _event.providerID; @@ -444,8 +429,6 @@ function _monitor(_conn, _f_conn, _event) case 'Resolved': case 'Refunded': case 'Paid': - // these events send notifications to the same users - // the finance ID uses a different connector, so that you can open it in a different window and still receive alerts. event.ID = _event.sellerID; _conn.sendUTF(JSON.stringify(event)); event.ID = _event.providerID; @@ -456,8 +439,6 @@ function _monitor(_conn, _f_conn, _event) _f_conn.sendUTF(JSON.stringify(event)); break; case 'PaymentAuthorized': - // these events send notifications to the same users - // the finance ID uses a different connector, so that you can open it in a different window and still receive alerts. event.ID = _event.sellerID; _conn.sendUTF(JSON.stringify(event)); event.ID = _event.financeCoID; diff --git a/Chapter12/Documentation/answers/js/z2b-buyer_complete.js b/Chapter12/Documentation/answers/js/z2b-buyer_complete.js index fba9d54..220fe89 100644 --- a/Chapter12/Documentation/answers/js/z2b-buyer_complete.js +++ b/Chapter12/Documentation/answers/js/z2b-buyer_complete.js @@ -18,8 +18,6 @@ var orderDiv = "orderDiv"; var itemTable = {}; var newItems = []; var totalAmount = 0; - -// create vars for the buyer to use for the notification process var b_notify = '#buyer_notify'; var b_count = '#buyer_count'; var b_id = ''; @@ -53,8 +51,6 @@ function setupBuyer(page, port) // empty the hetml element that will hold this page $("#buyerbody").empty(); $("#buyerbody").append(page); - - //set the alerts file to an empty array and update the html class appropriately b_alerts = []; if (b_alerts.length == 0) {$(b_notify).removeClass('on'); $(b_notify).addClass('off'); } @@ -78,19 +74,14 @@ function setupBuyer(page, port) })(each, buyers)} // display the name of the current buyer $("#company")[0].innerText = buyers[0].companyName; - // update the buyer id field b_id = buyers[0].id; - // subscribe to events z2bSubscribe('Buyer', b_id); // create a function to execute when the user selects a different buyer $("#buyer").on('change', function() { _orderDiv.empty(); $("#buyer_messages").empty(); $("#company")[0].innerText = findMember($("#buyer").find(":selected").text(),buyers).companyName; - // unsubscribe the current member z2bUnSubscribe(b_id); - // update the buyer id field b_id = findMember($("#buyer").find(":selected").text(),buyers).id; - // subscribe to events z2bSubscribe('Buyer', b_id); }); @@ -316,7 +307,6 @@ function formatOrders(_target, _orders) $.when($.post('/composer/client/orderAction', options)).done(function (_results) { $("#buyer_messages").prepend(formatMessage(_results.result)); }); }); - // using the notifyMe function in the events.js file, update the b_status+_idx HTML element appropriately if (notifyMe(b_alerts, _arr[_idx].id)) {$("#b_status"+_idx).addClass('highlight'); } })(each, _orders) } diff --git a/Chapter12/Documentation/answers/js/z2b-events_complete.js b/Chapter12/Documentation/answers/js/z2b-events_complete.js index 4a0542b..be2c0d1 100644 --- a/Chapter12/Documentation/answers/js/z2b-events_complete.js +++ b/Chapter12/Documentation/answers/js/z2b-events_complete.js @@ -149,7 +149,6 @@ function getAlertPort () wsSocket.onmessage = function (message) { console.log(message.data); var event = JSON.parse(message.data); - // use the addNotification routine in this file to update the alert status for the relevant subscriber addNotification(event.type, event.ID, event.orderID); }; @@ -172,7 +171,6 @@ function getFinanceAlertPort () wsSocket.onmessage = function (message) { console.log(message.data); var event = JSON.parse(message.data); - // use the addNotification routine in this file to update the alert status for the relevant subscriber addNotification(event.type, event.ID, event.orderID); }; @@ -185,16 +183,10 @@ function getFinanceAlertPort () */ function addNotification(_event, _id, _orderID) { - // let's display each received event var method = 'showNotification'; console.log(method+' _event'+_event+' id: '+_id+' orderID: '+_orderID); - // using the getSubscriber routine, find the class of this event type = getSubscriber(_id) - // if no one of the specified type is listening, just return with a value of 'none' if (type == 'none') {return} - // create a switch/case statement for each type of member - // update the x_alerts array with the new alert - // call the toggleAlert routine to update the alert icon switch(type) { case 'Buyer': @@ -227,12 +219,11 @@ function addNotification(_event, _id, _orderID) */ function toggleAlert(_target, _array, _count) { - // if there aren't any elements in the array, then hide the alert icon if (_array.length < 1) {$(_target).removeClass('on'); $(_target).addClass('off'); } - // if the alert array has anything in it, then show the alert icon and update the count with the number of items in the alert array else {$(_count).empty(); $(_count).append(_array.length); $(_target).removeClass('off'); $(_target).addClass('on'); } + } /** * check to see if _id is subscribing @@ -240,7 +231,6 @@ function toggleAlert(_target, _array, _count) function getSubscriber(_id) { var type = 'none'; - // get the member type from the subscriber array. if the member is not not found, return 'none' for (each in subscribers){(function(_idx, _arr){if (_arr[_idx].id == _id){type=_arr[_idx].type;}})(each, subscribers)} return(type); } @@ -251,7 +241,6 @@ function getSubscriber(_id) */ function z2bSubscribe(_type, _id) { - // update the subscriber array with the provided id and type. subscribers.push({'type': _type, 'id': _id}); } /** @@ -261,7 +250,6 @@ function z2bSubscribe(_type, _id) */ function z2bUnSubscribe(_id) { - // remove the provided id from the member array. If the id is not found, the subscriber array is returned in the original state. var _s1 = subscribers; var _s2 = []; for (each in _s1) {(function(_idx, _arr){if (_arr[_idx] != _id){_s2.push(_arr[_idx])}})(each, _s1)} @@ -273,7 +261,6 @@ function z2bUnSubscribe(_id) */ function notifyMe (_alerts, _id) { - // check to see if the provided orderID is in the provided alert array. If so, return true, else return false. var b_h = false; for (each in _alerts) {(function(_idx, _arr){if (_id === _arr[_idx].order){b_h = true;}})(each, _alerts)} return b_h; diff --git a/Chapter12/Documentation/answers/js/z2b-financeCo_complete.js b/Chapter12/Documentation/answers/js/z2b-financeCo_complete.js index 1803f55..46d0728 100644 --- a/Chapter12/Documentation/answers/js/z2b-financeCo_complete.js +++ b/Chapter12/Documentation/answers/js/z2b-financeCo_complete.js @@ -60,7 +60,6 @@ function setupFinanceCo(page, port) var _orderDiv = $("#"+financeCOorderDiv); _clear.on('click', function(){_orderDiv.empty();}); _list.on('click', function(){listFinanceOrders()}); - //set the alerts file to an empty array and update the html class appropriately z2bSubscribe('FinanceCo', f_id); } /** @@ -173,7 +172,6 @@ function formatFinanceOrders(_target, _orders) $("#finance_messages").prepend(formatMessage(_results.result)); }); }); - // using the notifyMe function in the events.js file, update the b_status+_idx HTML element appropriately if (notifyMe(f_alerts, _arr[_idx].id)) {$("#f_status"+_idx).addClass('highlight'); } })(each, _orders) } diff --git a/Chapter12/Documentation/answers/network/lib/sample_complete.js b/Chapter12/Documentation/answers/network/lib/sample_complete.js index 88c1755..c9ff3b3 100644 --- a/Chapter12/Documentation/answers/network/lib/sample_complete.js +++ b/Chapter12/Documentation/answers/network/lib/sample_complete.js @@ -347,11 +347,8 @@ function displayObjectValues (_string, _object) function z2bEmit(_event, _order) { var method = 'z2bEmit'; - // get the factory var factory = getFactory(); - // create a new event var z2bEvent = factory.newEvent(ns, _event); - // update the event with the order ID and the buyerID z2bEvent.orderID = _order.$identifier; z2bEvent.buyerID = _order.buyer.$identifier; switch (_event) @@ -361,7 +358,6 @@ function z2bEmit(_event, _order) break; case 'Bought': case 'PaymentRequested': - // these events have the same members z2bEvent.sellerID = _order.seller.$identifier; z2bEvent.financeCoID = _order.financeCo.$identifier; break; @@ -374,7 +370,6 @@ function z2bEmit(_event, _order) case 'ShipRequest': case 'DeliveryStarted': case 'DeliveryCompleted': - // these events have the same members z2bEvent.sellerID = _order.seller.$identifier; z2bEvent.providerID = _order.provider.$identifier; z2bEvent.shipperID = _order.shipper.$identifier; @@ -383,21 +378,18 @@ function z2bEmit(_event, _order) case 'Resolved': case 'Refunded': case 'Paid': - // these events have the same members z2bEvent.sellerID = _order.seller.$identifier; z2bEvent.providerID = _order.provider.$identifier; z2bEvent.shipperID = _order.shipper.$identifier; z2bEvent.financeCoID = _order.financeCo.$identifier; break; case 'PaymentAuthorized': - // these events have the same members z2bEvent.sellerID = _order.seller.$identifier; z2bEvent.financeCoID = _order.financeCo.$identifier; break; default: break; } - // emit the populated event emit(z2bEvent); return } \ No newline at end of file diff --git a/Chapter12/HTML/js/z2b-admin.js b/Chapter12/HTML/js/z2b-admin.js index af748d9..c716cb8 100644 --- a/Chapter12/HTML/js/z2b-admin.js +++ b/Chapter12/HTML/js/z2b-admin.js @@ -19,6 +19,7 @@ var connection; var connectionProfileName = 'z2b-test-profile'; var networkFile = 'zerotoblockchain-network.bna' var businessNetwork = 'zerotoblockchain-network'; +var msgPort = null; var _blctr = 0; /** @@ -75,6 +76,7 @@ function displayProfileForm () $.when($.get(toLoad)).done(function (page) {$('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("createConnectionProfile"); var _cancel = $('#cancel'); var _submit = $('#submit'); _cancel.on('click', function (){$('#admin-forms').empty();}); @@ -153,6 +155,7 @@ function listProfiles(_state) { $('#admin-forms').empty(); $('#admin-forms').append(page); + updatePage("deleteConnectionProfile"); $('#connection_profiles').on('change',function() { var name = $('#connection_profiles').find(':selected').text(); var profile = connection_profiles[name]; @@ -448,6 +451,7 @@ function addMember() { $('#admin-forms').empty(); $('#admin-forms').append(_page); + updatePage("createMember"); var _cancel = $('#cancel'); var _submit = $('#submit'); $('#messages').empty(); @@ -480,6 +484,7 @@ function removeMember() { $('#admin-forms').append(_page[0]); $('#member_type').append(options.registry); + updatePage("removeMember"); member_list = _results[0].members; for (each in _results[0].members) {(function(_idx, _arr){ @@ -520,6 +525,7 @@ function getSecret() $.when($.post('/composer/admin/getMembers', options),$.get('getMemberSecret.html')).done(function (_results, _page) { $('#admin-forms').append(_page[0]); + updatePage("getMemberSecret"); $('#member_type').append(options.registry); member_list = _results[0].members; for (each in _results[0].members) diff --git a/Chapter12/controller/restapi/features/composer/autoLoad.js b/Chapter12/controller/restapi/features/composer/autoLoad.js index 5401b0a..dc905ad 100644 --- a/Chapter12/controller/restapi/features/composer/autoLoad.js +++ b/Chapter12/controller/restapi/features/composer/autoLoad.js @@ -108,7 +108,6 @@ exports.getFinanceAlertPort = function(req, res, next) { */ exports.autoLoad = function(req, res, next) { // get the autoload file - var method = 'autoLoad'; let newFile = path.join(path.dirname(require.main.filename),'startup','memberList.json'); let startupFile = JSON.parse(fs.readFileSync(newFile)); // connect to the network @@ -122,7 +121,6 @@ exports.autoLoad = function(req, res, next) { .then(() => { // a businessNetworkConnection is required to add members businessNetworkConnection = new BusinessNetworkConnection(); - businessNetworkConnection.setMaxListeners(50); return businessNetworkConnection.connect(config.composer.connectionProfile, network, config.composer.adminID, config.composer.adminPW) .then(() => { // a factory is required to build the member object @@ -208,8 +206,6 @@ exports.autoLoad = function(req, res, next) { createNew.seller = factory.newRelationship(NS, 'Seller', _arr[_idx].seller); createNew.amount = order.amount; // then the order is added to the asset registry. - svc.addOrder(svc.m_connection, order, assetRegistry, createNew, businessNetworkConnection); - /* return assetRegistry.add(order) .then(() => { // then a createOrder transaction is processed which uses the chaincode @@ -226,7 +222,6 @@ exports.autoLoad = function(req, res, next) { } else {console.log('error with assetRegistry.add', error.message)} }); - */ }); }) .catch((error) => {console.log('error with getParticipantRegistry', error.message)}); diff --git a/Chapter12/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem b/Chapter12/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem deleted file mode 100644 index 3adfdfc..0000000 --- a/Chapter12/controller/restapi/features/composer/creds/Admin@org1.example.com-cert.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICGjCCAcCgAwIBAgIRANuOnVN+yd/BGyoX7ioEklQwCgYIKoZIzj0EAwIwczEL -MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG -cmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh -Lm9yZzEuZXhhbXBsZS5jb20wHhcNMTcwNjI2MTI0OTI2WhcNMjcwNjI0MTI0OTI2 -WjBbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN -U2FuIEZyYW5jaXNjbzEfMB0GA1UEAwwWQWRtaW5Ab3JnMS5leGFtcGxlLmNvbTBZ -MBMGByqGSM49AgEGCCqGSM49AwEHA0IABGu8KxBQ1GkxSTMVoLv7NXiYKWj5t6Dh -WRTJBHnLkWV7lRUfYaKAKFadSii5M7Z7ZpwD8NS7IsMdPR6Z4EyGgwKjTTBLMA4G -A1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIBmrZau7BIB9 -rRLkwKmqpmSecIaOOr0CF6Mi2J5H4aauMAoGCCqGSM49BAMCA0gAMEUCIQC4sKQ6 -CEgqbTYe48az95W9/hnZ+7DI5eSnWUwV9vCd/gIgS5K6omNJydoFoEpaEIwM97uS -XVMHPa0iyC497vdNURA= ------END CERTIFICATE----- diff --git a/Chapter12/controller/restapi/features/composer/creds/PeerAdmin-cert.pem b/Chapter12/controller/restapi/features/composer/creds/PeerAdmin-cert.pem deleted file mode 100644 index 3adfdfc..0000000 --- a/Chapter12/controller/restapi/features/composer/creds/PeerAdmin-cert.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICGjCCAcCgAwIBAgIRANuOnVN+yd/BGyoX7ioEklQwCgYIKoZIzj0EAwIwczEL -MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG -cmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh -Lm9yZzEuZXhhbXBsZS5jb20wHhcNMTcwNjI2MTI0OTI2WhcNMjcwNjI0MTI0OTI2 -WjBbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN -U2FuIEZyYW5jaXNjbzEfMB0GA1UEAwwWQWRtaW5Ab3JnMS5leGFtcGxlLmNvbTBZ -MBMGByqGSM49AgEGCCqGSM49AwEHA0IABGu8KxBQ1GkxSTMVoLv7NXiYKWj5t6Dh -WRTJBHnLkWV7lRUfYaKAKFadSii5M7Z7ZpwD8NS7IsMdPR6Z4EyGgwKjTTBLMA4G -A1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIBmrZau7BIB9 -rRLkwKmqpmSecIaOOr0CF6Mi2J5H4aauMAoGCCqGSM49BAMCA0gAMEUCIQC4sKQ6 -CEgqbTYe48az95W9/hnZ+7DI5eSnWUwV9vCd/gIgS5K6omNJydoFoEpaEIwM97uS -XVMHPa0iyC497vdNURA= ------END CERTIFICATE----- diff --git a/Chapter12/controller/restapi/features/composer/creds/admin-priv.pem b/Chapter12/controller/restapi/features/composer/creds/admin-priv.pem new file mode 100644 index 0000000..11b9fd4 --- /dev/null +++ b/Chapter12/controller/restapi/features/composer/creds/admin-priv.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg00IwLLBKoi/9ikb6 +ZOAV0S1XeNGWllvlFDeczRKQn2uhRANCAARrvCsQUNRpMUkzFaC7+zV4mClo+beg +4VkUyQR5y5Fle5UVH2GigChWnUoouTO2e2acA/DUuyLDHT0emeBMhoMC +-----END PRIVATE KEY----- diff --git a/Chapter12/controller/restapi/features/composer/creds/admin-pub.pem b/Chapter12/controller/restapi/features/composer/creds/admin-pub.pem new file mode 100644 index 0000000..8c2855f --- /dev/null +++ b/Chapter12/controller/restapi/features/composer/creds/admin-pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEa7wrEFDUaTFJMxWgu/s1eJgpaPm3 +oOFZFMkEecuRZXuVFR9hooAoVp1KKLkztntmnAPw1Lsiwx09HpngTIaDAg== +-----END PUBLIC KEY----- diff --git a/Chapter11/controller/restapi/features/composer/creds/PeerAdmin-cert.pem b/Chapter12/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem similarity index 100% rename from Chapter11/controller/restapi/features/composer/creds/PeerAdmin-cert.pem rename to Chapter12/controller/restapi/features/composer/creds/admin@org.hyperledger.composer.system-cert.pem diff --git a/Chapter12/controller/restapi/features/composer/hlcAdmin.js b/Chapter12/controller/restapi/features/composer/hlcAdmin.js index 3ff2256..7190361 100644 --- a/Chapter12/controller/restapi/features/composer/hlcAdmin.js +++ b/Chapter12/controller/restapi/features/composer/hlcAdmin.js @@ -56,7 +56,7 @@ exports.adminNew = function() { */ exports.adminConnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ console.log('create connection successful '); res.send({connection: 'succeeded'}); @@ -91,7 +91,7 @@ exports.createProfile = function(req, res, next) { peers: [{eventURL: req.body.peers.eventURL, requestURL: req.body.peers.requestRUL}] }; let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.createProfile(req.body.profileName, adminOptions) .then(function(result){ @@ -115,7 +115,7 @@ exports.createProfile = function(req, res, next) { */ exports.deleteProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deleteProfile(req.body.profileName) .then(function(result){ @@ -146,7 +146,7 @@ exports.deploy = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.deploy(archive) .then(function(){ @@ -177,7 +177,7 @@ exports.networkInstall = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); return BusinessNetworkDefinition.fromArchive(archiveFile) .then((businessNetworkDefinition) => { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { return adminConnection.install(businessNetworkDefinition.getName()) .then(() => { @@ -213,7 +213,7 @@ exports.networkStart = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.start(archive) .then(function(){ @@ -238,7 +238,7 @@ exports.networkStart = function(req, res, next) { */ exports.disconnect = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.disconnect() .then(function(result){ @@ -261,7 +261,7 @@ exports.disconnect = function(req, res, next) { */ exports.getAllProfiles = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getAllProfiles() .then((profiles) => { @@ -284,7 +284,7 @@ exports.getAllProfiles = function(req, res, next) { */ exports.getProfile = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.getProfile(req.body.connectionProfile) .then((profile) => { @@ -308,7 +308,7 @@ exports.getProfile = function(req, res, next) { exports.listAsAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); util.displayObjectValuesRecursive(adminConnection); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -335,7 +335,7 @@ exports.listAsAdmin = function(req, res, next) { */ exports.listAsPeerAdmin = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.peerAdmin, config.composer.secret) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(function(){ adminConnection.list() .then((businessNetworks) => { @@ -362,7 +362,7 @@ exports.listAsPeerAdmin = function(req, res, next) { */ exports.ping = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.ping() .then(function(result){ @@ -387,7 +387,7 @@ exports.ping = function(req, res, next) { */ exports.undeploy = function(req, res, next) { let adminConnection = new composerAdmin.AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, req.body.businessNetwork) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, req.body.businessNetwork) .then(function(){ adminConnection.undeploy(req.body.businessNetwork) .then(function(result){ @@ -419,7 +419,7 @@ exports.update = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then(function(archive) { - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW, netName) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW, netName) .then(function(){ adminConnection.update(archive) .then(function(){ @@ -451,10 +451,10 @@ exports.getRegistries = function(req, res, next) let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getAllParticipantRegistries() .then(function(participantRegistries){ @@ -488,10 +488,10 @@ exports.getMembers = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) .then(function(registry){ @@ -526,13 +526,17 @@ exports.getMembers = function(req, res, next) { } res.send({'result': 'success', 'members': allMembers}); }) - .catch((error) => {console.log('error with getAllMembers', error)}); + .catch((error) => {console.log('error with getAllMembers', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with getRegistry', error)}); + .catch((error) => {console.log('error with getRegistry', error); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with business network Connect', error)}); + .catch((error) => {console.log('error with business network Connect', error.message); + res.send({'result': 'failed '+error.message, 'members': []});}); }) - .catch((error) => {console.log('error with admin network Connect', error)}); + .catch((error) => {console.log('error with admin network Connect', error); + res.send({'result': 'failed '+error.message, 'members': []});}); } @@ -554,10 +558,10 @@ exports.getAssets = function(req, res, next) { let factory; let serializer; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { // let bnd = new BusinessNetworkDefinition(config.composer.network+'@0.1.6', config.composer.description, packageJSON); // retry this with fromArchive when time allows @@ -640,10 +644,10 @@ exports.addMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.type) @@ -680,10 +684,10 @@ exports.removeMember = function(req, res, next) { let businessNetworkConnection; let factory; let adminConnection = new AdminConnection(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { factory = businessNetworkConnection.getBusinessNetwork().getFactory(); return businessNetworkConnection.getParticipantRegistry(NS+'.'+req.body.registry) @@ -725,10 +729,10 @@ exports.getHistory = function(req, res, next) { return BusinessNetworkDefinition.fromArchive(archiveFile) .then((bnd) => { ser = bnd.getSerializer(); - adminConnection.connect(config.composer.connectionProfile, config.composer.PeerAdmin, config.composer.PeerPW) + adminConnection.connect(config.composer.connectionProfile, config.composer.adminID, config.composer.adminPW) .then(() => { businessNetworkConnection = new BusinessNetworkConnection(); - return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.PeerAdmin, config.composer.PeerPW) + return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW) .then(() => { return businessNetworkConnection.getRegistry('org.hyperledger.composer.system.HistorianRecord') .then(function(registry){ diff --git a/Chapter12/controller/restapi/features/composer/queryBlockChain.js b/Chapter12/controller/restapi/features/composer/queryBlockChain.js index 4a61c7d..a0b0b57 100644 --- a/Chapter12/controller/restapi/features/composer/queryBlockChain.js +++ b/Chapter12/controller/restapi/features/composer/queryBlockChain.js @@ -58,6 +58,7 @@ exports.getChainInfo = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -103,6 +104,7 @@ exports.getChainEvents = function(req, res, next) { return hfc.newDefaultKeyValueStore({ path: wallet_path }) .then((wallet) => { client.setStateStore(wallet); + // change PeerAdmin in following line to adminID return client.getUserContext(config.composer.PeerAdmin, true);}) .then((user) => { if (user === null || user === undefined || user.isEnrolled() === false) @@ -110,7 +112,8 @@ exports.getChainEvents = function(req, res, next) { channel = client.newChannel(config.fabric.channelName); channel.addPeer(client.newPeer(config.fabric.peerRequestURL)); channel.addOrderer(client.newOrderer(config.fabric.ordererURL)); - var pemPath = path.join(__dirname,'creds','Admin@org1.example.com-cert.pem'); + // change Admin in following line to admin + var pemPath = path.join(__dirname,'creds','admin@org.hyperledger.composer.system-cert.pem'); var adminPEM = fs.readFileSync(pemPath); var bcEvents = new hfcEH(client); bcEvents.setPeerAddr(config.fabric.peerEventURL, {pem: adminPEM}); diff --git a/Chapter12/deployNetwork.sh b/Chapter12/deployNetwork.sh index 78943ff..9c13a36 100755 --- a/Chapter12/deployNetwork.sh +++ b/Chapter12/deployNetwork.sh @@ -1,6 +1,35 @@ #!/bin/bash -. ../common_OSX.sh + YELLOW='\033[1;33m' + RED='\033[1;31m' + GREEN='\033[1;32m' + RESET='\033[0m' + +# indent text on echo +function indent() { + c='s/^/ /' + case $(uname) in + Darwin) sed -l "$c";; + *) sed -u "$c";; + esac +} + +# Grab the current directory +function getCurrent() + { + showStep "getting current directory" + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + THIS_SCRIPT=`basename "$0"` + showStep "Running '${THIS_SCRIPT}'" + } + +# displays where we are, uses the indent function (above) to indent each line +function showStep () + { + echo -e "${YELLOW}=====================================================" | indent + echo -e "${RESET}-----> $*" | indent + echo -e "${YELLOW}=====================================================${RESET}" | indent + } function printHelp () { @@ -19,7 +48,7 @@ function printHeader () { echo "" echo -e "${YELLOW}network deploy script for the Zero To Blockchain Series" | indent - echo -e "${GREEN}This has been tested on Mac OSX thru High Sierra and Ubuntu V16 LTS" | indent + echo -e "${RED}This has been successfully tested on OSX Sierra and Ubuntu 16.04" | indent echo -e "${YELLOW}This script will create your Composer archive" | indent echo "" } @@ -47,5 +76,16 @@ echo "Parameters:" echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "deploying network" +# original - V0.13 +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString +# +# what the documentation implies is required +# cd network/dist +# composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString +# +# what really works +composer identity request -p hlfv1 -i admin -s adminpw +composer identity import -p hlfv1 -u admin -c ~/.identityCredentials/admin-pub.pem -k ~/.identityCredentials/admin-priv.pem cd network/dist -composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -i PeerAdmin -s randomString \ No newline at end of file +composer network deploy -a $NETWORK_NAME.bna -p hlfv1 -A admin -S adminpw -i PeerAdmin -s randomString diff --git a/Chapter12/network/models/events.cto b/Chapter12/network/models/events.cto new file mode 100644 index 0000000..ab9f549 --- /dev/null +++ b/Chapter12/network/models/events.cto @@ -0,0 +1,91 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A library of standard reusable types + */ +namespace composer.events + +abstract event BasicEvent { +} + +// notify seller, financeCo that an order has been placed +event requested extends BasicEvent { + o String orderNumber + o String sellerID + o String orderID +} + +// notify seller, supplier that a fulfillment request has been placed +event ordered extends BasicEvent { + o String orderNumber + o String providerID + o String orderID +} + +// notify seller, buyer that items are on backorder +event backordered extends BasicEvent { + o String orderNumber + o String sellerID + o String orderID +} + +// notify seller, buyer, shipper that shipper has been contacted +event shipRequest extends BasicEvent { + o String orderNumber + o String shipperID + o String orderID +} + +// notify seller, supplier, buyer that order has been delivered +event delivering extends BasicEvent { + o String orderNumber + o String buyerID + o String orderID +} + +// notify seller, supplier, buyer that order has been delivered +event delivered extends BasicEvent { + o String orderNumber + o String buyerID + o String orderID +} + +// notify seller, financeCo that order is in dispute +event dispute extends BasicEvent { + o String orderNumber + o String sellerID + o String orderID +} + +// notify seller, buyer that dispute has been resolved +event resolved extends BasicEvent { + o String orderNumber + o String sellerID + o String orderID +} + +// notify financeCo, buyer that a request for payment has been issued +event requestPayment extends BasicEvent { + o String buyerID + o String orderID + o String orderNumber +} + +// notify seller, buyer that order has been paid / +event Paid extends BasicEvent { + o String sellerID + o String orderID + o String orderNumber +} diff --git a/Chapter12/network/package.json b/Chapter12/network/package.json index 6e58707..be89bc0 100644 --- a/Chapter12/network/package.json +++ b/Chapter12/network/package.json @@ -3,11 +3,12 @@ "composer": "" }, "name": "zerotoblockchain-network", - "version": "0.1.6", + "version": "0.1.5", "description": "Zero to Blockchain tutorial network", "networkImage": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimage.svg", "networkImageanimated": "https://hyperledger.github.io/composer-sample-networks/packages/basic-sample-network/networkimageanimated.svg", "scripts": { + "prepublish": "mkdirp ./network/dist && composer archive create --sourceType dir --sourceName . -a ./network/dist/zerotoblockchain-network.bna", "pretest": "npm run lint", "lint": "eslint ./network", "postlint": "npm run licchk", @@ -35,12 +36,11 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-admin": "", - "composer-cli": "", - "composer-client": "", - "composer-connector-embedded": "", - "composer-connector-hlf": "", - "composer-cucumber-steps": "", + "composer-admin": "^0.14.0", + "composer-cli": "^0.14.0", + "composer-client": "^0.14.0", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter12/network/permissions.acl b/Chapter12/network/permissions.acl index 0a57f6a..1457cc5 100644 --- a/Chapter12/network/permissions.acl +++ b/Chapter12/network/permissions.acl @@ -8,8 +8,11 @@ rule AllAccess { action: ALLOW } */ + /** -* added to support composer V0.14 +* Added to support V0.14 breaking changes +* +*/ rule NetworkAdminUser { description: "Grant business network administrators full access to user resources" participant: "org.hyperledger.composer.system.NetworkAdmin" @@ -17,9 +20,7 @@ rule NetworkAdminUser { resource: "**" action: ALLOW } -*/ -/** -* added to support composer V0.14 + rule NetworkAdminSystem { description: "Grant business network administrators full access to system resources" participant: "org.hyperledger.composer.system.NetworkAdmin" @@ -27,7 +28,10 @@ rule NetworkAdminSystem { resource: "org.hyperledger.composer.system.**" action: ALLOW } +/** +* end of V0.14 additions */ + /** * **/ diff --git a/Chapter12/package.json b/Chapter12/package.json index dfd50fe..1d086ff 100644 --- a/Chapter12/package.json +++ b/Chapter12/package.json @@ -37,13 +37,13 @@ "browserfs": "^1.2.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", - "composer-connector-embedded": "0.13.2", - "composer-cucumber-steps": "0.13.2", - "composer-admin": "0.13.2", - "composer-client": "0.13.2", - "composer-common": "0.13.2", - "composer-runtime": "0.13.2", - "composer-runtime-hlfv1": "0.13.2", + "composer-connector-embedded": "^0.14.0", + "composer-cucumber-steps": "^0.14.0", + "composer-admin": "^0.14.0", + "composer-client": "^0.14.0", + "composer-common": "^0.14.0", + "composer-runtime": "^0.14.0", + "composer-runtime-hlfv1": "^0.14.0", "cucumber": "^2.2.0", "eslint": "^3.6.1", "istanbul": "^0.4.5", diff --git a/Chapter12/start_rest_server.sh b/Chapter12/start_rest_server.sh index 4249418..61d94ed 100755 --- a/Chapter12/start_rest_server.sh +++ b/Chapter12/start_rest_server.sh @@ -77,4 +77,7 @@ echo -e "Network Name is: ${GREEN} $NETWORK_NAME ${RESET}" | indent showStep "testing rest server \n when this completes, \n go to your favorite browser \n and enter localhost:3000/explorer " -composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# original (pre V0.14) +# composer-rest-server -p hlfv1 -n $NETWORK_NAME -i PeerAdmin -s randomString +# V0.14 +composer-rest-server -p hlfv1 -n zerotoblockchain-network -i admin -s adminPW diff --git a/Chapter12/startup/itemList.txt b/Chapter12/startup/itemList.txt deleted file mode 100644 index 0b3f008..0000000 --- a/Chapter12/startup/itemList.txt +++ /dev/null @@ -1 +0,0 @@ -{"items": [{"itemNo":1,"itemDescription":"Macbook Pro 16Gb, 1Tb","quantity":2000,"unitPrice":1285}, {"itemNo":2,"itemDescription":"Macbook Pro 8Gb, .5Tb","quantity":2000,"unitPrice":985}, {"itemNo":3,"itemDescription":"Lenovo Thinkpad W520 16Gb, .25Tb","quantity":1000,"unitPrice":500}, {"itemNo":4,"itemDescription":"Lenovo Thinkpad W520 32Gb, 1Tb","quantity":4000,"unitPrice":1565}, {"itemNo":5,"itemDescription":"4K Monitor - 25","quantity":4000,"unitPrice":265}, {"itemNo":6,"itemDescription":"4K Monitor - 32","quantity":4000,"unitPrice":365}, {"itemNo":7,"itemDescription":"4K Monitor - 37","quantity":4000,"unitPrice":465}, {"itemNo":8,"itemDescription":"4K Monitor - 42","quantity":4000,"unitPrice":565}]} \ No newline at end of file diff --git a/Chapter12/startup/memberList.txt b/Chapter12/startup/memberList.txt deleted file mode 100644 index 90a7587..0000000 --- a/Chapter12/startup/memberList.txt +++ /dev/null @@ -1 +0,0 @@ -{"members": [{"type":"Seller","pw":"bob","companyName":"PC Hardware, Inc","id":"bob@pchardwareinc.com","secret":"WXRKKTFrbuFd","userID":"bob"}, {"type":"Seller","pw":"aiesha","companyName":"Cloud Nine Software, Inc","id":"aiesha@cloudninesoftwareinc.com","secret":"HwbNfhKXXKYa","userID":"aiesha"}, {"type":"Seller","pw":"wilber","companyName":"Cooling Systems R Us, Inc","id":"wilber@coolingsystemsrusinc.com","secret":"hqsLubfILpBU","userID":"wilber"}, {"type":"Provider","pw":"online","companyName":"The App Store, Inc","id":"online@theappstoreinc.com","secret":"ptbDbfRiCqRn","userID":"online"}, {"type":"Seller","pw":"anytime","companyName":"Virtual Paper, Inc","id":"anytime@virtualpaperinc.com","secret":"JOnXgdKuzGhZ","userID":"anytime"}, {"type":"Buyer","pw":"yes","companyName":"Software Solutions, Inc","id":"yes@softwaresolutionsinc.com","secret":"herjUgCDgJCL","userID":"yes"}, {"type":"Provider","pw":"dummyProvider","companyName":"dummy provider","id":"noop@dummy","secret":"RDSrDivozdYV","userID":"dummyProvider"}, {"type":"Shipper","pw":"wantitnow","companyName":"The Overnight Experts, Inc","id":"wantitnow@overnightexpressinc.com","secret":"iLDJtCHdlkrR","userID":"wantitnow"}, {"type":"Provider","pw":"power","companyName":"UPS Systems, Inc","id":"power@upssystemsinc.com","secret":"uyQQISfCwCkQ","userID":"power"}, {"type":"Seller","pw":"abdul","companyName":"The Cognitive Advantage, Inc","id":"abdul@cognitiveadvantageinc.com","secret":"HLOpfgigOdna","userID":"abdul"}, {"type":"Seller","pw":"erin","companyName":"2nd Life Systems, Inc","id":"Erin@2ndlifesystemsinc.com","secret":"TaHZIGDUYWgs","userID":"erin"}, {"type":"Buyer","pw":"eric","companyName":"Born On The Cloud, Inc","id":"eric@bornonthecloudinc.com","secret":"OpfdeTBQUwnZ","userID":"eric"}, {"type":"Seller","pw":"mary","companyName":"The i-Series Experts, Inc","id":"mary@iseriesexpertsinc.com","secret":"SHjXfZIMHpux","userID":"mary"}, {"type":"Buyer","pw":"buyer1","companyName":"Hybrid Cloud Designs, Inc","id":"buyer1@hybridclouddesignsinc.com","secret":"OURlaIWWIHzI","userID":"buyer1"}, {"type":"Seller","pw":"alwayson","companyName":"NonStop, Inc","id":"alwayson@nonstopinc.com","secret":"tNOKJfasjSBA","userID":"alwayson"}, {"type":"Shipper","pw":"speedmatters","companyName":"Fast Eddy, Inc","id":"speedmatters@fasteddyinc.com","secret":"sMXvXnmfOQys","userID":"speedmatters"}, {"type":"Buyer","pw":"abby","companyName":"Kid Friendly Learning, Inc","id":"abby@kidfriendlyinc.com","secret":"eTjEkNDsRBTk","userID":"abby"}, {"type":"Seller","pw":"jojo","companyName":"Inovative Solutions, Inc","id":"jojo@innovativesolutionsinc.com","secret":"VxIUvYHlxDMC","userID":"jojo"}, {"type":"FinanceCo","pw":"easymoney","companyName":"The Global Financier","id":"easymoney@easymoneyinc.com","secret":"RmCaHTbeMcwb","userID":"easymoney"}, {"type":"Shipper","pw":"dummyShipper","companyName":"dummy shipper","id":"noop@dummy","secret":"fYXcKpYtTxiQ","userID":"dummyShipper"}, {"type":"Seller","pw":"joshua","companyName":"Office Experts, Inc","id":"joshua@officeexpertsinc.com","secret":"aSmdrRQwNVCp","userID":"joshua"}, {"type":"Buyer","pw":"kristen","companyName":"The Education Game, Inc","id":"kristen@gameify.com","secret":"gfnhVDNRNwZj","userID":"kristen"}, {"type":"Provider","pw":"info","companyName":"PC Hardware Now, Inc","id":"info@pchardwarenowinc.com","secret":"LRvgINvpZKzO","userID":"info"}]} \ No newline at end of file diff --git a/setup_OSX.sh b/setup_OSX.sh index 78d0c97..79cbbdb 100755 --- a/setup_OSX.sh +++ b/setup_OSX.sh @@ -110,13 +110,13 @@ function installNodeDev () if [[ $SDK_INSTALL == "true" ]]; then showStep "The composer-cli contains all the command line operations for developing business networks." npm uninstall -g composer-cli - npm install -g composer-cli@0.13.2 + npm install -g composer-cli@0.14.2 showStep "The generator-hyperledger-composer is a Yeoman plugin that creates bespoke applications for your business network." npm uninstall -g generator-hyperledger-composer - npm install -g generator-hyperledger-composer@0.13.2 + npm install -g generator-hyperledger-composer@0.14.2 showStep "The composer-rest-server uses the Hyperledger Composer LoopBack Connector to connect to a business network, extract the models and then present a page containing the REST APIs that have been generated for the model." npm uninstall -g composer-rest-server - npm install -g composer-rest-server@0.13.2 + npm install -g composer-rest-server@0.14.2 showStep "Yeoman is a tool for generating applications. When combined with the generator-hyperledger-composer component, it can interpret business networks and generate applications based on them." npm install -g yo else diff --git a/setup_Ubuntu_Part_1.sh b/setup_Ubuntu_Part_1.sh index a4ab070..be79d01 100755 --- a/setup_Ubuntu_Part_1.sh +++ b/setup_Ubuntu_Part_1.sh @@ -148,13 +148,13 @@ function installNodeDev () if [[ $SDK_INSTALL == "true" ]]; then showStep "The composer-cli contains all the command line operations for developing business networks." npm uninstall -g composer-cli - npm install -g --python=python2.7 composer-cli@0.13.2 + npm install -g --python=python2.7 composer-cli@0.14.2 showStep "The generator-hyperledger-composer is a Yeoman plugin that creates bespoke applications for your business network." npm uninstall -g generator-hyperledger-composer - npm install -g --python=python2.7 generator-hyperledger-composer@0.13.2 + npm install -g --python=python2.7 generator-hyperledger-composer@0.14.2 showStep "The composer-rest-server uses the Hyperledger Composer LoopBack Connector to connect to a business network, extract the models and then present a page containing the REST APIs that have been generated for the model." npm uninstall -g composer-rest-server - npm install -g --python=python2.7 composer-rest-server@0.13.2 + npm install -g --python=python2.7 composer-rest-server@0.14.2 showStep "Yeoman is a tool for generating applications. When combined with the generator-hyperledger-composer component, it can interpret business networks and generate applications based on them." npm install -g --python=python2.7 yo else