From 9ae66c76da03fb266111617fa33351a8c2e1b0ab Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Wed, 28 Jul 2021 17:33:45 +0530 Subject: [PATCH] switch gateway based on user org Signed-off-by: sapthasurendran initialized fabric components to global app const getcontractforOrg for transaction router removed org and reused identityOrg1 env.sample file update liveness api update Signed-off-by: sapthasurendran --- .../rest-api-typescript/.env.sample | 17 ++++- .../scripts/generateEnv.sh | 25 +++++-- .../rest-api-typescript/src/assets.router.ts | 21 +++--- .../rest-api-typescript/src/auth.ts | 15 +++-- .../rest-api-typescript/src/config.ts | 67 ++++++++++++++++--- .../rest-api-typescript/src/fabric.ts | 38 ++++++++--- .../rest-api-typescript/src/index.ts | 6 +- .../rest-api-typescript/src/server.ts | 51 +++++++++++--- .../src/transactions.router.ts | 4 +- 9 files changed, 190 insertions(+), 54 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/.env.sample b/asset-transfer-basic/rest-api-typescript/.env.sample index 9fe7cf46..f81d0dcf 100644 --- a/asset-transfer-basic/rest-api-typescript/.env.sample +++ b/asset-transfer-basic/rest-api-typescript/.env.sample @@ -4,11 +4,18 @@ PORT=3000 RETRY_DELAY=3000 -HLF_CONNECTION_PROFILE={"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... } +HLF_CONNECTION_PROFILE_ORG1={"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... } -HLF_CERTIFICATE="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" +HLF_CERTIFICATE_ORG1="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" + +HLF_PRIVATE_KEY_ORG1="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" + +HLF_CONNECTION_PROFILE_ORG2={"name":"test-network-org2","version":"1.0.0","client":{"organization":"Org2" ... } + +HLF_CERTIFICATE_ORG2="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" + +HLF_PRIVATE_KEY_ORG2="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" -HLF_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" HLF_COMMIT_TIMEOUT=3000 @@ -18,6 +25,10 @@ REDIS_HOST=localhost REDIS_PORT=6379 +ORG1_APIKEY=D2F66BFF-D68B-458D-8FA6-285F172D5B03 + +ORG2_APIKEY=92042C1F-8E58-48F9-9EAF-91A98A2B7648 + #REDIS_USERNAME= #REDIS_PASSWORD= diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh index 3d2b7030..c0af2374 100755 --- a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -5,9 +5,14 @@ # : "${TEST_NETWORK_HOME:=../..}" -: "${CONNECTION_PROFILE_FILE:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/connection-org1.json}" -: "${CERTIFICATE_FILE:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem}" -: "${PRIVATE_KEY_FILE:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk}" +: "${CONNECTION_PROFILE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/connection-org1.json}" +: "${CERTIFICATE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem}" +: "${PRIVATE_KEY_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk}" + +: "${CONNECTION_PROFILE_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/connection-org2.json}" +: "${CERTIFICATE_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts/Admin@org2.example.com-cert.pem}" +: "${PRIVATE_KEY_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/priv_sk}" + cat << ENV_END > .env LOG_LEVEL=info @@ -16,11 +21,17 @@ PORT=3000 RETRY_DELAY=3000 -HLF_CONNECTION_PROFILE=$(cat ${CONNECTION_PROFILE_FILE} | jq -c .) +HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c .) -HLF_CERTIFICATE="$(cat ${CERTIFICATE_FILE} | sed -e 's/$/\\n/' | tr -d '\r\n')" +HLF_CERTIFICATE_ORG1="$(cat ${CERTIFICATE_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" -HLF_PRIVATE_KEY="$(cat ${PRIVATE_KEY_FILE} | sed -e 's/$/\\n/' | tr -d '\r\n')" +HLF_PRIVATE_KEY_ORG1="$(cat ${PRIVATE_KEY_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" + +HLF_CONNECTION_PROFILE_ORG2=$(cat ${CONNECTION_PROFILE_FILE_ORG2} | jq -c .) + +HLF_CERTIFICATE_ORG2="$(cat ${CERTIFICATE_FILE_ORG2} | sed -e 's/$/\\n/' | tr -d '\r\n')" + +HLF_PRIVATE_KEY_ORG2="$(cat ${PRIVATE_KEY_FILE_ORG2} | sed -e 's/$/\\n/' | tr -d '\r\n')" HLF_COMMIT_TIMEOUT=3000 @@ -32,6 +43,8 @@ REDIS_PORT=6379 ORG1_APIKEY=$(uuidgen) +ORG2_APIKEY=$(uuidgen) + #REDIS_USERNAME= #REDIS_PASSWORD= diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index ccf5690a..b1d89a71 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -16,7 +16,11 @@ import { Contract } from 'fabric-network'; import { getReasonPhrase, StatusCodes } from 'http-status-codes'; import { Redis } from 'ioredis'; import { AssetExistsError, AssetNotFoundError } from './errors'; -import { evatuateTransaction, submitTransaction } from './fabric'; +import { + evatuateTransaction, + submitTransaction, + getContractForOrg, +} from './fabric'; import { logger } from './logger'; const { @@ -34,8 +38,7 @@ assetsRouter.get('/', async (req: Request, res: Response) => { logger.debug('Get all assets request received'); try { - const contract: Contract = req.app.get('contracts').contract; - + const contract: Contract = getContractForOrg(req).contract; const data = await evatuateTransaction(contract, 'GetAllAssets'); const assets = JSON.parse(data.toString()); @@ -71,7 +74,7 @@ assetsRouter.post( }); } - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const redis: Redis = req.app.get('redis'); const assetId = req.body.id; @@ -122,7 +125,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { logger.debug('Asset options request received for asset ID %s', assetId); try { - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const data = await evatuateTransaction(contract, 'AssetExists', assetId); const exists = data.toString() === 'true'; @@ -161,7 +164,7 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { logger.debug('Read asset request received for asset ID %s', assetId); try { - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const data = await evatuateTransaction(contract, 'ReadAsset', assetId); const asset = JSON.parse(data.toString()); @@ -219,7 +222,7 @@ assetsRouter.put( }); } - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const redis: Redis = req.app.get('redis'); const assetId = req.params.assetId; @@ -288,7 +291,7 @@ assetsRouter.patch( }); } - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const redis: Redis = req.app.get('redis'); const assetId = req.params.assetId; const newOwner = req.body[0].value; @@ -333,7 +336,7 @@ assetsRouter.patch( assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { logger.debug(req.body, 'Delete asset request received'); - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const redis: Redis = req.app.get('redis'); const assetId = req.params.assetId; diff --git a/asset-transfer-basic/rest-api-typescript/src/auth.ts b/asset-transfer-basic/rest-api-typescript/src/auth.ts index fe56dd0e..fd40ed43 100644 --- a/asset-transfer-basic/rest-api-typescript/src/auth.ts +++ b/asset-transfer-basic/rest-api-typescript/src/auth.ts @@ -21,12 +21,13 @@ export const fabricAPIKeyStrategy: HeaderAPIKeyStrategy = org: '', }; if (apikey === config.org1ApiKey) { - user.org = 'Org1'; + user.org = config.identityNameOrg1; logger.debug('Organisation set to Org1'); done(null, user); - - //todo - //add org2 apikey check + } else if (apikey === config.org2ApiKey) { + user.org = config.identityNameOrg2; + logger.info('Organisation set to Org2'); + done(null, user); } else { logger.debug({ apikey }, 'No valid X-API-Key'); return done(null, false); @@ -42,7 +43,8 @@ export const authenticateApiKey = ( passport.authenticate( 'headerapikey', { session: false }, - function (err, user, _info) { + (err, user, _info) => { + logger.debug({ user }, 'USERUSERUSER'); if (err) return next(err); if (!user) return res.status(UNAUTHORIZED).json({ @@ -50,7 +52,8 @@ export const authenticateApiKey = ( reason: 'NO_VALID_APIKEY', timestamp: new Date().toISOString(), }); - req.logIn(user, { session: false }, (err) => { + + req.logIn(user, { session: false }, async (err) => { if (err) { return next(err); } diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index 08c33865..94c4d998 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -27,14 +27,21 @@ export const asLocalHost = env .example('true') .asBoolStrict(); -export const identityName = 'restServerIdentity'; +export const identityNameOrg1 = 'Org1'; +export const identityNameOrg2 = 'Org2'; -export const mspId = env - .get('HLF_MSP_ID') +const mspIdOrg1 = env + .get('HLF_MSP_ID_ORG1') .default('Org1MSP') .example('Org1MSP') .asString(); +const mspIdOrg2 = env + .get('HLF_MSP_ID_ORG2') + .default('Org2MSP') + .example('Org2MSP') + .asString(); + export const channelName = env .get('HLF_CHANNEL_NAME') .default('mychannel') @@ -59,22 +66,42 @@ export const endorseTimeout = env .example('30') .asIntPositive(); -export const connectionProfile = env - .get('HLF_CONNECTION_PROFILE') +const connectionProfileOrg1 = env + .get('HLF_CONNECTION_PROFILE_ORG1') .required() .example( '{"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... }' ) .asJsonObject(); -export const certificate = env - .get('HLF_CERTIFICATE') +const certificateOrg1 = env + .get('HLF_CERTIFICATE_ORG1') .required() .example('"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"') .asString(); -export const privateKey = env - .get('HLF_PRIVATE_KEY') +const privateKeyOrg1 = env + .get('HLF_PRIVATE_KEY_ORG1') + .required() + .example('"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"') + .asString(); + +const connectionProfileOrg2 = env + .get('HLF_CONNECTION_PROFILE_ORG2') + .required() + .example( + '{"name":"test-network-org2","version":"1.0.0","client":{"organization":"Org2" ... }' + ) + .asJsonObject(); + +const certificateOrg2 = env + .get('HLF_CERTIFICATE_ORG2') + .required() + .example('"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"') + .asString(); + +const privateKeyOrg2 = env + .get('HLF_PRIVATE_KEY_ORG2') .required() .example('"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"') .asString(); @@ -103,3 +130,25 @@ export const org1ApiKey = env .required() .example('123') .asString(); + +export const org2ApiKey = env + .get('ORG2_APIKEY') + .required() + .example('456') + .asString(); + +export const ORG1_CONFIG = { + identityName: identityNameOrg1, + mspId: mspIdOrg1, + connectionProfile: connectionProfileOrg1, + certificate: certificateOrg1, + privateKey: privateKeyOrg1, +}; + +export const ORG2_CONFIG = { + identityName: identityNameOrg2, + mspId: mspIdOrg2, + connectionProfile: connectionProfileOrg2, + certificate: certificateOrg2, + privateKey: privateKeyOrg2, +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index d96abe9b..1db73941 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -14,6 +14,7 @@ import { BlockEvent, TransactionEvent, } from 'fabric-network'; +import { Request } from 'express'; import { Redis } from 'ioredis'; import * as config from './config'; import { logger } from './logger'; @@ -31,24 +32,39 @@ export const getNetwork = async (gateway: Gateway): Promise => { return network; }; -export const getGateway = async (): Promise => { +interface FabricConfigType { + identityName: string; + mspId: string; + connectionProfile: { [key: string]: any }; + certificate: string; + privateKey: string; +} + +const FabricDataMapper: { [key: string]: FabricConfigType } = { + [config.identityNameOrg1]: config.ORG1_CONFIG, + [config.identityNameOrg2]: config.ORG2_CONFIG, +}; + +export const getGateway = async (org: string): Promise => { + const fabricConfig = FabricDataMapper[org]; + logger.debug('Configuring fabric gateway for %s', org); const wallet = await Wallets.newInMemoryWallet(); const x509Identity = { credentials: { - certificate: config.certificate, - privateKey: config.privateKey, + certificate: fabricConfig.certificate, + privateKey: fabricConfig.privateKey, }, - mspId: config.mspId, + mspId: fabricConfig.mspId, type: 'X.509', }; - await wallet.put(config.identityName, x509Identity); + await wallet.put(fabricConfig.identityName, x509Identity); const gateway = new Gateway(); const connectOptions: GatewayOptions = { wallet, - identity: config.identityName, + identity: fabricConfig.identityName, discovery: { enabled: true, asLocalhost: config.asLocalHost }, eventHandlerOptions: { commitTimeout: config.commitTimeout, @@ -61,8 +77,7 @@ export const getGateway = async (): Promise => { }, }; - await gateway.connect(config.connectionProfile, connectOptions); - + await gateway.connect(fabricConfig.connectionProfile, connectOptions); return gateway; }; @@ -306,3 +321,10 @@ export const getChainInfo = async (qscc: Contract): Promise => { return false; } }; + +export const getContractForOrg = ( + req: Request +): { contract: Contract; qscc: Contract } => { + const user: { org: string } = req.user as { org: string }; + return req.app.get('fabric')[user.org as string].contracts; +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index 9d65028e..94814eb6 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -12,9 +12,11 @@ import { createServer } from './server'; async function main() { const app = await createServer(); - const contract: Contract = app.get('contracts').contract; + const contract: Contract = + app.get('fabric')[config.identityNameOrg1].contracts.contract; const redis: Redis = app.get('redis'); - const network: Network = app.get('network'); + const network: Network = app.get('fabric')[config.identityNameOrg1].network; + await network.addBlockListener(blockEventHandler(redis)); startRetryLoop(contract, redis); diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 1b900248..31dc77c7 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -10,10 +10,16 @@ import pinoMiddleware from 'pino-http'; import { logger } from './logger'; import { assetsRouter } from './assets.router'; import { transactionsRouter } from './transactions.router'; -import { getContracts, getGateway, getNetwork, getChainInfo } from './fabric'; +import { + getContracts, + getGateway, + getNetwork, + getChainInfo, + getContractForOrg, +} from './fabric'; import { redis } from './redis'; import { Contract } from 'fabric-network'; - +import * as config from './config'; const { BAD_REQUEST, INTERNAL_SERVER_ERROR, @@ -24,6 +30,7 @@ const { import { authenticateApiKey, fabricAPIKeyStrategy } from './auth'; import passport from 'passport'; + export const createServer = async (): Promise => { const app = express(); @@ -63,13 +70,31 @@ export const createServer = async (): Promise => { if (process.env.NODE_ENV === 'production') { app.use(helmet()); } + // + const gatewayOrg1 = await getGateway(config.identityNameOrg1); + const gatewayOrg2 = await getGateway(config.identityNameOrg2); + const networkOrg1 = await getNetwork(gatewayOrg1); + const networkOrg2 = await getNetwork(gatewayOrg2); + + const contractsOrg1 = await getContracts(networkOrg1); + const contractsOrg2 = await getContracts(networkOrg2); + + const fabric = { + [config.identityNameOrg1]: { + gateway: gatewayOrg1, + contracts: contractsOrg1, + network: networkOrg1, + }, + [config.identityNameOrg2]: { + gateway: gatewayOrg2, + contracts: contractsOrg2, + network: networkOrg2, + }, + }; + + app.set('fabric', fabric); - const gateway = await getGateway(); - const network = await getNetwork(gateway); - const contracts = await getContracts(network); - app.set('contracts', contracts); app.set('redis', redis); - app.set('network', network); // Health routes app.get('/ready', (_req, res) => @@ -79,8 +104,16 @@ export const createServer = async (): Promise => { }) ); app.get('/live', async (_req, res) => { - const qscc: Contract = _req.app.get('contracts').qscc; - if ((await getChainInfo(qscc)) === true) { + _req.user = { org: config.identityNameOrg1 }; + const qsccOrg1: Contract = getContractForOrg(_req).qscc; + const Org1Liveness = await getChainInfo(qsccOrg1); + logger.debug('Org1 liveness %s', Org1Liveness); + _req.user = { org: config.identityNameOrg2 }; + const qsccOrg2: Contract = getContractForOrg(_req).qscc; + const Org2Liveness = await getChainInfo(qsccOrg2); + logger.debug('Org2 liveness %s', Org2Liveness); + + if (Org1Liveness && Org2Liveness) { res.status(OK).json({ status: getReasonPhrase(OK), timestamp: new Date().toISOString(), diff --git a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts index 2a0bc987..c3dd49bf 100644 --- a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts @@ -7,7 +7,7 @@ import { Contract } from 'fabric-network'; import { protos } from 'fabric-protos'; import { getReasonPhrase, StatusCodes } from 'http-status-codes'; import { Redis } from 'ioredis'; -import { evatuateTransaction } from './fabric'; +import { evatuateTransaction, getContractForOrg } from './fabric'; import { logger } from './logger'; import * as config from './config'; import { TransactionNotFoundError } from './errors'; @@ -28,7 +28,7 @@ transactionsRouter.get( let progress: Progress = 'DONE'; let validationCode = ''; - const qscc: Contract = req.app.get('contracts').qscc; + const qscc: Contract = getContractForOrg(req).qscc; const redis: Redis = req.app.get('redis'); try {