Skip to content

Commit

Permalink
refactor(cmd-socketio-server): remove code duplication
Browse files Browse the repository at this point in the history
- Move config-reading and signMessageJwt helper functions from validators to cmd-socketio-server
  to remove code duplication. Refactor validators to use these common instead of own implementation.
- Remove ValidatorAuthentication.ts that is not used anymore
  (not part of public interface, it was copied by validators during before couple commits ago).
- Updated readme with instructions of how to start asset-trade and electricity-trade samples
  without docker-compose (to be used during development).
  Added helper script for patching the config.

Signed-off-by: Michal Bajer <[email protected]>
  • Loading branch information
outSH committed Jul 22, 2022
1 parent 4ec5b88 commit e14caa0
Show file tree
Hide file tree
Showing 33 changed files with 317 additions and 331 deletions.
11 changes: 11 additions & 0 deletions examples/cactus-example-discounted-asset-trade/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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."
10 changes: 10 additions & 0 deletions examples/cactus-example-electricity-trade/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
1 change: 1 addition & 0 deletions examples/cactus-example-electricity-trade/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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/"
Expand Down
Original file line number Diff line number Diff line change
@@ -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."
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,25 @@ import { ISocketApiClient } from "@hyperledger/cactus-core-api";
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 {
verify,
VerifyOptions,
VerifyErrors,
JwtPayload,
Algorithm,
} from "jsonwebtoken";
import { Observable, ReplaySubject } from "rxjs";
import { finalize } from "rxjs/operators";

const supportedJwtAlgos: Algorithm[] = [
"ES256",
"ES384",
"ES512",
"RS256",
"RS384",
"RS512",
];

/**
* Default logic for validating responses from socketio connector (validator).
* Assumes that message is JWT signed with validator private key.
Expand All @@ -36,7 +51,7 @@ export function verifyValidatorJwt(
): Promise<JwtPayload> {
return new Promise((resolve, reject) => {
const option: VerifyOptions = {
algorithms: ["ES256", "ES384", "ES512", "RS256", "RS384", "RS512"],
algorithms: supportedJwtAlgos,
};

verify(
Expand Down
1 change: 1 addition & 0 deletions packages/cactus-cmd-socketio-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -25,3 +26,4 @@ export { LedgerOperation } from "./business-logic-plugin/LedgerOperation";

// Util
export { TransactionSigner } from "./util/TransactionSigner";
export { configRead } from "./util/config";
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -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<T>(key: string, defaultValue?: T): T {
export function configRead<T>(key: string, defaultValue?: T): T {
if (config.has(key)) {
return config.get(key);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright 2020-2022 Hyperledger Cactus Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import fs from "fs";
import jwt from "jsonwebtoken";
import crypto from "crypto";
import { configRead } from "../util/config";

type PayloadType = Parameters<typeof jwt.sign>[0];

const DEFAULT_EXPIRATION_TIME = 60 * 15; // 15 minutes

const supportedJwtAlgos: jwt.Algorithm[] = [
"ES256",
"ES384",
"ES512",
"RS256",
"RS384",
"RS512",
];

// Will keep the private key once it's succesfully read
let privateKey: string;

/**
* 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);
}

/**
* 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<string>('sslParam.keyValue');
} catch {
privateKey = fs.readFileSync(configRead('sslParam.key'), "ascii");
}
}
const jwtAlgo = configRead<jwt.Algorithm>('sslParam.jwtAlgo', 'ES256');
return signValidatorMessageJwt(privateKey, payload, jwtAlgo);
}
3 changes: 1 addition & 2 deletions packages/cactus-cmd-socketio-server/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
"./src/main/typescript/routing-interface/**/*.ts"
],
"exclude": [
"copyStaticAssets.ts",
"./src/main/typescript/verifier/ValidatorAuthentication.ts"
"copyStaticAssets.ts"
],
"references": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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<string>('sslParam.keyValue');
certString = config.read<string>('sslParam.certValue');
keyString = configRead<string>('sslParam.keyValue');
certString = configRead<string>('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.
Expand Down
Loading

0 comments on commit e14caa0

Please sign in to comment.