From bb3ac84e6e816a8ee634fc2850c2ec510ebd0ce6 Mon Sep 17 00:00:00 2001 From: Bret Harrison Date: Thu, 19 Oct 2017 20:17:31 -0400 Subject: [PATCH] [FAB-5363] fabric-samples update balance Update balance transfer sample to use the connection profile and node 8. Change-Id: I17c74c6cb23ebe55a8f2bba735d41525ae9e5ab1 Signed-off-by: Bret Harrison Signed-off-by: ratnakar --- balance-transfer/README.md | 67 +- balance-transfer/app.js | 155 +- balance-transfer/app/create-channel.js | 45 +- balance-transfer/app/helper.js | 329 +-- balance-transfer/app/install-chaincode.js | 73 +- balance-transfer/app/instantiate-chaincode.js | 224 +- balance-transfer/app/invoke-transaction.js | 206 +- balance-transfer/app/join-channel.js | 219 +- balance-transfer/app/network-config-aws.json | 55 - balance-transfer/app/network-config.json | 55 - balance-transfer/app/query.js | 303 +- .../artifacts/docker-compose.yaml | 2 + .../artifacts/network-config-aws.yaml | 236 ++ .../artifacts/network-config.yaml | 236 ++ balance-transfer/artifacts/org1.yaml | 53 + balance-transfer/artifacts/org2.yaml | 53 + balance-transfer/config.js | 12 +- balance-transfer/config.json | 1 - balance-transfer/package-lock.json | 2541 +++++++++++++++++ balance-transfer/runApp.sh | 4 +- balance-transfer/testAPIs.sh | 26 +- 21 files changed, 3856 insertions(+), 1039 deletions(-) delete mode 100644 balance-transfer/app/network-config-aws.json delete mode 100644 balance-transfer/app/network-config.json create mode 100644 balance-transfer/artifacts/network-config-aws.yaml create mode 100644 balance-transfer/artifacts/network-config.yaml create mode 100644 balance-transfer/artifacts/org1.yaml create mode 100644 balance-transfer/artifacts/org2.yaml create mode 100644 balance-transfer/package-lock.json diff --git a/balance-transfer/README.md b/balance-transfer/README.md index 3e4514ab3f..42fef2930c 100644 --- a/balance-transfer/README.md +++ b/balance-transfer/README.md @@ -7,7 +7,7 @@ A sample Node.js app to demonstrate **__fabric-client__** & **__fabric-ca-client * [Docker](https://www.docker.com/products/overview) - v1.12 or higher * [Docker Compose](https://docs.docker.com/compose/overview/) - v1.8 or higher * [Git client](https://git-scm.com/downloads) - needed for clone commands -* **Node.js** v6.9.0 - 6.10.0 ( __Node v7+ is not supported__ ) +* **Node.js** v8.4.0 or higher * [Download Docker images](http://hyperledger-fabric.readthedocs.io/en/latest/samples.html#binaries) ``` @@ -99,7 +99,7 @@ cd fabric-samples/balance-transfer * Register and enroll new users in Organization - **Org1**: -`curl -s -X POST http://localhost:4000/users -H "content-type: application/x-www-form-urlencoded" -d 'username=Jim&orgName=org1'` +`curl -s -X POST http://localhost:4000/users -H "content-type: application/x-www-form-urlencoded" -d 'username=Jim&orgName=Org1'` **OUTPUT:** @@ -137,7 +137,7 @@ curl -s -X POST \ -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" \ -H "content-type: application/json" \ -d '{ - "peers": ["peer1","peer2"] + "peers": ["peer0.org1.example.com","peer1.org1.example.com"] }' ``` ### Install chaincode @@ -148,7 +148,7 @@ curl -s -X POST \ -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" \ -H "content-type: application/json" \ -d '{ - "peers": ["peer1","peer2"], + "peers": ["peer0.org1.example.com","peer1.org1.example.com"], "chaincodeName":"mycc", "chaincodePath":"github.com/example_cc", "chaincodeType": "golang", @@ -163,7 +163,7 @@ curl -s -X POST \ -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" \ -H "content-type: application/json" \ -d "{ - \"peers\": [\"peer1\",\"peer2\"], + \"peers\": [\"peer0.org1.example.com\",\"peer1.org1.example.com\"], \"chaincodeName\":\"mycc\", \"chaincodePath\":\"$PWD/artifacts/src/github.com/example_cc/node\", \"chaincodeType\": \"node\", @@ -205,7 +205,7 @@ curl -s -X POST \ ``` curl -s -X GET \ - "http://localhost:4000/channels/mychannel/chaincodes/mycc?peer=peer1&fcn=query&args=%5B%22a%22%5D" \ + "http://localhost:4000/channels/mychannel/chaincodes/mycc?peer=peer0.org1.example.com&fcn=query&args=%5B%22a%22%5D" \ -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" \ -H "content-type: application/json" ``` @@ -214,7 +214,7 @@ curl -s -X GET \ ``` curl -s -X GET \ - "http://localhost:4000/channels/mychannel/blocks/1?peer=peer1" \ + "http://localhost:4000/channels/mychannel/blocks/1?peer=peer0.org1.example.com" \ -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" \ -H "content-type: application/json" ``` @@ -222,18 +222,18 @@ curl -s -X GET \ ### Query Transaction by TransactionID ``` -curl -s -X GET http://localhost:4000/channels/mychannel/transactions/TRX_ID?peer=peer1 \ +curl -s -X GET http://localhost:4000/channels/mychannel/transactions/TRX_ID?peer=peer0.org1.example.com \ -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" \ -H "content-type: application/json" ``` -**NOTE**: Here the TRX_ID can be from any previous invoke transaction +**NOTE**: Here the TRX_ID can be from any previous invoke transaction, see results of the invoke request, will look something like `8a95b1794cb17e7772164c3f1292f8410fcfdc1943955a35c9764a21fcd1d1b3`. ### Query ChainInfo ``` curl -s -X GET \ - "http://localhost:4000/channels/mychannel?peer=peer1" \ + "http://localhost:4000/channels/mychannel?peer=peer0.org1.example.com" \ -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" \ -H "content-type: application/json" ``` @@ -242,7 +242,7 @@ curl -s -X GET \ ``` curl -s -X GET \ - "http://localhost:4000/chaincodes?peer=peer1&type=installed" \ + "http://localhost:4000/chaincodes?peer=peer0.org1.example.com&type=installed" \ -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" \ -H "content-type: application/json" ``` @@ -251,7 +251,7 @@ curl -s -X GET \ ``` curl -s -X GET \ - "http://localhost:4000/chaincodes?peer=peer1&type=instantiated" \ + "http://localhost:4000/chaincodes?peer=peer0.org1.example.com&type=instantiated" \ -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" \ -H "content-type: application/json" ``` @@ -260,50 +260,23 @@ curl -s -X GET \ ``` curl -s -X GET \ - "http://localhost:4000/channels?peer=peer1" \ + "http://localhost:4000/channels?peer=peer0.org1.example.com" \ -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" \ -H "content-type: application/json" ``` ### Network configuration considerations -You have the ability to change configuration parameters by either directly editing the network-config.json file or provide an additional file for an alternative target network. The app uses an optional environment variable "TARGET_NETWORK" to control the configuration files to use. For example, if you deployed the target network on Amazon Web Services EC2, you can add a file "network-config-aws.json", and set the "TARGET_NETWORK" environment to 'aws'. The app will pick up the settings inside the "network-config-aws.json" file. +You have the ability to change configuration parameters by either directly editing the network-config.yaml file or provide an additional file for an alternative target network. The app uses an optional environment variable "TARGET_NETWORK" to control the configuration files to use. For example, if you deployed the target network on Amazon Web Services EC2, you can add a file "network-config-aws.yaml", and set the "TARGET_NETWORK" environment to 'aws'. The app will pick up the settings inside the "network-config-aws.yaml" file. #### IP Address** and PORT information -If you choose to customize your docker-compose yaml file by hardcoding IP Addresses and PORT information for your peers and orderer, then you MUST also add the identical values into the network-config.json file. The paths shown below will need to be adjusted to match your docker-compose yaml file. - -``` - "orderer": { - "url": "grpcs://x.x.x.x:7050", - "server-hostname": "orderer0", - "tls_cacerts": "../artifacts/tls/orderer/ca-cert.pem" - }, - "org1": { - "ca": "http://x.x.x.x:7054", - "peer1": { - "requests": "grpcs://x.x.x.x:7051", - "events": "grpcs://x.x.x.x:7053", - ... - }, - "peer2": { - "requests": "grpcs://x.x.x.x:7056", - "events": "grpcs://x.x.x.x:7058", - ... - } - }, - "org2": { - "ca": "http://x.x.x.x:8054", - "peer1": { - "requests": "grpcs://x.x.x.x:8051", - "events": "grpcs://x.x.x.x:8053", - ... }, - "peer2": { - "requests": "grpcs://x.x.x.x:8056", - "events": "grpcs://x.x.x.x:8058", - ... - } - } +If you choose to customize your docker-compose yaml file by hardcoding IP Addresses and PORT information for your peers and orderer, then you MUST also add the identical values into the network-config.yaml file. The url and eventUrl settings will need to be adjusted to match your docker-compose yaml file. + +``` +peer1.org1.example.com: + url: grpcs://x.x.x.x:7056 + eventUrl: grpcs://x.x.x.x:7058 ``` diff --git a/balance-transfer/app.js b/balance-transfer/app.js index e4bb1613e8..7b62b84a4e 100644 --- a/balance-transfer/app.js +++ b/balance-transfer/app.js @@ -32,7 +32,7 @@ require('./config.js'); var hfc = require('fabric-client'); var helper = require('./app/helper.js'); -var channels = require('./app/create-channel.js'); +var createChannel = require('./app/create-channel.js'); var join = require('./app/join-channel.js'); var install = require('./app/install-chaincode.js'); var instantiate = require('./app/instantiate-chaincode.js'); @@ -60,6 +60,7 @@ app.use(expressJWT({ })); app.use(bearerToken()); app.use(function(req, res, next) { + logger.debug(' ------>>>>>> new request for %s',req.originalUrl); if (req.originalUrl.indexOf('/users') >= 0) { return next(); } @@ -90,8 +91,7 @@ app.use(function(req, res, next) { /////////////////////////////////////////////////////////////////////////////// var server = http.createServer(app).listen(port, function() {}); logger.info('****************** SERVER STARTED ************************'); -logger.info('************** http://' + host + ':' + port + - ' ******************'); +logger.info('*************** http://%s:%s ******************',host,port); server.timeout = 240000; function getErrorMessage(field) { @@ -106,7 +106,7 @@ function getErrorMessage(field) { ///////////////////////// REST ENDPOINTS START HERE /////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Register and enroll user -app.post('/users', function(req, res) { +app.post('/users', async function(req, res) { var username = req.body.username; var orgName = req.body.orgName; logger.debug('End point : /users'); @@ -125,20 +125,18 @@ app.post('/users', function(req, res) { username: username, orgName: orgName }, app.get('secret')); - helper.getRegisteredUsers(username, orgName, true).then(function(response) { - if (response && typeof response !== 'string') { - response.token = token; - res.json(response); - } else { - res.json({ - success: false, - message: response - }); - } - }); + let response = await helper.getRegisteredUser(username, orgName, true); + logger.debug('Successfully returned from registering the username %s for organization %s',username,orgName); + if (response && typeof response !== 'string') { + response.token = token; + res.json(response); + } else { + res.json({success: false, message: response}); + } + }); // Create Channel -app.post('/channels', function(req, res) { +app.post('/channels', async function(req, res) { logger.info('<<<<<<<<<<<<<<<<< C R E A T E C H A N N E L >>>>>>>>>>>>>>>>>'); logger.debug('End point : /channels'); var channelName = req.body.channelName; @@ -154,18 +152,19 @@ app.post('/channels', function(req, res) { return; } - channels.createChannel(channelName, channelConfigPath, req.username, req.orgname) - .then(function(message) { - res.send(message); - }); + let message = await createChannel.createChannel(channelName, channelConfigPath, req.username, req.orgname); + res.send(message); }); // Join Channel -app.post('/channels/:channelName/peers', function(req, res) { +app.post('/channels/:channelName/peers', async function(req, res) { logger.info('<<<<<<<<<<<<<<<<< J O I N C H A N N E L >>>>>>>>>>>>>>>>>'); var channelName = req.params.channelName; var peers = req.body.peers; logger.debug('channelName : ' + channelName); logger.debug('peers : ' + peers); + logger.debug('username :' + req.username); + logger.debug('orgname:' + req.orgname); + if (!channelName) { res.json(getErrorMessage('\'channelName\'')); return; @@ -175,13 +174,11 @@ app.post('/channels/:channelName/peers', function(req, res) { return; } - join.joinChannel(channelName, peers, req.username, req.orgname) - .then(function(message) { - res.send(message); - }); + let message = await join.joinChannel(channelName, peers, req.username, req.orgname); + res.send(message); }); // Install chaincode on target peers -app.post('/chaincodes', function(req, res) { +app.post('/chaincodes', async function(req, res) { logger.debug('==================== INSTALL CHAINCODE =================='); var peers = req.body.peers; var chaincodeName = req.body.chaincodeName; @@ -213,13 +210,10 @@ app.post('/chaincodes', function(req, res) { res.json(getErrorMessage('\'chaincodeType\'')); return; } - install.installChaincode(peers, chaincodeName, chaincodePath, chaincodeVersion, chaincodeType, req.username, req.orgname) - .then(function(message) { - res.send(message); - }); -}); + let message = await install.installChaincode(peers, chaincodeName, chaincodePath, chaincodeVersion, chaincodeType, req.username, req.orgname) + res.send(message);}); // Instantiate chaincode on target peers -app.post('/channels/:channelName/chaincodes', function(req, res) { +app.post('/channels/:channelName/chaincodes', async function(req, res) { logger.debug('==================== INSTANTIATE CHAINCODE =================='); var chaincodeName = req.body.chaincodeName; var chaincodeVersion = req.body.chaincodeVersion; @@ -253,13 +247,12 @@ app.post('/channels/:channelName/chaincodes', function(req, res) { res.json(getErrorMessage('\'args\'')); return; } - instantiate.instantiateChaincode(channelName, chaincodeName, chaincodeVersion, chaincodeType, fcn, args, req.username, req.orgname) - .then(function(message) { - res.send(message); - }); + + let message = await instantiate.instantiateChaincode(channelName, chaincodeName, chaincodeVersion, chaincodeType, fcn, args, req.username, req.orgname); + res.send(message); }); // Invoke transaction on chaincode on target peers -app.post('/channels/:channelName/chaincodes/:chaincodeName', function(req, res) { +app.post('/channels/:channelName/chaincodes/:chaincodeName', async function(req, res) { logger.debug('==================== INVOKE ON CHAINCODE =================='); var peers = req.body.peers; var chaincodeName = req.params.chaincodeName; @@ -287,13 +280,11 @@ app.post('/channels/:channelName/chaincodes/:chaincodeName', function(req, res) return; } - invoke.invokeChaincode(peers, channelName, chaincodeName, fcn, args, req.username, req.orgname) - .then(function(message) { - res.send(message); - }); + let message = await invoke.invokeChaincode(peers, channelName, chaincodeName, fcn, args, req.username, req.orgname); + res.send(message); }); // Query on chaincode on target peers -app.get('/channels/:channelName/chaincodes/:chaincodeName', function(req, res) { +app.get('/channels/:channelName/chaincodes/:chaincodeName', async function(req, res) { logger.debug('==================== QUERY BY CHAINCODE =================='); var channelName = req.params.channelName; var chaincodeName = req.params.chaincodeName; @@ -326,13 +317,11 @@ app.get('/channels/:channelName/chaincodes/:chaincodeName', function(req, res) { args = JSON.parse(args); logger.debug(args); - query.queryChaincode(peer, channelName, chaincodeName, args, fcn, req.username, req.orgname) - .then(function(message) { - res.send(message); - }); + let message = await query.queryChaincode(peer, channelName, chaincodeName, args, fcn, req.username, req.orgname); + res.send(message); }); // Query Get Block by BlockNumber -app.get('/channels/:channelName/blocks/:blockId', function(req, res) { +app.get('/channels/:channelName/blocks/:blockId', async function(req, res) { logger.debug('==================== GET BLOCK BY NUMBER =================='); let blockId = req.params.blockId; let peer = req.query.peer; @@ -344,16 +333,12 @@ app.get('/channels/:channelName/blocks/:blockId', function(req, res) { return; } - query.getBlockByNumber(peer, blockId, req.username, req.orgname) - .then(function(message) { - res.send(message); - }); + let message = await query.getBlockByNumber(peer, req.params.channelName, blockId, req.username, req.orgname); + res.send(message); }); // Query Get Transaction by Transaction ID -app.get('/channels/:channelName/transactions/:trxnId', function(req, res) { - logger.debug( - '================ GET TRANSACTION BY TRANSACTION_ID ======================' - ); +app.get('/channels/:channelName/transactions/:trxnId', async function(req, res) { + logger.debug('================ GET TRANSACTION BY TRANSACTION_ID ======================'); logger.debug('channelName : ' + req.params.channelName); let trxnId = req.params.trxnId; let peer = req.query.peer; @@ -362,13 +347,11 @@ app.get('/channels/:channelName/transactions/:trxnId', function(req, res) { return; } - query.getTransactionByID(peer, trxnId, req.username, req.orgname) - .then(function(message) { - res.send(message); - }); + let message = await query.getTransactionByID(peer, req.params.channelName, trxnId, req.username, req.orgname); + res.send(message); }); // Query Get Block by Hash -app.get('/channels/:channelName/blocks', function(req, res) { +app.get('/channels/:channelName/blocks', async function(req, res) { logger.debug('================ GET BLOCK BY HASH ======================'); logger.debug('channelName : ' + req.params.channelName); let hash = req.query.hash; @@ -378,43 +361,38 @@ app.get('/channels/:channelName/blocks', function(req, res) { return; } - query.getBlockByHash(peer, hash, req.username, req.orgname).then( - function(message) { - res.send(message); - }); + let message = await query.getBlockByHash(peer, req.params.channelName, hash, req.username, req.orgname); + res.send(message); }); //Query for Channel Information -app.get('/channels/:channelName', function(req, res) { - logger.debug( - '================ GET CHANNEL INFORMATION ======================'); +app.get('/channels/:channelName', async function(req, res) { + logger.debug('================ GET CHANNEL INFORMATION ======================'); + logger.debug('channelName : ' + req.params.channelName); + let peer = req.query.peer; + + let message = await query.getChainInfo(peer, req.params.channelName, req.username, req.orgname); + res.send(message); +}); +//Query for Channel instantiated chaincodes +app.get('/channels/:channelName/chaincodes', async function(req, res) { + logger.debug('================ GET INSTANTIATED CHAINCODES ======================'); logger.debug('channelName : ' + req.params.channelName); let peer = req.query.peer; - query.getChainInfo(peer, req.username, req.orgname).then( - function(message) { - res.send(message); - }); + let message = await query.getInstalledChaincodes(peer, req.params.channelName, 'instantiated', req.username, req.orgname); + res.send(message); }); // Query to fetch all Installed/instantiated chaincodes -app.get('/chaincodes', function(req, res) { +app.get('/chaincodes', async function(req, res) { var peer = req.query.peer; var installType = req.query.type; - //TODO: add Constnats - if (installType === 'installed') { - logger.debug( - '================ GET INSTALLED CHAINCODES ======================'); - } else { - logger.debug( - '================ GET INSTANTIATED CHAINCODES ======================'); - } + logger.debug('================ GET INSTALLED CHAINCODES ======================'); - query.getInstalledChaincodes(peer, installType, req.username, req.orgname) - .then(function(message) { - res.send(message); - }); + let message = await query.getInstalledChaincodes(peer, null, 'installed', req.username, req.orgname) + res.send(message); }); // Query to fetch channels -app.get('/channels', function(req, res) { +app.get('/channels', async function(req, res) { logger.debug('================ GET CHANNELS ======================'); logger.debug('peer: ' + req.query.peer); var peer = req.query.peer; @@ -423,9 +401,6 @@ app.get('/channels', function(req, res) { return; } - query.getChannels(peer, req.username, req.orgname) - .then(function( - message) { - res.send(message); - }); + let message = await query.getChannels(peer, req.username, req.orgname); + res.send(message); }); diff --git a/balance-transfer/app/create-channel.js b/balance-transfer/app/create-channel.js index ca8680c738..80e27c19be 100644 --- a/balance-transfer/app/create-channel.js +++ b/balance-transfer/app/create-channel.js @@ -16,41 +16,37 @@ var util = require('util'); var fs = require('fs'); var path = require('path'); -var config = require('../config.json'); + var helper = require('./helper.js'); var logger = helper.getLogger('Create-Channel'); -//Attempt to send a request to the orderer with the sendCreateChain method -var createChannel = function(channelName, channelConfigPath, username, orgName) { +//Attempt to send a request to the orderer with the sendTransaction method +var createChannel = async function(channelName, channelConfigPath, username, orgName) { logger.debug('\n====== Creating Channel \'' + channelName + '\' ======\n'); - var client = helper.getClientForOrg(orgName); - var channel = helper.getChannelForOrg(orgName); + try { + // first setup the client for this org + var client = await helper.getClientForOrg(orgName); + logger.debug('Successfully got the fabric client for the organization "%s"', orgName); - // read in the envelope for the channel config raw bytes - var envelope = fs.readFileSync(path.join(__dirname, channelConfigPath)); - // extract the channel config bytes from the envelope to be signed - var channelConfig = client.extractChannelConfig(envelope); + // read in the envelope for the channel config raw bytes + var envelope = fs.readFileSync(path.join(__dirname, channelConfigPath)); + // extract the channel config bytes from the envelope to be signed + var channelConfig = client.extractChannelConfig(envelope); - //Acting as a client in the given organization provided with "orgName" param - return helper.getOrgAdmin(orgName).then((admin) => { - logger.debug(util.format('Successfully acquired admin user for the organization "%s"', orgName)); + //Acting as a client in the given organization provided with "orgName" param // sign the channel config bytes as "endorsement", this is required by // the orderer's channel creation policy + // this will use the admin identity assigned to the client when the connection profile was loaded let signature = client.signChannelConfig(channelConfig); let request = { config: channelConfig, signatures: [signature], name: channelName, - orderer: channel.getOrderers()[0], - txId: client.newTransactionID() + txId: client.newTransactionID(true) // get an admin based transactionID }; // send to orderer - return client.createChannel(request); - }, (err) => { - logger.error('Failed to enroll user \''+username+'\'. Error: ' + err); - throw new Error('Failed to enroll user \''+username+'\'' + err); - }).then((response) => { + var response = await client.createChannel(request) logger.debug(' response ::%j', response); if (response && response.status === 'SUCCESS') { logger.debug('Successfully created the channel.'); @@ -58,17 +54,16 @@ var createChannel = function(channelName, channelConfigPath, username, orgName) success: true, message: 'Channel \'' + channelName + '\' created Successfully' }; - return response; + return response; } else { logger.error('\n!!!!!!!!! Failed to create the channel \'' + channelName + '\' !!!!!!!!!\n\n'); throw new Error('Failed to create the channel \'' + channelName + '\''); } - }, (err) => { - logger.error('Failed to initialize the channel: ' + err.stack ? err.stack : - err); - throw new Error('Failed to initialize the channel: ' + err.stack ? err.stack : err); - }); + } catch (err) { + logger.error('Failed to initialize the channel: ' + err.stack ? err.stack : err); + throw new Error('Failed to initialize the channel: ' + err.toString()); + } }; exports.createChannel = createChannel; diff --git a/balance-transfer/app/helper.js b/balance-transfer/app/helper.js index 8a227f7476..20c7db19ff 100644 --- a/balance-transfer/app/helper.js +++ b/balance-transfer/app/helper.js @@ -33,270 +33,89 @@ var clients = {}; var channels = {}; var caClients = {}; -// set up the client and channel objects for each org -for (let key in ORGS) { - if (key.indexOf('org') === 0) { - let client = new hfc(); - - let cryptoSuite = hfc.newCryptoSuite(); - cryptoSuite.setCryptoKeyStore(hfc.newCryptoKeyStore({path: getKeyStoreForOrg(ORGS[key].name)})); - client.setCryptoSuite(cryptoSuite); - - let channel = client.newChannel(hfc.getConfigSetting('channelName')); - channel.addOrderer(newOrderer(client)); - - clients[key] = client; - channels[key] = channel; - - setupPeers(channel, key, client); - - let caUrl = ORGS[key].ca; - caClients[key] = new copService(caUrl, null /*defautl TLS opts*/, '' /* default CA */, cryptoSuite); - } +var sleep = async function (sleep_time_ms) { + return new Promise(resolve => setTimeout(resolve, sleep_time_ms)); } -function setupPeers(channel, org, client) { - for (let key in ORGS[org].peers) { - let data = fs.readFileSync(path.join(__dirname, ORGS[org].peers[key]['tls_cacerts'])); - let peer = client.newPeer( - ORGS[org].peers[key].requests, - { - pem: Buffer.from(data).toString(), - 'ssl-target-name-override': ORGS[org].peers[key]['server-hostname'] - } - ); - peer.setName(key); - - channel.addPeer(peer); - } -} - -function newOrderer(client) { - var caRootsPath = ORGS.orderer.tls_cacerts; - let data = fs.readFileSync(path.join(__dirname, caRootsPath)); - let caroots = Buffer.from(data).toString(); - return client.newOrderer(ORGS.orderer.url, { - 'pem': caroots, - 'ssl-target-name-override': ORGS.orderer['server-hostname'] - }); -} - -function readAllFiles(dir) { - var files = fs.readdirSync(dir); - var certs = []; - files.forEach((file_name) => { - let file_path = path.join(dir,file_name); - let data = fs.readFileSync(file_path); - certs.push(data); - }); - return certs; -} - -function getOrgName(org) { - return ORGS[org].name; -} - -function getKeyStoreForOrg(org) { - return hfc.getConfigSetting('keyValueStore') + '_' + org; -} - -function newRemotes(names, forPeers, userOrg) { - let client = getClientForOrg(userOrg); - - let targets = []; - // find the peer that match the names - for (let idx in names) { - let peerName = names[idx]; - if (ORGS[userOrg].peers[peerName]) { - // found a peer matching the name - let data = fs.readFileSync(path.join(__dirname, ORGS[userOrg].peers[peerName]['tls_cacerts'])); - let grpcOpts = { - pem: Buffer.from(data).toString(), - 'ssl-target-name-override': ORGS[userOrg].peers[peerName]['server-hostname'] - }; - - if (forPeers) { - targets.push(client.newPeer(ORGS[userOrg].peers[peerName].requests, grpcOpts)); - } else { - let eh = client.newEventHub(); - eh.setPeerAddr(ORGS[userOrg].peers[peerName].events, grpcOpts); - targets.push(eh); - } +async function getClientForOrg (userorg, username) { + logger.debug('getClientForOrg - ****** START %s %s', userorg, username) + // get a fabric client loaded with a connection profile for this org + let config = '-connection-profile-path'; + + // build a client context and load it with a connection profile + // lets only load the network settings and save the client for later + let client = hfc.loadFromConfig(hfc.getConfigSetting('network'+config)); + + // This will load a connection profile over the top of the current one one + // since the first one did not have a client section and the following one does + // nothing will actually be replaced. + // This will also set an admin identity because the organization defined in the + // client section has one defined + client.loadFromConfig(hfc.getConfigSetting(userorg+config)); + + // this will create both the state store and the crypto store based + // on the settings in the client section of the connection profile + await client.initCredentialStores(); + + // The getUserContext call tries to get the user from persistence. + // If the user has been saved to persistence then that means the user has + // been registered and enrolled. If the user is found in persistence + // the call will then assign the user to the client object. + if(username) { + let user = await client.getUserContext(username, true); + if(!user) { + throw new Error(util.format('User was not found :', username)); + } else { + logger.debug('User %s was found to be registered and enrolled', username); } } + logger.debug('getClientForOrg - ****** END %s %s \n\n', userorg, username) - if (targets.length === 0) { - logger.error(util.format('Failed to find peers matching the names %s', names)); - } - - return targets; + return client; } -//-------------------------------------// -// APIs -//-------------------------------------// -var getChannelForOrg = function(org) { - return channels[org]; -}; - -var getClientForOrg = function(org) { - return clients[org]; -}; - -var newPeers = function(names, org) { - return newRemotes(names, true, org); -}; - -var newEventHubs = function(names, org) { - return newRemotes(names, false, org); -}; - -var getMspID = function(org) { - logger.debug('Msp ID : ' + ORGS[org].mspid); - return ORGS[org].mspid; -}; - -var getAdminUser = function(userOrg) { - var users = hfc.getConfigSetting('admins'); - var username = users[0].username; - var password = users[0].secret; - var member; - var client = getClientForOrg(userOrg); - - return hfc.newDefaultKeyValueStore({ - path: getKeyStoreForOrg(getOrgName(userOrg)) - }).then((store) => { - client.setStateStore(store); - // clearing the user context before switching - client._userContext = null; - return client.getUserContext(username, true).then((user) => { - if (user && user.isEnrolled()) { - logger.info('Successfully loaded member from persistence'); - return user; - } else { - let caClient = caClients[userOrg]; - // need to enroll it with CA server - return caClient.enroll({ - enrollmentID: username, - enrollmentSecret: password - }).then((enrollment) => { - logger.info('Successfully enrolled user \'' + username + '\''); - member = new User(username); - member.setCryptoSuite(client.getCryptoSuite()); - return member.setEnrollment(enrollment.key, enrollment.certificate, getMspID(userOrg)); - }).then(() => { - return client.setUserContext(member); - }).then(() => { - return member; - }).catch((err) => { - logger.error('Failed to enroll and persist user. Error: ' + err.stack ? - err.stack : err); - return null; - }); - } - }); - }); -}; - -var getRegisteredUsers = function(username, userOrg, isJson) { - var member; - var client = getClientForOrg(userOrg); - var enrollmentSecret = null; - return hfc.newDefaultKeyValueStore({ - path: getKeyStoreForOrg(getOrgName(userOrg)) - }).then((store) => { - client.setStateStore(store); - // clearing the user context before switching - client._userContext = null; - return client.getUserContext(username, true).then((user) => { - if (user && user.isEnrolled()) { - logger.info('Successfully loaded member from persistence'); - return user; - } else { - let caClient = caClients[userOrg]; - return getAdminUser(userOrg).then(function(adminUserObj) { - member = adminUserObj; - return caClient.register({ - enrollmentID: username, - affiliation: userOrg + '.department1' - }, member); - }).then((secret) => { - enrollmentSecret = secret; - logger.debug(username + ' registered successfully'); - return caClient.enroll({ - enrollmentID: username, - enrollmentSecret: secret - }); - }, (err) => { - logger.debug(username + ' failed to register'); - return '' + err; - //return 'Failed to register '+username+'. Error: ' + err.stack ? err.stack : err; - }).then((message) => { - if (message && typeof message === 'string' && message.includes( - 'Error:')) { - logger.error(username + ' enrollment failed'); - return message; - } - logger.debug(username + ' enrolled successfully'); - - member = new User(username); - member._enrollmentSecret = enrollmentSecret; - return member.setEnrollment(message.key, message.certificate, getMspID(userOrg)); - }).then(() => { - client.setUserContext(member); - return member; - }, (err) => { - logger.error(util.format('%s enroll failed: %s', username, err.stack ? err.stack : err)); - return '' + err; - });; +var getRegisteredUser = async function(username, userOrg, isJson) { + try { + var client = await getClientForOrg(userOrg); + logger.debug('Successfully initialized the credential stores'); + // client can now act as an agent for organization Org1 + // first check to see if the user is already enrolled + var user = await client.getUserContext(username, true); + if (user && user.isEnrolled()) { + logger.info('Successfully loaded member from persistence'); + } else { + // user was not enrolled, so we will need an admin user object to register + var admins = hfc.getConfigSetting('admins'); + let adminUserObj = await client.setUserContext({username: admins[0].username, password: admins[0].secret}); + let caClient = client.getCertificateAuthority(); + let secret = await caClient.register({ + enrollmentID: username, + affiliation: userOrg.toLowerCase() + '.department1' + }, adminUserObj); + logger.debug('Successfully got the secret for user %s',username); + user = await client.setUserContext({username:username, password:secret}); + logger.debug('Successfully enrolled username %s and setUserContext on the client object', username); + } + if(user && user.isEnrolled) { + if (isJson && isJson === true) { + var response = { + success: true, + secret: user._enrollmentSecret, + message: username + ' enrolled Successfully', + }; + return response; } - }); - }).then((user) => { - if (isJson && isJson === true) { - var response = { - success: true, - secret: user._enrollmentSecret, - message: username + ' enrolled Successfully', - }; - return response; + } else { + throw new Error('User was not enrolled '); } - return user; - }, (err) => { - logger.error(util.format('Failed to get registered user: %s, error: %s', username, err.stack ? err.stack : err)); - return '' + err; - }); -}; - -var getOrgAdmin = function(userOrg) { - var admin = ORGS[userOrg].admin; - var keyPath = path.join(__dirname, admin.key); - var keyPEM = Buffer.from(readAllFiles(keyPath)[0]).toString(); - var certPath = path.join(__dirname, admin.cert); - var certPEM = readAllFiles(certPath)[0].toString(); - - var client = getClientForOrg(userOrg); - var cryptoSuite = hfc.newCryptoSuite(); - if (userOrg) { - cryptoSuite.setCryptoKeyStore(hfc.newCryptoKeyStore({path: getKeyStoreForOrg(getOrgName(userOrg))})); - client.setCryptoSuite(cryptoSuite); + } catch(error) { + logger.error('Failed to get registered user: %s with error: %s', username, error.toString()); + return 'failed '+error.toString(); } - return hfc.newDefaultKeyValueStore({ - path: getKeyStoreForOrg(getOrgName(userOrg)) - }).then((store) => { - client.setStateStore(store); - - return client.createUser({ - username: 'peer'+userOrg+'Admin', - mspid: getMspID(userOrg), - cryptoContent: { - privateKeyPEM: keyPEM, - signedCertPEM: certPEM - } - }); - }); }; + var setupChaincodeDeploy = function() { process.env.GOPATH = path.join(__dirname, hfc.getConfigSetting('CC_SRC_PATH')); }; @@ -307,13 +126,7 @@ var getLogger = function(moduleName) { return logger; }; -exports.getChannelForOrg = getChannelForOrg; exports.getClientForOrg = getClientForOrg; exports.getLogger = getLogger; exports.setupChaincodeDeploy = setupChaincodeDeploy; -exports.getMspID = getMspID; -exports.ORGS = ORGS; -exports.newPeers = newPeers; -exports.newEventHubs = newEventHubs; -exports.getRegisteredUsers = getRegisteredUsers; -exports.getOrgAdmin = getOrgAdmin; +exports.getRegisteredUser = getRegisteredUser; diff --git a/balance-transfer/app/install-chaincode.js b/balance-transfer/app/install-chaincode.js index 879e05c307..5d976f4e0a 100644 --- a/balance-transfer/app/install-chaincode.js +++ b/balance-transfer/app/install-chaincode.js @@ -22,29 +22,36 @@ var helper = require('./helper.js'); var logger = helper.getLogger('install-chaincode'); var tx_id = null; -var installChaincode = function(peers, chaincodeName, chaincodePath, - chaincodeVersion, chaincodeType, username, org) { - logger.debug( - '\n============ Install chaincode on organizations ============\n'); +var installChaincode = async function(peers, chaincodeName, chaincodePath, + chaincodeVersion, chaincodeType, username, org_name) { + logger.debug('\n\n============ Install chaincode on organizations ============\n'); helper.setupChaincodeDeploy(); - var channel = helper.getChannelForOrg(org); - var client = helper.getClientForOrg(org); + let error_message = null; + try { + logger.info('Calling peers in organization "%s" to join the channel', org_name); - return helper.getOrgAdmin(org).then((user) => { + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); + + tx_id = client.newTransactionID(true); //get an admin transactionID var request = { - targets: helper.newPeers(peers, org), + targets: peers, chaincodePath: chaincodePath, chaincodeId: chaincodeName, chaincodeVersion: chaincodeVersion, chaincodeType: chaincodeType }; - return client.installChaincode(request); - }, (err) => { - logger.error('Failed to enroll user \'' + username + '\'. ' + err); - throw new Error('Failed to enroll user \'' + username + '\'. ' + err); - }).then((results) => { + let results = await client.installChaincode(request); + // the returned object has both the endorsement results + // and the actual proposal, the proposal will be needed + // later when we send a transaction to the orederer var proposalResponses = results[0]; var proposal = results[1]; + + // lets have a look at the responses to see if they are + // all good, if good they will also include signatures + // required to be committed var all_good = true; for (var i in proposalResponses) { let one_good = false; @@ -53,28 +60,34 @@ var installChaincode = function(peers, chaincodeName, chaincodePath, one_good = true; logger.info('install proposal was good'); } else { - logger.error('install proposal was bad'); + logger.error('install proposal was bad %j',proposalResponses.toJSON()); } all_good = all_good & one_good; } if (all_good) { - logger.info(util.format( - 'Successfully sent install Proposal and received ProposalResponse: Status - %s', - proposalResponses[0].response.status)); - logger.debug('\nSuccessfully Installed chaincode on organization ' + org + - '\n'); - return 'Successfully Installed chaincode on organization ' + org; + logger.info('Successfully sent install Proposal and received ProposalResponse'); } else { - logger.error( - 'Failed to send install Proposal or receive valid response. Response null or status is not 200. exiting...' - ); - return 'Failed to send install Proposal or receive valid response. Response null or status is not 200. exiting...'; + error_message = 'Failed to send install Proposal or receive valid response. Response null or status is not 200' + logger.error(error_message); } - }, (err) => { - logger.error('Failed to send install proposal due to error: ' + err.stack ? - err.stack : err); - throw new Error('Failed to send install proposal due to error: ' + err.stack ? - err.stack : err); - }); + } catch(error) { + logger.error('Failed to install due to error: ' + error.stack ? error.stack : error); + error_message = error.toString(); + } + + if (!error_message) { + let message = util.format('Successfully install chaincode'); + logger.info(message); + // build a response to send back to the REST caller + let response = { + success: true, + message: message + }; + return response; + } else { + let message = util.format('Failed to install due to:%s',error_message); + logger.error(message); + throw new Error(message); + } }; exports.installChaincode = installChaincode; diff --git a/balance-transfer/app/instantiate-chaincode.js b/balance-transfer/app/instantiate-chaincode.js index d03c2cf0f7..fe529a6b19 100644 --- a/balance-transfer/app/instantiate-chaincode.js +++ b/balance-transfer/app/instantiate-chaincode.js @@ -18,32 +18,31 @@ var path = require('path'); var fs = require('fs'); var util = require('util'); var hfc = require('fabric-client'); -var Peer = require('fabric-client/lib/Peer.js'); -var EventHub = require('fabric-client/lib/EventHub.js'); var helper = require('./helper.js'); var logger = helper.getLogger('instantiate-chaincode'); -var ORGS = hfc.getConfigSetting('network-config'); -var tx_id = null; -var eh = null; -var instantiateChaincode = function(channelName, chaincodeName, chaincodeVersion, functionName, chaincodeType, - args, username, org) { - logger.debug('\n============ Instantiate chaincode on organization ' + org + +var instantiateChaincode = async function(channelName, chaincodeName, chaincodeVersion, functionName, chaincodeType, args, username, org_name) { + logger.debug('\n\n============ Instantiate chaincode on channel ' + channelName + ' ============\n'); + var error_message = null; + var eventhubs_in_use = []; + try { + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); + var channel = client.getChannel(channelName); + if(!channel) { + let message = util.format('Channel %s was not defined in the connection profile', channelName); + logger.error(message); + throw new Error(message); + } + var tx_id = client.newTransactionID(true); // Get an admin based transactionID + // An admin based transactionID will + // indicate that admin identity should + // be used to sign the proposal request. + // will need the transaction ID string for the event registration later + var deployId = tx_id.getTransactionID(); - var channel = helper.getChannelForOrg(org); - var client = helper.getClientForOrg(org); - - return helper.getOrgAdmin(org).then((user) => { - // read the config block from the orderer for the channel - // and initialize the verify MSPs based on the participating - // organizations - return channel.initialize(); - }, (err) => { - logger.error('Failed to enroll user \'' + username + '\'. ' + err); - throw new Error('Failed to enroll user \'' + username + '\'. ' + err); - }).then((success) => { - tx_id = client.newTransactionID(); // send proposal to endorser var request = { chaincodeId: chaincodeName, @@ -56,13 +55,17 @@ var instantiateChaincode = function(channelName, chaincodeName, chaincodeVersion if (functionName) request.fcn = functionName; - return channel.sendInstantiateProposal(request); - }, (err) => { - logger.error('Failed to initialize the channel'); - throw new Error('Failed to initialize the channel'); - }).then((results) => { + let results = await channel.sendInstantiateProposal(request, 60000); //instantiate takes much longer + + // the returned object has both the endorsement results + // and the actual proposal, the proposal will be needed + // later when we send a transaction to the orderer var proposalResponses = results[0]; var proposal = results[1]; + + // lets have a look at the responses to see if they are + // all good, if good they will also include signatures + // required to be committed var all_good = true; for (var i in proposalResponses) { let one_good = false; @@ -75,89 +78,118 @@ var instantiateChaincode = function(channelName, chaincodeName, chaincodeVersion } all_good = all_good & one_good; } + if (all_good) { logger.info(util.format( 'Successfully sent Proposal and received ProposalResponse: Status - %s, message - "%s", metadata - "%s", endorsement signature: %s', proposalResponses[0].response.status, proposalResponses[0].response.message, proposalResponses[0].response.payload, proposalResponses[0].endorsement .signature)); - var request = { - proposalResponses: proposalResponses, - proposal: proposal - }; - // set the transaction listener and set a timeout of 30sec - // if the transaction did not get committed within the timeout period, - // fail the test - var deployId = tx_id.getTransactionID(); - - eh = client.newEventHub(); - let data = fs.readFileSync(path.join(__dirname, ORGS[org].peers['peer1'][ - 'tls_cacerts' - ])); - eh.setPeerAddr(ORGS[org].peers['peer1']['events'], { - pem: Buffer.from(data).toString(), - 'ssl-target-name-override': ORGS[org].peers['peer1']['server-hostname'] - }); - eh.connect(); - - let txPromise = new Promise((resolve, reject) => { - let handle = setTimeout(() => { - eh.disconnect(); - reject(); - }, 30000); - eh.registerTxEvent(deployId, (tx, code) => { - logger.info( - 'The chaincode instantiate transaction has been committed on peer ' + - eh._ep._endpoint.addr); - clearTimeout(handle); - eh.unregisterTxEvent(deployId); - eh.disconnect(); + // tell each peer to join and wait for the event hub of each peer to tell us + // that the channel has been created on each peer + var promises = []; + let event_hubs = client.getEventHubsForOrg(org_name); + logger.debug('found %s eventhubs for this organization %s',event_hubs.length, org_name); + event_hubs.forEach((eh) => { + let instantiateEventPromise = new Promise((resolve, reject) => { + logger.debug('instantiateEventPromise - setting up event'); + let event_timeout = setTimeout(() => { + let message = 'REQUEST_TIMEOUT:' + eh._ep._endpoint.addr; + logger.error(message); + eh.disconnect(); + reject(new Error(message)); + }, 60000); + eh.registerTxEvent(deployId, (tx, code) => { + logger.info('The chaincode instantiate transaction has been committed on peer %s',eh._ep._endpoint.addr); + clearTimeout(event_timeout); + eh.unregisterTxEvent(deployId); - if (code !== 'VALID') { - logger.error('The chaincode instantiate transaction was invalid, code = ' + code); - reject(); - } else { - logger.info('The chaincode instantiate transaction was valid.'); - resolve(); - } + if (code !== 'VALID') { + let message = until.format('The chaincode instantiate transaction was invalid, code:%s',code); + logger.error(message); + reject(new Error(message)); + } else { + let message = 'The chaincode instantiate transaction was valid.'; + logger.info(message); + resolve(message); + } + }, (err) => { + clearTimeout(event_timeout); + eh.unregisterTxEvent(deployId); + let message = 'Problem setting up the event hub :'+ err.toString(); + logger.error(message); + reject(new Error(message)); + }); }); + promises.push(instantiateEventPromise); + eh.connect(); + eventhubs_in_use.push(eh); }); - var sendPromise = channel.sendTransaction(request); - return Promise.all([sendPromise].concat([txPromise])).then((results) => { - logger.debug('Event promise all complete and testing complete'); - return results[0]; // the first returned value is from the 'sendPromise' which is from the 'sendTransaction()' call - }).catch((err) => { - logger.error( - util.format('Failed to send instantiate transaction and get notifications within the timeout period. %s', err) - ); - return 'Failed to send instantiate transaction and get notifications within the timeout period.'; - }); - } else { - logger.error( - 'Failed to send instantiate Proposal or receive valid response. Response null or status is not 200. exiting...' - ); - return 'Failed to send instantiate Proposal or receive valid response. Response null or status is not 200. exiting...'; - } - }, (err) => { - logger.error('Failed to send instantiate proposal due to error: ' + err.stack ? - err.stack : err); - return 'Failed to send instantiate proposal due to error: ' + err.stack ? - err.stack : err; - }).then((response) => { - if (response.status === 'SUCCESS') { - logger.info('Successfully sent transaction to the orderer.'); - return 'Chaincode Instantiation is SUCCESS'; + var orderer_request = { + txId: tx_id, //must includethe transaction id so that the outbound + // transaction to the orderer will be signed by the admin + // id as was the proposal above, notice that transactionID + // generated above was based on the admin id not userContext. + proposalResponses: proposalResponses, + proposal: proposal + }; + var sendPromise = channel.sendTransaction(orderer_request); + // put the send to the orderer last so that the events get registered and + // are ready for the orderering and committing + promises.push(sendPromise); + let results = await Promise.all(promises); + logger.debug(util.format('------->>> R E S P O N S E : %j', results)); + let response = results.pop(); // orderer results are last in the results + if (response.status === 'SUCCESS') { + logger.info('Successfully sent transaction to the orderer.'); + } else { + error_message = util.format('Failed to order the transaction. Error code: %s',response.status); + logger.debug(error_message); + } + + // now see what each of the event hubs reported + for(let i in results) { + let event_hub_result = results[i]; + let event_hub = event_hubs[i]; + logger.debug('Event results for event hub :%s',event_hub._ep._endpoint.addr); + if(typeof event_hub_result === 'string') { + logger.debug(event_hub_result); + } else { + if(!error_message) error_message = event_hub_result.toString(); + logger.debug(event_hub_result.toString()); + } + } } else { - logger.error('Failed to order the transaction. Error code: ' + response.status); - return 'Failed to order the transaction. Error code: ' + response.status; + error_message = util.format('Failed to send Proposal and receive all good ProposalResponse'); + logger.debug(error_message); } - }, (err) => { - logger.error('Failed to send instantiate due to error: ' + err.stack ? err - .stack : err); - return 'Failed to send instantiate due to error: ' + err.stack ? err.stack : - err; + } catch (error) { + logger.error('Failed to send instantiate due to error: ' + error.stack ? error.stack : error); + error_message = error.toString(); + } + + // need to shutdown open event streams + eventhubs_in_use.forEach((eh) => { + eh.disconnect(); }); + + if (!error_message) { + let message = util.format( + 'Successfully instantiate chaingcode in organization %s to the channel \'%s\'', + org_name, channelName); + logger.info(message); + // build a response to send back to the REST caller + let response = { + success: true, + message: message + }; + return response; + } else { + let message = util.format('Failed to instantiate. cause:%s',error_message); + logger.error(message); + throw new Error(message); + } }; exports.instantiateChaincode = instantiateChaincode; diff --git a/balance-transfer/app/invoke-transaction.js b/balance-transfer/app/invoke-transaction.js index 2a63d7fb90..b6b13412d3 100644 --- a/balance-transfer/app/invoke-transaction.js +++ b/balance-transfer/app/invoke-transaction.js @@ -18,22 +18,28 @@ var path = require('path'); var fs = require('fs'); var util = require('util'); var hfc = require('fabric-client'); -var Peer = require('fabric-client/lib/Peer.js'); var helper = require('./helper.js'); var logger = helper.getLogger('invoke-chaincode'); -var EventHub = require('fabric-client/lib/EventHub.js'); -var ORGS = hfc.getConfigSetting('network-config'); -var invokeChaincode = function(peerNames, channelName, chaincodeName, fcn, args, username, org) { - logger.debug(util.format('\n============ invoke transaction on organization %s ============\n', org)); - var client = helper.getClientForOrg(org); - var channel = helper.getChannelForOrg(org); - var targets = (peerNames) ? helper.newPeers(peerNames, org) : undefined; - var tx_id = null; +var invokeChaincode = async function(peerNames, channelName, chaincodeName, fcn, args, username, org_name) { + logger.debug(util.format('\n============ invoke transaction on channel %s ============\n', channelName)); + var error_message = null; + var eventhubs_in_use = []; + var tx_id_string = null; + try { + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); + var channel = client.getChannel(channelName); + if(!channel) { + let message = util.format('Channel %s was not defined in the connection profile', channelName); + logger.error(message); + throw new Error(message); + } + var tx_id = client.newTransactionID(); + // will need the transaction ID string for the event registration later + tx_id_string = tx_id.getTransactionID(); - return helper.getRegisteredUsers(username, org).then((user) => { - tx_id = client.newTransactionID(); - logger.debug(util.format('Sending transaction "%j"', tx_id)); // send proposal to endorser var request = { chaincodeId: chaincodeName, @@ -43,115 +49,133 @@ var invokeChaincode = function(peerNames, channelName, chaincodeName, fcn, args, txId: tx_id }; - if (targets) - request.targets = targets; + let results = await channel.sendTransactionProposal(request); - return channel.sendTransactionProposal(request); - }, (err) => { - logger.error('Failed to enroll user \'' + username + '\'. ' + err); - throw new Error('Failed to enroll user \'' + username + '\'. ' + err); - }).then((results) => { + // the returned object has both the endorsement results + // and the actual proposal, the proposal will be needed + // later when we send a transaction to the orderer var proposalResponses = results[0]; var proposal = results[1]; + + // lets have a look at the responses to see if they are + // all good, if good they will also include signatures + // required to be committed var all_good = true; for (var i in proposalResponses) { let one_good = false; if (proposalResponses && proposalResponses[i].response && proposalResponses[i].response.status === 200) { one_good = true; - logger.info('transaction proposal was good'); + logger.info('invoke chaincode proposal was good'); } else { - logger.error('transaction proposal was bad'); + logger.error('invoke chaincode proposal was bad'); } all_good = all_good & one_good; } + if (all_good) { - logger.debug(util.format( + logger.info(util.format( 'Successfully sent Proposal and received ProposalResponse: Status - %s, message - "%s", metadata - "%s", endorsement signature: %s', proposalResponses[0].response.status, proposalResponses[0].response.message, proposalResponses[0].response.payload, proposalResponses[0].endorsement .signature)); - var request = { - proposalResponses: proposalResponses, - proposal: proposal - }; - // set the transaction listener and set a timeout of 30sec - // if the transaction did not get committed within the timeout period, - // fail the test - var transactionID = tx_id.getTransactionID(); - var eventPromises = []; - - if (!peerNames) { - peerNames = channel.getPeers().map(function(peer) { - return peer.getName(); - }); - } - - var eventhubs = helper.newEventHubs(peerNames, org); - for (let key in eventhubs) { - let eh = eventhubs[key]; - eh.connect(); - let txPromise = new Promise((resolve, reject) => { - let handle = setTimeout(() => { - eh.disconnect(); - reject(); - }, 30000); - - eh.registerTxEvent(transactionID, (tx, code) => { - clearTimeout(handle); - eh.unregisterTxEvent(transactionID); + // tell each peer to join and wait for the event hub of each peer to tell us + // that the channel has been created on each peer + var promises = []; + let event_hubs = client.getEventHubsForOrg(org_name); + event_hubs.forEach((eh) => { + logger.debug('invokeEventPromise - setting up event'); + let invokeEventPromise = new Promise((resolve, reject) => { + let event_timeout = setTimeout(() => { + let message = 'REQUEST_TIMEOUT:' + eh._ep._endpoint.addr; + logger.error(message); eh.disconnect(); + reject(new Error(message)); + }, 3000); + eh.registerTxEvent(tx_id_string, (tx, code) => { + logger.info('The chaincode invoke chaincode transaction has been committed on peer %s',eh._ep._endpoint.addr); + clearTimeout(event_timeout); + eh.unregisterTxEvent(tx_id_string); if (code !== 'VALID') { - logger.error( - 'The balance transfer transaction was invalid, code = ' + code); - reject(); + let message = until.format('The invoke chaincode transaction was invalid, code:%s',code); + logger.error(message); + reject(new Error(message)); } else { - logger.info( - 'The balance transfer transaction has been committed on peer ' + - eh._ep._endpoint.addr); - resolve(); + let message = 'The invoke chaincode transaction was valid.'; + logger.info(message); + resolve(message); } + }, (err) => { + clearTimeout(event_timeout); + eh.unregisterTxEvent(tx_id_string); + let message = 'Problem setting up the event hub :'+ err.toString(); + logger.error(message); + reject(new Error(message)); }); }); - eventPromises.push(txPromise); - }; - var sendPromise = channel.sendTransaction(request); - return Promise.all([sendPromise].concat(eventPromises)).then((results) => { - logger.debug(' event promise all complete and testing complete'); - return results[0]; // the first returned value is from the 'sendPromise' which is from the 'sendTransaction()' call - }).catch((err) => { - logger.error( - 'Failed to send transaction and get notifications within the timeout period.' - ); - return 'Failed to send transaction and get notifications within the timeout period.'; + promises.push(invokeEventPromise); + eh.connect(); + eventhubs_in_use.push(eh); }); + + var orderer_request = { + txId: tx_id, + proposalResponses: proposalResponses, + proposal: proposal + }; + var sendPromise = channel.sendTransaction(orderer_request); + // put the send to the orderer last so that the events get registered and + // are ready for the orderering and committing + promises.push(sendPromise); + let results = await Promise.all(promises); + logger.debug(util.format('------->>> R E S P O N S E : %j', results)); + let response = results.pop(); // orderer results are last in the results + if (response.status === 'SUCCESS') { + logger.info('Successfully sent transaction to the orderer.'); + } else { + error_message = util.format('Failed to order the transaction. Error code: %s',response.status); + logger.debug(error_message); + } + + // now see what each of the event hubs reported + for(let i in results) { + let event_hub_result = results[i]; + let event_hub = event_hubs[i]; + logger.debug('Event results for event hub :%s',event_hub._ep._endpoint.addr); + if(typeof event_hub_result === 'string') { + logger.debug(event_hub_result); + } else { + if(!error_message) error_message = event_hub_result.toString(); + logger.debug(event_hub_result.toString()); + } + } } else { - logger.error( - 'Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...' - ); - return 'Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...'; - } - }, (err) => { - logger.error('Failed to send proposal due to error: ' + err.stack ? err.stack : - err); - return 'Failed to send proposal due to error: ' + err.stack ? err.stack : - err; - }).then((response) => { - if (response.status === 'SUCCESS') { - logger.info('Successfully sent transaction to the orderer.'); - return tx_id.getTransactionID(); - } else { - logger.error('Failed to order the transaction. Error code: ' + response.status); - return 'Failed to order the transaction. Error code: ' + response.status; + error_message = util.format('Failed to send Proposal and receive all good ProposalResponse'); + logger.debug(error_message); } - }, (err) => { - logger.error('Failed to send transaction due to error: ' + err.stack ? err - .stack : err); - return 'Failed to send transaction due to error: ' + err.stack ? err.stack : - err; + } catch (error) { + logger.error('Failed to invoke due to error: ' + error.stack ? error.stack : error); + error_message = error.toString(); + } + + // need to shutdown open event streams + eventhubs_in_use.forEach((eh) => { + eh.disconnect(); }); + + if (!error_message) { + let message = util.format( + 'Successfully invoked the chaincode %s to the channel \'%s\'', + org_name, channelName); + logger.info(message); + return tx_id_string; + } else { + let message = util.format('Failed to invoke chaincode. cause:%s',error_message); + logger.error(message); + throw new Error(message); + } }; exports.invokeChaincode = invokeChaincode; diff --git a/balance-transfer/app/join-channel.js b/balance-transfer/app/join-channel.js index 5e174c9aeb..854994a68c 100644 --- a/balance-transfer/app/join-channel.js +++ b/balance-transfer/app/join-channel.js @@ -17,123 +17,144 @@ var util = require('util'); var path = require('path'); var fs = require('fs'); -var Peer = require('fabric-client/lib/Peer.js'); -var EventHub = require('fabric-client/lib/EventHub.js'); -var tx_id = null; -var nonce = null; -var config = require('../config.json'); var helper = require('./helper.js'); var logger = helper.getLogger('Join-Channel'); -//helper.hfc.addConfigFile(path.join(__dirname, 'network-config.json')); -var ORGS = helper.ORGS; -var allEventhubs = []; -// -//Attempt to send a request to the orderer with the sendCreateChain method -// -var joinChannel = function(channelName, peers, username, org) { - // on process exit, always disconnect the event hub - var closeConnections = function(isSuccess) { - if (isSuccess) { - logger.debug('\n============ Join Channel is SUCCESS ============\n'); - } else { - logger.debug('\n!!!!!!!! ERROR: Join Channel FAILED !!!!!!!!\n'); - } - logger.debug(''); - for (var key in allEventhubs) { - var eventhub = allEventhubs[key]; - if (eventhub && eventhub.isconnected()) { - //logger.debug('Disconnecting the event hub'); - eventhub.disconnect(); - } - } - }; - //logger.debug('\n============ Join Channel ============\n') - logger.info(util.format( - 'Calling peers in organization "%s" to join the channel', org)); +/* + * Have an organization join a channel + */ +var joinChannel = async function(channel_name, peers, username, org_name) { + logger.debug('\n\n============ Join Channel start ============\n') + var error_message = null; + var all_eventhubs = []; + try { + logger.info('Calling peers in organization "%s" to join the channel', org_name); - var client = helper.getClientForOrg(org); - var channel = helper.getChannelForOrg(org); - var eventhubs = []; + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); + var channel = client.getChannel(channel_name); + if(!channel) { + let message = util.format('Channel %s was not defined in the connection profile', channel_name); + logger.error(message); + throw new Error(message); + } - return helper.getOrgAdmin(org).then((admin) => { - logger.info(util.format('received member object for admin of the organization "%s": ', org)); - tx_id = client.newTransactionID(); + // next step is to get the genesis_block from the orderer, + // the starting point for the channel that we want to join let request = { - txId : tx_id + txId : client.newTransactionID(true) //get an admin based transactionID }; + let genesis_block = await channel.getGenesisBlock(request); - return channel.getGenesisBlock(request); - }).then((genesis_block) => { - tx_id = client.newTransactionID(); - var request = { - targets: helper.newPeers(peers, org), - txId: tx_id, - block: genesis_block - }; - - eventhubs = helper.newEventHubs(peers, org); - for (let key in eventhubs) { - let eh = eventhubs[key]; - eh.connect(); - allEventhubs.push(eh); - } - - var eventPromises = []; - eventhubs.forEach((eh) => { - let txPromise = new Promise((resolve, reject) => { - let handle = setTimeout(reject, parseInt(config.eventWaitTime)); - eh.registerBlockEvent((block) => { - clearTimeout(handle); - // in real-world situations, a peer may have more than one channels so - // we must check that this block came from the channel we asked the peer to join + // tell each peer to join and wait for the event hub of each peer to tell us + // that the channel has been created on each peer + var promises = []; + var block_registration_numbers = []; + let event_hubs = client.getEventHubsForOrg(org_name); + event_hubs.forEach((eh) => { + let configBlockPromise = new Promise((resolve, reject) => { + let event_timeout = setTimeout(() => { + let message = 'REQUEST_TIMEOUT:' + eh._ep._endpoint.addr; + logger.error(message); + eh.disconnect(); + reject(new Error(message)); + }, 60000); + let block_registration_number = eh.registerBlockEvent((block) => { + clearTimeout(event_timeout); + // a peer may have more than one channel so + // we must check that this block came from the channel we + // asked the peer to join if (block.data.data.length === 1) { // Config block must only contain one transaction var channel_header = block.data.data[0].payload.header.channel_header; - if (channel_header.channel_id === channelName) { - resolve(); - } - else { - reject(); + if (channel_header.channel_id === channel_name) { + let message = util.format('EventHub % has reported a block update for channel %s',eh._ep._endpoint.addr,channel_name); + logger.info(message) + resolve(message); + } else { + let message = util.format('Unknown channel block event received from %s',eh._ep._endpoint.addr); + logger.error(message); + reject(new Error(message)); } } + }, (err) => { + clearTimeout(event_timeout); + let message = 'Problem setting up the event hub :'+ err.toString(); + logger.error(message); + reject(new Error(message)); }); + // save the registration handle so able to deregister + block_registration_numbers.push(block_registration_number); + all_eventhubs.push(eh); //save for later so that we can shut it down }); - eventPromises.push(txPromise); + promises.push(configBlockPromise); + eh.connect(); //this opens the event stream that must be shutdown at some point with a disconnect() }); - let sendPromise = channel.joinChannel(request); - return Promise.all([sendPromise].concat(eventPromises)); - }, (err) => { - logger.error('Failed to enroll user \'' + username + '\' due to error: ' + - err.stack ? err.stack : err); - throw new Error('Failed to enroll user \'' + username + - '\' due to error: ' + err.stack ? err.stack : err); - }).then((results) => { + + let join_request = { + targets: peers, //using the peer names which only is allowed when a connection profile is loaded + txId: client.newTransactionID(true), //get an admin based transactionID + block: genesis_block + }; + let join_promise = channel.joinChannel(join_request); + promises.push(join_promise); + let results = await Promise.all(promises); logger.debug(util.format('Join Channel R E S P O N S E : %j', results)); - if (results[0] && results[0][0] && results[0][0].response && results[0][0] - .response.status == 200) { - logger.info(util.format( - 'Successfully joined peers in organization %s to the channel \'%s\'', - org, channelName)); - closeConnections(true); - let response = { - success: true, - message: util.format( - 'Successfully joined peers in organization %s to the channel \'%s\'', - org, channelName) - }; - return response; - } else { - logger.error(' Failed to join channel'); - closeConnections(); - throw new Error('Failed to join channel'); + + // lets check the results of sending to the peers which is + // last in the results array + let peers_results = results.pop(); + // then each peer results + for(let i in peers_results) { + let peer_result = peers_results[i]; + if(peer_result.response && peer_result.response.status == 200) { + logger.info('Successfully joined peer to the channel %s',channel_name); + } else { + let message = util.format('Failed to joined peer to the channel %s',channel_name); + error_message = message; + logger.error(message); + } } - }, (err) => { - logger.error('Failed to join channel due to error: ' + err.stack ? err.stack : - err); - closeConnections(); - throw new Error('Failed to join channel due to error: ' + err.stack ? err.stack : - err); + // now see what each of the event hubs reported + for(let i in results) { + let event_hub_result = results[i]; + let event_hub = event_hubs[i]; + let block_registration_number = block_registration_numbers[i]; + logger.debug('Event results for event hub :%s',event_hub._ep._endpoint.addr); + if(typeof event_hub_result === 'string') { + logger.debug(event_hub_result); + } else { + if(!error_message) error_message = event_hub_result.toString(); + logger.debug(event_hub_result.toString()); + } + event_hub.unregisterBlockEvent(block_registration_number); + } + } catch(error) { + logger.error('Failed to join channel due to error: ' + error.stack ? error.stack : error); + error_message = error.toString(); + } + + // need to shutdown open event streams + all_eventhubs.forEach((eh) => { + eh.disconnect(); }); + + if (!error_message) { + let message = util.format( + 'Successfully joined peers in organization %s to the channel:%s', + org_name, channel_name); + logger.info(message); + // build a response to send back to the REST caller + let response = { + success: true, + message: message + }; + return response; + } else { + let message = util.format('Failed to join all peers to channel. cause:%s',error_message); + logger.error(message); + throw new Error(message); + } }; exports.joinChannel = joinChannel; diff --git a/balance-transfer/app/network-config-aws.json b/balance-transfer/app/network-config-aws.json deleted file mode 100644 index 310cfbe97b..0000000000 --- a/balance-transfer/app/network-config-aws.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "network-config": { - "orderer": { - "url": "grpc://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7050", - "server-hostname": "orderer.example.com", - "tls_cacerts": "../artifacts/channel/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt" - }, - "org1": { - "name": "peerOrg1", - "mspid": "Org1MSP", - "ca": "https://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7054", - "peers": { - "peer1": { - "requests": "grpc://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7051", - "events": "grpc://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7053", - "server-hostname": "peer0.org1.example.com", - "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" - }, - "peer2": { - "requests": "grpc://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7056", - "events": "grpc://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7058", - "server-hostname": "peer1.org1.example.com", - "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt" - } - }, - "admin": { - "key": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore", - "cert": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts" - } - }, - "org2": { - "name": "peerOrg2", - "mspid": "Org2MSP", - "ca": "https://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:8054", - "peers": { - "peer1": { - "requests": "grpc://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:8051", - "events": "grpc://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:8053", - "server-hostname": "peer0.org2.example.com", - "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" - }, - "peer2": { - "requests": "grpc://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:8056", - "events": "grpc://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:8058", - "server-hostname": "peer1.org2.example.com", - "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt" - } - }, - "admin": { - "key": "../artifacts/channel/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore", - "cert": "../artifacts/channel/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts" - } - } - } -} diff --git a/balance-transfer/app/network-config.json b/balance-transfer/app/network-config.json deleted file mode 100644 index 80289fa782..0000000000 --- a/balance-transfer/app/network-config.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "network-config": { - "orderer": { - "url": "grpcs://localhost:7050", - "server-hostname": "orderer.example.com", - "tls_cacerts": "../artifacts/channel/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt" - }, - "org1": { - "name": "peerOrg1", - "mspid": "Org1MSP", - "ca": "https://localhost:7054", - "peers": { - "peer1": { - "requests": "grpcs://localhost:7051", - "events": "grpcs://localhost:7053", - "server-hostname": "peer0.org1.example.com", - "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" - }, - "peer2": { - "requests": "grpcs://localhost:7056", - "events": "grpcs://localhost:7058", - "server-hostname": "peer1.org1.example.com", - "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt" - } - }, - "admin": { - "key": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore", - "cert": "../artifacts/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts" - } - }, - "org2": { - "name": "peerOrg2", - "mspid": "Org2MSP", - "ca": "https://localhost:8054", - "peers": { - "peer1": { - "requests": "grpcs://localhost:8051", - "events": "grpcs://localhost:8053", - "server-hostname": "peer0.org2.example.com", - "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" - }, - "peer2": { - "requests": "grpcs://localhost:8056", - "events": "grpcs://localhost:8058", - "server-hostname": "peer1.org2.example.com", - "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt" - } - }, - "admin": { - "key": "../artifacts/channel/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore", - "cert": "../artifacts/channel/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts" - } - } - } -} diff --git a/balance-transfer/app/query.js b/balance-transfer/app/query.js index ef8676b16c..22ed5162d0 100644 --- a/balance-transfer/app/query.js +++ b/balance-transfer/app/query.js @@ -17,31 +17,29 @@ var path = require('path'); var fs = require('fs'); var util = require('util'); var hfc = require('fabric-client'); -var Peer = require('fabric-client/lib/Peer.js'); -var EventHub = require('fabric-client/lib/EventHub.js'); -var config = require('../config.json'); var helper = require('./helper.js'); var logger = helper.getLogger('Query'); -var queryChaincode = function(peer, channelName, chaincodeName, args, fcn, username, org) { - var channel = helper.getChannelForOrg(org); - var client = helper.getClientForOrg(org); - var target = buildTarget(peer, org); - return helper.getRegisteredUsers(username, org).then((user) => { - tx_id = client.newTransactionID(); +var queryChaincode = async function(peer, channelName, chaincodeName, args, fcn, username, org_name) { + try { + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); + var channel = client.getChannel(channelName); + if(!channel) { + let message = util.format('Channel %s was not defined in the connection profile', channelName); + logger.error(message); + throw new Error(message); + } + // send query var request = { + targets : [peer], //queryByChaincode allows for multiple targets chaincodeId: chaincodeName, - txId: tx_id, fcn: fcn, args: args }; - return channel.queryByChaincode(request, target); - }, (err) => { - logger.info('Failed to get submitter \''+username+'\''); - return 'Failed to get submitter \''+username+'\'. Error: ' + err.stack ? err.stack : - err; - }).then((response_payloads) => { + let response_payloads = await channel.queryByChaincode(request); if (response_payloads) { for (let i = 0; i < response_payloads.length; i++) { logger.info(args[0]+' now has ' + response_payloads[i].toString('utf8') + @@ -53,147 +51,130 @@ var queryChaincode = function(peer, channelName, chaincodeName, args, fcn, usern logger.error('response_payloads is null'); return 'response_payloads is null'; } - }, (err) => { - logger.error('Failed to send query due to error: ' + err.stack ? err.stack : - err); - return 'Failed to send query due to error: ' + err.stack ? err.stack : err; - }).catch((err) => { - logger.error('Failed to end to end test with error:' + err.stack ? err.stack : - err); - return 'Failed to end to end test with error:' + err.stack ? err.stack : - err; - }); + } catch(error) { + logger.error('Failed to query due to error: ' + error.stack ? error.stack : error); + return error.toString(); + } }; -var getBlockByNumber = function(peer, blockNumber, username, org) { - var target = buildTarget(peer, org); - var channel = helper.getChannelForOrg(org); +var getBlockByNumber = async function(peer, channelName, blockNumber, username, org_name) { + try { + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); + var channel = client.getChannel(channelName); + if(!channel) { + let message = util.format('Channel %s was not defined in the connection profile', channelName); + logger.error(message); + throw new Error(message); + } - return helper.getRegisteredUsers(username, org).then((member) => { - return channel.queryBlock(parseInt(blockNumber), target); - }, (err) => { - logger.info('Failed to get submitter "' + username + '"'); - return 'Failed to get submitter "' + username + '". Error: ' + err.stack ? - err.stack : err; - }).then((response_payloads) => { - if (response_payloads) { - //logger.debug(response_payloads); - logger.debug(response_payloads); - return response_payloads; //response_payloads.data.data[0].buffer; + let response_payload = await channel.queryBlock(parseInt(blockNumber, peer)); + if (response_payload) { + logger.debug(response_payload); + return response_payload; } else { - logger.error('response_payloads is null'); - return 'response_payloads is null'; + logger.error('response_payload is null'); + return 'response_payload is null'; } - }, (err) => { - logger.error('Failed to send query due to error: ' + err.stack ? err.stack : - err); - return 'Failed to send query due to error: ' + err.stack ? err.stack : err; - }).catch((err) => { - logger.error('Failed to query with error:' + err.stack ? err.stack : err); - return 'Failed to query with error:' + err.stack ? err.stack : err; - }); + } catch(error) { + logger.error('Failed to query due to error: ' + error.stack ? error.stack : error); + return error.toString(); + } }; -var getTransactionByID = function(peer, trxnID, username, org) { - var target = buildTarget(peer, org); - var channel = helper.getChannelForOrg(org); +var getTransactionByID = async function(peer, channelName, trxnID, username, org_name) { + try { + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); + var channel = client.getChannel(channelName); + if(!channel) { + let message = util.format('Channel %s was not defined in the connection profile', channelName); + logger.error(message); + throw new Error(message); + } - return helper.getRegisteredUsers(username, org).then((member) => { - return channel.queryTransaction(trxnID, target); - }, (err) => { - logger.info('Failed to get submitter "' + username + '"'); - return 'Failed to get submitter "' + username + '". Error: ' + err.stack ? - err.stack : err; - }).then((response_payloads) => { - if (response_payloads) { - logger.debug(response_payloads); - return response_payloads; + let response_payload = await channel.queryTransaction(trxnID, peer); + if (response_payload) { + logger.debug(response_payload); + return response_payload; } else { - logger.error('response_payloads is null'); - return 'response_payloads is null'; + logger.error('response_payload is null'); + return 'response_payload is null'; } - }, (err) => { - logger.error('Failed to send query due to error: ' + err.stack ? err.stack : - err); - return 'Failed to send query due to error: ' + err.stack ? err.stack : err; - }).catch((err) => { - logger.error('Failed to query with error:' + err.stack ? err.stack : err); - return 'Failed to query with error:' + err.stack ? err.stack : err; - }); + } catch(error) { + logger.error('Failed to query due to error: ' + error.stack ? error.stack : error); + return error.toString(); + } }; -var getBlockByHash = function(peer, hash, username, org) { - var target = buildTarget(peer, org); - var channel = helper.getChannelForOrg(org); +var getBlockByHash = async function(peer, channelName, hash, username, org_name) { + try { + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); + var channel = client.getChannel(channelName); + if(!channel) { + let message = util.format('Channel %s was not defined in the connection profile', channelName); + logger.error(message); + throw new Error(message); + } - return helper.getRegisteredUsers(username, org).then((member) => { - return channel.queryBlockByHash(Buffer.from(hash), target); - }, (err) => { - logger.info('Failed to get submitter "' + username + '"'); - return 'Failed to get submitter "' + username + '". Error: ' + err.stack ? - err.stack : err; - }).then((response_payloads) => { - if (response_payloads) { - logger.debug(response_payloads); - return response_payloads; + let response_payload = await channel.queryBlockByHash(Buffer.from(hash), peer); + if (response_payload) { + logger.debug(response_payload); + return response_payload; } else { - logger.error('response_payloads is null'); - return 'response_payloads is null'; + logger.error('response_payload is null'); + return 'response_payload is null'; } - }, (err) => { - logger.error('Failed to send query due to error: ' + err.stack ? err.stack : - err); - return 'Failed to send query due to error: ' + err.stack ? err.stack : err; - }).catch((err) => { - logger.error('Failed to query with error:' + err.stack ? err.stack : err); - return 'Failed to query with error:' + err.stack ? err.stack : err; - }); + } catch(error) { + logger.error('Failed to query due to error: ' + error.stack ? error.stack : error); + return error.toString(); + } }; -var getChainInfo = function(peer, username, org) { - var target = buildTarget(peer, org); - var channel = helper.getChannelForOrg(org); +var getChainInfo = async function(peer, channelName, username, org_name) { + try { + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); + var channel = client.getChannel(channelName); + if(!channel) { + let message = util.format('Channel %s was not defined in the connection profile', channelName); + logger.error(message); + throw new Error(message); + } - return helper.getRegisteredUsers(username, org).then((member) => { - return channel.queryInfo(target); - }, (err) => { - logger.info('Failed to get submitter "' + username + '"'); - return 'Failed to get submitter "' + username + '". Error: ' + err.stack ? - err.stack : err; - }).then((blockchainInfo) => { - if (blockchainInfo) { - // FIXME: Save this for testing 'getBlockByHash' ? - logger.debug('==========================================='); - logger.debug(blockchainInfo.currentBlockHash); - logger.debug('==========================================='); - //logger.debug(blockchainInfo); - return blockchainInfo; + let response_payload = await channel.queryInfo(peer); + if (response_payload) { + logger.debug(response_payload); + return response_payload; } else { - logger.error('response_payloads is null'); - return 'response_payloads is null'; + logger.error('response_payload is null'); + return 'response_payload is null'; } - }, (err) => { - logger.error('Failed to send query due to error: ' + err.stack ? err.stack : - err); - return 'Failed to send query due to error: ' + err.stack ? err.stack : err; - }).catch((err) => { - logger.error('Failed to query with error:' + err.stack ? err.stack : err); - return 'Failed to query with error:' + err.stack ? err.stack : err; - }); + } catch(error) { + logger.error('Failed to query due to error: ' + error.stack ? error.stack : error); + return error.toString(); + } }; //getInstalledChaincodes -var getInstalledChaincodes = function(peer, type, username, org) { - var target = buildTarget(peer, org); - var channel = helper.getChannelForOrg(org); - var client = helper.getClientForOrg(org); +var getInstalledChaincodes = async function(peer, channelName, type, username, org_name) { + try { + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); - return helper.getOrgAdmin(org).then((member) => { + let response = null if (type === 'installed') { - return client.queryInstalledChaincodes(target); + response = await client.queryInstalledChaincodes(peer, true); //use the admin identity } else { - return channel.queryInstantiatedChaincodes(target); + var channel = client.getChannel(channelName); + if(!channel) { + let message = util.format('Channel %s was not defined in the connection profile', channelName); + logger.error(message); + throw new Error(message); + } + response = await channel.queryInstantiatedChaincodes(peer, true); //use the admin identity } - }, (err) => { - logger.info('Failed to get submitter "' + username + '"'); - return 'Failed to get submitter "' + username + '". Error: ' + err.stack ? - err.stack : err; - }).then((response) => { if (response) { if (type === 'installed') { logger.debug('<<< Installed Chaincodes >>>'); @@ -214,28 +195,18 @@ var getInstalledChaincodes = function(peer, type, username, org) { logger.error('response is null'); return 'response is null'; } - }, (err) => { - logger.error('Failed to send query due to error: ' + err.stack ? err.stack : - err); - return 'Failed to send query due to error: ' + err.stack ? err.stack : err; - }).catch((err) => { - logger.error('Failed to query with error:' + err.stack ? err.stack : err); - return 'Failed to query with error:' + err.stack ? err.stack : err; - }); + } catch(error) { + logger.error('Failed to query due to error: ' + error.stack ? error.stack : error); + return error.toString(); + } }; -var getChannels = function(peer, username, org) { - var target = buildTarget(peer, org); - var channel = helper.getChannelForOrg(org); - var client = helper.getClientForOrg(org); +var getChannels = async function(peer, username, org_name) { + try { + // first setup the client for this org + var client = await helper.getClientForOrg(org_name, username); + logger.debug('Successfully got the fabric client for the organization "%s"', org_name); - return helper.getRegisteredUsers(username, org).then((member) => { - //channel.setPrimaryPeer(targets[0]); - return client.queryChannels(target); - }, (err) => { - logger.info('Failed to get submitter "' + username + '"'); - return 'Failed to get submitter "' + username + '". Error: ' + err.stack ? - err.stack : err; - }).then((response) => { + let response = await client.queryChannels(peer); if (response) { logger.debug('<<< channels >>>'); var channelNames = []; @@ -248,25 +219,11 @@ var getChannels = function(peer, username, org) { logger.error('response_payloads is null'); return 'response_payloads is null'; } - }, (err) => { - logger.error('Failed to send query due to error: ' + err.stack ? err.stack : - err); - return 'Failed to send query due to error: ' + err.stack ? err.stack : err; - }).catch((err) => { - logger.error('Failed to query with error:' + err.stack ? err.stack : err); - return 'Failed to query with error:' + err.stack ? err.stack : err; - }); -}; - -function buildTarget(peer, org) { - var target = null; - if (typeof peer !== 'undefined') { - let targets = helper.newPeers([peer], org); - if (targets && targets.length > 0) target = targets[0]; + } catch(error) { + logger.error('Failed to query due to error: ' + error.stack ? error.stack : error); + return error.toString(); } - - return target; -} +}; exports.queryChaincode = queryChaincode; exports.getBlockByNumber = getBlockByNumber; diff --git a/balance-transfer/artifacts/docker-compose.yaml b/balance-transfer/artifacts/docker-compose.yaml index 5e64248dff..c5098077e5 100644 --- a/balance-transfer/artifacts/docker-compose.yaml +++ b/balance-transfer/artifacts/docker-compose.yaml @@ -11,6 +11,7 @@ services: image: hyperledger/fabric-ca environment: - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server + - FABRIC_CA_SERVER_CA_NAME=ca-org1 - FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/0e729224e8b3f31784c8a93c5b8ef6f4c1c91d9e6e577c45c33163609fe40011_sk - FABRIC_CA_SERVER_TLS_ENABLED=true @@ -27,6 +28,7 @@ services: image: hyperledger/fabric-ca environment: - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server + - FABRIC_CA_SERVER_CA_NAME=ca-org2 - FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org2.example.com-cert.pem - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/a7d47efa46a6ba07730c850fed2c1375df27360d7227f48cdc2f80e505678005_sk - FABRIC_CA_SERVER_TLS_ENABLED=true diff --git a/balance-transfer/artifacts/network-config-aws.yaml b/balance-transfer/artifacts/network-config-aws.yaml new file mode 100644 index 0000000000..7402a67f12 --- /dev/null +++ b/balance-transfer/artifacts/network-config-aws.yaml @@ -0,0 +1,236 @@ +--- +# +# The network connection profile provides client applications the information about the target +# blockchain network that are necessary for the applications to interact with it. These are all +# knowledge that must be acquired from out-of-band sources. This file provides such a source. +# +name: "balance-transfer" + +# +# Any properties with an "x-" prefix will be treated as application-specific, exactly like how naming +# in HTTP headers or swagger properties work. The SDK will simply ignore these fields and leave +# them for the applications to process. This is a mechanism for different components of an application +# to exchange information that are not part of the standard schema described below. In particular, +# the "x-type" property with the "hlfv1" value example below is used by Hyperledger Composer to +# determine the type of Fabric networks (v0.6 vs. v1.0) it needs to work with. +# +x-type: "hlfv1" + +# +# Describe what the target network is/does. +# +description: "Balance Transfer Network" + +# +# Schema version of the content. Used by the SDK to apply the corresponding parsing rules. +# +version: "1.0" + +# +# The client section will be added on a per org basis see org1.yaml and org2.yaml +# +#client: + +# +# [Optional]. But most apps would have this section so that channel objects can be constructed +# based on the content below. If an app is creating channels, then it likely will not need this +# section. +# +channels: + # name of the channel + mychannel: + # Required. list of orderers designated by the application to use for transactions on this + # channel. This list can be a result of access control ("org1" can only access "ordererA"), or + # operational decisions to share loads from applications among the orderers. The values must + # be "names" of orgs defined under "organizations/peers" + orderers: + - orderer.example.com + + # Required. list of peers from participating orgs + peers: + peer0.org1.example.com: + # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must + # have the chaincode installed. The app can also use this property to decide which peers + # to send the chaincode install request. Default: true + endorsingPeer: true + + # [Optional]. will this peer be sent query proposals? The peer must have the chaincode + # installed. The app can also use this property to decide which peers to send the + # chaincode install request. Default: true + chaincodeQuery: true + + # [Optional]. will this peer be sent query proposals that do not require chaincodes, like + # queryBlock(), queryTransaction(), etc. Default: true + ledgerQuery: true + + # [Optional]. will this peer be the target of the SDK's listener registration? All peers can + # produce events but the app typically only needs to connect to one to listen to events. + # Default: true + eventSource: true + + peer1.org1.example.com: + endorsingPeer: false + chaincodeQuery: true + ledgerQuery: true + eventSource: false + + peer0.org2.example.com: + endorsingPeer: true + chaincodeQuery: true + ledgerQuery: true + eventSource: true + + peer1.org2.example.com: + endorsingPeer: false + chaincodeQuery: true + ledgerQuery: true + eventSource: false + + # [Optional]. what chaincodes are expected to exist on this channel? The application can use + # this information to validate that the target peers are in the expected state by comparing + # this list with the query results of getInstalledChaincodes() and getInstantiatedChaincodes() + chaincodes: + # the format follows the "cannonical name" of chaincodes by fabric code + - mycc:v0 + +# +# list of participating organizations in this network +# +organizations: + Org1: + mspid: Org1MSP + + peers: + - peer0.org1.example.com + - peer1.org1.example.com + + # [Optional]. Certificate Authorities issue certificates for identification purposes in a Fabric based + # network. Typically certificates provisioning is done in a separate process outside of the + # runtime network. Fabric-CA is a special certificate authority that provides a REST APIs for + # dynamic certificate management (enroll, revoke, re-enroll). The following section is only for + # Fabric-CA servers. + certificateAuthorities: + - ca-org1 + + # [Optional]. If the application is going to make requests that are reserved to organization + # administrators, including creating/updating channels, installing/instantiating chaincodes, it + # must have access to the admin identity represented by the private key and signing certificate. + # Both properties can be the PEM string or local path to the PEM file. Note that this is mainly for + # convenience in development mode, production systems should not expose sensitive information + # this way. The SDK should allow applications to set the org admin identity via APIs, and only use + # this route as an alternative when it exists. + adminPrivateKey: + path: artifacts/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/5890f0061619c06fb29dea8cb304edecc020fe63f41a6db109f1e227cc1cb2a8_sk + signedCert: + path: artifacts/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem + + # the profile will contain public information about organizations other than the one it belongs to. + # These are necessary information to make transaction lifecycles work, including MSP IDs and + # peers with a public URL to send transaction proposals. The file will not contain private + # information reserved for members of the organization, such as admin key and certificate, + # fabric-ca registrar enroll ID and secret, etc. + Org2: + mspid: Org2MSP + peers: + - peer0.org2.example.com + - peer1.org2.example.com + certificateAuthorities: + - ca-org2 + adminPrivateKey: + path: artifacts/channel/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/1995b11d6573ed3be52fcd7a5fa477bc0f183e1f5f398c8281d0ce7c2c75a076_sk + signedCert: + path: artifacts/channel/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts/Admin@org2.example.com-cert.pem + +# +# List of orderers to send transaction and channel create/update requests to. For the time +# being only one orderer is needed. If more than one is defined, which one get used by the +# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers. +# +orderers: + orderer.example.com: + url: grpcs://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7050 + + # these are standard properties defined by the gRPC library + # they will be passed in as-is to gRPC client constructor + grpcOptions: + ssl-target-name-override: orderer.example.com + grpc-max-send-message-length: 15 + + tlsCACerts: + path: artifacts/channel/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt + +# +# List of peers to send various requests to, including endorsement, query +# and event listener registration. +# +peers: + peer0.org1.example.com: + # this URL is used to send endorsement and query requests + url: grpcs://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7051 + + # this URL is used to connect the EventHub and registering event listeners + eventUrl: grpcs://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7053 + + grpcOptions: + ssl-target-name-override: peer0.org1.example.com + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt + + peer1.org1.example.com: + url: grpcs://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7056 + eventUrl: grpcs://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7058 + grpcOptions: + ssl-target-name-override: peer1.org1.example.com + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt + + peer0.org2.example.com: + url: grpcs://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:8051 + eventUrl: grpcs://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:8053 + grpcOptions: + ssl-target-name-override: peer0.org2.example.com + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt + + peer1.org2.example.com: + url: grpcs://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:8056 + eventUrl: grpcs://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:8058 + grpcOptions: + ssl-target-name-override: peer1.org2.example.com + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt + +# +# Fabric-CA is a special kind of Certificate Authority provided by Hyperledger Fabric which allows +# certificate management to be done via REST APIs. Application may choose to use a standard +# Certificate Authority instead of Fabric-CA, in which case this section would not be specified. +# +certificateAuthorities: + ca-org1: + url: https://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:7054 + # the properties specified under this object are passed to the 'http' client verbatim when + # making the request to the Fabric-CA server + httpOptions: + verify: false + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem + + # Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is + # needed to enroll and invoke new users. + registrar: + - enrollId: admin + enrollSecret: adminpw + # [Optional] The optional name of the CA. + caName: ca-org1 + + ca-org2: + url: https://ec2-13-59-99-140.us-east-2.compute.amazonaws.com:8054 + httpOptions: + verify: false + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem + registrar: + - enrollId: admin + enrollSecret: adminpw + # [Optional] The optional name of the CA. + caName: ca-org2 diff --git a/balance-transfer/artifacts/network-config.yaml b/balance-transfer/artifacts/network-config.yaml new file mode 100644 index 0000000000..e01768a426 --- /dev/null +++ b/balance-transfer/artifacts/network-config.yaml @@ -0,0 +1,236 @@ +--- +# +# The network connection profile provides client applications the information about the target +# blockchain network that are necessary for the applications to interact with it. These are all +# knowledge that must be acquired from out-of-band sources. This file provides such a source. +# +name: "balance-transfer" + +# +# Any properties with an "x-" prefix will be treated as application-specific, exactly like how naming +# in HTTP headers or swagger properties work. The SDK will simply ignore these fields and leave +# them for the applications to process. This is a mechanism for different components of an application +# to exchange information that are not part of the standard schema described below. In particular, +# the "x-type" property with the "hlfv1" value example below is used by Hyperledger Composer to +# determine the type of Fabric networks (v0.6 vs. v1.0) it needs to work with. +# +x-type: "hlfv1" + +# +# Describe what the target network is/does. +# +description: "Balance Transfer Network" + +# +# Schema version of the content. Used by the SDK to apply the corresponding parsing rules. +# +version: "1.0" + +# +# The client section will be added on a per org basis see org1.yaml and org2.yaml +# +#client: + +# +# [Optional]. But most apps would have this section so that channel objects can be constructed +# based on the content below. If an app is creating channels, then it likely will not need this +# section. +# +channels: + # name of the channel + mychannel: + # Required. list of orderers designated by the application to use for transactions on this + # channel. This list can be a result of access control ("org1" can only access "ordererA"), or + # operational decisions to share loads from applications among the orderers. The values must + # be "names" of orgs defined under "organizations/peers" + orderers: + - orderer.example.com + + # Required. list of peers from participating orgs + peers: + peer0.org1.example.com: + # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must + # have the chaincode installed. The app can also use this property to decide which peers + # to send the chaincode install request. Default: true + endorsingPeer: true + + # [Optional]. will this peer be sent query proposals? The peer must have the chaincode + # installed. The app can also use this property to decide which peers to send the + # chaincode install request. Default: true + chaincodeQuery: true + + # [Optional]. will this peer be sent query proposals that do not require chaincodes, like + # queryBlock(), queryTransaction(), etc. Default: true + ledgerQuery: true + + # [Optional]. will this peer be the target of the SDK's listener registration? All peers can + # produce events but the app typically only needs to connect to one to listen to events. + # Default: true + eventSource: true + + peer1.org1.example.com: + endorsingPeer: false + chaincodeQuery: true + ledgerQuery: true + eventSource: false + + peer0.org2.example.com: + endorsingPeer: true + chaincodeQuery: true + ledgerQuery: true + eventSource: true + + peer1.org2.example.com: + endorsingPeer: false + chaincodeQuery: true + ledgerQuery: true + eventSource: false + + # [Optional]. what chaincodes are expected to exist on this channel? The application can use + # this information to validate that the target peers are in the expected state by comparing + # this list with the query results of getInstalledChaincodes() and getInstantiatedChaincodes() + chaincodes: + # the format follows the "cannonical name" of chaincodes by fabric code + - mycc:v0 + +# +# list of participating organizations in this network +# +organizations: + Org1: + mspid: Org1MSP + + peers: + - peer0.org1.example.com + - peer1.org1.example.com + + # [Optional]. Certificate Authorities issue certificates for identification purposes in a Fabric based + # network. Typically certificates provisioning is done in a separate process outside of the + # runtime network. Fabric-CA is a special certificate authority that provides a REST APIs for + # dynamic certificate management (enroll, revoke, re-enroll). The following section is only for + # Fabric-CA servers. + certificateAuthorities: + - ca-org1 + + # [Optional]. If the application is going to make requests that are reserved to organization + # administrators, including creating/updating channels, installing/instantiating chaincodes, it + # must have access to the admin identity represented by the private key and signing certificate. + # Both properties can be the PEM string or local path to the PEM file. Note that this is mainly for + # convenience in development mode, production systems should not expose sensitive information + # this way. The SDK should allow applications to set the org admin identity via APIs, and only use + # this route as an alternative when it exists. + adminPrivateKey: + path: artifacts/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/5890f0061619c06fb29dea8cb304edecc020fe63f41a6db109f1e227cc1cb2a8_sk + signedCert: + path: artifacts/channel/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem + + # the profile will contain public information about organizations other than the one it belongs to. + # These are necessary information to make transaction lifecycles work, including MSP IDs and + # peers with a public URL to send transaction proposals. The file will not contain private + # information reserved for members of the organization, such as admin key and certificate, + # fabric-ca registrar enroll ID and secret, etc. + Org2: + mspid: Org2MSP + peers: + - peer0.org2.example.com + - peer1.org2.example.com + certificateAuthorities: + - ca-org2 + adminPrivateKey: + path: artifacts/channel/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/1995b11d6573ed3be52fcd7a5fa477bc0f183e1f5f398c8281d0ce7c2c75a076_sk + signedCert: + path: artifacts/channel/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts/Admin@org2.example.com-cert.pem + +# +# List of orderers to send transaction and channel create/update requests to. For the time +# being only one orderer is needed. If more than one is defined, which one get used by the +# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers. +# +orderers: + orderer.example.com: + url: grpcs://localhost:7050 + + # these are standard properties defined by the gRPC library + # they will be passed in as-is to gRPC client constructor + grpcOptions: + ssl-target-name-override: orderer.example.com + grpc-max-send-message-length: 15 + + tlsCACerts: + path: artifacts/channel/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt + +# +# List of peers to send various requests to, including endorsement, query +# and event listener registration. +# +peers: + peer0.org1.example.com: + # this URL is used to send endorsement and query requests + url: grpcs://localhost:7051 + + # this URL is used to connect the EventHub and registering event listeners + eventUrl: grpcs://localhost:7053 + + grpcOptions: + ssl-target-name-override: peer0.org1.example.com + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt + + peer1.org1.example.com: + url: grpcs://localhost:7056 + eventUrl: grpcs://localhost:7058 + grpcOptions: + ssl-target-name-override: peer1.org1.example.com + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt + + peer0.org2.example.com: + url: grpcs://localhost:8051 + eventUrl: grpcs://localhost:8053 + grpcOptions: + ssl-target-name-override: peer0.org2.example.com + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt + + peer1.org2.example.com: + url: grpcs://localhost:8056 + eventUrl: grpcs://localhost:8058 + grpcOptions: + ssl-target-name-override: peer1.org2.example.com + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt + +# +# Fabric-CA is a special kind of Certificate Authority provided by Hyperledger Fabric which allows +# certificate management to be done via REST APIs. Application may choose to use a standard +# Certificate Authority instead of Fabric-CA, in which case this section would not be specified. +# +certificateAuthorities: + ca-org1: + url: https://localhost:7054 + # the properties specified under this object are passed to the 'http' client verbatim when + # making the request to the Fabric-CA server + httpOptions: + verify: false + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem + + # Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is + # needed to enroll and invoke new users. + registrar: + - enrollId: admin + enrollSecret: adminpw + # [Optional] The optional name of the CA. + caName: ca-org1 + + ca-org2: + url: https://localhost:8054 + httpOptions: + verify: false + tlsCACerts: + path: artifacts/channel/crypto-config/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem + registrar: + - enrollId: admin + enrollSecret: adminpw + # [Optional] The optional name of the CA. + caName: ca-org2 diff --git a/balance-transfer/artifacts/org1.yaml b/balance-transfer/artifacts/org1.yaml new file mode 100644 index 0000000000..9f80b2a9cc --- /dev/null +++ b/balance-transfer/artifacts/org1.yaml @@ -0,0 +1,53 @@ +--- +# +# The network connection profile provides client applications the information about the target +# blockchain network that are necessary for the applications to interact with it. These are all +# knowledge that must be acquired from out-of-band sources. This file provides such a source. +# +name: "balance-transfer-org1" + +# +# Any properties with an "x-" prefix will be treated as application-specific, exactly like how naming +# in HTTP headers or swagger properties work. The SDK will simply ignore these fields and leave +# them for the applications to process. This is a mechanism for different components of an application +# to exchange information that are not part of the standard schema described below. In particular, +# the "x-type" property with the "hlfv1" value example below is used by Hyperledger Composer to +# determine the type of Fabric networks (v0.6 vs. v1.0) it needs to work with. +# +x-type: "hlfv1" + +# +# Describe what the target network is/does. +# +description: "Balance Transfer Network - client definition for Org1" + +# +# Schema version of the content. Used by the SDK to apply the corresponding parsing rules. +# +version: "1.0" + +# +# The client section is SDK-specific. The sample below is for the node.js SDK +# +client: + # Which organization does this application instance belong to? The value must be the name of an org + # defined under "organizations" + organization: Org1 + + # Some SDKs support pluggable KV stores, the properties under "credentialStore" + # are implementation specific + credentialStore: + # [Optional]. Specific to FileKeyValueStore.js or similar implementations in other SDKs. Can be others + # if using an alternative impl. For instance, CouchDBKeyValueStore.js would require an object + # here for properties like url, db name, etc. + path: "./fabric-client-kv-org1" + + # [Optional]. Specific to the CryptoSuite implementation. Software-based implementations like + # CryptoSuite_ECDSA_AES.js in node SDK requires a key store. PKCS#11 based implementations does + # not. + cryptoStore: + # Specific to the underlying KeyValueStore that backs the crypto key store. + path: "/tmp/fabric-client-kv-org1" + + # [Optional]. Specific to Composer environment + wallet: wallet-name diff --git a/balance-transfer/artifacts/org2.yaml b/balance-transfer/artifacts/org2.yaml new file mode 100644 index 0000000000..6edc731cf0 --- /dev/null +++ b/balance-transfer/artifacts/org2.yaml @@ -0,0 +1,53 @@ +--- +# +# The network connection profile provides client applications the information about the target +# blockchain network that are necessary for the applications to interact with it. These are all +# knowledge that must be acquired from out-of-band sources. This file provides such a source. +# +name: "balance-transfer-org2" + +# +# Any properties with an "x-" prefix will be treated as application-specific, exactly like how naming +# in HTTP headers or swagger properties work. The SDK will simply ignore these fields and leave +# them for the applications to process. This is a mechanism for different components of an application +# to exchange information that are not part of the standard schema described below. In particular, +# the "x-type" property with the "hlfv1" value example below is used by Hyperledger Composer to +# determine the type of Fabric networks (v0.6 vs. v1.0) it needs to work with. +# +x-type: "hlfv1" + +# +# Describe what the target network is/does. +# +description: "Balance Transfer Network - client definition for Org2" + +# +# Schema version of the content. Used by the SDK to apply the corresponding parsing rules. +# +version: "1.0" + +# +# The client section is SDK-specific. The sample below is for the node.js SDK +# +client: + # Which organization does this application instance belong to? The value must be the name of an org + # defined under "organizations" + organization: Org2 + + # Some SDKs support pluggable KV stores, the properties under "credentialStore" + # are implementation specific + credentialStore: + # [Optional]. Specific to FileKeyValueStore.js or similar implementations in other SDKs. Can be others + # if using an alternative impl. For instance, CouchDBKeyValueStore.js would require an object + # here for properties like url, db name, etc. + path: "./fabric-client-kv-org2" + + # [Optional]. Specific to the CryptoSuite implementation. Software-based implementations like + # CryptoSuite_ECDSA_AES.js in node SDK requires a key store. PKCS#11 based implementations does + # not. + cryptoStore: + # Specific to the underlying KeyValueStore that backs the crypto key store. + path: "/tmp/fabric-client-kv-org2" + + # [Optional]. Specific to Composer environment + wallet: wallet-name diff --git a/balance-transfer/config.js b/balance-transfer/config.js index 3ff928f7f8..d4436ed561 100644 --- a/balance-transfer/config.js +++ b/balance-transfer/config.js @@ -2,13 +2,17 @@ var util = require('util'); var path = require('path'); var hfc = require('fabric-client'); -var file = 'network-config%s.json'; +var file = 'network-config%s.yaml'; var env = process.env.TARGET_NETWORK; if (env) file = util.format(file, '-' + env); else file = util.format(file, ''); - -hfc.addConfigFile(path.join(__dirname, 'app', file)); -hfc.addConfigFile(path.join(__dirname, 'config.json')); \ No newline at end of file +// indicate to the application where the setup file is located so it able +// to have the hfc load it to initalize the fabric client instance +hfc.setConfigSetting('network-connection-profile-path',path.join(__dirname, 'app', '../artifacts',file)); +hfc.setConfigSetting('Org1-connection-profile-path',path.join(__dirname, 'app', '../artifacts','org1.yaml')); +hfc.setConfigSetting('Org2-connection-profile-path',path.join(__dirname, 'app', '../artifacts','org2.yaml')); +// some other settings the application might need to know +hfc.addConfigFile(path.join(__dirname, 'config.json')); diff --git a/balance-transfer/config.json b/balance-transfer/config.json index d2fe9c0bbf..3af47311d8 100644 --- a/balance-transfer/config.json +++ b/balance-transfer/config.json @@ -4,7 +4,6 @@ "jwt_expiretime": "36000", "channelName":"mychannel", "CC_SRC_PATH":"../artifacts", - "keyValueStore":"/tmp/fabric-client-kvs", "eventWaitTime":"30000", "admins":[ { diff --git a/balance-transfer/package-lock.json b/balance-transfer/package-lock.json new file mode 100644 index 0000000000..a022a0acf6 --- /dev/null +++ b/balance-transfer/package-lock.json @@ -0,0 +1,2541 @@ +{ + "name": "balance-transfer", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", + "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + } + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arguejs": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/arguejs/-/arguejs-0.2.3.tgz", + "integrity": "sha1-tvk59f4OPNHz+T4qqSYkJL8xKvc=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "ascli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz", + "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=", + "requires": { + "colour": "0.7.1", + "optjs": "3.2.2" + } + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz", + "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs=" + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "bl": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", + "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.1", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "1.6.15" + } + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-request": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz", + "integrity": "sha1-ns5bWsqJopkyJC4Yv5M975h2zBc=" + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "bytebuffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", + "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", + "requires": { + "long": "3.2.0" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "cloudant-follow": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/cloudant-follow/-/cloudant-follow-0.13.0.tgz", + "integrity": "sha1-fs6teQYbADmfXuNUA2jdYGV83Cs=", + "requires": { + "browser-request": "0.3.3", + "debug": "2.6.9", + "request": "2.81.0" + }, + "dependencies": { + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" + }, + "colour": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz", + "integrity": "sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz", + "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=", + "requires": { + "cookie": "0.3.1", + "cookie-signature": "1.0.6" + } + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cors": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz", + "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=", + "requires": { + "object-assign": "4.1.1", + "vary": "1.1.2" + } + }, + "crc": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz", + "integrity": "sha1-naHpgOO9RPxck79as9ozeNheRms=" + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "requires": { + "boom": "2.10.1" + } + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz", + "integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=", + "requires": { + "base64url": "2.0.0", + "safe-buffer": "5.1.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "elliptic": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.3", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "encodeurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", + "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" + }, + "end-of-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", + "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", + "requires": { + "once": "1.4.0" + } + }, + "errs": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/errs/-/errs-0.3.2.tgz", + "integrity": "sha1-eYCZstvTfKK8dJ5TinwTB9C1BJk=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", + "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", + "requires": { + "accepts": "1.3.4", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.1", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.0", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.2", + "qs": "6.5.1", + "range-parser": "1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.1", + "serve-static": "1.13.1", + "setprototypeof": "1.1.0", + "statuses": "1.3.1", + "type-is": "1.6.15", + "utils-merge": "1.0.1", + "vary": "1.1.2" + }, + "dependencies": { + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + } + } + }, + "express-bearer-token": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/express-bearer-token/-/express-bearer-token-2.1.0.tgz", + "integrity": "sha1-1cgjxNGA+dKwh5j87T3enMnEkG4=" + }, + "express-jwt": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-5.3.0.tgz", + "integrity": "sha1-PZDNZYAuYzYlLxnmo98+FJ4MXqA=", + "requires": { + "async": "1.5.2", + "express-unless": "0.3.1", + "jsonwebtoken": "7.4.3", + "lodash.set": "4.3.2" + } + }, + "express-session": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.15.6.tgz", + "integrity": "sha512-r0nrHTCYtAMrFwZ0kBzZEXa1vtPVrw0dKvGSrKP4dahwBQ1BJpF2/y1Pp4sCD/0kvxV4zZeclyvfmw0B4RMJQA==", + "requires": { + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "crc": "3.4.4", + "debug": "2.6.9", + "depd": "1.1.1", + "on-headers": "1.0.1", + "parseurl": "1.3.2", + "uid-safe": "2.1.5", + "utils-merge": "1.0.1" + } + }, + "express-unless": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-0.3.1.tgz", + "integrity": "sha1-JVfBRudb65A+LSR/m1ugFFJpbiA=" + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, + "fabric-ca-client": { + "version": "1.1.0-snapshot.25", + "resolved": "https://registry.npmjs.org/fabric-ca-client/-/fabric-ca-client-1.1.0-snapshot.25.tgz", + "integrity": "sha512-mhMasJ/y7pkzF4EJi4zk4mjKu/DGy6NyRCzmX9bV2SW0Kyqz4UMFmOe5iV9P0BXTDm31peplp2XCvRNyH3MV+g==", + "requires": { + "bn.js": "4.11.8", + "elliptic": "6.4.0", + "fs-extra": "0.30.0", + "js-sha3": "0.5.7", + "jsrsasign": "6.2.2", + "jssha": "2.3.1", + "nconf": "0.8.5", + "sjcl": "1.0.3", + "sjcl-codec": "0.1.1", + "url": "0.11.0", + "util": "0.10.3", + "winston": "2.4.0" + }, + "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0", + "klaw": "1.3.1", + "path-is-absolute": "1.0.1", + "rimraf": "2.6.2" + } + } + } + }, + "fabric-client": { + "version": "1.1.0-snapshot.25", + "resolved": "https://registry.npmjs.org/fabric-client/-/fabric-client-1.1.0-snapshot.25.tgz", + "integrity": "sha512-gZYoVvs1Q1BzIY8HZZi6adl7OerDaqxiCbCErivv6s23vgHYmcvulFIvhQZQt3IdBiT25yOnhfdpcjlj5d4O7w==", + "requires": { + "bn.js": "4.11.8", + "callsite": "1.0.0", + "elliptic": "6.4.0", + "fs": "0.0.2", + "fs-extra": "0.30.0", + "grpc": "1.6.6", + "ignore-walk": "3.0.1", + "js-sha3": "0.5.7", + "js-yaml": "3.10.0", + "jsrsasign": "6.2.2", + "jssha": "2.3.1", + "long": "3.2.0", + "nano": "6.4.2", + "nconf": "0.8.5", + "path": "0.12.7", + "pkcs11js": "1.0.10", + "promise-settle": "0.3.0", + "sjcl": "1.0.3", + "sjcl-codec": "0.1.1", + "stream-buffers": "3.0.1", + "tar-stream": "1.5.2", + "url": "0.11.0", + "util": "0.10.3", + "winston": "2.4.0" + }, + "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0", + "klaw": "1.3.1", + "path-is-absolute": "1.0.1", + "rimraf": "2.6.2" + } + } + } + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.2.tgz", + "integrity": "sha1-4fJE7zkzwbKmS9R5kTYGDQ9ZFPg=" + }, + "fs-extra": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", + "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=", + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "grpc": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.6.6.tgz", + "integrity": "sha1-IFF4T2vWE0aB+ixLXnXcgsbCP/o=", + "requires": { + "arguejs": "0.2.3", + "lodash": "4.17.4", + "nan": "2.7.0", + "node-pre-gyp": "0.6.38", + "protobufjs": "5.0.2" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.3" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.8", + "bundled": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "caseless": { + "version": "0.12.0", + "bundled": true + }, + "co": { + "version": "4.6.0", + "bundled": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true + }, + "extsprintf": { + "version": "1.3.0", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "requires": { + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.4", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true + }, + "jsprim": { + "version": "1.4.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, + "mime-db": { + "version": "1.30.0", + "bundled": true + }, + "mime-types": { + "version": "2.1.17", + "bundled": true, + "requires": { + "mime-db": "1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "ms": { + "version": "2.0.0", + "bundled": true + }, + "node-pre-gyp": { + "version": "0.6.38", + "bundled": true, + "requires": { + "hawk": "3.1.3", + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.2", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.2", + "semver": "5.4.1", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "requires": { + "abbrev": "1.1.1", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true + }, + "qs": { + "version": "6.4.0", + "bundled": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + } + }, + "readable-stream": { + "version": "2.3.3", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true + }, + "semver": { + "version": "5.4.1", + "bundled": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.1", + "bundled": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, + "string_decoder": { + "version": "1.0.3", + "bundled": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "requires": { + "debug": "2.6.9", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.3.3", + "rimraf": "2.6.2", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.3", + "bundled": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "uuid": { + "version": "3.1.0", + "bundled": true + }, + "verror": { + "version": "1.10.0", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + } + } + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "1.1.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.3.1" + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "requires": { + "minimatch": "3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=" + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "ipaddr.js": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isemail": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", + "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "joi": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", + "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", + "requires": { + "hoek": "2.16.3", + "isemail": "1.2.0", + "moment": "2.19.1", + "topo": "1.1.0" + } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "4.1.11" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonwebtoken": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.3.tgz", + "integrity": "sha1-d/UCHeBYtgWheD+hKD6ZgS5kVjg=", + "requires": { + "joi": "6.10.1", + "jws": "3.1.4", + "lodash.once": "4.1.1", + "ms": "2.0.0", + "xtend": "4.0.1" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "jsrsasign": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-6.2.2.tgz", + "integrity": "sha1-hKD4W6Sqx6ecNYutsm7ZmRMXLbw=" + }, + "jssha": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/jssha/-/jssha-2.3.1.tgz", + "integrity": "sha1-FHshJTaQNcpLL30hDcU58Amz3po=" + }, + "jwa": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz", + "integrity": "sha1-oFUs4CIHQs1S4VN3SjKQXDDnVuU=", + "requires": { + "base64url": "2.0.0", + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.9", + "safe-buffer": "5.1.1" + } + }, + "jws": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz", + "integrity": "sha1-+ei5M46KhHJ31kRLFGT2GIDgUKI=", + "requires": { + "base64url": "2.0.0", + "jwa": "1.1.5", + "safe-buffer": "5.1.1" + } + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "requires": { + "graceful-fs": "4.1.11" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "1.0.0" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" + }, + "log4js": { + "version": "0.6.38", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz", + "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=", + "requires": { + "readable-stream": "1.0.34", + "semver": "4.3.6" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "minimalistic-assert": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.8" + } + }, + "moment": { + "version": "2.19.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.19.1.tgz", + "integrity": "sha1-VtoaLRy/AdOLfhr8McELz6GSkWc=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", + "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=" + }, + "nano": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/nano/-/nano-6.4.2.tgz", + "integrity": "sha1-ubD6geuRS4ucY0odVeh44PRbCb8=", + "requires": { + "cloudant-follow": "0.13.0", + "debug": "2.6.9", + "errs": "0.3.2", + "request": "2.83.0", + "underscore": "1.8.3" + } + }, + "nconf": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/nconf/-/nconf-0.8.5.tgz", + "integrity": "sha1-8pQeFWGVL6kGu7MjKM+I1MY155Q=", + "requires": { + "async": "1.5.2", + "ini": "1.3.4", + "secure-keys": "1.0.0", + "yargs": "3.32.0" + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "optjs": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz", + "integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4=" + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "requires": { + "process": "0.11.10", + "util": "0.10.3" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" + }, + "pkcs11js": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pkcs11js/-/pkcs11js-1.0.10.tgz", + "integrity": "sha512-RZQ0MkksFoTTik+hH4JvnICLnVcMA+pjtwt81p3u9yBAtEIIBIUNaJNn0au+jo//wu/BHvVfTXs8XRQloSG79w==", + "requires": { + "nan": "2.7.0" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "promise-settle": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/promise-settle/-/promise-settle-0.3.0.tgz", + "integrity": "sha1-tO/VcqHrdM95T4KM00naQKCOTpY=" + }, + "protobufjs": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.2.tgz", + "integrity": "sha1-WXSNfc8D0tsiwT2p/rAk4Wq4DJE=", + "requires": { + "ascli": "1.0.1", + "bytebuffer": "5.0.1", + "glob": "7.1.2", + "yargs": "3.32.0" + } + }, + "proxy-addr": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", + "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.5.2" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + }, + "dependencies": { + "ajv": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz", + "integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "requires": { + "hoek": "4.2.0" + } + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "requires": { + "ajv": "5.3.0", + "har-schema": "2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "secure-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz", + "integrity": "sha1-8MgtmKOxOah3aogIBQuCRDEIf8o=" + }, + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=" + }, + "send": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", + "requires": { + "debug": "2.6.9", + "depd": "1.1.1", + "destroy": "1.0.4", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + } + }, + "serve-static": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", + "requires": { + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.1" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + }, + "sjcl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.3.tgz", + "integrity": "sha1-TtSGSY7Wt0K11KIZAiaBFvBUpwk=" + }, + "sjcl-codec": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/sjcl-codec/-/sjcl-codec-0.1.1.tgz", + "integrity": "sha1-aub9c2xOBb/9pLxhoYox9X12HZU=" + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "requires": { + "hoek": "2.16.3" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "stream-buffers": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.1.tgz", + "integrity": "sha1-aKOMX6re3tef95mI02jj+xMl7wY=" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "tar-stream": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.2.tgz", + "integrity": "sha1-+8bG6DwaGdTLSMfZYXH8JI7/x78=", + "requires": { + "bl": "1.2.1", + "end-of-stream": "1.4.0", + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + }, + "topo": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", + "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", + "requires": { + "hoek": "2.16.3" + } + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.17" + } + }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "1.0.0" + } + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" + }, + "winston": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.0.tgz", + "integrity": "sha1-gIBQuT1SZh7Z+2wms/DIJnCLCu4=", + "requires": { + "async": "1.0.0", + "colors": "1.0.3", + "cycle": "1.0.3", + "eyes": "0.1.8", + "isstream": "0.1.2", + "stack-trace": "0.0.10" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" + } + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "requires": { + "camelcase": "2.1.1", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "os-locale": "1.4.0", + "string-width": "1.0.2", + "window-size": "0.1.4", + "y18n": "3.2.1" + } + } + } +} diff --git a/balance-transfer/runApp.sh b/balance-transfer/runApp.sh index 7357d60743..59ca5f2a6d 100755 --- a/balance-transfer/runApp.sh +++ b/balance-transfer/runApp.sh @@ -36,8 +36,8 @@ function restartNetwork() { dkcl dkrm - #Cleanup the material - rm -rf /tmp/hfc-test-kvs_peerOrg* $HOME/.hfc-key-store/ /tmp/fabric-client-kvs_peerOrg* + #Cleanup the stores + rm -rf ./fabric-client-kv-org* #Start the network docker-compose up -d diff --git a/balance-transfer/testAPIs.sh b/balance-transfer/testAPIs.sh index a195822ac0..191d299f14 100755 --- a/balance-transfer/testAPIs.sh +++ b/balance-transfer/testAPIs.sh @@ -57,7 +57,7 @@ echo ORG1_TOKEN=$(curl -s -X POST \ http://localhost:4000/users \ -H "content-type: application/x-www-form-urlencoded" \ - -d 'username=Jim&orgName=org1') + -d 'username=Jim&orgName=Org1') echo $ORG1_TOKEN ORG1_TOKEN=$(echo $ORG1_TOKEN | jq ".token" | sed "s/\"//g") echo @@ -68,7 +68,7 @@ echo ORG2_TOKEN=$(curl -s -X POST \ http://localhost:4000/users \ -H "content-type: application/x-www-form-urlencoded" \ - -d 'username=Barry&orgName=org2') + -d 'username=Barry&orgName=Org2') echo $ORG2_TOKEN ORG2_TOKEN=$(echo $ORG2_TOKEN | jq ".token" | sed "s/\"//g") echo @@ -95,7 +95,7 @@ curl -s -X POST \ -H "authorization: Bearer $ORG1_TOKEN" \ -H "content-type: application/json" \ -d '{ - "peers": ["peer1","peer2"] + "peers": ["peer0.org1.example.com","peer1.org1.example.com"] }' echo echo @@ -107,7 +107,7 @@ curl -s -X POST \ -H "authorization: Bearer $ORG2_TOKEN" \ -H "content-type: application/json" \ -d '{ - "peers": ["peer1","peer2"] + "peers": ["peer0.org2.example.com","peer1.org2.example.com"] }' echo echo @@ -119,7 +119,7 @@ curl -s -X POST \ -H "authorization: Bearer $ORG1_TOKEN" \ -H "content-type: application/json" \ -d "{ - \"peers\": [\"peer1\", \"peer2\"], + \"peers\": [\"peer0.org1.example.com\",\"peer1.org1.example.com\"], \"chaincodeName\":\"mycc\", \"chaincodePath\":\"$CC_SRC_PATH\", \"chaincodeType\": \"$LANGUAGE\", @@ -135,7 +135,7 @@ curl -s -X POST \ -H "authorization: Bearer $ORG2_TOKEN" \ -H "content-type: application/json" \ -d "{ - \"peers\": [\"peer1\",\"peer2\"], + \"peers\": [\"peer0.org2.example.com\",\"peer1.org2.example.com\"], \"chaincodeName\":\"mycc\", \"chaincodePath\":\"$CC_SRC_PATH\", \"chaincodeType\": \"$LANGUAGE\", @@ -176,7 +176,7 @@ echo echo "GET query chaincode on peer1 of Org1" echo curl -s -X GET \ - "http://localhost:4000/channels/mychannel/chaincodes/mycc?peer=peer1&fcn=query&args=%5B%22a%22%5D" \ + "http://localhost:4000/channels/mychannel/chaincodes/mycc?peer=peer0.org1.example.com&fcn=query&args=%5B%22a%22%5D" \ -H "authorization: Bearer $ORG1_TOKEN" \ -H "content-type: application/json" echo @@ -185,7 +185,7 @@ echo echo "GET query Block by blockNumber" echo curl -s -X GET \ - "http://localhost:4000/channels/mychannel/blocks/1?peer=peer1" \ + "http://localhost:4000/channels/mychannel/blocks/1?peer=peer0.org1.example.com" \ -H "authorization: Bearer $ORG1_TOKEN" \ -H "content-type: application/json" echo @@ -193,7 +193,7 @@ echo echo "GET query Transaction by TransactionID" echo -curl -s -X GET http://localhost:4000/channels/mychannel/transactions/$TRX_ID?peer=peer1 \ +curl -s -X GET http://localhost:4000/channels/mychannel/transactions/$TRX_ID?peer=peer0.org1.example.com \ -H "authorization: Bearer $ORG1_TOKEN" \ -H "content-type: application/json" echo @@ -217,7 +217,7 @@ echo echo "GET query ChainInfo" echo curl -s -X GET \ - "http://localhost:4000/channels/mychannel?peer=peer1" \ + "http://localhost:4000/channels/mychannel?peer=peer0.org1.example.com" \ -H "authorization: Bearer $ORG1_TOKEN" \ -H "content-type: application/json" echo @@ -226,7 +226,7 @@ echo echo "GET query Installed chaincodes" echo curl -s -X GET \ - "http://localhost:4000/chaincodes?peer=peer1&type=installed" \ + "http://localhost:4000/chaincodes?peer=peer0.org1.example.com" \ -H "authorization: Bearer $ORG1_TOKEN" \ -H "content-type: application/json" echo @@ -235,7 +235,7 @@ echo echo "GET query Instantiated chaincodes" echo curl -s -X GET \ - "http://localhost:4000/chaincodes?peer=peer1&type=instantiated" \ + "http://localhost:4000/channels/mychannel/chaincodes?peer=peer0.org1.example.com" \ -H "authorization: Bearer $ORG1_TOKEN" \ -H "content-type: application/json" echo @@ -244,7 +244,7 @@ echo echo "GET query Channels" echo curl -s -X GET \ - "http://localhost:4000/channels?peer=peer1" \ + "http://localhost:4000/channels?peer=peer0.org1.example.com" \ -H "authorization: Bearer $ORG1_TOKEN" \ -H "content-type: application/json" echo