diff --git a/asset-transfer-basic/.gitignore b/asset-transfer-basic/.gitignore index e69de29b..1ddbcb2f 100755 --- a/asset-transfer-basic/.gitignore +++ b/asset-transfer-basic/.gitignore @@ -0,0 +1,2 @@ +wallet +!wallet/.gitkeep diff --git a/asset-transfer-basic/application-javascript/.eslintignore b/asset-transfer-basic/application-javascript/.eslintignore new file mode 100644 index 00000000..15958470 --- /dev/null +++ b/asset-transfer-basic/application-javascript/.eslintignore @@ -0,0 +1,5 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + +coverage diff --git a/asset-transfer-basic/application-javascript/.eslintrc.js b/asset-transfer-basic/application-javascript/.eslintrc.js new file mode 100644 index 00000000..8b83df73 --- /dev/null +++ b/asset-transfer-basic/application-javascript/.eslintrc.js @@ -0,0 +1,37 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +module.exports = { + env: { + node: true, + mocha: true + }, + parserOptions: { + ecmaVersion: 8, + sourceType: 'script' + }, + extends: "eslint:recommended", + rules: { + indent: ['error', 4], + 'linebreak-style': ['error', 'unix'], + quotes: ['error', 'single'], + semi: ['error', 'always'], + 'no-unused-vars': ['error', { args: 'none' }], + 'no-console': 'off', + curly: 'error', + eqeqeq: 'error', + 'no-throw-literal': 'error', + strict: 'error', + 'no-var': 'error', + 'dot-notation': 'error', + 'no-tabs': 'error', + 'no-trailing-spaces': 'error', + 'no-use-before-define': 'error', + 'no-useless-call': 'error', + 'no-with': 'error', + 'operator-linebreak': 'error', + yoda: 'error', + 'quote-props': ['error', 'as-needed'] + } +}; diff --git a/asset-transfer-basic/application-javascript/.gitignore b/asset-transfer-basic/application-javascript/.gitignore new file mode 100644 index 00000000..21b287f7 --- /dev/null +++ b/asset-transfer-basic/application-javascript/.gitignore @@ -0,0 +1,14 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Coverage directory used by tools like istanbul +coverage + +# Dependency directories +node_modules/ +jspm_packages/ +package-lock.json + +wallet +!wallet/.gitkeep diff --git a/asset-transfer-basic/application-javascript/enrollAdmin.js b/asset-transfer-basic/application-javascript/enrollAdmin.js new file mode 100644 index 00000000..85d36a0b --- /dev/null +++ b/asset-transfer-basic/application-javascript/enrollAdmin.js @@ -0,0 +1,60 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const FabricCAServices = require('fabric-ca-client'); +const { Wallets } = require('fabric-network'); +const fs = require('fs'); +const path = require('path'); + +async function main() { + try { + // load the network configuration + const ccpPath = path.resolve(__dirname, '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json'); + const fileExists = fs.existsSync(ccpPath); + if (!fileExists) { + throw new Error(`no such file or directory: ${ccpPath}`); + } + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')); + + // Create a new CA client for interacting with the CA. + const caInfo = ccp.certificateAuthorities['ca.org1.example.com']; + const caTLSCACerts = caInfo.tlsCACerts.pem; + const ca = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName); + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(__dirname, 'wallet'); + const wallet = await Wallets.newFileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the admin user. + const identity = await wallet.get('admin'); + if (identity) { + console.log('An identity for the admin user "admin" already exists in the wallet'); + return; + } + + // Enroll the admin user, and import the new identity into the wallet. + const enrollment = await ca.enroll({ enrollmentID: 'admin', enrollmentSecret: 'adminpw' }); + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes(), + }, + mspId: 'Org1MSP', + type: 'X.509', + }; + await wallet.put('admin', x509Identity); + console.log('Successfully enrolled admin user "admin" and imported it into the wallet'); + + } catch (error) { + console.error(`Failed to enroll admin user "admin": ${error}`); + process.exit(1); + } +} + +main(); diff --git a/asset-transfer-basic/application-javascript/invoke.js b/asset-transfer-basic/application-javascript/invoke.js new file mode 100644 index 00000000..8654c1d6 --- /dev/null +++ b/asset-transfer-basic/application-javascript/invoke.js @@ -0,0 +1,59 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const { Gateway, Wallets } = require('fabric-network'); +const fs = require('fs'); +const path = require('path'); + +async function main() { + try { + // load the network configuration + const ccpPath = path.resolve(__dirname, '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json'); + let ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')); + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(__dirname, 'wallet'); + const wallet = await Wallets.newFileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the user. + const identity = await wallet.get('appUser'); + if (!identity) { + console.log('An identity for the user "appUser" does not exist in the wallet'); + console.log('Run the registerUser.js application before retrying'); + return; + } + + // Create a new gateway for connecting to our peer node. + const gateway = new Gateway(); + await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } }); + + // Get the network (channel) our contract is deployed to. + const network = await gateway.getNetwork('mychannel'); + + // Get the contract from the network. + const contract = network.getContract('basic'); + + // Submit the specified transaction. (several example transactions are listed below) + // createAsset creates an asset with ID asset1, color yellow, owner Dave, size 5 and appraizedValue of 130 requires 6 arguments. + // ex: ('createAsset', 'asset1', 'yellow', 'Dave', 5, 1300) + // transferAsset transfers an asset with ID asset1 to new owner Tom - requires 2 arguments. + // ex: ('transferAsset', 'asset1', 'Tom') + await contract.submitTransaction('createAsset', 'asset13', 'yellow', 'Tom', 5, 1300); + console.log('Transaction has been submitted'); + + // Disconnect from the gateway. + await gateway.disconnect(); + + } catch (error) { + console.error(`Failed to submit transaction: ${error}`); + process.exit(1); + } +} + +main(); diff --git a/asset-transfer-basic/application-javascript/package.json b/asset-transfer-basic/application-javascript/package.json new file mode 100644 index 00000000..fd2e25c2 --- /dev/null +++ b/asset-transfer-basic/application-javascript/package.json @@ -0,0 +1,45 @@ +{ + "name": "asset-transfer-basic", + "version": "1.0.0", + "description": "Asset-transfer-basic application implemented in JavaScript", + "engines": { + "node": ">=12", + "npm": ">=5" + }, + "scripts": { + "lint": "eslint .", + "pretest": "npm run lint", + "test": "nyc mocha --recursive" + }, + "engineStrict": true, + "author": "Hyperledger", + "license": "Apache-2.0", + "dependencies": { + "fabric-ca-client": "^2.1.0", + "fabric-network": "^2.1.0" + }, + "devDependencies": { + "chai": "^4.2.0", + "eslint": "^5.9.0", + "mocha": "^5.2.0", + "nyc": "^14.1.1", + "sinon": "^7.1.1", + "sinon-chai": "^3.3.0" + }, + "nyc": { + "exclude": [ + "coverage/**", + "test/**" + ], + "reporter": [ + "text-summary", + "html" + ], + "all": true, + "check-coverage": true, + "statements": 100, + "branches": 100, + "functions": 100, + "lines": 100 + } +} diff --git a/asset-transfer-basic/application-javascript/query.js b/asset-transfer-basic/application-javascript/query.js new file mode 100644 index 00000000..9c9adff0 --- /dev/null +++ b/asset-transfer-basic/application-javascript/query.js @@ -0,0 +1,64 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const { Gateway, Wallets } = require('fabric-network'); +const path = require('path'); +const fs = require('fs'); + + +async function main() { + try { + // load the network configuration + const ccpPath = path.resolve(__dirname, '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json'); + const fileExists = fs.existsSync(ccpPath); + if (!fileExists) { + throw new Error(`no such file or directory: ${ccpPath}`); + } + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')); + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(__dirname, 'wallet'); + const wallet = await Wallets.newFileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the user. + const identity = await wallet.get('appUser'); + if (!identity) { + console.log('An identity for the user "appUser" does not exist in the wallet'); + console.log('Run the registerUser.js application before retrying'); + return; + } + + // Create a new gateway for connecting to our peer node. + const gateway = new Gateway(); + await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } }); + + // Get the network (channel) our contract is deployed to. + const network = await gateway.getNetwork('mychannel'); + + // Get the contract from the network. + const contract = network.getContract('basic'); + + // Evaluate the specified transaction. (several example transactions are listed below) + // getAsset returns an asset with given assetID asset4 - requires 1 argument. + // ex: ('getAsset', 'asset4') + // getAllAssets returns all assets in the world state - requires no arguments. + // ex: ('getAllAssets') + const result = await contract.evaluateTransaction('getAllAssets'); + console.log(`Transaction has been evaluated, result is: ${result.toString()}`); + + // Disconnect from the gateway. + await gateway.disconnect(); + + } catch (error) { + console.error(`Failed to evaluate transaction: ${error}`); + process.exit(1); + } +} + +main(); diff --git a/asset-transfer-basic/application-javascript/registerUser.js b/asset-transfer-basic/application-javascript/registerUser.js new file mode 100644 index 00000000..8320b1bd --- /dev/null +++ b/asset-transfer-basic/application-javascript/registerUser.js @@ -0,0 +1,79 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const { Wallets } = require('fabric-network'); +const FabricCAServices = require('fabric-ca-client'); +const fs = require('fs'); +const path = require('path'); + +async function main() { + try { + // load the network configuration + const ccpPath = path.resolve(__dirname, '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json'); + const fileExists = fs.existsSync(ccpPath); + if (!fileExists) { + throw new Error(`no such file or directory: ${ccpPath}`); + } + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')); + + // Create a new CA client for interacting with the CA. + const caURL = ccp.certificateAuthorities['ca.org1.example.com'].url; + const ca = new FabricCAServices(caURL); + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(__dirname, 'wallet'); + const wallet = await Wallets.newFileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the user. + const userIdentity = await wallet.get('appUser'); + if (userIdentity) { + console.log('An identity for the user "appUser" already exists in the wallet'); + return; + } + + // Check to see if we've already enrolled the admin user. + const adminIdentity = await wallet.get('admin'); + if (!adminIdentity) { + console.log('An identity for the admin user "admin" does not exist in the wallet'); + console.log('Run the enrollAdmin.js application before retrying'); + return; + } + + // build a user object for authenticating with the CA + const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type); + const adminUser = await provider.getUserContext(adminIdentity, 'admin'); + + // Register the user, enroll the user, and import the new identity into the wallet. + const secret = await ca.register({ + affiliation: 'org1.department1', + enrollmentID: 'appUser', + role: 'client' + }, adminUser); + const enrollment = await ca.enroll({ + enrollmentID: 'appUser', + enrollmentSecret: secret + }); + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes(), + }, + mspId: 'Org1MSP', + type: 'X.509', + }; + await wallet.put('appUser', x509Identity); + console.log('Successfully registered and enrolled admin user "appUser" and imported it into the wallet'); + + } catch (error) { + console.error(`Failed to register user "appUser": ${error}`); + process.exit(1); + } +} + +main();