diff --git a/examples/cactus-example-discounted-asset-trade/README.md b/examples/cactus-example-discounted-asset-trade/README.md index 2654d1a609..14cb062a33 100644 --- a/examples/cactus-example-discounted-asset-trade/README.md +++ b/examples/cactus-example-discounted-asset-trade/README.md @@ -117,6 +117,17 @@ Alice will use credentials and other Indy formats such as schema and definition cactus-example-discounted-asset-trade-blp | [2022-01-31T16:00:56.208] [INFO] www - listening on *: 5034 ``` +### Dockerless run +For development purposes, it might be useful to run the sample application outside of docker-compose environment. + +1. Configure cactus and start the ledgers as described above. +1. Run `./script-dockerless-config-patch.sh` from `cactus-example-discounted-asset-trade/` directory. This will patch the configs and copy it to global location. +1. Start validators (each in separate cmd window). + 1. `cd packages/cactus-plugin-ledger-connector-fabric-socketio/ && npm run start` + 1. `cd packages/cactus-plugin-ledger-connector-go-ethereum-socketio/ && npm run start` + 1. `docker build packages-python/cactus_validator_socketio_indy/ -t indy-validator && docker run -v/etc/cactus/:/etc/cactus --rm --net="indy-testnet_indy_net" -p 10080:8000 indy-validator` +1. Start asset-trade: `npm run start-dockerless` + ## How to use this application 1. (Optional) Check the balance on Ethereum and the asset ownership on Fabric using the following script: diff --git a/examples/cactus-example-discounted-asset-trade/package.json b/examples/cactus-example-discounted-asset-trade/package.json index 41f53f22ab..d06a560f2a 100644 --- a/examples/cactus-example-discounted-asset-trade/package.json +++ b/examples/cactus-example-discounted-asset-trade/package.json @@ -8,6 +8,7 @@ "private": true, "scripts": { "start": "npm run build_pip_indy_package && docker-compose build && docker-compose up", + "start-dockerless": "node ./dist/www.js", "build": "npm run build-ts && npm run build:dev:backend:postbuild", "build-ts": "tsc", "build_pip_indy_package": "cd ../../packages-python/cactus_validator_socketio_indy && python3 setup.py bdist_wheel", diff --git a/examples/cactus-example-discounted-asset-trade/script-dockerless-config-patch.sh b/examples/cactus-example-discounted-asset-trade/script-dockerless-config-patch.sh new file mode 100755 index 0000000000..4445214e1c --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade/script-dockerless-config-patch.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# Copyright 2020-2022 Hyperledger Cactus Contributors +# SPDX-License-Identifier: Apache-2.0 + +COMMON_CACTUS_CONFIG="/etc/cactus/" + +echo "Note - script must executed from within cactus-example-discounted-asset-trade directory!" + +echo "Copy local cactus config to common location ($COMMON_CACTUS_CONFIG)" +sudo rm -rf "$COMMON_CACTUS_CONFIG" +sudo cp -ar "./etc/cactus" "/etc" +sudo chown -hR $(whoami) "$COMMON_CACTUS_CONFIG" + +echo "Patch validators..." +sed -i 's/asset_trade_faio2x_testnet/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-fabric-socketio/default.yaml" +sed -i 's/geth1/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-go-ethereum-socketio/default.yaml" + +echo "Patch validator-registry-config.yaml..." +sed -i 's/ethereum-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml" +sed -i 's/fabric-socketio-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml" +sed -i 's/indy-validator-nginx/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml" + +echo "Patch path to asset-trade modules." +current_pwd=$(pwd) +escaped_pwd=${current_pwd//\//\\/} +sed -i "s/\/root\/cactus/$escaped_pwd/g" "${COMMON_CACTUS_CONFIG}/usersetting.yaml" + +echo "Done." diff --git a/examples/cactus-example-electricity-trade/README.md b/examples/cactus-example-electricity-trade/README.md index 3b1c8ce174..b72a5c0583 100644 --- a/examples/cactus-example-electricity-trade/README.md +++ b/examples/cactus-example-electricity-trade/README.md @@ -77,6 +77,16 @@ In this example, we use the Sawtooth intkey transaction processor as an applicat cactus-example-electricity-trade-blp | [2022-02-14T15:47:47.399] [INFO] www - listening on *: 5034 ``` +### Dockerless run +For development purposes, it might be useful to run the sample application outside of docker-compose environment. + +1. Configure cactus and start the ledgers as described above. +1. Run `./script-dockerless-config-patch.sh` from `cactus-example-discounted-asset-trade/` directory. This will patch the configs and copy it to global location. +1. Start validators (each in separate cmd window). + 1. `cd packages/cactus-plugin-ledger-connector-go-ethereum-socketio/ && npm run start` + 1. `cd packages/cactus-plugin-ledger-connector-sawtooth-socketio/ && npm run start` +1. Start electricity-trade: `npm run start-dockerless` + ## How to use this application - Source account on Ethereum: `06fc56347d91c6ad2dae0c3ba38eb12ab0d72e97` - The privkey of source account on Ethereum: `cb5d48d371916a4ea1627189d8af4f642a5d72746a06b559780c3f5932658207` diff --git a/examples/cactus-example-electricity-trade/package.json b/examples/cactus-example-electricity-trade/package.json index 442b3a7f13..5cc9d3e016 100644 --- a/examples/cactus-example-electricity-trade/package.json +++ b/examples/cactus-example-electricity-trade/package.json @@ -8,6 +8,7 @@ "private": true, "scripts": { "start": "docker-compose build && docker-compose up", + "start-dockerless": "node ./dist/www.js", "build": "npm run build-ts && npm run build:dev:backend:postbuild", "build-ts": "tsc", "build:dev:backend:postbuild": "cp -f ../../yarn.lock ./dist/" diff --git a/examples/cactus-example-electricity-trade/script-dockerless-config-patch.sh b/examples/cactus-example-electricity-trade/script-dockerless-config-patch.sh new file mode 100755 index 0000000000..c602ab4aff --- /dev/null +++ b/examples/cactus-example-electricity-trade/script-dockerless-config-patch.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Copyright 2020-2022 Hyperledger Cactus Contributors +# SPDX-License-Identifier: Apache-2.0 + +COMMON_CACTUS_CONFIG="/etc/cactus/" + +echo "Note - script must executed from within cactus-example-electricity-trade directory!" + +echo "Copy local cactus config to common location ($COMMON_CACTUS_CONFIG)" +sudo rm -rf "$COMMON_CACTUS_CONFIG" +sudo cp -ar "./etc/cactus" "/etc" +sudo chown -hR $(whoami) "$COMMON_CACTUS_CONFIG" + +echo "Patch validators..." +sed -i 's/geth1/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-go-ethereum-socketio/default.yaml" +sed -i 's/rest-api/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-sawtooth-socketio/default.yaml" + +echo "Patch validator-registry-config.yaml..." +sed -i 's/ethereum-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml" +sed -i 's/sawtooth-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml" + +echo "Patch path to electricity-trade modules." +current_pwd=$(pwd) +escaped_pwd=${current_pwd//\//\\/} +sed -i "s/\/root\/cactus/$escaped_pwd/g" "${COMMON_CACTUS_CONFIG}/usersetting.yaml" + +echo "Done." diff --git a/packages/cactus-api-client/src/main/typescript/socketio-api-client.ts b/packages/cactus-api-client/src/main/typescript/socketio-api-client.ts index c2266b42de..9488496c45 100644 --- a/packages/cactus-api-client/src/main/typescript/socketio-api-client.ts +++ b/packages/cactus-api-client/src/main/typescript/socketio-api-client.ts @@ -15,47 +15,14 @@ import { LoggerProvider, } from "@hyperledger/cactus-common"; import { ISocketApiClient } from "@hyperledger/cactus-core-api"; - +import { verifyValidatorMessageJwt } from "@hyperledger/cactus-common"; import { Socket, SocketOptions, ManagerOptions, io } from "socket.io-client"; import { readFileSync } from "fs"; import { resolve as resolvePath } from "path"; -import { verify, VerifyOptions, VerifyErrors, JwtPayload } from "jsonwebtoken"; +import { JwtPayload } from "jsonwebtoken"; import { Observable, ReplaySubject } from "rxjs"; import { finalize } from "rxjs/operators"; -/** - * Default logic for validating responses from socketio connector (validator). - * Assumes that message is JWT signed with validator private key. - * @param publicKey - Validator public key. - * @param targetData - Signed JWT message to be decoded. - * @returns Promise resolving to decoded JwtPayload. - */ -export function verifyValidatorJwt( - publicKey: string, - targetData: string, -): Promise { - return new Promise((resolve, reject) => { - const option: VerifyOptions = { - algorithms: ["ES256", "ES384", "ES512", "RS256", "RS384", "RS512"], - }; - - verify( - targetData, - publicKey, - option, - (err: VerifyErrors | null, decoded: JwtPayload | undefined) => { - if (err) { - reject(err); - } else if (decoded === undefined) { - reject(Error("Decoded message is undefined")); - } else { - resolve(decoded); - } - }, - ); - }); -} - /** * Input parameters for SocketIOApiClient construction. */ @@ -96,7 +63,7 @@ export class SocketIOApiClient implements ISocketApiClient { checkValidator: ( publicKey: string, data: string, - ) => Promise = verifyValidatorJwt; + ) => Promise = verifyValidatorMessageJwt; /** * @param validatorID - (required) ID of validator. diff --git a/packages/cactus-api-client/src/test/typescript/unit/socketio-api-client.test.ts b/packages/cactus-api-client/src/test/typescript/unit/socketio-api-client.test.ts index a6da7bafa1..ce5c41d79c 100644 --- a/packages/cactus-api-client/src/test/typescript/unit/socketio-api-client.test.ts +++ b/packages/cactus-api-client/src/test/typescript/unit/socketio-api-client.test.ts @@ -3,7 +3,6 @@ * Don't use jest timer mocks here, they do not work well with node http module. * With timer mocks tests will either hang or report open timeout handle. * Tests: - * - verifyValidatorJwt(), * - SocketIOApiClient construction, * - SocketIOApiClient.sendAsyncRequest(), * - SocketIOApiClient.sendSyncRequest(), @@ -17,7 +16,6 @@ const setupTimeout = 1000 * 60; // 1 minute timeout for setup import "jest-extended"; import { cloneDeep } from "lodash"; -import { sign, JwtPayload } from "jsonwebtoken"; // Unit Test logger setup import { @@ -48,7 +46,7 @@ const defaultConfigOptions = { // Generate private / public keys for test purposes import { generateKeyPairSync } from "crypto"; -const { publicKey, privateKey } = generateKeyPairSync("ec", { +const { publicKey } = generateKeyPairSync("ec", { namedCurve: "P-256", }); const publicKeyString = publicKey.export({ @@ -64,7 +62,6 @@ jest.spyOn(fs, "readFileSync").mockReturnValue(publicKeyString); import { SocketIOApiClient, - verifyValidatorJwt, SocketLedgerEvent, } from "../../../main/typescript/socketio-api-client"; @@ -74,81 +71,6 @@ import { jest.setTimeout(testTimeout); -////////////////////////////////// -// verifyValidatorJwt() -////////////////////////////////// - -describe("verifyValidatorJwt tests", () => { - const message = { - message: "Hello", - from: "Someone", - }; - let signedMessage = ""; - - beforeAll(() => { - log.debug("input message:", message); - - // Encrypt the message (from validator) - signedMessage = sign( - message, - privateKey.export({ type: "sec1", format: "pem" }), - { - algorithm: "ES256", - expiresIn: "1 day", - }, - ); - expect(signedMessage).toBeTruthy(); - log.debug("signedMessage:", signedMessage); - }, setupTimeout); - - test("Decrypts the payload from the validator using it's public key", async () => { - // Verify (decrypt) - const decryptedMessage = await verifyValidatorJwt( - publicKeyString, - signedMessage, - ); - - // Assert decrypted message - log.debug("decryptedMessage:", decryptedMessage); - expect(decryptedMessage).toMatchObject(message); - const decryptedJwt = decryptedMessage as JwtPayload; - expect(decryptedJwt.iat).toBeNumber(); - expect(decryptedJwt.exp).toBeNumber(); - }); - - test("Rejects malicious message", () => { - // Reverse original message to produce wrong input - const maliciousMessage = signedMessage.split("").reverse().join(""); - log.debug("maliciousMessage", maliciousMessage); - - // Verify (decrypt) - return expect( - verifyValidatorJwt(publicKeyString, maliciousMessage), - ).toReject(); - }); - - test("Rejects expired message", (done) => { - // Encrypt the message (from validator) with short expiration time - signedMessage = sign( - message, - privateKey.export({ type: "sec1", format: "pem" }), - { - algorithm: "ES256", - expiresIn: "1", - }, - ); - expect(signedMessage).toBeTruthy(); - - setTimeout(async () => { - // Verify after short timeout - await expect( - verifyValidatorJwt(publicKeyString, signedMessage), - ).toReject(); - done(); - }, 1000); - }); -}); - ////////////////////////////////// // SocketIOApiClient Constructor ////////////////////////////////// diff --git a/packages/cactus-cmd-socketio-server/package.json b/packages/cactus-cmd-socketio-server/package.json index aaf26a4c92..9b9850c4f9 100644 --- a/packages/cactus-cmd-socketio-server/package.json +++ b/packages/cactus-cmd-socketio-server/package.json @@ -15,6 +15,7 @@ "@hyperledger/cactus-core-api": "1.0.0", "@types/node": "14.17.32", "body-parser": "1.19.2", + "config": "3.3.7", "cookie-parser": "1.4.5", "debug": "2.6.9", "escape-html": "1.0.3", diff --git a/packages/cactus-cmd-socketio-server/src/main/typescript/public-api.ts b/packages/cactus-cmd-socketio-server/src/main/typescript/public-api.ts index 8425177c2d..d987ec775d 100644 --- a/packages/cactus-cmd-socketio-server/src/main/typescript/public-api.ts +++ b/packages/cactus-cmd-socketio-server/src/main/typescript/public-api.ts @@ -2,6 +2,7 @@ export { Verifier } from "./verifier/Verifier"; export { LedgerEvent } from "./verifier/LedgerPlugin"; export { json2str } from "./verifier/DriverCommon"; +export { signMessageJwt } from './verifier/validator-authentication'; // Routing Interface export { RIFError } from "./routing-interface/RIFError"; @@ -25,3 +26,4 @@ export { LedgerOperation } from "./business-logic-plugin/LedgerOperation"; // Util export { TransactionSigner } from "./util/TransactionSigner"; +export { configRead } from "./util/config"; diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/config.ts b/packages/cactus-cmd-socketio-server/src/main/typescript/util/config.ts similarity index 61% rename from packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/config.ts rename to packages/cactus-cmd-socketio-server/src/main/typescript/util/config.ts index 1c65258360..bc7e328b90 100644 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/config.ts +++ b/packages/cactus-cmd-socketio-server/src/main/typescript/util/config.ts @@ -1,15 +1,13 @@ /* - * Copyright 2021 Hyperledger Cactus Contributors + * Copyright 2022 Hyperledger Cactus Contributors * SPDX-License-Identifier: Apache-2.0 * + * NOTE: Be sure that NODE_CONFIG_DIR env variable points to the location + * of current module config files before loading this. + * * config.js */ -export const DEFAULT_NODE_CONFIG_DIR = "/etc/cactus/connector-fabric-socketio/"; -if (!process.env["NODE_CONFIG_DIR"]) { - // Must be set before import config - process.env["NODE_CONFIG_DIR"] = DEFAULT_NODE_CONFIG_DIR; -} import config from "config"; @@ -20,7 +18,7 @@ import config from "config"; * @param defaultValue : Value to return if key is not present in the config. * @returns : Configuration value */ -export function read(key: string, defaultValue?: T): T { +export function configRead(key: string, defaultValue?: T): T { if (config.has(key)) { return config.get(key); } diff --git a/packages/cactus-cmd-socketio-server/src/main/typescript/verifier/ValidatorAuthentication.ts b/packages/cactus-cmd-socketio-server/src/main/typescript/verifier/ValidatorAuthentication.ts deleted file mode 100644 index 7ddeae8141..0000000000 --- a/packages/cactus-cmd-socketio-server/src/main/typescript/verifier/ValidatorAuthentication.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2020-2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * ValidatorAuthentication.ts - */ - -const fs = require("fs"); -const path = require("path"); -const jwt = require("jsonwebtoken"); -import { config } from "../common/core/config/default"; -import { getLogger } from "log4js"; -const logger = getLogger("ValidatorAuthentication[" + process.pid + "]"); -logger.level = config.logLevel; - -const privateKey = fs.readFileSync( - path.resolve(__dirname, config.validatorKeyPath) -); - -export class ValidatorAuthentication { - static sign(payload: object): string { - const option = { - algorithm: "ES256", - expiresIn: "1000", - }; - - // logger.debug(`payload = ${JSON.stringify(payload)}`); - const signature: string = jwt.sign(payload, privateKey, option); - // logger.debug(`signature = ${signature}`); - logger.debug(`signature: OK`); - return signature; - } -} diff --git a/packages/cactus-cmd-socketio-server/src/main/typescript/verifier/validator-authentication.ts b/packages/cactus-cmd-socketio-server/src/main/typescript/verifier/validator-authentication.ts new file mode 100644 index 0000000000..1830a27edf --- /dev/null +++ b/packages/cactus-cmd-socketio-server/src/main/typescript/verifier/validator-authentication.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2020-2022 Hyperledger Cactus Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import fs from "fs"; +import jwt from "jsonwebtoken"; +import { configRead } from "../util/config"; +import { signValidatorMessageJwt } from "@hyperledger/cactus-common" + +// Will keep the private key once it's succesfully read +let privateKey: string; + +/** + * Validator-side function to sign message to be sent to the client. + * Will read the private key either as value in validator config `sslParam.keyValue`, + * or read from filesystem under path `sslParam.key`. + * + * @param payload - Message to sign + * @returns Signed message + */ +export function signMessageJwt(payload: object): string { + if (!privateKey) { + try { + privateKey = configRead('sslParam.keyValue'); + } catch { + privateKey = fs.readFileSync(configRead('sslParam.key'), "ascii"); + } + } + const jwtAlgo = configRead('sslParam.jwtAlgo', 'ES256'); + return signValidatorMessageJwt(privateKey, payload, jwtAlgo); +} diff --git a/packages/cactus-cmd-socketio-server/tsconfig.json b/packages/cactus-cmd-socketio-server/tsconfig.json index da82ead53f..2916d20e7a 100644 --- a/packages/cactus-cmd-socketio-server/tsconfig.json +++ b/packages/cactus-cmd-socketio-server/tsconfig.json @@ -14,8 +14,7 @@ "./src/main/typescript/routing-interface/**/*.ts" ], "exclude": [ - "copyStaticAssets.ts", - "./src/main/typescript/verifier/ValidatorAuthentication.ts" + "copyStaticAssets.ts" ], "references": [ { diff --git a/packages/cactus-common/package.json b/packages/cactus-common/package.json index 7700411a97..f3e2298ec7 100644 --- a/packages/cactus-common/package.json +++ b/packages/cactus-common/package.json @@ -51,6 +51,7 @@ }, "dependencies": { "json-stable-stringify": "1.0.1", + "jsonwebtoken": "8.5.1", "key-encoder": "2.0.3", "loglevel": "1.7.1", "loglevel-plugin-prefix": "0.8.4", diff --git a/packages/cactus-common/src/main/typescript/public-api.ts b/packages/cactus-common/src/main/typescript/public-api.ts index 209b91f6dc..226228df30 100755 --- a/packages/cactus-common/src/main/typescript/public-api.ts +++ b/packages/cactus-common/src/main/typescript/public-api.ts @@ -1,5 +1,9 @@ export { LoggerProvider } from "./logging/logger-provider"; export { Logger, ILoggerOptions } from "./logging/logger"; +export { + signValidatorMessageJwt, + verifyValidatorMessageJwt, +} from "./verifier/jwt-message-authentication"; export { LogLevelDesc } from "loglevel"; export { Objects } from "./objects"; export { Strings } from "./strings"; diff --git a/packages/cactus-common/src/main/typescript/verifier/jwt-message-authentication.ts b/packages/cactus-common/src/main/typescript/verifier/jwt-message-authentication.ts new file mode 100644 index 0000000000..a677a20795 --- /dev/null +++ b/packages/cactus-common/src/main/typescript/verifier/jwt-message-authentication.ts @@ -0,0 +1,92 @@ +/* + * Copyright 2020-2022 Hyperledger Cactus Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import crypto from "crypto"; +import jwt from "jsonwebtoken"; + +const DEFAULT_EXPIRATION_TIME = 60 * 15; // 15 minutes +type PayloadType = Parameters[0]; + +const supportedJwtAlgos: jwt.Algorithm[] = [ + "ES256", + "ES384", + "ES512", + "RS256", + "RS384", + "RS512", +]; + +/** + * Sign a message to be sent from socketio connector (validator) to a client. + * + * @param privateKey - Validator private key. Only ECDSA and RSA keys are supported. + * @param payload - Message to be encoded. + * @param jwtAlgo - JWT algorithm to use. Must match key used (ES*** or RS***) + * @param expirationTime - JWT expiration time + * @returns JWT signed message that can be sent over the wire. + */ +export function signValidatorMessageJwt( + privateKey: jwt.Secret, + payload: PayloadType, + jwtAlgo: jwt.Algorithm = "ES256", + expirationTime: number = DEFAULT_EXPIRATION_TIME, +): string { + if (!supportedJwtAlgos.includes(jwtAlgo)) { + throw new Error( + `Wrong JWT Algorithm. Supported algos: ${supportedJwtAlgos.toString()}`, + ); + } + + // Check if key supported and JWT algorithm matches the provided key type + const keyType = crypto.createPrivateKey(privateKey).asymmetricKeyType; + if ( + !( + (keyType === "rsa" && jwtAlgo.startsWith("RS")) || + (keyType === "ec" && jwtAlgo.startsWith("ES")) + ) + ) { + throw new Error(`Not supported combination ${keyType}/${jwtAlgo}.`); + } + + const option: jwt.SignOptions = { + algorithm: jwtAlgo, + expiresIn: expirationTime, + }; + + return jwt.sign(payload, privateKey, option); +} + +/** + * Validate response from socketio connector (validator). + * Input message must be JWT signed with validator private key, + * that match public key (cert) from input. + * + * @param publicKey - Validator public key. Only ECDSA and RSA keys are supported. + * @param targetData - Signed JWT message to be decoded. + * @returns Promise resolving to decoded jwt.JwtPayload. + */ +export function verifyValidatorMessageJwt( + publicKey: jwt.Secret, + targetData: string, +): Promise { + return new Promise((resolve, reject) => { + jwt.verify( + targetData, + publicKey, + { + algorithms: supportedJwtAlgos, + }, + (err: jwt.VerifyErrors | null, decoded: jwt.JwtPayload | undefined) => { + if (err) { + reject(err); + } else if (decoded === undefined) { + reject(Error("Decoded message is undefined")); + } else { + resolve(decoded); + } + }, + ); + }); +} diff --git a/packages/cactus-common/src/test/typescript/unit/verifier/jwt-message-authentication.test.ts b/packages/cactus-common/src/test/typescript/unit/verifier/jwt-message-authentication.test.ts new file mode 100644 index 0000000000..88c30d64b6 --- /dev/null +++ b/packages/cactus-common/src/test/typescript/unit/verifier/jwt-message-authentication.test.ts @@ -0,0 +1,132 @@ +/** + * Base File: packages/cactus-common/src/main/typescript/verifier/jwt-message-authentication.ts + */ + +const testLogLevel: LogLevelDesc = "info"; +const setupTimeout = 1000 * 60; // 1 minute timeout for setup + +import "jest-extended"; + +// Unit Test logger setup +import { + Logger, + LoggerProvider, + LogLevelDesc, +} from "../../../../main/typescript/public-api"; +const log: Logger = LoggerProvider.getOrCreate({ + label: "jwt-message-authentication.test", + level: testLogLevel, +}); + +// Generate private / public keys for test purposes +import { generateKeyPairSync } from "crypto"; +const { publicKey, privateKey } = generateKeyPairSync("ec", { + namedCurve: "P-256", +}); +const publicKeyString = publicKey.export({ + type: "spki", + format: "pem", +}) as string; + +import { sign, JwtPayload } from "jsonwebtoken"; +import { + signValidatorMessageJwt, + verifyValidatorMessageJwt, +} from "../../../../main/typescript/verifier/jwt-message-authentication"; + +////////////////////////////////// +// Tests +////////////////////////////////// + +describe("jwt-message-authentication tests", () => { + const message = { + message: "Hello", + from: "Someone", + }; + let signedMessage = ""; + + beforeAll(() => { + log.debug("input message:", message); + + // Encrypt the message (from validator) + signedMessage = sign( + message, + privateKey.export({ type: "sec1", format: "pem" }), + { + algorithm: "ES256", + expiresIn: "1 day", + }, + ); + expect(signedMessage).toBeTruthy(); + log.debug("signedMessage:", signedMessage); + }, setupTimeout); + + test("Decrypts the payload from the validator using it's public key", async () => { + // Verify (decrypt) + const decryptedMessage = await verifyValidatorMessageJwt( + publicKeyString, + signedMessage, + ); + + // Assert decrypted message + log.debug("decryptedMessage:", decryptedMessage); + expect(decryptedMessage).toMatchObject(message); + const decryptedJwt = decryptedMessage as JwtPayload; + expect(decryptedJwt.iat).toBeNumber(); + expect(decryptedJwt.exp).toBeNumber(); + }); + + test("Rejects malicious message", () => { + // Reverse original message to produce wrong input + const maliciousMessage = signedMessage.split("").reverse().join(""); + log.debug("maliciousMessage", maliciousMessage); + + // Verify (decrypt) + return expect( + verifyValidatorMessageJwt(publicKeyString, maliciousMessage), + ).toReject(); + }); + + test("Rejects expired message", (done) => { + // Encrypt the message (from validator) with short expiration time + signedMessage = sign( + message, + privateKey.export({ type: "sec1", format: "pem" }), + { + algorithm: "ES256", + expiresIn: "1", + }, + ); + expect(signedMessage).toBeTruthy(); + + setTimeout(async () => { + // Verify after short timeout + await expect( + verifyValidatorMessageJwt(publicKeyString, signedMessage), + ).toReject(); + done(); + }, 1000); + }); + + test("Verifies message signed with the same module", async () => { + // Sign (encrypt) + const signed = signValidatorMessageJwt( + privateKey.export({ type: "sec1", format: "pem" }), + message, + ); + expect(signed).toBeTruthy(); + + // Verify (decrypt) + const decryptedMessage = await verifyValidatorMessageJwt( + publicKeyString, + signed, + ); + + // Assert decrypted message + log.debug("decryptedMessage:", decryptedMessage); + expect(decryptedMessage).toMatchObject(message); + const decryptedJwt = decryptedMessage as JwtPayload; + expect(decryptedJwt.iat).toBeNumber(); + expect(decryptedJwt.exp).toBeNumber(); + }); +}); diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/package.json b/packages/cactus-plugin-ledger-connector-fabric-socketio/package.json index 6409db0ce7..6b87986657 100644 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/package.json +++ b/packages/cactus-plugin-ledger-connector-fabric-socketio/package.json @@ -15,8 +15,8 @@ }, "dependencies": { "@types/node": "14.17.32", + "@hyperledger/cactus-cmd-socket-server": "1.0.0", "body-parser": "1.17.2", - "config": "3.3.7", "cookie-parser": "1.4.6", "debug": "4.1.1", "express": "4.17.3", diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/bin/www.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/bin/www.ts index 9180560472..54d84819a8 100644 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/bin/www.ts +++ b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/bin/www.ts @@ -13,13 +13,21 @@ import app from "../app"; import https = require("https"); -import * as config from "../config"; + +// Overwrite config read path +export const DEFAULT_NODE_CONFIG_DIR = "/etc/cactus/connector-fabric-socketio/"; +if (!process.env["NODE_CONFIG_DIR"]) { + // Must be set before import config + process.env["NODE_CONFIG_DIR"] = DEFAULT_NODE_CONFIG_DIR; +} +import { configRead } from "@hyperledger/cactus-cmd-socket-server"; + import fs = require("fs"); import { Server } from "socket.io" // Log settings import { getLogger } from "log4js"; const logger = getLogger("connector_main[" + process.pid + "]"); -logger.level = config.read('logLevel', 'info'); +logger.level = configRead('logLevel', 'info'); // implementation class of a part dependent of end-chains (server plugin) import { ServerPlugin } from "../../../connector/ServerPlugin"; @@ -32,18 +40,18 @@ export async function startFabricSocketIOConnector() { const Smonitor = new ServerMonitorPlugin(); // Get port from environment and store in Express. - const sslport = normalizePort(process.env.PORT || config.read('sslParam.port')); + const sslport = normalizePort(process.env.PORT || configRead('sslParam.port')); app.set("port", sslport); // Specify private key and certificate let keyString: string; let certString: string; try { - keyString = config.read('sslParam.keyValue'); - certString = config.read('sslParam.certValue'); + keyString = configRead('sslParam.keyValue'); + certString = configRead('sslParam.certValue'); } catch { - keyString = fs.readFileSync(config.read('sslParam.key'), "ascii"); - certString = fs.readFileSync(config.read('sslParam.cert'), "ascii"); + keyString = fs.readFileSync(configRead('sslParam.key'), "ascii"); + certString = fs.readFileSync(configRead('sslParam.cert'), "ascii"); } // Create HTTPS server. diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts index f131531849..8c02dfffd3 100644 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts +++ b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts @@ -19,13 +19,12 @@ import FabricClient from "fabric-client"; // IF declaration for fabric import { getClientAndChannel, getSubmitterAndEnroll } from "./fabricaccess"; // config file -import * as config from "../common/core/config"; +import { configRead, signMessageJwt } from "@hyperledger/cactus-cmd-socket-server"; // Log settings import { getLogger } from "log4js"; const logger = getLogger("ServerMonitorPlugin[" + process.pid + "]"); -logger.level = config.read("logLevel", "info"); +logger.level = configRead("logLevel", "info"); // utility -import { ValidatorAuthentication } from "./ValidatorAuthentication"; import safeStringify from "fast-safe-stringify"; export type MonitorCallback = (callback: { @@ -81,7 +80,7 @@ export class ServerMonitorPlugin { console.log("##[HL-BC] Notify new block data(D2)"); logger.info( - "chain id :" + config.read("fabric.channelName"), + "chain id :" + configRead("fabric.channelName"), ); logger.info("blocknumber : " + block.header.number); const len = block.data.data.length; @@ -104,7 +103,7 @@ export class ServerMonitorPlugin { const ccid = invocationSpec.chaincode_spec.chaincode_id.name; logger.info("chaincode id :" + ccid); // Only notify transactions from the chaincode used in ServerPlugin - if (ccid == config.read("fabric.chaincodeId")) { + if (ccid == configRead("fabric.chaincodeId")) { const args = invocationSpec.chaincode_spec.input.args; logger.info("args.length :" + args.length); for (let j = 0; j < args.length; j++) { @@ -133,7 +132,7 @@ export class ServerMonitorPlugin { } logger.info("*** SEND BLOCK DATA ***"); logger.debug(`txlist = ${JSON.stringify(txlist)}`); - const signedTxlist = ValidatorAuthentication.sign({ + const signedTxlist = signMessageJwt({ blockData: txlist, }); logger.debug(`signedTxlist = ${signedTxlist}`); diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerPlugin.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerPlugin.ts index 254607667e..eef9fe3693 100644 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerPlugin.ts +++ b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerPlugin.ts @@ -12,12 +12,12 @@ */ // config file -import * as config from "../common/core/config"; +import { configRead, signMessageJwt } from "@hyperledger/cactus-cmd-socket-server"; + // Log settings import { getLogger } from "log4js"; const logger = getLogger("ServerPlugin[" + process.pid + "]"); -logger.level = config.read("logLevel", "info"); -import { ValidatorAuthentication } from "./ValidatorAuthentication"; +logger.level = configRead("logLevel", "info"); // Read the library, SDK, etc. according to EC specifications as needed import { getClientAndChannel, getSubmitterAndEnroll } from "./fabricaccess"; @@ -27,7 +27,7 @@ import safeStringify from "fast-safe-stringify"; const path = require("path"); const { FileSystemWallet, Gateway } = require("fabric-network"); const fs = require("fs"); -const connUserName = config.read("fabric.connUserName"); +const connUserName = configRead("fabric.connUserName"); // Cryptographic for fabric const hash = require("fabric-client/lib/hash"); @@ -130,7 +130,7 @@ export class ServerPlugin { // logger.debug(`##evaluateTransaction(B6)`); objRetValue = JSON.parse(returnvalue); } - const signedResults = ValidatorAuthentication.sign({ + const signedResults = signMessageJwt({ result: objRetValue, }); retObj = { @@ -274,7 +274,7 @@ export class ServerPlugin { ) .then((signedTx) => { if (signedTx != null) { - const signedResults = ValidatorAuthentication.sign({ + const signedResults = signMessageJwt({ result: signedTx, }); retObj = { @@ -325,8 +325,8 @@ async function Invoke(reqBody: any) { const args = reqBody.args; // Create a new file system based wallet for managing identities. - const wallet = new FileSystemWallet(config.read("fabric.keystore")); - console.log(`Wallet path: ${config.read("fabric.keystore")}`); + const wallet = new FileSystemWallet(configRead("fabric.keystore")); + console.log(`Wallet path: ${configRead("fabric.keystore")}`); // Check to see if we've already enrolled the user. const userExists = await wallet.exists(connUserName); @@ -391,9 +391,9 @@ async function InvokeSync(reqBody: any) { // Create a new file system based wallet for managing identities. // logger.debug(`##InvokeSync(B)`); const wallet = new FileSystemWallet( - config.read("fabric.keystore"), + configRead("fabric.keystore"), ); - console.log(`Wallet path: ${config.read("fabric.keystore")}`); + console.log(`Wallet path: ${configRead("fabric.keystore")}`); // Check to see if we've already enrolled the user. // logger.debug(`##InvokeSync(C)`); @@ -639,9 +639,9 @@ async function InvokeSendSignedProposal( // Low-level access to local-store cert and private key of submitter (in case request is missing those) if (!certPem || !privateKeyPem) { - const wallet = new FileSystemWallet(config.read("fabric.keystore")); + const wallet = new FileSystemWallet(configRead("fabric.keystore")); logger.debug( - `Wallet path: ${path.resolve(config.read("fabric.keystore"))}`, + `Wallet path: ${path.resolve(configRead("fabric.keystore"))}`, ); const submitterName = user.getName(); @@ -663,7 +663,7 @@ async function InvokeSendSignedProposal( const { proposal, txId } = channel.generateUnsignedProposal( transactionProposalReq, - config.read("fabric.mspid"), + configRead("fabric.mspid"), certPem, false, ) as any; @@ -671,7 +671,7 @@ async function InvokeSendSignedProposal( const signedProposal = signProposal(proposal.toBuffer(), privateKeyPem); const targets = []; - for (const peerInfo of config.read("fabric.peers")) { + for (const peerInfo of configRead("fabric.peers")) { const peer = channel.getPeer(peerInfo.requests.split("//")[1]); targets.push(peer); } diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ValidatorAuthentication.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ValidatorAuthentication.ts deleted file mode 100644 index c42f100e8a..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ValidatorAuthentication.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020-2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * ValidatorAuthentication.ts - */ - -import fs from "fs"; -import crypto from "crypto"; -import jwt from "jsonwebtoken"; -import * as config from "../common/core/config"; -import { getLogger } from "log4js"; -const logger = getLogger("ValidatorAuthentication[" + process.pid + "]"); -logger.level = config.read("logLevel", "info"); - -let privateKey: string; - -export class ValidatorAuthentication { - static sign(payload: object): string { - if (!privateKey) { - try { - privateKey = config.read('sslParam.keyValue'); - } catch { - privateKey = fs.readFileSync(config.read('sslParam.key'), "ascii"); - } - } - - const jwtAlgo = config.read('sslParam.jwtAlgo', 'ES256'); - const keyType = crypto.createPrivateKey(privateKey).asymmetricKeyType; - if (keyType === 'rsa' && jwtAlgo.startsWith('RS')) { - logger.debug(`Using RSA key with JWT algorithm ${jwtAlgo}`); - } - else if (keyType === 'ec' && jwtAlgo.startsWith('ES')) { - logger.debug(`Using ECDSA key with JWT algorithm ${jwtAlgo}`); - } - else { - throw new Error(`Not supported combination ${keyType}/${jwtAlgo}. Please use either RSA or ECDSA key.`); - } - - const option: jwt.SignOptions = { - algorithm: jwtAlgo, - expiresIn: 60 * 15, // 15 minutes - }; - - const signature = jwt.sign(payload, privateKey, option); - logger.debug(`signature: OK`); - return signature; - } -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabricaccess.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabricaccess.ts index 96511f821f..14d4b6a451 100644 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabricaccess.ts +++ b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabricaccess.ts @@ -11,7 +11,7 @@ */ //Dependent library -import * as config from "../common/core/config"; +import { configRead } from "@hyperledger/cactus-cmd-socket-server"; const path = require("path"); import fs from "fs"; @@ -25,28 +25,28 @@ const clients = new Map(); // Log settings import { getLogger } from "log4js"; const logger = getLogger("fabricaccess[" + process.pid + "]"); -logger.level = config.read("logLevel", "info"); +logger.level = configRead("logLevel", "info"); // Get user object to send Proposal to EP export function getSubmitterAndEnroll(cli: FabricClient): Promise { logger.info("##fabricaccess_getSubmitter"); - const caUrl = config.read("fabric.ca.url"); - const caName = config.read("fabric.ca.name"); + const caUrl = configRead("fabric.ca.url"); + const caName = configRead("fabric.ca.name"); // Returns Promise when checkPersistence is true (poor typing) return (cli.getUserContext( - config.read("fabric.submitter.name"), + configRead("fabric.submitter.name"), true, ) as Promise).then((user) => { return new Promise((resolve, reject) => { if (user && user.isEnrolled()) { return resolve(user); } - const member = new User(config.read("fabric.submitter.name")); + const member = new User(configRead("fabric.submitter.name")); let cryptoSuite = cli.getCryptoSuite(); if (!cryptoSuite) { const storePath = path.join( - config.read("fabric.keystore"), - config.read("fabric.submitter.name"), + configRead("fabric.keystore"), + configRead("fabric.submitter.name"), ); cryptoSuite = FabricClient.newCryptoSuite(); cryptoSuite.setCryptoKeyStore( @@ -65,14 +65,14 @@ export function getSubmitterAndEnroll(cli: FabricClient): Promise { const cop = new copService(caUrl, tlsOptions, caName, cryptoSuite); return cop .enroll({ - enrollmentID: config.read("fabric.submitter.name"), - enrollmentSecret: config.read("fabric.submitter.secret"), + enrollmentID: configRead("fabric.submitter.name"), + enrollmentSecret: configRead("fabric.submitter.secret"), }) .then((enrollment) => { return member.setEnrollment( enrollment.key, enrollment.certificate, - config.read("fabric.mspid"), + configRead("fabric.mspid"), ); }) .then(() => { @@ -90,16 +90,16 @@ export function getSubmitterAndEnroll(cli: FabricClient): Promise { // fabric-client and Channel object generation export async function getClientAndChannel( - channelName = config.read("fabric.channelName"), + channelName = configRead("fabric.channelName"), ) { logger.info("##fabricaccess_getClientAndChannel"); // Since only one KVS can be set in the client, management in CA units as well as KVS path let isNewClient = false; - let client = clients.get(config.read("fabric.ca.name")); + let client = clients.get(configRead("fabric.ca.name")); if (!client) { logger.info("create new fabric-client"); client = new FabricClient(); - clients.set(config.read("fabric.ca.name"), client); + clients.set(configRead("fabric.ca.name"), client); isNewClient = true; } @@ -116,23 +116,23 @@ export async function getClientAndChannel( let ordererCA: string; try { - ordererCA = config.read('fabric.orderer.tlscaValue'); + ordererCA = configRead('fabric.orderer.tlscaValue'); } catch { - ordererCA = fs.readFileSync(config.read('fabric.orderer.tlsca'), 'ascii'); + ordererCA = fs.readFileSync(configRead('fabric.orderer.tlsca'), 'ascii'); } const orderer = client.newOrderer( - config.read("fabric.orderer.url"), + configRead("fabric.orderer.url"), { pem: ordererCA, - "ssl-target-name-override": config.read( + "ssl-target-name-override": configRead( "fabric.orderer.name", ), }, ); channel.addOrderer(orderer); // EP settings - const peersConfig = config.read("fabric.peers"); + const peersConfig = configRead("fabric.peers"); for (let i = 0; i < peersConfig.length; i++) { let peerCA: string; if ("tlscaValue" in peersConfig[i]) { @@ -146,12 +146,12 @@ export async function getClientAndChannel( "ssl-target-name-override": peersConfig[i].name, }); - channel.addPeer(peer, config.read("fabric.mspid")); + channel.addPeer(peer, configRead("fabric.mspid")); } const storePath = path.join( - config.read("fabric.keystore"), - config.read("fabric.submitter.name"), + configRead("fabric.keystore"), + configRead("fabric.submitter.name"), ); const cryptoSuite = FabricClient.newCryptoSuite(); cryptoSuite.setCryptoKeyStore( diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/tsconfig.json b/packages/cactus-plugin-ledger-connector-fabric-socketio/tsconfig.json index 2cef1d13d9..9056029438 100644 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/tsconfig.json +++ b/packages/cactus-plugin-ledger-connector-fabric-socketio/tsconfig.json @@ -16,6 +16,9 @@ { "path": "../cactus-api-client/tsconfig.json" }, + { + "path": "../cactus-cmd-socketio-server/tsconfig.json" + }, { "path": "../cactus-cmd-api-server/tsconfig.json" } diff --git a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/package.json b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/package.json index f4cf463043..2a1dc9f35a 100644 --- a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/package.json +++ b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/package.json @@ -12,8 +12,8 @@ }, "dependencies": { "@types/node": "14.17.32", + "@hyperledger/cactus-cmd-socket-server": "1.0.0", "body-parser": "1.17.2", - "config": "3.3.7", "cookie-parser": "1.4.6", "debug": "4.1.1", "express": "4.17.3", diff --git a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/common/core/bin/www.ts b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/common/core/bin/www.ts index 52444e2a5b..848c11154b 100644 --- a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/common/core/bin/www.ts +++ b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/common/core/bin/www.ts @@ -18,14 +18,23 @@ import app from "../app"; const debug = require("debug")("connector:server"); import https = require("https"); -import * as config from "../config"; + +// Overwrite config read path +export const DEFAULT_NODE_CONFIG_DIR = + "/etc/cactus/connector-go-ethereum-socketio/"; +if (!process.env["NODE_CONFIG_DIR"]) { + // Must be set before import config + process.env["NODE_CONFIG_DIR"] = DEFAULT_NODE_CONFIG_DIR; +} +import { configRead } from "@hyperledger/cactus-cmd-socket-server"; + import fs = require("fs"); import { Server } from "socket.io" // Log settings import { getLogger } from "log4js"; const logger = getLogger("connector_main[" + process.pid + "]"); -logger.level = config.read('logLevel', 'info'); +logger.level = configRead('logLevel', 'info'); // implementation class of a part dependent of end-chains (server plugin) import { ServerPlugin } from "../../../connector/ServerPlugin"; @@ -39,13 +48,13 @@ const Smonitor = new ServerMonitorPlugin(); * Get port from environment and store in Express. */ -const sslport = normalizePort(process.env.PORT || config.read('sslParam.port')); +const sslport = normalizePort(process.env.PORT || configRead('sslParam.port')); app.set("port", sslport); // Specify private key and certificate const sslParam = { - key: fs.readFileSync(config.read('sslParam.key')), - cert: fs.readFileSync(config.read('sslParam.cert')), + key: fs.readFileSync(configRead('sslParam.key')), + cert: fs.readFileSync(configRead('sslParam.cert')), }; /** diff --git a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/common/core/config.ts b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/common/core/config.ts deleted file mode 100644 index a976570e6d..0000000000 --- a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/common/core/config.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * config.js - */ - -// TODO - Common - -export const DEFAULT_NODE_CONFIG_DIR = - "/etc/cactus/connector-go-ethereum-socketio/"; -if (!process.env["NODE_CONFIG_DIR"]) { - // Must be set before import config - process.env["NODE_CONFIG_DIR"] = DEFAULT_NODE_CONFIG_DIR; -} - -import config from "config"; - -/** - * Get configuration entry (uses node-config setup) - * - * @param key : Key to retrieve - * @param defaultValue : Value to return if key is not present in the config. - * @returns : Configuration value - */ -export function read(key: string, defaultValue?: T): T { - if (config.has(key)) { - return config.get(key); - } - - if (defaultValue) { - return defaultValue; - } - - throw Error( - `Missing configuration entry '${key}', config dir = ${process.env["NODE_CONFIG_DIR"]}`, - ); -} diff --git a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts index 51d383ae95..4fcc9fa53c 100644 --- a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts +++ b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts @@ -14,13 +14,11 @@ */ // configuration file -import * as config from "../common/core/config"; +import { configRead, signMessageJwt } from "@hyperledger/cactus-cmd-socket-server"; // Log settings import { getLogger } from "log4js"; const logger = getLogger("ServerMonitorPlugin[" + process.pid + "]"); -logger.level = config.read("logLevel", "info"); -// utility -import { ValidatorAuthentication } from "./ValidatorAuthentication"; +logger.level = configRead("logLevel", "info"); // Load libraries, SDKs, etc. according to specifications of endchains as needed const Web3 = require("web3"); import safeStringify from "fast-safe-stringify"; @@ -57,7 +55,7 @@ export class ServerMonitorPlugin { try { const web3 = new Web3(); const provider = new web3.providers.HttpProvider( - config.read("ledgerUrl"), + configRead("ledgerUrl"), ); web3.setProvider(provider); filter = web3.eth.filter("latest"); @@ -78,7 +76,7 @@ export class ServerMonitorPlugin { if (trLength > 0) { logger.info("*** SEND BLOCK DATA ***"); logger.debug(`blockData = ${JSON.stringify(blockData)}`); - const signedBlockData = ValidatorAuthentication.sign({ + const signedBlockData = signMessageJwt({ blockData: blockData, }); logger.debug(`signedBlockData = ${signedBlockData}`); diff --git a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/connector/ServerPlugin.ts b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/connector/ServerPlugin.ts index bfe8b4c34c..62562a7469 100644 --- a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/connector/ServerPlugin.ts +++ b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/connector/ServerPlugin.ts @@ -12,14 +12,13 @@ */ // configuration file -import * as config from "../common/core/config"; +import { configRead, signMessageJwt } from "@hyperledger/cactus-cmd-socket-server"; // Log settings import { getLogger } from "log4js"; const logger = getLogger("ServerPlugin[" + process.pid + "]"); -logger.level = config.read("logLevel", "info"); +logger.level = configRead("logLevel", "info"); // utility import * as SplugUtil from "./PluginUtil"; -import { ValidatorAuthentication } from "./ValidatorAuthentication"; // Load libraries, SDKs, etc. according to specifications of endchains as needed const Web3 = require("web3"); import safeStringify from "fast-safe-stringify"; @@ -92,7 +91,7 @@ export class ServerPlugin { try { const web3 = new Web3(); web3.setProvider( - new web3.providers.HttpProvider(config.read("ledgerUrl")), + new web3.providers.HttpProvider(configRead("ledgerUrl")), ); const balance = web3.eth.getBalance(ethargs); const amountVal = balance.toNumber(); @@ -182,7 +181,7 @@ export class ServerPlugin { try { const web3 = new Web3(); web3.setProvider( - new web3.providers.HttpProvider(config.read("ledgerUrl")), + new web3.providers.HttpProvider(configRead("ledgerUrl")), ); const res = web3.eth[sendFunction](sendArgs); @@ -261,7 +260,7 @@ export class ServerPlugin { try { const web3 = new Web3(); web3.setProvider( - new web3.providers.HttpProvider(config.read("ledgerUrl")), + new web3.providers.HttpProvider(configRead("ledgerUrl")), ); const txnCount = web3.eth.getTransactionCount(ethargs); logger.info(`getNonce(): txnCount: ${txnCount}`); @@ -273,7 +272,7 @@ export class ServerPlugin { }; logger.debug(`getNonce(): result: ${result}`); - const signedResults = ValidatorAuthentication.sign({ result: result }); + const signedResults = signMessageJwt({ result: result }); logger.debug(`getNonce(): signedResults: ${signedResults}`); retObj = { resObj: { @@ -342,7 +341,7 @@ export class ServerPlugin { try { const web3 = new Web3(); web3.setProvider( - new web3.providers.HttpProvider(config.read("ledgerUrl")), + new web3.providers.HttpProvider(configRead("ledgerUrl")), ); const hexStr = web3.toHex(targetValue); logger.info(`toHex(): hexStr: ${hexStr}`); @@ -351,7 +350,7 @@ export class ServerPlugin { }; logger.debug(`toHex(): result: ${result}`); - const signedResults = ValidatorAuthentication.sign({ result: result }); + const signedResults = signMessageJwt({ result: result }); logger.debug(`toHex(): signedResults: ${signedResults}`); retObj = { resObj: { @@ -419,7 +418,7 @@ export class ServerPlugin { try { const web3 = new Web3(); web3.setProvider( - new web3.providers.HttpProvider(config.read("ledgerUrl")), + new web3.providers.HttpProvider(configRead("ledgerUrl")), ); const res = web3.eth.sendRawTransaction(serializedTx); @@ -467,7 +466,7 @@ export class ServerPlugin { try { const web3 = new Web3(); web3.setProvider( - new web3.providers.HttpProvider(config.read("ledgerUrl")), + new web3.providers.HttpProvider(configRead("ledgerUrl")), ); let result: any = null; if (sendArgs !== undefined) { @@ -475,7 +474,7 @@ export class ServerPlugin { } else { result = web3.eth[sendFunction](); } - const signedResults = ValidatorAuthentication.sign({ result: result }); + const signedResults = signMessageJwt({ result: result }); retObj = { resObj: { status: 200, @@ -536,7 +535,7 @@ export class ServerPlugin { try { const web3 = new Web3(); web3.setProvider( - new web3.providers.HttpProvider(config.read("ledgerUrl")), + new web3.providers.HttpProvider(configRead("ledgerUrl")), ); const contract = web3.eth .contract(args.contract.abi) @@ -570,7 +569,7 @@ export class ServerPlugin { } logger.debug(`##contract: result: ${result}`); - const signedResults = ValidatorAuthentication.sign({ result: result }); + const signedResults = signMessageJwt({ result: result }); retObj = { resObj: { status: 200, diff --git a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/connector/ValidatorAuthentication.ts b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/connector/ValidatorAuthentication.ts deleted file mode 100644 index 4ab02e4521..0000000000 --- a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/src/main/typescript/connector/ValidatorAuthentication.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2020-2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * ValidatorAuthentication.ts - */ - -const fs = require("fs"); -const path = require("path"); -const jwt = require("jsonwebtoken"); -import * as config from "../common/core/config"; -import { getLogger } from "log4js"; -const logger = getLogger("ValidatorAuthentication[" + process.pid + "]"); -logger.level = config.read("logLevel", "info"); - -const privateKey = fs.readFileSync( - path.resolve(__dirname, config.read("sslParam.key")), -); - -export class ValidatorAuthentication { - static sign(payload: object): string { - const option = { - algorithm: "ES256", - expiresIn: "1000", - }; - - // logger.debug(`payload = ${JSON.stringify(payload)}`); - const signature: string = jwt.sign(payload, privateKey, option); - // logger.debug(`signature = ${signature}`); - logger.debug(`signature: OK`); - return signature; - } -} diff --git a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/tsconfig.json b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/tsconfig.json index 7713871089..0403f799cf 100644 --- a/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/tsconfig.json +++ b/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/tsconfig.json @@ -15,5 +15,10 @@ "./src/main/typescript/common/core/bin/*.ts", "./src/main/typescript/common/core/config/*.ts", "./src/main/typescript/connector/*.ts" + ], + "references": [ + { + "path": "../cactus-cmd-socketio-server/tsconfig.json" + } ] } diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/package.json b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/package.json index 1d6c7f364b..69c3b36734 100644 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/package.json +++ b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/package.json @@ -12,9 +12,9 @@ }, "dependencies": { "@types/node": "14.17.32", + "@hyperledger/cactus-cmd-socket-server": "1.0.0", "body-parser": "1.17.2", "cbor": "6.0.1", - "config": "3.3.7", "cookie-parser": "1.4.6", "debug": "4.1.1", "express": "4.17.3", diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/bin/www.ts b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/bin/www.ts index 5496bc8b98..74bfd4e0a4 100755 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/bin/www.ts +++ b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/bin/www.ts @@ -18,14 +18,22 @@ import app from "../app"; const debug = require("debug")("connector:server"); import https = require("https"); -import * as config from "../config"; + +// Overwrite config read path +export const DEFAULT_NODE_CONFIG_DIR = + "/etc/cactus/connector-sawtooth-socketio/"; +if (!process.env["NODE_CONFIG_DIR"]) { + // Must be set before import config + process.env["NODE_CONFIG_DIR"] = DEFAULT_NODE_CONFIG_DIR; +} +import { configRead } from "@hyperledger/cactus-cmd-socket-server"; + import fs = require("fs"); import { Server } from "socket.io" - // Log settings import { getLogger } from "log4js"; const logger = getLogger("connector_main[" + process.pid + "]"); -logger.level = config.read('logLevel', 'info'); +logger.level = configRead('logLevel', 'info'); // destination dependency (MONITOR) implementation class import { ServerMonitorPlugin } from "../../../connector/ServerMonitorPlugin"; @@ -35,13 +43,13 @@ const Smonitor = new ServerMonitorPlugin(); * Get port from environment and store in Express. */ -const sslport = normalizePort(process.env.PORT || config.read('sslParam.port')); +const sslport = normalizePort(process.env.PORT || configRead('sslParam.port')); app.set("port", sslport); // Specify private key and certificate const sslParam = { - key: fs.readFileSync(config.read('sslParam.key')), - cert: fs.readFileSync(config.read('sslParam.cert')), + key: fs.readFileSync(configRead('sslParam.key')), + cert: fs.readFileSync(configRead('sslParam.cert')), }; /** diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/config.ts b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/config.ts deleted file mode 100644 index 76860b45f6..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/config.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * config.js - */ - -// TODO - Common - -export const DEFAULT_NODE_CONFIG_DIR = - "/etc/cactus/connector-sawtooth-socketio/"; -if (!process.env["NODE_CONFIG_DIR"]) { - // Must be set before import config - process.env["NODE_CONFIG_DIR"] = DEFAULT_NODE_CONFIG_DIR; -} - -import config from "config"; - -/** - * Get configuration entry (uses node-config setup) - * - * @param key : Key to retrieve - * @param defaultValue : Value to return if key is not present in the config. - * @returns : Configuration value - */ -export function read(key: string, defaultValue?: T): T { - if (config.has(key)) { - return config.get(key); - } - - if (defaultValue) { - return defaultValue; - } - - throw Error( - `Missing configuration entry '${key}', config dir = ${process.env["NODE_CONFIG_DIR"]}`, - ); -} diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts index a54a291870..5b5f0730ed 100644 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts +++ b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts @@ -15,13 +15,11 @@ // configuration file const SplugUtil = require("./PluginUtil"); -import * as config from "../common/core/config"; +import { configRead, signMessageJwt } from "@hyperledger/cactus-cmd-socket-server"; // Log settings import { getLogger } from "log4js"; const logger = getLogger("ServerMonitorPlugin[" + process.pid + "]"); -logger.level = config.read("logLevel", "info"); -// utility -import { ValidatorAuthentication } from "./ValidatorAuthentication"; +logger.level = configRead("logLevel", "info"); const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; /* @@ -61,9 +59,9 @@ export class ServerMonitorPlugin { that.periodicMonitoring(clientId, filterKey, cb); }; httpReq.open( - config.read("blockMonitor.request.method"), - config.read("blockMonitor.request.host") + - config.read("blockMonitor.request.getLatestBlockNumberCommand"), + configRead("blockMonitor.request.method"), + configRead("blockMonitor.request.host") + + configRead("blockMonitor.request.getLatestBlockNumberCommand"), ); httpReq.send(); } @@ -122,7 +120,7 @@ export class ServerMonitorPlugin { logger.debug( `transactionDataArray = ${JSON.stringify(transactionDataArray)}`, ); - const signedTransactionDataArray = ValidatorAuthentication.sign({ + const signedTransactionDataArray = signMessageJwt({ blockData: transactionDataArray, }); logger.debug( @@ -143,13 +141,13 @@ export class ServerMonitorPlugin { }; const timerBlockMonitoring = setInterval(function () { const callURL = - config.read("blockMonitor.request.host") + - config.read("blockMonitor.request.periodicMonitoringCommand1") + + configRead("blockMonitor.request.host") + + configRead("blockMonitor.request.periodicMonitoringCommand1") + SplugUtil.convertBlockNumber(that.currentBlockNumber) + - config.read("blockMonitor.request.periodicMonitoringCommand2"); + configRead("blockMonitor.request.periodicMonitoringCommand2"); logger.debug(`call URL = ${callURL}`); - httpReq.open(config.read("blockMonitor.request.method"), callURL); + httpReq.open(configRead("blockMonitor.request.method"), callURL); httpReq.send(); - }, config.read("blockMonitor.pollingInterval")); + }, configRead("blockMonitor.pollingInterval")); } } diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/ValidatorAuthentication.ts b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/ValidatorAuthentication.ts deleted file mode 100644 index 4ab02e4521..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/ValidatorAuthentication.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2020-2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * ValidatorAuthentication.ts - */ - -const fs = require("fs"); -const path = require("path"); -const jwt = require("jsonwebtoken"); -import * as config from "../common/core/config"; -import { getLogger } from "log4js"; -const logger = getLogger("ValidatorAuthentication[" + process.pid + "]"); -logger.level = config.read("logLevel", "info"); - -const privateKey = fs.readFileSync( - path.resolve(__dirname, config.read("sslParam.key")), -); - -export class ValidatorAuthentication { - static sign(payload: object): string { - const option = { - algorithm: "ES256", - expiresIn: "1000", - }; - - // logger.debug(`payload = ${JSON.stringify(payload)}`); - const signature: string = jwt.sign(payload, privateKey, option); - // logger.debug(`signature = ${signature}`); - logger.debug(`signature: OK`); - return signature; - } -} diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/tsconfig.json b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/tsconfig.json index 3b69ed1097..11df4752b8 100644 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/tsconfig.json +++ b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/tsconfig.json @@ -15,5 +15,10 @@ "./src/main/typescript/common/core/bin/*.ts", "./src/main/typescript/common/core/config/*.ts", "./src/main/typescript/connector/*.ts" + ], + "references": [ + { + "path": "../cactus-cmd-socketio-server/tsconfig.json" + } ] }