diff --git a/fabcar/javascript/.editorconfig b/fabcar/javascript/.editorconfig new file mode 100755 index 0000000000..75a13be205 --- /dev/null +++ b/fabcar/javascript/.editorconfig @@ -0,0 +1,16 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/fabcar/javascript/.eslintignore b/fabcar/javascript/.eslintignore new file mode 100644 index 0000000000..1595847010 --- /dev/null +++ b/fabcar/javascript/.eslintignore @@ -0,0 +1,5 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + +coverage diff --git a/fabcar/javascript/.eslintrc.js b/fabcar/javascript/.eslintrc.js new file mode 100644 index 0000000000..8b83df7355 --- /dev/null +++ b/fabcar/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/fabcar/javascript/.gitignore b/fabcar/javascript/.gitignore new file mode 100644 index 0000000000..1dcaf1f247 --- /dev/null +++ b/fabcar/javascript/.gitignore @@ -0,0 +1,80 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless + +wallet +!wallet/.gitkeep diff --git a/fabcar/javascript/enrollAdmin.js b/fabcar/javascript/enrollAdmin.js new file mode 100644 index 0000000000..788227ea8a --- /dev/null +++ b/fabcar/javascript/enrollAdmin.js @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const FabricCAServices = require('fabric-ca-client'); +const { FileSystemWallet, X509WalletMixin } = require('fabric-network'); +const fs = require('fs'); +const path = require('path'); + +const ccpPath = path.resolve(__dirname, '..', '..', 'basic-network', 'connection.json'); +const ccpJSON = fs.readFileSync(ccpPath, 'utf8'); +const ccp = JSON.parse(ccpJSON); + +async function main() { + try { + + // Create a new CA client for interacting with the CA. + const caURL = ccp.certificateAuthorities['ca.example.com'].url; + const ca = new FabricCAServices(caURL); + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(process.cwd(), 'wallet'); + const wallet = new FileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the admin user. + const adminExists = await wallet.exists('admin'); + if (adminExists) { + 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 identity = X509WalletMixin.createIdentity('Org1MSP', enrollment.certificate, enrollment.key.toBytes()); + wallet.import('admin', identity); + 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/fabcar/javascript/invoke.js b/fabcar/javascript/invoke.js new file mode 100644 index 0000000000..a46d48c80d --- /dev/null +++ b/fabcar/javascript/invoke.js @@ -0,0 +1,56 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const { FileSystemWallet, Gateway } = require('fabric-network'); +const fs = require('fs'); +const path = require('path'); + +const ccpPath = path.resolve(__dirname, '..', '..', 'basic-network', 'connection.json'); +const ccpJSON = fs.readFileSync(ccpPath, 'utf8'); +const ccp = JSON.parse(ccpJSON); + +async function main() { + try { + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(process.cwd(), 'wallet'); + const wallet = new FileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the user. + const userExists = await wallet.exists('user1'); + if (!userExists) { + console.log('An identity for the user "user1" 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: 'user1', discovery: { useLocalhost: 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('fabcar'); + + // Submit the specified transaction. + // createCar transaction - requires 5 argument, ex: ('createCar', 'CAR12', 'Honda', 'Accord', 'Black', 'Tom') + // changeCarOwner transaction - requires 2 args , ex: ('changeCarOwner', 'CAR10', 'Dave') + await contract.submitTransaction('createCar', 'CAR12', 'Honda', 'Accord', 'Black', 'Tom'); + 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/fabcar/javascript/package.json b/fabcar/javascript/package.json new file mode 100644 index 0000000000..f040b62414 --- /dev/null +++ b/fabcar/javascript/package.json @@ -0,0 +1,46 @@ +{ + "name": "fabcar", + "version": "1.0.0", + "description": "FabCar application implemented in JavaScript", + "engines": { + "node": ">=8", + "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": "unstable", + "fabric-client": "unstable", + "fabric-network": "unstable" + }, + "devDependencies": { + "chai": "^4.2.0", + "eslint": "^5.9.0", + "mocha": "^5.2.0", + "nyc": "^13.1.0", + "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/fabcar/javascript/query.js b/fabcar/javascript/query.js new file mode 100644 index 0000000000..5fc035e6a1 --- /dev/null +++ b/fabcar/javascript/query.js @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const { FileSystemWallet, Gateway } = require('fabric-network'); +const fs = require('fs'); +const path = require('path'); + +const ccpPath = path.resolve(__dirname, '..', '..', 'basic-network', 'connection.json'); +const ccpJSON = fs.readFileSync(ccpPath, 'utf8'); +const ccp = JSON.parse(ccpJSON); + +async function main() { + try { + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(process.cwd(), 'wallet'); + const wallet = new FileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the user. + const userExists = await wallet.exists('user1'); + if (!userExists) { + console.log('An identity for the user "user1" 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: 'user1' }); + + // 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('fabcar'); + + // Evaluate the specified transaction. + // queryCar transaction - requires 1 argument, ex: ('queryCar', 'CAR4') + // queryAllCars transaction - requires no arguments, ex: ('queryAllCars') + const result = await contract.evaluateTransaction('queryAllCars'); + console.log(`Transaction has been evaluated, result is: ${result.toString()}`); + + } catch (error) { + console.error(`Failed to evaluate transaction: ${error}`); + process.exit(1); + } +} + +main(); diff --git a/fabcar/javascript/registerUser.js b/fabcar/javascript/registerUser.js new file mode 100644 index 0000000000..ad916032ea --- /dev/null +++ b/fabcar/javascript/registerUser.js @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const { FileSystemWallet, Gateway, X509WalletMixin } = require('fabric-network'); +const fs = require('fs'); +const path = require('path'); + +const ccpPath = path.resolve(__dirname, '..', '..', 'basic-network', 'connection.json'); +const ccpJSON = fs.readFileSync(ccpPath, 'utf8'); +const ccp = JSON.parse(ccpJSON); + +async function main() { + try { + + // Create a new file system based wallet for managing identities. + const walletPath = path.join(process.cwd(), 'wallet'); + const wallet = new FileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + // Check to see if we've already enrolled the user. + const userExists = await wallet.exists('user1'); + if (userExists) { + console.log('An identity for the user "user1" already exists in the wallet'); + return; + } + + // Check to see if we've already enrolled the admin user. + const adminExists = await wallet.exists('admin'); + if (!adminExists) { + 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; + } + + // Create a new gateway for connecting to our peer node. + const gateway = new Gateway(); + await gateway.connect(ccp, { wallet, identity: 'admin' }); + + // Get the CA client object from the gateway for interacting with the CA. + const ca = gateway.getClient().getCertificateAuthority(); + const adminIdentity = gateway.getCurrentIdentity(); + + // Register the user, enroll the user, and import the new identity into the wallet. + const secret = await ca.register({ affiliation: 'org1.department1', enrollmentID: 'user1', role: 'client' }, adminIdentity); + const enrollment = await ca.enroll({ enrollmentID: 'user1', enrollmentSecret: secret }); + const userIdentity = X509WalletMixin.createIdentity('Org1MSP', enrollment.certificate, enrollment.key.toBytes()); + wallet.import('user1', userIdentity); + console.log('Successfully registered and enrolled admin user "user1" and imported it into the wallet'); + + } catch (error) { + console.error(`Failed to register user "user1": ${error}`); + process.exit(1); + } +} + +main(); diff --git a/fabcar/javascript/wallet/.gitkeep b/fabcar/javascript/wallet/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/scripts/Jenkins_Scripts/fabcar.sh b/scripts/Jenkins_Scripts/fabcar.sh index 3dce2da1c0..d47d46827c 100755 --- a/scripts/Jenkins_Scripts/fabcar.sh +++ b/scripts/Jenkins_Scripts/fabcar.sh @@ -40,7 +40,12 @@ for LANGUAGE in ${LANGUAGES}; do # If an application exists for this language, test it if [ -d ${LANGUAGE} ]; then pushd ${LANGUAGE} - if [ ${LANGUAGE} = "typescript" ]; then + if [ ${LANGUAGE} = "javascript" ]; then + COMMAND=node + PREFIX= + SUFFIX=.js + npm install + elif [ ${LANGUAGE} = "typescript" ]; then COMMAND=node PREFIX=dist/ SUFFIX=.js