Skip to content

Commit 4fb5d7b

Browse files
committed
refactor(cmd-socketio-server): remove code duplication
- 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]>
1 parent 31a5774 commit 4fb5d7b

File tree

33 files changed

+320
-331
lines changed

33 files changed

+320
-331
lines changed

examples/cactus-example-discounted-asset-trade/README.md

+11
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,17 @@ Alice will use credentials and other Indy formats such as schema and definition
117117
cactus-example-discounted-asset-trade-blp | [2022-01-31T16:00:56.208] [INFO] www - listening on *: 5034
118118
```
119119
120+
### Dockerless run
121+
For development purposes, it might be useful to run the sample application outside of docker-compose environment.
122+
123+
1. Configure cactus and start the ledgers as described above.
124+
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.
125+
1. Start validators (each in separate cmd window).
126+
1. `cd packages/cactus-plugin-ledger-connector-fabric-socketio/ && npm run start`
127+
1. `cd packages/cactus-plugin-ledger-connector-go-ethereum-socketio/ && npm run start`
128+
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`
129+
1. Start asset-trade: `npm run start-dockerless`
130+
120131
## How to use this application
121132
122133
1. (Optional) Check the balance on Ethereum and the asset ownership on Fabric using the following script:

examples/cactus-example-discounted-asset-trade/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"private": true,
99
"scripts": {
1010
"start": "npm run build_pip_indy_package && docker-compose build && docker-compose up",
11+
"start-dockerless": "node ./dist/www.js",
1112
"build": "npm run build-ts && npm run build:dev:backend:postbuild",
1213
"build-ts": "tsc",
1314
"build_pip_indy_package": "cd ../../packages-python/cactus_validator_socketio_indy && python3 setup.py bdist_wheel",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env bash
2+
# Copyright 2020-2022 Hyperledger Cactus Contributors
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
COMMON_CACTUS_CONFIG="/etc/cactus/"
6+
7+
echo "Note - script must executed from within cactus-example-discounted-asset-trade directory!"
8+
9+
echo "Copy local cactus config to common location ($COMMON_CACTUS_CONFIG)"
10+
sudo rm -rf "$COMMON_CACTUS_CONFIG"
11+
sudo cp -ar "./etc/cactus" "/etc"
12+
sudo chown -hR $(whoami) "$COMMON_CACTUS_CONFIG"
13+
14+
echo "Patch validators..."
15+
sed -i 's/asset_trade_faio2x_testnet/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-fabric-socketio/default.yaml"
16+
sed -i 's/geth1/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-go-ethereum-socketio/default.yaml"
17+
18+
echo "Patch validator-registry-config.yaml..."
19+
sed -i 's/ethereum-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml"
20+
sed -i 's/fabric-socketio-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml"
21+
sed -i 's/indy-validator-nginx/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml"
22+
23+
echo "Patch path to asset-trade modules."
24+
current_pwd=$(pwd)
25+
escaped_pwd=${current_pwd//\//\\/}
26+
sed -i "s/\/root\/cactus/$escaped_pwd/g" "${COMMON_CACTUS_CONFIG}/usersetting.yaml"
27+
28+
echo "Done."

examples/cactus-example-electricity-trade/README.md

+10
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,16 @@ In this example, we use the Sawtooth intkey transaction processor as an applicat
7777
cactus-example-electricity-trade-blp | [2022-02-14T15:47:47.399] [INFO] www - listening on *: 5034
7878
```
7979
80+
### Dockerless run
81+
For development purposes, it might be useful to run the sample application outside of docker-compose environment.
82+
83+
1. Configure cactus and start the ledgers as described above.
84+
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.
85+
1. Start validators (each in separate cmd window).
86+
1. `cd packages/cactus-plugin-ledger-connector-go-ethereum-socketio/ && npm run start`
87+
1. `cd packages/cactus-plugin-ledger-connector-sawtooth-socketio/ && npm run start`
88+
1. Start electricity-trade: `npm run start-dockerless`
89+
8090
## How to use this application
8191
- Source account on Ethereum: `06fc56347d91c6ad2dae0c3ba38eb12ab0d72e97`
8292
- The privkey of source account on Ethereum: `cb5d48d371916a4ea1627189d8af4f642a5d72746a06b559780c3f5932658207`

examples/cactus-example-electricity-trade/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"private": true,
99
"scripts": {
1010
"start": "docker-compose build && docker-compose up",
11+
"start-dockerless": "node ./dist/www.js",
1112
"build": "npm run build-ts && npm run build:dev:backend:postbuild",
1213
"build-ts": "tsc",
1314
"build:dev:backend:postbuild": "cp -f ../../yarn.lock ./dist/"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env bash
2+
# Copyright 2020-2022 Hyperledger Cactus Contributors
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
COMMON_CACTUS_CONFIG="/etc/cactus/"
6+
7+
echo "Note - script must executed from within cactus-example-electricity-trade directory!"
8+
9+
echo "Copy local cactus config to common location ($COMMON_CACTUS_CONFIG)"
10+
sudo rm -rf "$COMMON_CACTUS_CONFIG"
11+
sudo cp -ar "./etc/cactus" "/etc"
12+
sudo chown -hR $(whoami) "$COMMON_CACTUS_CONFIG"
13+
14+
echo "Patch validators..."
15+
sed -i 's/geth1/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-go-ethereum-socketio/default.yaml"
16+
sed -i 's/rest-api/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-sawtooth-socketio/default.yaml"
17+
18+
echo "Patch validator-registry-config.yaml..."
19+
sed -i 's/ethereum-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml"
20+
sed -i 's/sawtooth-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml"
21+
22+
echo "Patch path to electricity-trade modules."
23+
current_pwd=$(pwd)
24+
escaped_pwd=${current_pwd//\//\\/}
25+
sed -i "s/\/root\/cactus/$escaped_pwd/g" "${COMMON_CACTUS_CONFIG}/usersetting.yaml"
26+
27+
echo "Done."

packages/cactus-api-client/src/main/typescript/socketio-api-client.ts

+17-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,25 @@ import { ISocketApiClient } from "@hyperledger/cactus-core-api";
1919
import { Socket, SocketOptions, ManagerOptions, io } from "socket.io-client";
2020
import { readFileSync } from "fs";
2121
import { resolve as resolvePath } from "path";
22-
import { verify, VerifyOptions, VerifyErrors, JwtPayload } from "jsonwebtoken";
22+
import {
23+
verify,
24+
VerifyOptions,
25+
VerifyErrors,
26+
JwtPayload,
27+
Algorithm,
28+
} from "jsonwebtoken";
2329
import { Observable, ReplaySubject } from "rxjs";
2430
import { finalize } from "rxjs/operators";
2531

32+
const supportedJwtAlgos: Algorithm[] = [
33+
"ES256",
34+
"ES384",
35+
"ES512",
36+
"RS256",
37+
"RS384",
38+
"RS512",
39+
];
40+
2641
/**
2742
* Default logic for validating responses from socketio connector (validator).
2843
* Assumes that message is JWT signed with validator private key.
@@ -36,7 +51,7 @@ export function verifyValidatorJwt(
3651
): Promise<JwtPayload> {
3752
return new Promise((resolve, reject) => {
3853
const option: VerifyOptions = {
39-
algorithms: ["ES256", "ES384", "ES512", "RS256", "RS384", "RS512"],
54+
algorithms: supportedJwtAlgos,
4055
};
4156

4257
verify(

packages/cactus-cmd-socketio-server/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"@hyperledger/cactus-core-api": "1.0.0",
1616
"@types/node": "14.17.32",
1717
"body-parser": "1.19.2",
18+
"config": "3.3.7",
1819
"cookie-parser": "1.4.5",
1920
"debug": "2.6.9",
2021
"escape-html": "1.0.3",

packages/cactus-cmd-socketio-server/src/main/typescript/public-api.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
export { Verifier } from "./verifier/Verifier";
33
export { LedgerEvent } from "./verifier/LedgerPlugin";
44
export { json2str } from "./verifier/DriverCommon";
5+
export { signMessageJwt } from './verifier/validator-authentication';
56

67
// Routing Interface
78
export { RIFError } from "./routing-interface/RIFError";
@@ -25,3 +26,4 @@ export { LedgerOperation } from "./business-logic-plugin/LedgerOperation";
2526

2627
// Util
2728
export { TransactionSigner } from "./util/TransactionSigner";
29+
export { configRead } from "./util/config";
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
/*
2-
* Copyright 2021 Hyperledger Cactus Contributors
2+
* Copyright 2022 Hyperledger Cactus Contributors
33
* SPDX-License-Identifier: Apache-2.0
44
*
5+
* NOTE: Be sure that NODE_CONFIG_DIR env variable points to the location
6+
* of current module config files before loading this.
7+
*
58
* config.js
69
*/
710

8-
export const DEFAULT_NODE_CONFIG_DIR = "/etc/cactus/connector-fabric-socketio/";
9-
if (!process.env["NODE_CONFIG_DIR"]) {
10-
// Must be set before import config
11-
process.env["NODE_CONFIG_DIR"] = DEFAULT_NODE_CONFIG_DIR;
12-
}
1311

1412
import config from "config";
1513

@@ -20,7 +18,7 @@ import config from "config";
2018
* @param defaultValue : Value to return if key is not present in the config.
2119
* @returns : Configuration value
2220
*/
23-
export function read<T>(key: string, defaultValue?: T): T {
21+
export function configRead<T>(key: string, defaultValue?: T): T {
2422
if (config.has(key)) {
2523
return config.get(key);
2624
}

packages/cactus-cmd-socketio-server/src/main/typescript/verifier/ValidatorAuthentication.ts

-33
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright 2020-2022 Hyperledger Cactus Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import fs from "fs";
7+
import jwt from "jsonwebtoken";
8+
import crypto from "crypto";
9+
import { configRead } from "../util/config";
10+
11+
type PayloadType = Parameters<typeof jwt.sign>[0];
12+
13+
const DEFAULT_EXPIRATION_TIME = 60 * 15; // 15 minutes
14+
15+
const supportedJwtAlgos: jwt.Algorithm[] = [
16+
"ES256",
17+
"ES384",
18+
"ES512",
19+
"RS256",
20+
"RS384",
21+
"RS512",
22+
];
23+
24+
// Will keep the private key once it's succesfully read
25+
let privateKey: string;
26+
27+
/**
28+
* Sign a message to be sent from socketio connector (validator) to a client.
29+
*
30+
* @param privateKey - Validator private key. Only ECDSA and RSA keys are supported.
31+
* @param payload - Message to be encoded.
32+
* @param jwtAlgo - JWT algorithm to use. Must match key used (ES*** or RS***)
33+
* @param expirationTime - JWT expiration time
34+
* @returns JWT signed message that can be sent over the wire.
35+
*/
36+
export function signValidatorMessageJwt(
37+
privateKey: jwt.Secret,
38+
payload: PayloadType,
39+
jwtAlgo: jwt.Algorithm = "ES256",
40+
expirationTime: number = DEFAULT_EXPIRATION_TIME,
41+
): string {
42+
if (!supportedJwtAlgos.includes(jwtAlgo)) {
43+
throw new Error(
44+
`Wrong JWT Algorithm. Supported algos: ${supportedJwtAlgos.toString()}`,
45+
);
46+
}
47+
48+
// Check if key supported and JWT algorithm matches the provided key type
49+
const keyType = crypto.createPrivateKey(privateKey).asymmetricKeyType;
50+
if (
51+
!(
52+
(keyType === "rsa" && jwtAlgo.startsWith("RS")) ||
53+
(keyType === "ec" && jwtAlgo.startsWith("ES"))
54+
)
55+
) {
56+
throw new Error(`Not supported combination ${keyType}/${jwtAlgo}.`);
57+
}
58+
59+
const option: jwt.SignOptions = {
60+
algorithm: jwtAlgo,
61+
expiresIn: expirationTime,
62+
};
63+
64+
return jwt.sign(payload, privateKey, option);
65+
}
66+
67+
/**
68+
* Validator-side function to sign message to be sent to the client.
69+
* Will read the private key either as value in validator config `sslParam.keyValue`,
70+
* or read from filesystem under path `sslParam.key`.
71+
*
72+
* @param payload - Message to sign
73+
* @returns Signed message
74+
*/
75+
export function signMessageJwt(payload: object): string {
76+
if (!privateKey) {
77+
try {
78+
privateKey = configRead<string>('sslParam.keyValue');
79+
} catch {
80+
privateKey = fs.readFileSync(configRead('sslParam.key'), "ascii");
81+
}
82+
}
83+
const jwtAlgo = configRead<jwt.Algorithm>('sslParam.jwtAlgo', 'ES256');
84+
return signValidatorMessageJwt(privateKey, payload, jwtAlgo);
85+
}

packages/cactus-cmd-socketio-server/tsconfig.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
"./src/main/typescript/routing-interface/**/*.ts"
1515
],
1616
"exclude": [
17-
"copyStaticAssets.ts",
18-
"./src/main/typescript/verifier/ValidatorAuthentication.ts"
17+
"copyStaticAssets.ts"
1918
],
2019
"references": [
2120
{

packages/cactus-plugin-ledger-connector-fabric-socketio/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
},
1616
"dependencies": {
1717
"@types/node": "14.17.32",
18+
"@hyperledger/cactus-cmd-socket-server": "1.0.0",
1819
"body-parser": "1.17.2",
19-
"config": "3.3.7",
2020
"cookie-parser": "1.4.6",
2121
"debug": "4.1.1",
2222
"express": "4.17.3",

packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/bin/www.ts

+15-7
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,21 @@
1313

1414
import app from "../app";
1515
import https = require("https");
16-
import * as config from "../config";
16+
17+
// Overwrite config read path
18+
export const DEFAULT_NODE_CONFIG_DIR = "/etc/cactus/connector-fabric-socketio/";
19+
if (!process.env["NODE_CONFIG_DIR"]) {
20+
// Must be set before import config
21+
process.env["NODE_CONFIG_DIR"] = DEFAULT_NODE_CONFIG_DIR;
22+
}
23+
import { configRead } from "@hyperledger/cactus-cmd-socket-server";
24+
1725
import fs = require("fs");
1826
import { Server } from "socket.io"
1927
// Log settings
2028
import { getLogger } from "log4js";
2129
const logger = getLogger("connector_main[" + process.pid + "]");
22-
logger.level = config.read('logLevel', 'info');
30+
logger.level = configRead('logLevel', 'info');
2331

2432
// implementation class of a part dependent of end-chains (server plugin)
2533
import { ServerPlugin } from "../../../connector/ServerPlugin";
@@ -32,18 +40,18 @@ export async function startFabricSocketIOConnector() {
3240
const Smonitor = new ServerMonitorPlugin();
3341

3442
// Get port from environment and store in Express.
35-
const sslport = normalizePort(process.env.PORT || config.read('sslParam.port'));
43+
const sslport = normalizePort(process.env.PORT || configRead('sslParam.port'));
3644
app.set("port", sslport);
3745

3846
// Specify private key and certificate
3947
let keyString: string;
4048
let certString: string;
4149
try {
42-
keyString = config.read<string>('sslParam.keyValue');
43-
certString = config.read<string>('sslParam.certValue');
50+
keyString = configRead<string>('sslParam.keyValue');
51+
certString = configRead<string>('sslParam.certValue');
4452
} catch {
45-
keyString = fs.readFileSync(config.read('sslParam.key'), "ascii");
46-
certString = fs.readFileSync(config.read('sslParam.cert'), "ascii");
53+
keyString = fs.readFileSync(configRead('sslParam.key'), "ascii");
54+
certString = fs.readFileSync(configRead('sslParam.cert'), "ascii");
4755
}
4856

4957
// Create HTTPS server.

0 commit comments

Comments
 (0)