mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 15:35:09 +00:00
wip - add nodejs sample showing abac (attribute based access control)
This commit is contained in:
parent
ed81d7b9b1
commit
fd1dcf1b34
6 changed files with 217 additions and 3 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -9,3 +9,4 @@
|
|||
/config
|
||||
.DS_Store
|
||||
.project
|
||||
node_modules
|
||||
|
|
|
|||
145
chaincode/abac/node/abac.js
Normal file
145
chaincode/abac/node/abac.js
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
# Copyright IBM Corp. All Rights Reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
const shim = require('fabric-shim');
|
||||
const util = require('util');
|
||||
|
||||
// this is exact same chaincode as balance-transfer app except that
|
||||
// it adds ABAC (Attribute Based Access Control) to the Init method
|
||||
var Chaincode = class {
|
||||
|
||||
// Initialize the chaincode
|
||||
async Init(stub) {
|
||||
console.info('========= abac Init =========');
|
||||
let ret = stub.getFunctionAndParameters();
|
||||
console.info(ret);
|
||||
let cid = new shim.ClientIdentity(stub);
|
||||
if (!cid.assertAttributeValue("abac.init", "true")) {
|
||||
return shim.error("Insufficient privileges");
|
||||
}
|
||||
let args = ret.params;
|
||||
// initialise only if 4 parameters passed.
|
||||
if (args.length != 4) {
|
||||
return shim.error('Incorrect number of arguments. Expecting 4');
|
||||
}
|
||||
|
||||
let A = args[0];
|
||||
let B = args[2];
|
||||
let Aval = args[1];
|
||||
let Bval = args[3];
|
||||
|
||||
if (typeof parseInt(Aval) !== 'number' || typeof parseInt(Bval) !== 'number') {
|
||||
return shim.error('Expecting integer value for asset holding');
|
||||
}
|
||||
|
||||
try {
|
||||
await stub.putState(A, Buffer.from(Aval));
|
||||
try {
|
||||
await stub.putState(B, Buffer.from(Bval));
|
||||
return shim.success();
|
||||
} catch (err) {
|
||||
return shim.error(err);
|
||||
}
|
||||
} catch (err) {
|
||||
return shim.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
async Invoke(stub) {
|
||||
let ret = stub.getFunctionAndParameters();
|
||||
console.info(ret);
|
||||
let method = this[ret.fcn];
|
||||
if (!method) {
|
||||
console.log('no method of name:' + ret.fcn + ' found');
|
||||
return shim.success();
|
||||
}
|
||||
try {
|
||||
let payload = await method(stub, ret.params);
|
||||
return shim.success(payload);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return shim.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction makes payment of X units from A to B
|
||||
async invoke(stub, args) {
|
||||
if (args.length != 3) {
|
||||
throw new Error('Incorrect number of arguments. Expecting 3');
|
||||
}
|
||||
|
||||
let A = args[0];
|
||||
let B = args[1];
|
||||
if (!A || !B) {
|
||||
throw new Error('asset holding must not be empty');
|
||||
}
|
||||
|
||||
// Get the state from the ledger
|
||||
let Avalbytes = await stub.getState(A);
|
||||
if (!Avalbytes) {
|
||||
throw new Error('Failed to get state of asset holder A');
|
||||
}
|
||||
let Aval = parseInt(Avalbytes.toString());
|
||||
|
||||
let Bvalbytes = await stub.getState(B);
|
||||
if (!Bvalbytes) {
|
||||
throw new Error('Failed to get state of asset holder B');
|
||||
}
|
||||
|
||||
let Bval = parseInt(Bvalbytes.toString());
|
||||
// Perform the execution
|
||||
let amount = parseInt(args[2]);
|
||||
if (typeof amount !== 'number') {
|
||||
throw new Error('Expecting integer value for amount to be transaferred');
|
||||
}
|
||||
|
||||
Aval = Aval - amount;
|
||||
Bval = Bval + amount;
|
||||
console.info(util.format('Aval = %d, Bval = %d\n', Aval, Bval));
|
||||
|
||||
// Write the states back to the ledger
|
||||
await stub.putState(A, Buffer.from(Aval.toString()));
|
||||
await stub.putState(B, Buffer.from(Bval.toString()));
|
||||
|
||||
}
|
||||
|
||||
// Deletes an entity from state
|
||||
async delete(stub, args) {
|
||||
if (args.length != 1) {
|
||||
throw new Error('Incorrect number of arguments. Expecting 1');
|
||||
}
|
||||
|
||||
let A = args[0];
|
||||
|
||||
// Delete the key from the state in ledger
|
||||
await stub.deleteState(A);
|
||||
}
|
||||
|
||||
// query callback representing the query of a chaincode
|
||||
async query(stub, args) {
|
||||
if (args.length != 1) {
|
||||
throw new Error('Incorrect number of arguments. Expecting name of the person to query')
|
||||
}
|
||||
|
||||
let jsonResp = {};
|
||||
let A = args[0];
|
||||
|
||||
// Get the state from the ledger
|
||||
let Avalbytes = await stub.getState(A);
|
||||
if (!Avalbytes) {
|
||||
jsonResp.error = 'Failed to get state for ' + A;
|
||||
throw new Error(JSON.stringify(jsonResp));
|
||||
}
|
||||
|
||||
jsonResp.name = A;
|
||||
jsonResp.amount = Avalbytes.toString();
|
||||
console.info('Query Response:');
|
||||
console.info(jsonResp);
|
||||
return Avalbytes;
|
||||
}
|
||||
};
|
||||
|
||||
shim.start(new Chaincode());
|
||||
15
chaincode/abac/node/package.json
Normal file
15
chaincode/abac/node/package.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "abac",
|
||||
"version": "1.0.0",
|
||||
"description": "attribute based access control chaincode implemented in node.js",
|
||||
"engines": {
|
||||
"node": ">=8.4.0",
|
||||
"npm": ">=5.3.0"
|
||||
},
|
||||
"scripts": { "start" : "node abac.js" },
|
||||
"engine-strict": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"fabric-shim": "1.3.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -93,7 +93,7 @@ function writeRunFabric {
|
|||
image: hyperledger/fabric-ca-tools
|
||||
environment:
|
||||
- GOPATH=/opt/gopath
|
||||
command: /bin/bash -c 'sleep 3;/scripts/run-fabric.sh 2>&1 | tee /$RUN_LOGFILE; sleep 99999'
|
||||
command: /bin/bash -c 'sleep 3;/scripts/run-fabric.sh -l ${LANGUAGE} 2>&1 | tee /$RUN_LOGFILE; sleep 99999'
|
||||
volumes:
|
||||
- ./scripts:/scripts
|
||||
- ./$DATA:/$DATA
|
||||
|
|
|
|||
|
|
@ -8,9 +8,39 @@
|
|||
set -e
|
||||
|
||||
source $(dirname "$0")/env.sh
|
||||
LANGUAGE=golang
|
||||
while getopts ":l:" opt; do
|
||||
case "$opt" in
|
||||
l)
|
||||
LANGUAGE=$OPTARG
|
||||
;;
|
||||
: )
|
||||
echo "Invalid option: $OPTARG requires an argument" 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ "$LANGUAGE" = "go" ]; then
|
||||
LANGUAGE = "golang"
|
||||
fi
|
||||
if [[ "$LANGUAGE" != "node" && "$LANGUAGE" != "golang" ]]; then
|
||||
echo "LANGUAGE = ${LANGUAGE} is not supported"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
function main {
|
||||
|
||||
logr "LANGUAGE=${LANGUAGE}"
|
||||
|
||||
if [ "$LANGUAGE" = "golang" ]; then
|
||||
CC_SRC_PATH="github.com/hyperledger/fabric-samples/chaincode/abac/go"
|
||||
elif [ "$LANGUAGE" = "node" ]; then
|
||||
CC_SRC_PATH="github.com/hyperledger/fabric-samples/chaincode/abac/node"
|
||||
fi
|
||||
|
||||
logr "CC_SRC_PATH=${CC_SRC_PATH}"
|
||||
|
||||
|
||||
done=false
|
||||
|
||||
# Wait for setup to complete and then wait another 10 seconds for the orderer and peers to start
|
||||
|
|
@ -62,7 +92,7 @@ function main {
|
|||
initPeerVars ${PORGS[1]} 1
|
||||
switchToAdminIdentity
|
||||
logr "Instantiating chaincode on $PEER_HOST ..."
|
||||
peer chaincode instantiate -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "$POLICY" $ORDERER_CONN_ARGS
|
||||
peer chaincode instantiate -C $CHANNEL_NAME -n mycc -v 1.0 -l ${LANGUAGE} -c '{"Args":["init","a","100","b","200"]}' -P "$POLICY" $ORDERER_CONN_ARGS
|
||||
|
||||
# Query chaincode from the 1st peer of the 1st org
|
||||
initPeerVars ${PORGS[0]} 1
|
||||
|
|
@ -215,7 +245,8 @@ function makePolicy {
|
|||
function installChaincode {
|
||||
switchToAdminIdentity
|
||||
logr "Installing chaincode on $PEER_HOST ..."
|
||||
peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric-samples/chaincode/abac/go
|
||||
logr "peer chaincode install -n mycc -v 1.0 -l ${LANGUAGE} -p ${CC_SRC_PATH}"
|
||||
peer chaincode install -n mycc -v 1.0 -l ${LANGUAGE} -p ${CC_SRC_PATH}
|
||||
}
|
||||
|
||||
function fetchConfigBlock {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,28 @@
|
|||
|
||||
set -e
|
||||
|
||||
# use golang as the default language for chaincode
|
||||
export LANGUAGE=golang
|
||||
while getopts ":l:" opt; do
|
||||
case "$opt" in
|
||||
l)
|
||||
LANGUAGE=$OPTARG
|
||||
;;
|
||||
: )
|
||||
echo "Invalid option: $OPTARG requires an argument" 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ "$LANGUAGE" = "go" ]; then
|
||||
LANGUAGE = "golang"
|
||||
fi
|
||||
if [[ "$LANGUAGE" != "node" && "$LANGUAGE" != "golang" ]]; then
|
||||
echo "LANGUAGE = ${LANGUAGE} is not supported"
|
||||
exit 1;
|
||||
fi
|
||||
echo "start.sh: LANGUAGE = ${LANGUAGE}"
|
||||
|
||||
SDIR=$(dirname "$0")
|
||||
source ${SDIR}/scripts/env.sh
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue