From 22b5f5ce05a82b80e067da327b47331ed34e289e Mon Sep 17 00:00:00 2001 From: suyukuoacn Date: Tue, 18 Aug 2020 10:17:04 -0700 Subject: [PATCH] feat(common): Stable Signature Generation from JS Objects Signed-off-by: suyukuoacn --- packages/cactus-common/package-lock.json | 139 ++++++++++++ packages/cactus-common/package.json | 10 +- .../src/main/typescript/js-object-signer.ts | 104 +++++++++ .../src/main/typescript/public-api.ts | 9 + .../src/main/typescript/secp256k1-keys.ts | 26 +++ .../src/main/typescript/signer-key-pair.ts | 4 + .../typescript/unit/js-object-signer.test.ts | 210 ++++++++++++++++++ .../unit/objects/get-all-method-names.ts | 4 +- 8 files changed, 500 insertions(+), 6 deletions(-) create mode 100644 packages/cactus-common/src/main/typescript/js-object-signer.ts create mode 100644 packages/cactus-common/src/main/typescript/secp256k1-keys.ts create mode 100644 packages/cactus-common/src/main/typescript/signer-key-pair.ts create mode 100644 packages/cactus-common/src/test/typescript/unit/js-object-signer.test.ts diff --git a/packages/cactus-common/package-lock.json b/packages/cactus-common/package-lock.json index bc554f1ecc..ff90cdcf59 100644 --- a/packages/cactus-common/package-lock.json +++ b/packages/cactus-common/package-lock.json @@ -10,11 +10,99 @@ "integrity": "sha512-1TQNDJvIKlgYXGNIABfgFp9y0FziDpuGrd799Q5RcnsDu+krD+eeW/0Fs5PHARvWWFelOhIG2OPCo6KbadBM4A==", "dev": true }, + "@types/json-stable-stringify": { + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.32.tgz", + "integrity": "sha512-q9Q6+eUEGwQkv4Sbst3J4PNgDOvpuVuKj79Hl/qnmBMEIPzB5QoFRUtjcgcg2xNUZyYUGXBk5wYIBKHt0A+Mxw==", + "dev": true + }, + "@types/node": { + "version": "14.0.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.24.tgz", + "integrity": "sha512-btt/oNOiDWcSuI721MdL8VQGnjsKjlTMdrKyTcLCKeQp/n4AAMFJ961wMbp+09y8WuGPClDEv07RIItdXKIXAA==", + "dev": true + }, + "@types/secp256k1": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.1.tgz", + "integrity": "sha512-+ZjSA8ELlOp8SlKi0YLB2tz9d5iPNEmOBd+8Rz21wTMdaXQIa9b6TEnD6l5qKOCypE7FSyPyck12qZJxSDNoog==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "hoek": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, "isemail": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", @@ -33,6 +121,19 @@ "topo": "3.x.x" } }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "~0.0.0" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, "loglevel": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.7.tgz", @@ -43,11 +144,49 @@ "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz", "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==" }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" + }, + "node-gyp-build": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", + "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==" + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "secp256k1": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", + "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", + "requires": { + "elliptic": "^6.5.2", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "sha3": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.3.tgz", + "integrity": "sha512-Io53D4o9qOmf3Ow9p/DoGLQiQHhtuR0ulbyambvRSG+OX5yXExk2yYfvjHtb7AtOyk6K6+sPeK/qaowWc/E/GA==", + "requires": { + "buffer": "5.6.0" + } + }, "topo": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", diff --git a/packages/cactus-common/package.json b/packages/cactus-common/package.json index 05971436a6..2ef012a107 100644 --- a/packages/cactus-common/package.json +++ b/packages/cactus-common/package.json @@ -13,13 +13,10 @@ ], "scripts": { "tsc": "tsc --project ./tsconfig.json", - "webpack": "npm-run-all webpack:dev webpack:prod", - "webpack:dev": "npm-run-all webpack:dev:node webpack:dev:web", "webpack:dev:web": "webpack --env=dev --target=web --config ../../webpack.config.js", "webpack:dev:node": "webpack --env=dev --target=node --config ../../webpack.config.js", - "webpack:prod": "npm-run-all webpack:prod:node webpack:prod:web", "webpack:prod:web": "webpack --env=prod --target=web --config ../../webpack.config.js", "webpack:prod:node": "webpack --env=prod --target=node --config ../../webpack.config.js" @@ -66,11 +63,16 @@ "homepage": "https://github.com/hyperledger/cactus#readme", "dependencies": { "joi": "14.3.1", + "json-stable-stringify": "1.0.1", "loglevel": "1.6.7", "loglevel-plugin-prefix": "0.8.4", + "secp256k1": "4.0.2", + "sha3": "2.1.3", "typescript-optional": "2.0.1" }, "devDependencies": { - "@types/joi": "14.3.4" + "@types/joi": "14.3.4", + "@types/json-stable-stringify": "1.0.32", + "@types/secp256k1": "4.0.1" } } diff --git a/packages/cactus-common/src/main/typescript/js-object-signer.ts b/packages/cactus-common/src/main/typescript/js-object-signer.ts new file mode 100644 index 0000000000..f6161f5c2c --- /dev/null +++ b/packages/cactus-common/src/main/typescript/js-object-signer.ts @@ -0,0 +1,104 @@ +import { Logger } from "./logging/logger"; +import { LoggerProvider } from "./logging/logger-provider"; +import { LogLevelDesc } from "loglevel"; + +import secp256k1 from "secp256k1"; +import sha3 from "sha3"; +import stringify from "json-stable-stringify"; + +export type SignatureFunction = (msg: any, pkey: any) => any; +export type VerifySignatureFunction = ( + msg: any, + signature: any, + pubKey: Uint8Array +) => boolean; +export type HashFunction = (data: any) => string; + +export interface IJsObjectSignerOptions { + privateKey: any; + signatureFunc?: SignatureFunction; + verifySignatureFunc?: VerifySignatureFunction; + hashFunc?: HashFunction; + logLevel?: LogLevelDesc; +} + +export class JsObjectSigner { + private privateKey: any; + private signatureFunc: any; + private verifySignatureFunc: any; + private hashFunc: any; + private readonly logger: Logger; + + constructor(public readonly options: IJsObjectSignerOptions) { + if (!options) { + throw new Error(`JsObjectSigner#ctor options falsy.`); + } + if (!options.privateKey) { + throw new Error(`JsObjectSigner#ctor options.privateKey falsy.`); + } + + this.privateKey = options.privateKey; + this.signatureFunc = options.signatureFunc; + this.verifySignatureFunc = options.verifySignatureFunc; + this.hashFunc = options.hashFunc; + + this.logger = LoggerProvider.getOrCreate({ + label: "js-object-signer", + level: options.logLevel || "INFO", + }); + } + + /** + * Generate signature from formated message + * @param msg + * @returns Generated signature + */ + public sign(msg: any): any { + this.logger.debug("Message to sign: " + stringify(msg)); + + if (this.signatureFunc) { + return this.signatureFunc(msg, this.privateKey); + } else { + let hashMsg: any; + if (this.hashFunc) { + hashMsg = this.hashFunc(msg); + } else { + hashMsg = this.dataHash(msg); + } + + const pkey = Buffer.from(this.privateKey, `hex`); + const signObj = secp256k1.ecdsaSign(Buffer.from(hashMsg, `hex`), pkey); + return signObj.signature; + } + } + + /** + * Verify if a signature corresponds to given message and public key + * @param msg + * @param pubKey + * @param signature + * @returns {boolean} + */ + public verify(msg: any, signature: Uint8Array, pubKey: any): boolean { + if (this.verifySignatureFunc) { + return this.verifySignatureFunc(msg, signature, pubKey); + } + return secp256k1.ecdsaVerify( + signature, + Buffer.from(this.dataHash(msg), `hex`), + pubKey + ); + } + + /** + * Format message to be signed + * @param data + * @returns {string} + */ + private dataHash(data: any): string { + const hashObj = new sha3.SHA3Hash(256); + hashObj.update(stringify(data)); + const hashMsg = hashObj.digest(`hex`); + return hashMsg; + } +} diff --git a/packages/cactus-common/src/main/typescript/public-api.ts b/packages/cactus-common/src/main/typescript/public-api.ts index 33356a798f..74970bf805 100755 --- a/packages/cactus-common/src/main/typescript/public-api.ts +++ b/packages/cactus-common/src/main/typescript/public-api.ts @@ -3,3 +3,12 @@ export { Logger, ILoggerOptions } from "./logging/logger"; export { LogLevelDesc } from "loglevel"; export { Objects } from "./objects"; export { Strings } from "./strings"; +export { + JsObjectSigner, + IJsObjectSignerOptions, + SignatureFunction, + VerifySignatureFunction, + HashFunction, +} from "./js-object-signer"; +export { ISignerKeyPair } from "./signer-key-pair"; +export { Secp256k1Keys } from "./secp256k1-keys"; diff --git a/packages/cactus-common/src/main/typescript/secp256k1-keys.ts b/packages/cactus-common/src/main/typescript/secp256k1-keys.ts new file mode 100644 index 0000000000..ad112f2ec6 --- /dev/null +++ b/packages/cactus-common/src/main/typescript/secp256k1-keys.ts @@ -0,0 +1,26 @@ +import crypto from "crypto"; +import secp256k1 from "secp256k1"; + +export interface ISignerKeyPair { + privateKey: any; + publicKey: any; +} + +export class Secp256k1Keys { + /** + * Generate random private and public secp256k1 key in Buffer format + * @return Generated key pair + */ + static generateKeyPairsBuffer(): ISignerKeyPair { + let privKey: any; + // generate secp256K1 private key + do { + privKey = crypto.randomBytes(32); + } while (!secp256k1.privateKeyVerify(privKey)); + + // generate secp256K1 public key + const pubKey = secp256k1.publicKeyCreate(privKey); + + return { privateKey: privKey, publicKey: pubKey }; + } +} diff --git a/packages/cactus-common/src/main/typescript/signer-key-pair.ts b/packages/cactus-common/src/main/typescript/signer-key-pair.ts new file mode 100644 index 0000000000..bd705788ff --- /dev/null +++ b/packages/cactus-common/src/main/typescript/signer-key-pair.ts @@ -0,0 +1,4 @@ +export interface ISignerKeyPair { + privateKey: Uint8Array | Buffer | string; + publicKey: Uint8Array | Buffer | string; +} diff --git a/packages/cactus-common/src/test/typescript/unit/js-object-signer.test.ts b/packages/cactus-common/src/test/typescript/unit/js-object-signer.test.ts new file mode 100644 index 0000000000..d4a9b76734 --- /dev/null +++ b/packages/cactus-common/src/test/typescript/unit/js-object-signer.test.ts @@ -0,0 +1,210 @@ +// tslint:disable-next-line: no-var-requires +import test, { Test } from "tape"; + +import { + JsObjectSigner, + IJsObjectSignerOptions, +} from "../../../main/typescript/js-object-signer"; + +import { Secp256k1Keys } from "../../../main/typescript/secp256k1-keys"; + +import crypto from "crypto"; +import secp256k1 from "secp256k1"; +import stringify from "json-stable-stringify"; + +const keyPairs = Secp256k1Keys.generateKeyPairsBuffer(); + +const hashFunction = (data: any): string => { + return crypto.createHash("sha256").update(stringify(data)).digest("hex"); +}; + +const signFunction = (msg: any, pkey: any): any => { + const signObj = secp256k1.ecdsaSign( + Buffer.from(hashFunction(msg), `hex`), + Buffer.from(pkey, `hex`) + ); + return signObj.signature; +}; + +const verifySignFunction = ( + msg: any, + signature: any, + pubKey: Uint8Array +): boolean => { + return secp256k1.ecdsaVerify( + signature, + Buffer.from(hashFunction(msg), `hex`), + pubKey + ); +}; + +test("Simple JSON Test", async (assert: Test) => { + const jsObjectSignerOptions: IJsObjectSignerOptions = { + privateKey: keyPairs.privateKey, + logLevel: "debug", + }; + const jsObjectSigner = new JsObjectSigner(jsObjectSignerOptions); + + const payload1 = { field1: "test11", field2: "test12", field3: 13 }; + const sign1 = jsObjectSigner.sign(payload1); + + const payload2 = { field3: 13, field2: "test12", field1: "test11" }; + const sign2 = jsObjectSigner.sign(payload2); + + assert.equals(sign1.toString, sign2.toString); +}); + +test("Simple Nested JSON Test", async (assert: Test) => { + const jsObjectSignerOptions: IJsObjectSignerOptions = { + privateKey: keyPairs.privateKey, + logLevel: "debug", + }; + const jsObjectSigner = new JsObjectSigner(jsObjectSignerOptions); + + const inner1 = { someProperty: "cool", otherStuff: "also cool" }; + const outer1 = { innerProperty: inner1, outerProperty: "test" }; + const sign1 = jsObjectSigner.sign(outer1); + + const inner2 = { otherStuff: "also cool", someProperty: "cool" }; + const outer2 = { outerProperty: "test", innerProperty: inner2 }; + const sign2 = jsObjectSigner.sign(outer2); + + assert.equals(sign1.toString, sign2.toString); +}); + +test("Simple Date JSON Test", async (assert: Test) => { + const jsObjectSignerOptions: IJsObjectSignerOptions = { + privateKey: keyPairs.privateKey, + logLevel: "debug", + }; + const jsObjectSigner = new JsObjectSigner(jsObjectSignerOptions); + + const date: Date = new Date(); + + const inner1 = { + someProperty: "cool", + otherStuff: "also cool", + dateProperty: date, + }; + const outer1 = { + innerProperty: inner1, + outerProperty: "test", + outerDateProperty: date, + }; + const sign1 = jsObjectSigner.sign(outer1); + + const inner2 = { + dateProperty: date, + otherStuff: "also cool", + someProperty: "cool", + }; + const outer2 = { + outerDateProperty: date, + outerProperty: "test", + innerProperty: inner2, + }; + const sign2 = jsObjectSigner.sign(outer2); + + assert.equals(sign1.toString, sign2.toString); +}); + +test("Circular JSON Test", async (assert: Test) => { + const jsObjectSignerOptions: IJsObjectSignerOptions = { + privateKey: keyPairs.privateKey, + logLevel: "debug", + }; + const jsObjectSigner = new JsObjectSigner(jsObjectSignerOptions); + + const date: Date = new Date(); + + const obj: any = { a: "foo" }; + obj.b = obj; + + assert.throws(() => jsObjectSigner.sign(obj)); +}); + +test("Very Signature Test", async (assert: Test) => { + const jsObjectSignerOptions: IJsObjectSignerOptions = { + privateKey: keyPairs.privateKey, + logLevel: "debug", + }; + const jsObjectSigner = new JsObjectSigner(jsObjectSignerOptions); + + const payload1 = { field1: "test11", field2: "test12", field3: 13 }; + const sign1 = jsObjectSigner.sign(payload1); + + const verify = jsObjectSigner.verify(payload1, sign1, keyPairs.publicKey); + + assert.equals(true, verify); +}); + +test("Test optional sign function", async (assert: Test) => { + const jsObjectSignerOptions: IJsObjectSignerOptions = { + privateKey: keyPairs.privateKey, + logLevel: "debug", + signatureFunc: signFunction, + }; + + const jsObjectSigner = new JsObjectSigner(jsObjectSignerOptions); + + const inner1 = { someProperty: "cool", otherStuff: "also cool" }; + const outer1 = { innerProperty: inner1, outerProperty: "test" }; + const sign1 = jsObjectSigner.sign(outer1); + + const inner2 = { otherStuff: "also cool", someProperty: "cool" }; + const outer2 = { outerProperty: "test", innerProperty: inner2 }; + const sign2 = jsObjectSigner.sign(outer2); + + assert.equals(sign1.toString, sign2.toString); +}); + +test("Test optional verify sign function", async (assert: Test) => { + const jsObjectSignerOptions: IJsObjectSignerOptions = { + privateKey: keyPairs.privateKey, + logLevel: "debug", + signatureFunc: signFunction, + verifySignatureFunc: verifySignFunction, + }; + + const jsObjectSigner = new JsObjectSigner(jsObjectSignerOptions); + + const inner1 = { someProperty: "cool", otherStuff: "also cool" }; + const outer1 = { innerProperty: inner1, outerProperty: "test" }; + const sign1 = jsObjectSigner.sign(outer1); + + const verify = jsObjectSigner.verify(outer1, sign1, keyPairs.publicKey); + + assert.equals(true, verify); +}); + +test("Test optional hash function", async (assert: Test) => { + const jsObjectSignerOptions: IJsObjectSignerOptions = { + privateKey: keyPairs.privateKey, + logLevel: "debug", + hashFunc: hashFunction, + }; + + const jsObjectSigner = new JsObjectSigner(jsObjectSignerOptions); + + const inner1 = { someProperty: "cool", otherStuff: "also cool" }; + const outer1 = { innerProperty: inner1, outerProperty: "test" }; + const sign1 = jsObjectSigner.sign(outer1); + + const inner2 = { otherStuff: "also cool", someProperty: "cool" }; + const outer2 = { outerProperty: "test", innerProperty: inner2 }; + const sign2 = jsObjectSigner.sign(outer2); + + assert.equals(sign1.toString, sign2.toString); +}); + +test("Test missing required constructor field", async (assert: Test) => { + try { + const jsObjectSignerOptions: IJsObjectSignerOptions = { + privateKey: undefined, + }; + + const jsObjectSigner = new JsObjectSigner(jsObjectSignerOptions); + } catch (e) { + assert.equal(e.message, "JsObjectSigner#ctor options.privateKey falsy."); + } +}); diff --git a/packages/cactus-common/src/test/typescript/unit/objects/get-all-method-names.ts b/packages/cactus-common/src/test/typescript/unit/objects/get-all-method-names.ts index e3c5ce9dad..91ab737a50 100644 --- a/packages/cactus-common/src/test/typescript/unit/objects/get-all-method-names.ts +++ b/packages/cactus-common/src/test/typescript/unit/objects/get-all-method-names.ts @@ -1,10 +1,10 @@ // tslint:disable-next-line: no-var-requires -import test from "tape"; +import test, { Test } from "tape"; import { Objects } from "../../../../main/typescript/public-api"; import { A } from "../../fixtures/dummy-classes"; -test("handles inheritance correctly", (assert: any) => { +test("handles inheritance correctly", (assert: Test) => { const a = new A(); const methodNames = Objects.getAllMethodNames(a); assert.ok(Array.isArray(methodNames), "expect an arran of strings returned");