From 62e54032fb5f38bca4a614ae9a693ce396c36257 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 18 Oct 2018 16:03:26 +0200 Subject: [PATCH 01/38] added reference to the secret store lib ultra-wip --- src/secretstore/SecretStore.ts | 8 ++++++++ test/secretstore/SecretStore.test.ts | 13 +++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/secretstore/SecretStore.ts create mode 100644 test/secretstore/SecretStore.test.ts diff --git a/src/secretstore/SecretStore.ts b/src/secretstore/SecretStore.ts new file mode 100644 index 0000000..ed9b191 --- /dev/null +++ b/src/secretstore/SecretStore.ts @@ -0,0 +1,8 @@ +import SecretStoreDocumentHandler from "@oceanprotocol/secret-store-client" + +export default class SecretStore { + + public test() { + return new SecretStoreDocumentHandler() + } +} diff --git a/test/secretstore/SecretStore.test.ts b/test/secretstore/SecretStore.test.ts new file mode 100644 index 0000000..9431542 --- /dev/null +++ b/test/secretstore/SecretStore.test.ts @@ -0,0 +1,13 @@ +import {assert} from "chai" +import SecretStore from "../../src/secretstore/SecretStore" + +describe("SecretStore", () => { + + describe("#test()", () => { + it("should return instance", () => { + + const fu = new SecretStore().test() + assert(fu) + }) + }) +}) From 61d4f9f64dc1b39aae8ab40f921788c8da64423d Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 18 Oct 2018 17:36:55 +0200 Subject: [PATCH 02/38] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0b4722..77f9dd5 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Start by adding the package to your dependencies: ```bash -npm i @oceanprotocol/squid +npm i @oceanprotocol/squid --save ``` The package exposes `Ocean` and `Logger` which you can import in your code like this: From d777bd9030c73aac8a60f88f71e72879dcb7c425 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Fri, 19 Oct 2018 12:27:46 +0200 Subject: [PATCH 03/38] moved before into describe to enable running of single unit tests --- test/keeper/ContractBase.test.ts | 12 ++++++------ test/keeper/ContractHandler.test.ts | 10 +++++----- test/keeper/Keeper.test.ts | 12 ++++++------ test/ocean/Account.test.ts | 16 ++++++++-------- test/ocean/Asset.test.ts | 26 +++++++++++++------------- test/ocean/Ocean.test.ts | 20 ++++++++++---------- test/ocean/Order.test.ts | 24 ++++++++++++------------ 7 files changed, 60 insertions(+), 60 deletions(-) diff --git a/test/keeper/ContractBase.test.ts b/test/keeper/ContractBase.test.ts index a77424a..d7daf16 100644 --- a/test/keeper/ContractBase.test.ts +++ b/test/keeper/ContractBase.test.ts @@ -5,13 +5,13 @@ import ContractBaseMock from "../mocks/ContractBase.Mock" const wrappedContract = new ContractBaseMock("OceanToken") -before(async () => { - ConfigProvider.configure(config) - await ContractHandler.deployContracts() - wrappedContract.initMock() -}) +describe("ContractBase", () => { -describe("ContractWrapperBase", () => { + before(async () => { + ConfigProvider.configure(config) + await ContractHandler.deployContracts() + wrappedContract.initMock() + }) describe("#call()", () => { diff --git a/test/keeper/ContractHandler.test.ts b/test/keeper/ContractHandler.test.ts index 0f6510a..5ea96f7 100644 --- a/test/keeper/ContractHandler.test.ts +++ b/test/keeper/ContractHandler.test.ts @@ -3,13 +3,13 @@ import ConfigProvider from "../../src/ConfigProvider" import ContractHandler from "../../src/keeper/ContractHandler" import config from "../config" -before(async () => { - ConfigProvider.configure(config) - await ContractHandler.deployContracts() -}) - describe("ContractHandler", () => { + before(async () => { + ConfigProvider.configure(config) + await ContractHandler.deployContracts() + }) + describe("#get()", () => { it("should load and get OceanToken correctly", async () => { diff --git a/test/keeper/Keeper.test.ts b/test/keeper/Keeper.test.ts index b70001b..89bae86 100644 --- a/test/keeper/Keeper.test.ts +++ b/test/keeper/Keeper.test.ts @@ -6,14 +6,14 @@ import config from "../config" let keeper: Keeper -before(async () => { - ConfigProvider.configure(config) - await ContractHandler.deployContracts() - keeper = await Keeper.getInstance() -}) - describe("Keeper", () => { + before(async () => { + ConfigProvider.configure(config) + await ContractHandler.deployContracts() + keeper = await Keeper.getInstance() + }) + describe("public interface", () => { it("should have market", () => { diff --git a/test/ocean/Account.test.ts b/test/ocean/Account.test.ts index 6914f05..4b5f887 100644 --- a/test/ocean/Account.test.ts +++ b/test/ocean/Account.test.ts @@ -9,16 +9,16 @@ import config from "../config" let ocean: Ocean let accounts: Account[] -before(async () => { - ConfigProvider.configure(config) - await ContractHandler.deployContracts() - ocean = await Ocean.getInstance(config) - - accounts = await ocean.getAccounts() -}) - describe("Account", () => { + before(async () => { + ConfigProvider.configure(config) + await ContractHandler.deployContracts() + ocean = await Ocean.getInstance(config) + + accounts = await ocean.getAccounts() + }) + describe("#getOceanBalance()", () => { it("should get initial ocean balance", async () => { diff --git a/test/ocean/Asset.test.ts b/test/ocean/Asset.test.ts index 4f9d96c..d799fe5 100644 --- a/test/ocean/Asset.test.ts +++ b/test/ocean/Asset.test.ts @@ -19,21 +19,21 @@ let testAsset: Asset let accounts: Account[] let testPublisher: Account -before(async () => { - ConfigProvider.configure(config) - ProviderProvider.setProvider(ProviderMock) - - await ContractHandler.deployContracts() - ocean = await Ocean.getInstance(config) - accounts = await ocean.getAccounts() - testPublisher = accounts[0] - testAsset = new Asset(testName, testDescription, testPrice, testPublisher) - - await ocean.register(testAsset) -}) - describe("Asset", () => { + before(async () => { + ConfigProvider.configure(config) + ProviderProvider.setProvider(ProviderMock) + + await ContractHandler.deployContracts() + ocean = await Ocean.getInstance(config) + accounts = await ocean.getAccounts() + testPublisher = accounts[0] + testAsset = new Asset(testName, testDescription, testPrice, testPublisher) + + await ocean.register(testAsset) + }) + describe("#purchase()", () => { it("should purchase an asset", async () => { diff --git a/test/ocean/Ocean.test.ts b/test/ocean/Ocean.test.ts index fc855ee..49b6212 100644 --- a/test/ocean/Ocean.test.ts +++ b/test/ocean/Ocean.test.ts @@ -17,18 +17,18 @@ const description = "This asset is pure owange" const price = 100 const timeout = 100000000 -before(async () => { - ConfigProvider.configure(config) - await ContractHandler.deployContracts() - ocean = await Ocean.getInstance(config) - accounts = await ocean.getAccounts() - - testPublisher = accounts[0] - testAsset = new Asset(name, description, price, testPublisher) -}) - describe("Ocean", () => { + before(async () => { + ConfigProvider.configure(config) + await ContractHandler.deployContracts() + ocean = await Ocean.getInstance(config) + accounts = await ocean.getAccounts() + + testPublisher = accounts[0] + testAsset = new Asset(name, description, price, testPublisher) + }) + describe("#getInstance()", () => { it("should list accounts", async () => { diff --git a/test/ocean/Order.test.ts b/test/ocean/Order.test.ts index 8624502..d03c72c 100644 --- a/test/ocean/Order.test.ts +++ b/test/ocean/Order.test.ts @@ -20,20 +20,20 @@ let accounts: Account[] let testPublisher: Account let testConsumer: Account -before(async () => { - ConfigProvider.configure(config) - await ContractHandler.deployContracts() - ocean = await Ocean.getInstance(config) - accounts = await ocean.getAccounts() - testPublisher = accounts[0] - testConsumer = accounts[1] - // register an asset to play around with - testAsset = new Asset(testName, testDescription, testPrice, testPublisher) - await ocean.register(testAsset) -}) - describe("Order", () => { + before(async () => { + ConfigProvider.configure(config) + await ContractHandler.deployContracts() + ocean = await Ocean.getInstance(config) + accounts = await ocean.getAccounts() + testPublisher = accounts[0] + testConsumer = accounts[1] + // register an asset to play around with + testAsset = new Asset(testName, testDescription, testPrice, testPublisher) + await ocean.register(testAsset) + }) + describe("#pay()", async () => { it("should pay for an order", async () => { From 2662a7795b59ed6a38e70c76010ff58d3d088e65 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Fri, 19 Oct 2018 13:42:24 +0200 Subject: [PATCH 04/38] added secret store connection --- package-lock.json | 61 +++++++++++++++ package.json | 1 + src/secretstore/ParityClient.ts | 75 ++++++++++++++++++ src/secretstore/SecretStore.ts | 57 +++++++++++++- src/secretstore/SecretStoreClient.ts | 108 ++++++++++++++++++++++++++ test/secretstore/SecretStore.test.ts | 13 ---- test/secretstore/SecretStore.test_.ts | 52 +++++++++++++ 7 files changed, 351 insertions(+), 16 deletions(-) create mode 100644 src/secretstore/ParityClient.ts create mode 100644 src/secretstore/SecretStoreClient.ts delete mode 100644 test/secretstore/SecretStore.test.ts create mode 100644 test/secretstore/SecretStore.test_.ts diff --git a/package-lock.json b/package-lock.json index 38133bd..14432bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -382,6 +382,15 @@ "long": "^3.2.0" } }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -1782,6 +1791,21 @@ "resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", + "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==" + } + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -2240,6 +2264,11 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -3587,6 +3616,33 @@ "is-object": "^1.0.1" } }, + "jayson": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-2.1.0.tgz", + "integrity": "sha512-WQhCph4BgSDbRUPdZYqGMojKMxjzPqCCKmWYMsRWX/Bvh1oP+Irs2upeEJy8flU3ZAZzm68TjuL1X8u9Rt4wWQ==", + "requires": { + "@types/node": "^10.3.5", + "JSONStream": "^1.3.1", + "commander": "^2.12.2", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.10", + "uuid": "^3.2.1" + }, + "dependencies": { + "@types/node": { + "version": "10.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.0.tgz", + "integrity": "sha512-3TUHC3jsBAB7qVRGxT6lWyYo2v96BMmD2PTcl47H25Lu7UXtFH/2qqmKiVrnel6Ne//0TFYf6uvNX+HW2FRkLQ==" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + } + } + }, "js-sha3": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", @@ -3653,6 +3709,11 @@ "graceful-fs": "^4.1.6" } }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, "jsonwebtoken": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz", diff --git a/package.json b/package.json index 905ba40..41a8da3 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "eth-crypto": "^1.2.4", "eth-ecies": "^1.0.3", "ethereumjs-util": "^6.0.0", + "jayson": "^2.1.0", "jsonwebtoken": "^8.3.0", "node-fetch": "^2.2.0", "web3": "1.0.0-beta.36", diff --git a/src/secretstore/ParityClient.ts b/src/secretstore/ParityClient.ts new file mode 100644 index 0000000..c040e0a --- /dev/null +++ b/src/secretstore/ParityClient.ts @@ -0,0 +1,75 @@ +import * as jayson from "jayson" +import {Client} from "jayson" +import {URL} from "url" +import Logger from "../utils/Logger" + +function add0xPrefix(key) { + return key.startsWith("0x") ? key : "0x" + key +} + +export default class ParityClient { + + private rpcClient: Client + + constructor(private url: string, private address: string, private password: string) { + this.rpcClient = jayson.Client.http(new URL(this.url)) + } + + public async signKeyId(keyId): Promise { + return this.sendJsonRpcRequest(this.rpcClient, + "secretstore_signRawHash", + [this.address, this.password, add0xPrefix(keyId)]) + .then((result: string) => { + Logger.log("fu", result) + return result + }) + + } + + public generateDocumentKeyFromKey(serverKey) { + return this.sendJsonRpcRequest(this.rpcClient, + "secretstore_generateDocumentKey", + [this.address, this.password, serverKey]) + .then((result: string) => { + return result + }) + + } + + public encryptDocument(encryptedKey, document: string) { + // `document` must be encoded in hex when sent to encryption + return this.sendJsonRpcRequest(this.rpcClient, "secretstore_encrypt", + [this.address, this.password, encryptedKey, + add0xPrefix(new Buffer(document).toString("hex"))]) + .then((result: string) => { + return result + }) + } + + public decryptDocument(decryptedSecret, commonPoint, decryptShadows, encryptedDocument) { + return this.sendJsonRpcRequest(this.rpcClient, + "secretstore_shadowDecrypt", + [this.address, this.password, decryptedSecret, + commonPoint, decryptShadows, encryptedDocument]) + .then((result: string) => { + return result + }) + } + + private sendJsonRpcRequest(rpcClient: Client, methodName: string, paramsList: any[]) { + return new Promise((resolve, reject) => { + rpcClient.request( + methodName, + paramsList, + (err, response) => { + const error = response.error || err + if (error) { + Logger.error("JSON RPC call failed:", error) + Logger.error(`Method ${methodName}`) + return reject(error) + } + return resolve(response.result.toString()) + }) + }) + } +} \ No newline at end of file diff --git a/src/secretstore/SecretStore.ts b/src/secretstore/SecretStore.ts index ed9b191..0dd5e1f 100644 --- a/src/secretstore/SecretStore.ts +++ b/src/secretstore/SecretStore.ts @@ -1,8 +1,59 @@ -import SecretStoreDocumentHandler from "@oceanprotocol/secret-store-client" +import Logger from "../utils/Logger" +import ParityClient from "./ParityClient" +import SecretStoreClient from "./SecretStoreClient" export default class SecretStore { - public test() { - return new SecretStoreDocumentHandler() + private partiyClient: ParityClient + private secretStoreClient: SecretStoreClient + + constructor(config: { secretStoreUrl: string, parityUrl: string, address: string, password: string }) { + + this.partiyClient = new ParityClient(config.parityUrl, config.address, config.password) + this.secretStoreClient = new SecretStoreClient(config.secretStoreUrl) } + + public async generateServerKey(serverKeyId: string): Promise { + + const serverKeyIdSig = await this.partiyClient.signKeyId(serverKeyId) + + Logger.log("serverKeyId:", serverKeyId, "serverKeyIdSig:", serverKeyIdSig) + + const key = await this.secretStoreClient.generateServerKey(serverKeyId, serverKeyIdSig) + + Logger.log("key:", key) + + return key + } + + public async storeDocumentKey(serverKeyId: string, documentKeyId): Promise { + + const serverKeyIdSig = await this.partiyClient.signKeyId(serverKeyId) + const documentKeyIdSig = await this.partiyClient.signKeyId(documentKeyId) + + Logger.log("serverKeyId:", serverKeyId, "serverKeyIdSig:", serverKeyIdSig) + + const key = await this.secretStoreClient.storeDocumentKey( + serverKeyId, serverKeyIdSig, + documentKeyId, documentKeyIdSig, + ) + + Logger.log("key:", key) + + return key + } + + public async retrieveDocumentKey(serverKeyId: string): Promise { + + const serverKeyIdSig = await this.partiyClient.signKeyId(serverKeyId) + + Logger.log("serverKeyId:", serverKeyId, "serverKeyIdSig:", serverKeyIdSig) + + const key = await this.secretStoreClient.retrieveDocumentKey(serverKeyId, serverKeyIdSig) + + Logger.log("key:", key) + + return key + } + } diff --git a/src/secretstore/SecretStoreClient.ts b/src/secretstore/SecretStoreClient.ts new file mode 100644 index 0000000..a2b4ce9 --- /dev/null +++ b/src/secretstore/SecretStoreClient.ts @@ -0,0 +1,108 @@ +import fetch from "node-fetch" +import Logger from "../utils/Logger" + +function removeLeading0xPrefix(key) { + return key.startsWith("0x") ? key.replace("0x", "") : key +} + +export default class SecretStoreClient { + + constructor(private url: string, private threshold?: number) { + this.url = url + this.threshold = threshold || 1 + } + + public async generateServerKey(serverKeyId: string, serverKeyIdSig: string): Promise { + + const url = [ + this.url, "shadow", serverKeyId, + removeLeading0xPrefix(serverKeyIdSig), + this.threshold, + ].join("/") + + const result = await fetch(url, { + method: "POST", + }) + .then((response) => { + if (response.ok) { + return response.json() + } + throw Error(`Unable to generate Server Key ${response.statusText}`) + }) + .catch((error) => { + throw Error(`Unable to generate Server Key: ${error.message}`) + }) + + if (!result) { + throw Error(`Unable to generate Server Key`) + } + + return result + } + + /* + curl -X POST http://localhost:8082/shadow/ + 0000000000000000000000000000000000000000000000000000000000000000/ + de12681e0b8f7a428f12a6694a5f7e1324deef3d627744d95d51b862afc13799251831b3611ae436c452b54cdf5c4e78b361a396ae183e8b4c34519e895e623c00/ + 368244efaf441c2dabf7a723355a97b3b86f27bdb2827ae6f34ddece5132efd37af4ba808957b7113b4296bc4ae9ec7be38f9de6bae00504e775883a50d4658a/ + b7ad0603946987f1a154ae7f074e45da224eaa83704aac16a2d43a675d219654cf087b5d7aacce0790a65abbc1a495b26e71a5c6e9a4a71b543bf0048935bc13 + */ + + public async storeDocumentKey(serverKeyId: string, serverKeyIdSig: string, + commonPoint: string, encryptedPoint: string) { + const url = [this.url, "shadow", serverKeyId, removeLeading0xPrefix(serverKeyIdSig), + removeLeading0xPrefix(commonPoint), removeLeading0xPrefix(encryptedPoint)] + .join("/") + + Logger.log("url", url) + const result = await fetch(url, { + method: "POST", + }) + .then((response) => { + if (response.ok) { + return response + } + throw Error(`Unable to store document Keys ${response.statusText}`) + }) + .catch((error) => { + throw Error(`Unable to store document keys: ${error.message}`) + }) + + if (!result) { + throw Error(`Unable to store document Keys`) + } + + return result + } + + public async retrieveDocumentKey(documentKeyId, documentKeyIdSig) { + + const url = [ + this.url, documentKeyId, + removeLeading0xPrefix(documentKeyIdSig), + ].join("/") + + Logger.log(url) + + const result = await fetch(url, { + method: "GET", + }) + .then((response) => { + + if (response.ok) { + return response.json() + } + throw Error(`Unable to retrieve decryption Keys ${response.statusText}`) + }) + .catch((e) => { + throw Error(`Unable to retrieve decryption keys: ${e.message}`) + }) + + if (!result) { + throw Error(`Unable to retrieve decryption Keys`) + } + + // results should have (decrypted_secret, common_point, decrypt_shadows) + return JSON.parse(result) + } +} diff --git a/test/secretstore/SecretStore.test.ts b/test/secretstore/SecretStore.test.ts deleted file mode 100644 index 9431542..0000000 --- a/test/secretstore/SecretStore.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {assert} from "chai" -import SecretStore from "../../src/secretstore/SecretStore" - -describe("SecretStore", () => { - - describe("#test()", () => { - it("should return instance", () => { - - const fu = new SecretStore().test() - assert(fu) - }) - }) -}) diff --git a/test/secretstore/SecretStore.test_.ts b/test/secretstore/SecretStore.test_.ts new file mode 100644 index 0000000..e107b55 --- /dev/null +++ b/test/secretstore/SecretStore.test_.ts @@ -0,0 +1,52 @@ +import BigNumber from "bignumber.js" +import {assert} from "chai" +import ConfigProvider from "../../src/ConfigProvider" +import Config from "../../src/models/Config" +import SecretStore from "../../src/secretstore/SecretStore" + +const parityUrl = "http://localhost:8545" +const ssUrl = "https://secret-store.dev-ocean.com" + +ConfigProvider.configure({ + nodeUri: ssUrl, +} as Config) + +const address = "0xa50f397644973dba99624404b2894825840aa03b" +const password = "unittest" + +const secretStore: SecretStore = new SecretStore({ + secretStoreUrl: ssUrl, parityUrl, + address, + password, +}) + +function generateRandomId(): string { + const id: string = BigNumber.random(64).toString().replace("0.", "") + + // sometimes it only generates 63 digits + return id.length === 63 ? id + "0" : id +} + +describe("SecretStore", () => { + + describe("#generateServerKey()", () => { + it("should generate Server key", async () => { + + const serverKeyId = generateRandomId() + const serverKey = await secretStore.generateServerKey(serverKeyId) + + assert(serverKey) + }) + }) + + describe("#storeDocumentKey()", () => { + it("should store Document key", async () => { + + const serverKeyId = generateRandomId() + const documentKeyId = generateRandomId() + const documentKey = await secretStore.storeDocumentKey(serverKeyId, documentKeyId) + + assert(documentKey) + }) + }) +}) From da5386f49087c32b92f266bf94edc123d55aad84 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Mon, 22 Oct 2018 09:06:36 +0200 Subject: [PATCH 05/38] added holder for parity document key storage, wip, added unit tests --- src/secretstore/DocumentKeys.ts | 5 ++ src/secretstore/ParityClient.ts | 35 +++++++------ src/secretstore/SecretStore.ts | 26 ++++++---- test/secretstore/ParityClient.test_.ts | 72 ++++++++++++++++++++++++++ test/secretstore/SecretStore.test_.ts | 2 +- 5 files changed, 114 insertions(+), 26 deletions(-) create mode 100644 src/secretstore/DocumentKeys.ts create mode 100644 test/secretstore/ParityClient.test_.ts diff --git a/src/secretstore/DocumentKeys.ts b/src/secretstore/DocumentKeys.ts new file mode 100644 index 0000000..1adb0ea --- /dev/null +++ b/src/secretstore/DocumentKeys.ts @@ -0,0 +1,5 @@ +export default class DocumentKeys { + commonPoint: string + encryptedKey: string + encryptedPoint: string +} diff --git a/src/secretstore/ParityClient.ts b/src/secretstore/ParityClient.ts index c040e0a..cdaf8e7 100644 --- a/src/secretstore/ParityClient.ts +++ b/src/secretstore/ParityClient.ts @@ -2,6 +2,7 @@ import * as jayson from "jayson" import {Client} from "jayson" import {URL} from "url" import Logger from "../utils/Logger" +import DocumentKeys from "./DocumentKeys" function add0xPrefix(key) { return key.startsWith("0x") ? key : "0x" + key @@ -9,10 +10,14 @@ function add0xPrefix(key) { export default class ParityClient { + private address: string + private password: string private rpcClient: Client - constructor(private url: string, private address: string, private password: string) { - this.rpcClient = jayson.Client.http(new URL(this.url)) + constructor(config: { url: string, address: string, password: string }) { + this.password = config.password + this.address = config.address + this.rpcClient = jayson.Client.http(new URL(config.url)) } public async signKeyId(keyId): Promise { @@ -20,33 +25,35 @@ export default class ParityClient { "secretstore_signRawHash", [this.address, this.password, add0xPrefix(keyId)]) .then((result: string) => { - Logger.log("fu", result) return result }) - } - public generateDocumentKeyFromKey(serverKey) { + public async generateDocumentKeyFromKey(serverKey: string): Promise { return this.sendJsonRpcRequest(this.rpcClient, "secretstore_generateDocumentKey", [this.address, this.password, serverKey]) - .then((result: string) => { - return result + .then((result: any) => { + return { + commonPoint: result.common_point, + encryptedKey: result.encrypted_key, + encryptedPoint: result.encrypted_point, + } as DocumentKeys }) - } - public encryptDocument(encryptedKey, document: string) { + public encryptDocument(encryptedKey, document: any): Promise { // `document` must be encoded in hex when sent to encryption return this.sendJsonRpcRequest(this.rpcClient, "secretstore_encrypt", [this.address, this.password, encryptedKey, - add0xPrefix(new Buffer(document).toString("hex"))]) + add0xPrefix(new Buffer(JSON.stringify(document)).toString("hex"))]) .then((result: string) => { return result }) } - public decryptDocument(decryptedSecret, commonPoint, decryptShadows, encryptedDocument) { + public decryptDocument(decryptedSecret: string, commonPoint: string, + decryptShadows: string, encryptedDocument: string): Promise { return this.sendJsonRpcRequest(this.rpcClient, "secretstore_shadowDecrypt", [this.address, this.password, decryptedSecret, @@ -58,9 +65,7 @@ export default class ParityClient { private sendJsonRpcRequest(rpcClient: Client, methodName: string, paramsList: any[]) { return new Promise((resolve, reject) => { - rpcClient.request( - methodName, - paramsList, + rpcClient.request(methodName, paramsList, (err, response) => { const error = response.error || err if (error) { @@ -68,7 +73,7 @@ export default class ParityClient { Logger.error(`Method ${methodName}`) return reject(error) } - return resolve(response.result.toString()) + return resolve(response.result) }) }) } diff --git a/src/secretstore/SecretStore.ts b/src/secretstore/SecretStore.ts index 0dd5e1f..59b6150 100644 --- a/src/secretstore/SecretStore.ts +++ b/src/secretstore/SecretStore.ts @@ -9,7 +9,10 @@ export default class SecretStore { constructor(config: { secretStoreUrl: string, parityUrl: string, address: string, password: string }) { - this.partiyClient = new ParityClient(config.parityUrl, config.address, config.password) + this.partiyClient = new ParityClient({ + url: config.parityUrl, address: config.address, + password: config.password, + }) this.secretStoreClient = new SecretStoreClient(config.secretStoreUrl) } @@ -29,18 +32,14 @@ export default class SecretStore { public async storeDocumentKey(serverKeyId: string, documentKeyId): Promise { const serverKeyIdSig = await this.partiyClient.signKeyId(serverKeyId) - const documentKeyIdSig = await this.partiyClient.signKeyId(documentKeyId) - Logger.log("serverKeyId:", serverKeyId, "serverKeyIdSig:", serverKeyIdSig) + const serverKey = await this.secretStoreClient.generateServerKey( + serverKeyId, serverKeyIdSig) + Logger.log("key:", serverKey) - const key = await this.secretStoreClient.storeDocumentKey( - serverKeyId, serverKeyIdSig, - documentKeyId, documentKeyIdSig, - ) + const documentKey = this.partiyClient.generateDocumentKeyFromKey(serverKey) - Logger.log("key:", key) - - return key + return documentKey } public async retrieveDocumentKey(serverKeyId: string): Promise { @@ -56,4 +55,11 @@ export default class SecretStore { return key } + public encryptDocument(document: string) { + } + + public decryptDocument(encryptedDocument: string) { + + } + } diff --git a/test/secretstore/ParityClient.test_.ts b/test/secretstore/ParityClient.test_.ts new file mode 100644 index 0000000..1f97125 --- /dev/null +++ b/test/secretstore/ParityClient.test_.ts @@ -0,0 +1,72 @@ +import BigNumber from "bignumber.js" +import {assert} from "chai" +import ConfigProvider from "../../src/ConfigProvider" +import Config from "../../src/models/Config" +import DocumentKeys from "../../src/secretstore/DocumentKeys" +import ParityClient from "../../src/secretstore/ParityClient" + +const parityUrl = "http://localhost:8545" + +ConfigProvider.configure({ + nodeUri: parityUrl, +} as Config) + +const address = "0xa50f397644973dba99624404b2894825840aa03b" +const password = "unittest" +const serverKey = + "0x36131d552e561d8231cd91c8020d869e14c11b16e79fb80ecf8302ea0a0539c969dbc0b547398daf293c259431d7c483ee5974b0ef179297edbe6d39af4374d5" + +const testDocument = { + so: "secure", + soWow: true, +} +const parityClient: ParityClient = new ParityClient({ + url: parityUrl, + address, password, +}) + +function generateRandomId(): string { + const id: string = BigNumber.random(64).toString().replace("0.", "") + + // sometimes it only generates 63 digits + return id.length === 63 ? id + "0" : id +} + +describe("ParityClient", () => { + + describe("#signKeyId()", () => { + it("should generate sig from given key", async () => { + + const keyId = generateRandomId() + const keyIdSig = await parityClient.signKeyId(keyId) + + assert(keyIdSig) + }) + }) + + describe("#generateDocumentKeyFromKey()", () => { + it("should generate a document key from a server key", async () => { + + const documentKey = await parityClient.generateDocumentKeyFromKey(serverKey) + assert(documentKey) + }) + }) + + describe("#encryptDocument()", () => { + it("should encrypt an document", async () => { + + const documentKey: DocumentKeys = await parityClient.generateDocumentKeyFromKey(serverKey) + const encryptedDocument = await parityClient.encryptDocument(documentKey.encryptedKey, testDocument) + assert(encryptedDocument) + }) + }) + + describe("#decryptDocument()", () => { + it("should decrypt an document", async () => { + + const documentKey: DocumentKeys = await parityClient.generateDocumentKeyFromKey(serverKey) + const encryptedDocument = await parityClient.encryptDocument(documentKey.encryptedKey, testDocument) + assert(encryptedDocument) + }) + }) +}) diff --git a/test/secretstore/SecretStore.test_.ts b/test/secretstore/SecretStore.test_.ts index e107b55..7ca8c87 100644 --- a/test/secretstore/SecretStore.test_.ts +++ b/test/secretstore/SecretStore.test_.ts @@ -8,7 +8,7 @@ const parityUrl = "http://localhost:8545" const ssUrl = "https://secret-store.dev-ocean.com" ConfigProvider.configure({ - nodeUri: ssUrl, + nodeUri: parityUrl, } as Config) const address = "0xa50f397644973dba99624404b2894825840aa03b" From b172a245b1255d610d4ec520c2b895308e5bfe33 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Mon, 22 Oct 2018 12:46:27 +0200 Subject: [PATCH 06/38] added encrypt and decrypt document --- src/secretstore/DocumentKeys.ts | 5 -- src/secretstore/HexHelpler.ts | 10 +++ src/secretstore/ParityClient.ts | 31 ++++----- src/secretstore/SecretStore.ts | 83 ++++++++++++++++--------- src/secretstore/SecretStoreClient.ts | 64 +++++++++---------- src/secretstore/keys/GeneratedKey.ts | 6 ++ src/secretstore/keys/KeyBase.ts | 3 + src/secretstore/keys/RetrievedKey.ts | 6 ++ test/secretstore/ParityClient.test_.ts | 24 ++++--- test/secretstore/SecretStore.test_.ts | 29 ++++++--- test/secretstore/keys/GeneratedKey.json | 5 ++ test/secretstore/keys/RetrievedKey.json | 8 +++ test/secretstore/keys/ServerKey.json | 1 + test/tsconfig.json | 1 + 14 files changed, 177 insertions(+), 99 deletions(-) delete mode 100644 src/secretstore/DocumentKeys.ts create mode 100644 src/secretstore/HexHelpler.ts create mode 100644 src/secretstore/keys/GeneratedKey.ts create mode 100644 src/secretstore/keys/KeyBase.ts create mode 100644 src/secretstore/keys/RetrievedKey.ts create mode 100644 test/secretstore/keys/GeneratedKey.json create mode 100644 test/secretstore/keys/RetrievedKey.json create mode 100644 test/secretstore/keys/ServerKey.json diff --git a/src/secretstore/DocumentKeys.ts b/src/secretstore/DocumentKeys.ts deleted file mode 100644 index 1adb0ea..0000000 --- a/src/secretstore/DocumentKeys.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default class DocumentKeys { - commonPoint: string - encryptedKey: string - encryptedPoint: string -} diff --git a/src/secretstore/HexHelpler.ts b/src/secretstore/HexHelpler.ts new file mode 100644 index 0000000..a9ec07d --- /dev/null +++ b/src/secretstore/HexHelpler.ts @@ -0,0 +1,10 @@ +export default class HexHelpler { + public static removeLeading0xPrefix(key) { + return key.startsWith("0x") ? key.replace("0x", "") : key + } + + public static add0xPrefix(key) { + return key.startsWith("0x") ? key : "0x" + key + } + +} diff --git a/src/secretstore/ParityClient.ts b/src/secretstore/ParityClient.ts index cdaf8e7..e3e4c84 100644 --- a/src/secretstore/ParityClient.ts +++ b/src/secretstore/ParityClient.ts @@ -2,11 +2,8 @@ import * as jayson from "jayson" import {Client} from "jayson" import {URL} from "url" import Logger from "../utils/Logger" -import DocumentKeys from "./DocumentKeys" - -function add0xPrefix(key) { - return key.startsWith("0x") ? key : "0x" + key -} +import HexHelpler from "./HexHelpler" +import GeneratedKey from "./keys/GeneratedKey" export default class ParityClient { @@ -23,7 +20,7 @@ export default class ParityClient { public async signKeyId(keyId): Promise { return this.sendJsonRpcRequest(this.rpcClient, "secretstore_signRawHash", - [this.address, this.password, add0xPrefix(keyId)]) + [this.address, this.password, HexHelpler.add0xPrefix(keyId)]) .then((result: string) => { return result }) @@ -34,32 +31,36 @@ export default class ParityClient { "secretstore_generateDocumentKey", [this.address, this.password, serverKey]) .then((result: any) => { - return { + const generatedKey = { commonPoint: result.common_point, encryptedKey: result.encrypted_key, encryptedPoint: result.encrypted_point, - } as DocumentKeys + } as GeneratedKey + return generatedKey }) } - public encryptDocument(encryptedKey, document: any): Promise { + public encryptDocument(encryptedKey: string, document: any): Promise { // `document` must be encoded in hex when sent to encryption - return this.sendJsonRpcRequest(this.rpcClient, "secretstore_encrypt", - [this.address, this.password, encryptedKey, - add0xPrefix(new Buffer(JSON.stringify(document)).toString("hex"))]) + const documentString = JSON.stringify(document) + const documentHexed = HexHelpler.add0xPrefix(new Buffer(documentString).toString("hex")) + return this.sendJsonRpcRequest(this.rpcClient, + "secretstore_encrypt", + [this.address, this.password, encryptedKey, documentHexed]) .then((result: string) => { return result }) } public decryptDocument(decryptedSecret: string, commonPoint: string, - decryptShadows: string, encryptedDocument: string): Promise { + decryptShadows: string[], encryptedDocument: string): Promise { return this.sendJsonRpcRequest(this.rpcClient, "secretstore_shadowDecrypt", [this.address, this.password, decryptedSecret, commonPoint, decryptShadows, encryptedDocument]) .then((result: string) => { - return result + const documentString = new Buffer(HexHelpler.removeLeading0xPrefix(result), "hex").toString("utf8") + return JSON.parse(documentString) }) } @@ -77,4 +78,4 @@ export default class ParityClient { }) }) } -} \ No newline at end of file +} diff --git a/src/secretstore/SecretStore.ts b/src/secretstore/SecretStore.ts index 59b6150..9b5becb 100644 --- a/src/secretstore/SecretStore.ts +++ b/src/secretstore/SecretStore.ts @@ -1,4 +1,5 @@ -import Logger from "../utils/Logger" +import GeneratedKey from "./keys/GeneratedKey" +import RetrievedKey from "./keys/RetrievedKey" import ParityClient from "./ParityClient" import SecretStoreClient from "./SecretStoreClient" @@ -13,53 +14,77 @@ export default class SecretStore { url: config.parityUrl, address: config.address, password: config.password, }) - this.secretStoreClient = new SecretStoreClient(config.secretStoreUrl) + this.secretStoreClient = new SecretStoreClient({url: config.secretStoreUrl}) } - public async generateServerKey(serverKeyId: string): Promise { + public async encryptDocument(serverKeyId: string, document: any): Promise { + const serverKey = await this.generateServerKey(serverKeyId) + // generate document key + const documentKey: GeneratedKey = await this.generateDocumentKey(serverKey) + + // store the document key in secret store + await this.storeDocumentKey(serverKeyId, documentKey) + + // encrypt document + const encryptedDocument = + await this.partiyClient.encryptDocument(documentKey.encryptedKey, document) + return encryptedDocument + } + + public async decryptDocument(serverkeyId: string, encryptedDocument: string): Promise { + + // get document key from secret store + const documentKey: RetrievedKey = await this.retrieveDocumentKey(serverkeyId) + + const decryptDocument: any = await this.partiyClient.decryptDocument( + documentKey.decryptedSecret, documentKey.commonPoint, + documentKey.decryptShadows, encryptedDocument) + + return decryptDocument + } + + private async generateServerKey(serverKeyId: string): Promise { + + // sign server key id const serverKeyIdSig = await this.partiyClient.signKeyId(serverKeyId) - Logger.log("serverKeyId:", serverKeyId, "serverKeyIdSig:", serverKeyIdSig) + // Logger.log("serverKeyId:", serverKeyId, "serverKeyIdSig:", serverKeyIdSig) - const key = await this.secretStoreClient.generateServerKey(serverKeyId, serverKeyIdSig) + // generate server key + const serverKey = await this.secretStoreClient.generateServerKey(serverKeyId, serverKeyIdSig) - Logger.log("key:", key) - - return key + return serverKey } - public async storeDocumentKey(serverKeyId: string, documentKeyId): Promise { - - const serverKeyIdSig = await this.partiyClient.signKeyId(serverKeyId) - Logger.log("serverKeyId:", serverKeyId, "serverKeyIdSig:", serverKeyIdSig) - const serverKey = await this.secretStoreClient.generateServerKey( - serverKeyId, serverKeyIdSig) - Logger.log("key:", serverKey) - - const documentKey = this.partiyClient.generateDocumentKeyFromKey(serverKey) - - return documentKey + private async generateDocumentKey(serverKey: string): Promise { + // generate document key from server key + const documentKeys: GeneratedKey = await this.partiyClient.generateDocumentKeyFromKey(serverKey) + return documentKeys } - public async retrieveDocumentKey(serverKeyId: string): Promise { + private async storeDocumentKey(serverKeyId: string, documentKeys: GeneratedKey): Promise { + // sign server key id const serverKeyIdSig = await this.partiyClient.signKeyId(serverKeyId) - Logger.log("serverKeyId:", serverKeyId, "serverKeyIdSig:", serverKeyIdSig) + // store document key in secret store + await this.secretStoreClient.storeDocumentKey(serverKeyId, serverKeyIdSig, + documentKeys.commonPoint, documentKeys.encryptedPoint) - const key = await this.secretStoreClient.retrieveDocumentKey(serverKeyId, serverKeyIdSig) - - Logger.log("key:", key) - - return key + return true } - public encryptDocument(document: string) { - } + private async retrieveDocumentKey(serverKeyId: string): Promise { - public decryptDocument(encryptedDocument: string) { + // sign server key id + const serverKeyIdSig = await this.partiyClient.signKeyId(serverKeyId) + // Logger.log("serverKeyId:", serverKeyId, "serverKeyIdSig:", serverKeyIdSig) + + // retrieve document key from secret store + const documentKeys: RetrievedKey = await this.secretStoreClient.retrieveDocumentKey(serverKeyId, serverKeyIdSig) + return documentKeys } } diff --git a/src/secretstore/SecretStoreClient.ts b/src/secretstore/SecretStoreClient.ts index a2b4ce9..9d5f3dd 100644 --- a/src/secretstore/SecretStoreClient.ts +++ b/src/secretstore/SecretStoreClient.ts @@ -1,25 +1,27 @@ import fetch from "node-fetch" -import Logger from "../utils/Logger" - -function removeLeading0xPrefix(key) { - return key.startsWith("0x") ? key.replace("0x", "") : key -} +import HexHelpler from "./HexHelpler" +import RetrievedKey from "./keys/RetrievedKey" export default class SecretStoreClient { - constructor(private url: string, private threshold?: number) { - this.url = url - this.threshold = threshold || 1 + private threshold: number + private url: string + + constructor(config: { url: string, threshold?: number }) { + this.url = config.url + this.threshold = config.threshold || 1 } public async generateServerKey(serverKeyId: string, serverKeyIdSig: string): Promise { const url = [ this.url, "shadow", serverKeyId, - removeLeading0xPrefix(serverKeyIdSig), + HexHelpler.removeLeading0xPrefix(serverKeyIdSig), this.threshold, ].join("/") + // Logger.log("url", url) + const result = await fetch(url, { method: "POST", }) @@ -40,27 +42,20 @@ export default class SecretStoreClient { return result } - /* - curl -X POST http://localhost:8082/shadow/ - 0000000000000000000000000000000000000000000000000000000000000000/ - de12681e0b8f7a428f12a6694a5f7e1324deef3d627744d95d51b862afc13799251831b3611ae436c452b54cdf5c4e78b361a396ae183e8b4c34519e895e623c00/ - 368244efaf441c2dabf7a723355a97b3b86f27bdb2827ae6f34ddece5132efd37af4ba808957b7113b4296bc4ae9ec7be38f9de6bae00504e775883a50d4658a/ - b7ad0603946987f1a154ae7f074e45da224eaa83704aac16a2d43a675d219654cf087b5d7aacce0790a65abbc1a495b26e71a5c6e9a4a71b543bf0048935bc13 - */ - public async storeDocumentKey(serverKeyId: string, serverKeyIdSig: string, - commonPoint: string, encryptedPoint: string) { - const url = [this.url, "shadow", serverKeyId, removeLeading0xPrefix(serverKeyIdSig), - removeLeading0xPrefix(commonPoint), removeLeading0xPrefix(encryptedPoint)] + commonPoint: string, encryptedPoint: string): Promise { + const url = [this.url, "shadow", serverKeyId, HexHelpler.removeLeading0xPrefix(serverKeyIdSig), + HexHelpler.removeLeading0xPrefix(commonPoint), HexHelpler.removeLeading0xPrefix(encryptedPoint)] .join("/") - Logger.log("url", url) + // Logger.log("url", url) + const result = await fetch(url, { method: "POST", }) .then((response) => { - if (response.ok) { - return response + if (response.ok && response.status === 200) { + return true } throw Error(`Unable to store document Keys ${response.statusText}`) }) @@ -75,25 +70,29 @@ export default class SecretStoreClient { return result } - public async retrieveDocumentKey(documentKeyId, documentKeyIdSig) { + public async retrieveDocumentKey(serverKeyId, serverKeyIdSig): Promise { - const url = [ - this.url, documentKeyId, - removeLeading0xPrefix(documentKeyIdSig), - ].join("/") + const url = [this.url, "shadow", serverKeyId, HexHelpler.removeLeading0xPrefix(serverKeyIdSig)] + .join("/") - Logger.log(url) + // Logger.log("url", url) - const result = await fetch(url, { + const result: RetrievedKey = await fetch(url, { method: "GET", }) .then((response) => { - if (response.ok) { return response.json() } throw Error(`Unable to retrieve decryption Keys ${response.statusText}`) }) + .then((data) => { + return { + commonPoint: data.common_point, + decryptedSecret: data.decrypted_secret, + decryptShadows: data.decrypt_shadows, + } as RetrievedKey + }) .catch((e) => { throw Error(`Unable to retrieve decryption keys: ${e.message}`) }) @@ -102,7 +101,6 @@ export default class SecretStoreClient { throw Error(`Unable to retrieve decryption Keys`) } - // results should have (decrypted_secret, common_point, decrypt_shadows) - return JSON.parse(result) + return result } } diff --git a/src/secretstore/keys/GeneratedKey.ts b/src/secretstore/keys/GeneratedKey.ts new file mode 100644 index 0000000..0a426af --- /dev/null +++ b/src/secretstore/keys/GeneratedKey.ts @@ -0,0 +1,6 @@ +import KeyBase from "./KeyBase" + +export default class GeneratedKey extends KeyBase { + public encryptedKey: string + public encryptedPoint: string +} diff --git a/src/secretstore/keys/KeyBase.ts b/src/secretstore/keys/KeyBase.ts new file mode 100644 index 0000000..2d6b8e5 --- /dev/null +++ b/src/secretstore/keys/KeyBase.ts @@ -0,0 +1,3 @@ +export default class KeyBase { + public commonPoint: string +} diff --git a/src/secretstore/keys/RetrievedKey.ts b/src/secretstore/keys/RetrievedKey.ts new file mode 100644 index 0000000..95e2f86 --- /dev/null +++ b/src/secretstore/keys/RetrievedKey.ts @@ -0,0 +1,6 @@ +import KeyBase from "./KeyBase" + +export default class RetrievedKey extends KeyBase { + public decryptedSecret: string + public decryptShadows: string[] +} diff --git a/test/secretstore/ParityClient.test_.ts b/test/secretstore/ParityClient.test_.ts index 1f97125..a47661e 100644 --- a/test/secretstore/ParityClient.test_.ts +++ b/test/secretstore/ParityClient.test_.ts @@ -2,8 +2,11 @@ import BigNumber from "bignumber.js" import {assert} from "chai" import ConfigProvider from "../../src/ConfigProvider" import Config from "../../src/models/Config" -import DocumentKeys from "../../src/secretstore/DocumentKeys" +import GeneratedKey from "../../src/secretstore/keys/GeneratedKey" import ParityClient from "../../src/secretstore/ParityClient" +import * as GeneratedKeyMaterial from "./keys/GeneratedKey.json" +import * as RetrievedKeyMaterial from "./keys/RetrievedKey.json" +import * as ServerKey from "./keys/ServerKey.json" const parityUrl = "http://localhost:8545" @@ -13,13 +16,11 @@ ConfigProvider.configure({ const address = "0xa50f397644973dba99624404b2894825840aa03b" const password = "unittest" -const serverKey = - "0x36131d552e561d8231cd91c8020d869e14c11b16e79fb80ecf8302ea0a0539c969dbc0b547398daf293c259431d7c483ee5974b0ef179297edbe6d39af4374d5" - const testDocument = { so: "secure", soWow: true, } + const parityClient: ParityClient = new ParityClient({ url: parityUrl, address, password, @@ -47,7 +48,7 @@ describe("ParityClient", () => { describe("#generateDocumentKeyFromKey()", () => { it("should generate a document key from a server key", async () => { - const documentKey = await parityClient.generateDocumentKeyFromKey(serverKey) + const documentKey = await parityClient.generateDocumentKeyFromKey(ServerKey) assert(documentKey) }) }) @@ -55,7 +56,7 @@ describe("ParityClient", () => { describe("#encryptDocument()", () => { it("should encrypt an document", async () => { - const documentKey: DocumentKeys = await parityClient.generateDocumentKeyFromKey(serverKey) + const documentKey: GeneratedKey = await parityClient.generateDocumentKeyFromKey(ServerKey) const encryptedDocument = await parityClient.encryptDocument(documentKey.encryptedKey, testDocument) assert(encryptedDocument) }) @@ -64,9 +65,16 @@ describe("ParityClient", () => { describe("#decryptDocument()", () => { it("should decrypt an document", async () => { - const documentKey: DocumentKeys = await parityClient.generateDocumentKeyFromKey(serverKey) - const encryptedDocument = await parityClient.encryptDocument(documentKey.encryptedKey, testDocument) + const encryptedDocument: string = + await parityClient.encryptDocument(GeneratedKeyMaterial.encryptedKey, testDocument) assert(encryptedDocument) + + const decryptedDocument: any = await parityClient.decryptDocument( + RetrievedKeyMaterial.decryptedSecret, RetrievedKeyMaterial.commonPoint, + RetrievedKeyMaterial.decryptShadows, encryptedDocument) + assert(decryptedDocument) + + assert(testDocument.soWow === decryptedDocument.soWow) }) }) }) diff --git a/test/secretstore/SecretStore.test_.ts b/test/secretstore/SecretStore.test_.ts index 7ca8c87..9fdfc62 100644 --- a/test/secretstore/SecretStore.test_.ts +++ b/test/secretstore/SecretStore.test_.ts @@ -11,6 +11,13 @@ ConfigProvider.configure({ nodeUri: parityUrl, } as Config) +const testDocument = { + so: "ocean", + soWow: true, + many: "text is nice to have", + i: "blow up this document with blind text", +} + const address = "0xa50f397644973dba99624404b2894825840aa03b" const password = "unittest" @@ -29,24 +36,28 @@ function generateRandomId(): string { describe("SecretStore", () => { - describe("#generateServerKey()", () => { - it("should generate Server key", async () => { + describe("#encryptDocument()", () => { + it("should encrypt an document", async () => { const serverKeyId = generateRandomId() - const serverKey = await secretStore.generateServerKey(serverKeyId) - assert(serverKey) + const encryptedDocument = await secretStore.encryptDocument(serverKeyId, testDocument) + assert(encryptedDocument) }) }) - describe("#storeDocumentKey()", () => { - it("should store Document key", async () => { + describe("#decryptDocument()", () => { + it("should decrypt an document", async () => { const serverKeyId = generateRandomId() - const documentKeyId = generateRandomId() - const documentKey = await secretStore.storeDocumentKey(serverKeyId, documentKeyId) - assert(documentKey) + const encryptedDocument: string = await secretStore.encryptDocument(serverKeyId, testDocument) + assert(encryptedDocument) + + const decryptedDocument: any = await secretStore.decryptDocument(serverKeyId, encryptedDocument) + assert(decryptedDocument) + + assert(testDocument.soWow === decryptedDocument.soWow) }) }) }) diff --git a/test/secretstore/keys/GeneratedKey.json b/test/secretstore/keys/GeneratedKey.json new file mode 100644 index 0000000..a0469fe --- /dev/null +++ b/test/secretstore/keys/GeneratedKey.json @@ -0,0 +1,5 @@ +{ + "commonPoint": "0xba52313ef585265b52434b1c45a7aa19cf59e371b8d4f5d5f3ef45863e51341b9648dc83ce11b7158347b2cfb2613f92689d6d3704e84dee4eafd38abd0c7ca6", + "encryptedKey": "0x04e77b1d4b3919354550900d871c8ee698ca592e45ee715dad607c408fc18982bae479b3c752dec27eebbe00b102b512e6454e747138f4d882a2fa3dbe84bb3851518766c01e216fc5b01f7a4eb2e18ea2f159063801b0e43f5f632089a80ab982520707ee9e3f4980931a8814e44febdd960b366336ee35b26bfe523950d28bb6bdc0a65240c43b999cae3cd8258a06cb8dd52b2a2516bf15ad4d00d8c50f4e5f8bc48cf7173db5cce77a182093404402", + "encryptedPoint": "0x1697d31ba17eb819177004618f2a5e00fceb355b12ceb4a476ade59adfc9f6579f9b951ef0695eb852f1ff1deff1f12205760b8d1c5a46ba44cce7d54571200a" +} \ No newline at end of file diff --git a/test/secretstore/keys/RetrievedKey.json b/test/secretstore/keys/RetrievedKey.json new file mode 100644 index 0000000..b84eda5 --- /dev/null +++ b/test/secretstore/keys/RetrievedKey.json @@ -0,0 +1,8 @@ +{ + "commonPoint": "0xba52313ef585265b52434b1c45a7aa19cf59e371b8d4f5d5f3ef45863e51341b69b7237c31ee48ea7cb84d304d9ec06d976292c8fb17b211b1502c7442f37f89", + "decryptedSecret": "0x7b6bee06bd00dc825d2c99f324b47e4aee9219d5453076a735cfc3d55c730df285c6e0117ceb90805aee7cfb86e0574d04c17aa09cdff9957b4a91a2af79a3d3", + "decryptShadows": [ + "0x0429f62a48a25306bb64d8a5b74b0d6ee01f062fe1f7238f6b5078e3e7726751b46dd8834c5346bca3d6059ddc923747ecfea545579210db09f8a6708ab05f452ace3956408afddcb3b8796637198109fa046af23c6bcd6da5424cf8d7165d805c6265ea4e358731e4a71d32760d0423d12cf117d9b401bd2d7c321a4b9d47a79d383adce06c45352e23f2bec3262d637b", + "0x045fdbbb9782c046f3023e1d699ee9ae80413e44162ecf4f5ac6ace369f7e0604035abb3b7aed9d087293561ef75eb9296a6582cbefb1af7f449a97bcb5282f9b6cbb1059d595b2e2ec6cef40fceacf228462bebe985b8738e22c6ec196b25e408b7cbb608a74a167a2b5d4e12182e2942ded30d18a6b99b243395d4a4cabe25168560946ce3dd5d77b48b5148c78491e1" + ] +} \ No newline at end of file diff --git a/test/secretstore/keys/ServerKey.json b/test/secretstore/keys/ServerKey.json new file mode 100644 index 0000000..17e92d3 --- /dev/null +++ b/test/secretstore/keys/ServerKey.json @@ -0,0 +1 @@ +"0x92c18be2b3f6aea31fc1e58f833936f16f635c0657bf03c3b05a0e3f5809ffec64736f0774b9be536e65a125b05fd21c0ae32a03c1338dcbe6ddb1ce2cd5b95a" \ No newline at end of file diff --git a/test/tsconfig.json b/test/tsconfig.json index 4ca49cc..ef87166 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "resolveJsonModule": true, "lib": [ "es6", "es7" From 717ca1d07c0efccacbfed5c1ebc7d024f538a08b Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Mon, 22 Oct 2018 13:39:31 +0200 Subject: [PATCH 07/38] moved secret store to secret-store-client-js --- package-lock.json | 9 ++ package.json | 2 +- src/secretstore/HexHelpler.ts | 10 --- src/secretstore/ParityClient.ts | 81 ------------------ src/secretstore/SecretStore.ts | 90 -------------------- src/secretstore/SecretStoreClient.ts | 106 ------------------------ src/secretstore/keys/GeneratedKey.ts | 6 -- src/secretstore/keys/KeyBase.ts | 3 - src/secretstore/keys/RetrievedKey.ts | 6 -- test/secretstore/ParityClient.test_.ts | 80 ------------------ test/secretstore/SecretStore.test_.ts | 63 -------------- test/secretstore/keys/GeneratedKey.json | 5 -- test/secretstore/keys/RetrievedKey.json | 8 -- test/secretstore/keys/ServerKey.json | 1 - 14 files changed, 10 insertions(+), 460 deletions(-) delete mode 100644 src/secretstore/HexHelpler.ts delete mode 100644 src/secretstore/ParityClient.ts delete mode 100644 src/secretstore/SecretStore.ts delete mode 100644 src/secretstore/SecretStoreClient.ts delete mode 100644 src/secretstore/keys/GeneratedKey.ts delete mode 100644 src/secretstore/keys/KeyBase.ts delete mode 100644 src/secretstore/keys/RetrievedKey.ts delete mode 100644 test/secretstore/ParityClient.test_.ts delete mode 100644 test/secretstore/SecretStore.test_.ts delete mode 100644 test/secretstore/keys/GeneratedKey.json delete mode 100644 test/secretstore/keys/RetrievedKey.json delete mode 100644 test/secretstore/keys/ServerKey.json diff --git a/package-lock.json b/package-lock.json index 14432bd..a2c5913 100644 --- a/package-lock.json +++ b/package-lock.json @@ -124,6 +124,15 @@ "resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.3.3.tgz", "integrity": "sha512-UVt9m9WmFm4mTDWmMekT8lhBh2hWr2baEVnF0dEN3OL5BDAWoynFQeeKtUqTepVuOVgNy5bHYKLiHkCWzbOEqA==" }, + "@oceanprotocol/secret-store-client": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.1.tgz", + "integrity": "sha512-WFqpT6Am6ptFiLrBDAyGzCNMpT1iJM/yq4eRHZX9GbWrDbvmR3lbjxbQiQaepFqMSDATKrBp4oFGE0x2m6hQIA==", + "requires": { + "jayson": "^2.0.6", + "node-fetch": "^2.2.0" + } + }, "@types/chai": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.6.tgz", diff --git a/package.json b/package.json index 41a8da3..8e3d577 100644 --- a/package.json +++ b/package.json @@ -50,11 +50,11 @@ }, "dependencies": { "@oceanprotocol/keeper-contracts": "^0.3.3", + "@oceanprotocol/secret-store-client": "0.0.1", "bignumber.js": "^7.2.1", "eth-crypto": "^1.2.4", "eth-ecies": "^1.0.3", "ethereumjs-util": "^6.0.0", - "jayson": "^2.1.0", "jsonwebtoken": "^8.3.0", "node-fetch": "^2.2.0", "web3": "1.0.0-beta.36", diff --git a/src/secretstore/HexHelpler.ts b/src/secretstore/HexHelpler.ts deleted file mode 100644 index a9ec07d..0000000 --- a/src/secretstore/HexHelpler.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default class HexHelpler { - public static removeLeading0xPrefix(key) { - return key.startsWith("0x") ? key.replace("0x", "") : key - } - - public static add0xPrefix(key) { - return key.startsWith("0x") ? key : "0x" + key - } - -} diff --git a/src/secretstore/ParityClient.ts b/src/secretstore/ParityClient.ts deleted file mode 100644 index e3e4c84..0000000 --- a/src/secretstore/ParityClient.ts +++ /dev/null @@ -1,81 +0,0 @@ -import * as jayson from "jayson" -import {Client} from "jayson" -import {URL} from "url" -import Logger from "../utils/Logger" -import HexHelpler from "./HexHelpler" -import GeneratedKey from "./keys/GeneratedKey" - -export default class ParityClient { - - private address: string - private password: string - private rpcClient: Client - - constructor(config: { url: string, address: string, password: string }) { - this.password = config.password - this.address = config.address - this.rpcClient = jayson.Client.http(new URL(config.url)) - } - - public async signKeyId(keyId): Promise { - return this.sendJsonRpcRequest(this.rpcClient, - "secretstore_signRawHash", - [this.address, this.password, HexHelpler.add0xPrefix(keyId)]) - .then((result: string) => { - return result - }) - } - - public async generateDocumentKeyFromKey(serverKey: string): Promise { - return this.sendJsonRpcRequest(this.rpcClient, - "secretstore_generateDocumentKey", - [this.address, this.password, serverKey]) - .then((result: any) => { - const generatedKey = { - commonPoint: result.common_point, - encryptedKey: result.encrypted_key, - encryptedPoint: result.encrypted_point, - } as GeneratedKey - return generatedKey - }) - } - - public encryptDocument(encryptedKey: string, document: any): Promise { - // `document` must be encoded in hex when sent to encryption - const documentString = JSON.stringify(document) - const documentHexed = HexHelpler.add0xPrefix(new Buffer(documentString).toString("hex")) - return this.sendJsonRpcRequest(this.rpcClient, - "secretstore_encrypt", - [this.address, this.password, encryptedKey, documentHexed]) - .then((result: string) => { - return result - }) - } - - public decryptDocument(decryptedSecret: string, commonPoint: string, - decryptShadows: string[], encryptedDocument: string): Promise { - return this.sendJsonRpcRequest(this.rpcClient, - "secretstore_shadowDecrypt", - [this.address, this.password, decryptedSecret, - commonPoint, decryptShadows, encryptedDocument]) - .then((result: string) => { - const documentString = new Buffer(HexHelpler.removeLeading0xPrefix(result), "hex").toString("utf8") - return JSON.parse(documentString) - }) - } - - private sendJsonRpcRequest(rpcClient: Client, methodName: string, paramsList: any[]) { - return new Promise((resolve, reject) => { - rpcClient.request(methodName, paramsList, - (err, response) => { - const error = response.error || err - if (error) { - Logger.error("JSON RPC call failed:", error) - Logger.error(`Method ${methodName}`) - return reject(error) - } - return resolve(response.result) - }) - }) - } -} diff --git a/src/secretstore/SecretStore.ts b/src/secretstore/SecretStore.ts deleted file mode 100644 index 9b5becb..0000000 --- a/src/secretstore/SecretStore.ts +++ /dev/null @@ -1,90 +0,0 @@ -import GeneratedKey from "./keys/GeneratedKey" -import RetrievedKey from "./keys/RetrievedKey" -import ParityClient from "./ParityClient" -import SecretStoreClient from "./SecretStoreClient" - -export default class SecretStore { - - private partiyClient: ParityClient - private secretStoreClient: SecretStoreClient - - constructor(config: { secretStoreUrl: string, parityUrl: string, address: string, password: string }) { - - this.partiyClient = new ParityClient({ - url: config.parityUrl, address: config.address, - password: config.password, - }) - this.secretStoreClient = new SecretStoreClient({url: config.secretStoreUrl}) - } - - public async encryptDocument(serverKeyId: string, document: any): Promise { - const serverKey = await this.generateServerKey(serverKeyId) - - // generate document key - const documentKey: GeneratedKey = await this.generateDocumentKey(serverKey) - - // store the document key in secret store - await this.storeDocumentKey(serverKeyId, documentKey) - - // encrypt document - const encryptedDocument = - await this.partiyClient.encryptDocument(documentKey.encryptedKey, document) - return encryptedDocument - } - - public async decryptDocument(serverkeyId: string, encryptedDocument: string): Promise { - - // get document key from secret store - const documentKey: RetrievedKey = await this.retrieveDocumentKey(serverkeyId) - - const decryptDocument: any = await this.partiyClient.decryptDocument( - documentKey.decryptedSecret, documentKey.commonPoint, - documentKey.decryptShadows, encryptedDocument) - - return decryptDocument - } - - private async generateServerKey(serverKeyId: string): Promise { - - // sign server key id - const serverKeyIdSig = await this.partiyClient.signKeyId(serverKeyId) - - // Logger.log("serverKeyId:", serverKeyId, "serverKeyIdSig:", serverKeyIdSig) - - // generate server key - const serverKey = await this.secretStoreClient.generateServerKey(serverKeyId, serverKeyIdSig) - - return serverKey - } - - private async generateDocumentKey(serverKey: string): Promise { - // generate document key from server key - const documentKeys: GeneratedKey = await this.partiyClient.generateDocumentKeyFromKey(serverKey) - return documentKeys - } - - private async storeDocumentKey(serverKeyId: string, documentKeys: GeneratedKey): Promise { - - // sign server key id - const serverKeyIdSig = await this.partiyClient.signKeyId(serverKeyId) - - // store document key in secret store - await this.secretStoreClient.storeDocumentKey(serverKeyId, serverKeyIdSig, - documentKeys.commonPoint, documentKeys.encryptedPoint) - - return true - } - - private async retrieveDocumentKey(serverKeyId: string): Promise { - - // sign server key id - const serverKeyIdSig = await this.partiyClient.signKeyId(serverKeyId) - - // Logger.log("serverKeyId:", serverKeyId, "serverKeyIdSig:", serverKeyIdSig) - - // retrieve document key from secret store - const documentKeys: RetrievedKey = await this.secretStoreClient.retrieveDocumentKey(serverKeyId, serverKeyIdSig) - return documentKeys - } - -} diff --git a/src/secretstore/SecretStoreClient.ts b/src/secretstore/SecretStoreClient.ts deleted file mode 100644 index 9d5f3dd..0000000 --- a/src/secretstore/SecretStoreClient.ts +++ /dev/null @@ -1,106 +0,0 @@ -import fetch from "node-fetch" -import HexHelpler from "./HexHelpler" -import RetrievedKey from "./keys/RetrievedKey" - -export default class SecretStoreClient { - - private threshold: number - private url: string - - constructor(config: { url: string, threshold?: number }) { - this.url = config.url - this.threshold = config.threshold || 1 - } - - public async generateServerKey(serverKeyId: string, serverKeyIdSig: string): Promise { - - const url = [ - this.url, "shadow", serverKeyId, - HexHelpler.removeLeading0xPrefix(serverKeyIdSig), - this.threshold, - ].join("/") - - // Logger.log("url", url) - - const result = await fetch(url, { - method: "POST", - }) - .then((response) => { - if (response.ok) { - return response.json() - } - throw Error(`Unable to generate Server Key ${response.statusText}`) - }) - .catch((error) => { - throw Error(`Unable to generate Server Key: ${error.message}`) - }) - - if (!result) { - throw Error(`Unable to generate Server Key`) - } - - return result - } - - public async storeDocumentKey(serverKeyId: string, serverKeyIdSig: string, - commonPoint: string, encryptedPoint: string): Promise { - const url = [this.url, "shadow", serverKeyId, HexHelpler.removeLeading0xPrefix(serverKeyIdSig), - HexHelpler.removeLeading0xPrefix(commonPoint), HexHelpler.removeLeading0xPrefix(encryptedPoint)] - .join("/") - - // Logger.log("url", url) - - const result = await fetch(url, { - method: "POST", - }) - .then((response) => { - if (response.ok && response.status === 200) { - return true - } - throw Error(`Unable to store document Keys ${response.statusText}`) - }) - .catch((error) => { - throw Error(`Unable to store document keys: ${error.message}`) - }) - - if (!result) { - throw Error(`Unable to store document Keys`) - } - - return result - } - - public async retrieveDocumentKey(serverKeyId, serverKeyIdSig): Promise { - - const url = [this.url, "shadow", serverKeyId, HexHelpler.removeLeading0xPrefix(serverKeyIdSig)] - .join("/") - - // Logger.log("url", url) - - const result: RetrievedKey = await fetch(url, { - method: "GET", - }) - .then((response) => { - if (response.ok) { - return response.json() - } - throw Error(`Unable to retrieve decryption Keys ${response.statusText}`) - }) - .then((data) => { - return { - commonPoint: data.common_point, - decryptedSecret: data.decrypted_secret, - decryptShadows: data.decrypt_shadows, - } as RetrievedKey - }) - .catch((e) => { - throw Error(`Unable to retrieve decryption keys: ${e.message}`) - }) - - if (!result) { - throw Error(`Unable to retrieve decryption Keys`) - } - - return result - } -} diff --git a/src/secretstore/keys/GeneratedKey.ts b/src/secretstore/keys/GeneratedKey.ts deleted file mode 100644 index 0a426af..0000000 --- a/src/secretstore/keys/GeneratedKey.ts +++ /dev/null @@ -1,6 +0,0 @@ -import KeyBase from "./KeyBase" - -export default class GeneratedKey extends KeyBase { - public encryptedKey: string - public encryptedPoint: string -} diff --git a/src/secretstore/keys/KeyBase.ts b/src/secretstore/keys/KeyBase.ts deleted file mode 100644 index 2d6b8e5..0000000 --- a/src/secretstore/keys/KeyBase.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default class KeyBase { - public commonPoint: string -} diff --git a/src/secretstore/keys/RetrievedKey.ts b/src/secretstore/keys/RetrievedKey.ts deleted file mode 100644 index 95e2f86..0000000 --- a/src/secretstore/keys/RetrievedKey.ts +++ /dev/null @@ -1,6 +0,0 @@ -import KeyBase from "./KeyBase" - -export default class RetrievedKey extends KeyBase { - public decryptedSecret: string - public decryptShadows: string[] -} diff --git a/test/secretstore/ParityClient.test_.ts b/test/secretstore/ParityClient.test_.ts deleted file mode 100644 index a47661e..0000000 --- a/test/secretstore/ParityClient.test_.ts +++ /dev/null @@ -1,80 +0,0 @@ -import BigNumber from "bignumber.js" -import {assert} from "chai" -import ConfigProvider from "../../src/ConfigProvider" -import Config from "../../src/models/Config" -import GeneratedKey from "../../src/secretstore/keys/GeneratedKey" -import ParityClient from "../../src/secretstore/ParityClient" -import * as GeneratedKeyMaterial from "./keys/GeneratedKey.json" -import * as RetrievedKeyMaterial from "./keys/RetrievedKey.json" -import * as ServerKey from "./keys/ServerKey.json" - -const parityUrl = "http://localhost:8545" - -ConfigProvider.configure({ - nodeUri: parityUrl, -} as Config) - -const address = "0xa50f397644973dba99624404b2894825840aa03b" -const password = "unittest" -const testDocument = { - so: "secure", - soWow: true, -} - -const parityClient: ParityClient = new ParityClient({ - url: parityUrl, - address, password, -}) - -function generateRandomId(): string { - const id: string = BigNumber.random(64).toString().replace("0.", "") - - // sometimes it only generates 63 digits - return id.length === 63 ? id + "0" : id -} - -describe("ParityClient", () => { - - describe("#signKeyId()", () => { - it("should generate sig from given key", async () => { - - const keyId = generateRandomId() - const keyIdSig = await parityClient.signKeyId(keyId) - - assert(keyIdSig) - }) - }) - - describe("#generateDocumentKeyFromKey()", () => { - it("should generate a document key from a server key", async () => { - - const documentKey = await parityClient.generateDocumentKeyFromKey(ServerKey) - assert(documentKey) - }) - }) - - describe("#encryptDocument()", () => { - it("should encrypt an document", async () => { - - const documentKey: GeneratedKey = await parityClient.generateDocumentKeyFromKey(ServerKey) - const encryptedDocument = await parityClient.encryptDocument(documentKey.encryptedKey, testDocument) - assert(encryptedDocument) - }) - }) - - describe("#decryptDocument()", () => { - it("should decrypt an document", async () => { - - const encryptedDocument: string = - await parityClient.encryptDocument(GeneratedKeyMaterial.encryptedKey, testDocument) - assert(encryptedDocument) - - const decryptedDocument: any = await parityClient.decryptDocument( - RetrievedKeyMaterial.decryptedSecret, RetrievedKeyMaterial.commonPoint, - RetrievedKeyMaterial.decryptShadows, encryptedDocument) - assert(decryptedDocument) - - assert(testDocument.soWow === decryptedDocument.soWow) - }) - }) -}) diff --git a/test/secretstore/SecretStore.test_.ts b/test/secretstore/SecretStore.test_.ts deleted file mode 100644 index 9fdfc62..0000000 --- a/test/secretstore/SecretStore.test_.ts +++ /dev/null @@ -1,63 +0,0 @@ -import BigNumber from "bignumber.js" -import {assert} from "chai" -import ConfigProvider from "../../src/ConfigProvider" -import Config from "../../src/models/Config" -import SecretStore from "../../src/secretstore/SecretStore" - -const parityUrl = "http://localhost:8545" -const ssUrl = "https://secret-store.dev-ocean.com" - -ConfigProvider.configure({ - nodeUri: parityUrl, -} as Config) - -const testDocument = { - so: "ocean", - soWow: true, - many: "text is nice to have", - i: "blow up this document with blind text", -} - -const address = "0xa50f397644973dba99624404b2894825840aa03b" -const password = "unittest" - -const secretStore: SecretStore = new SecretStore({ - secretStoreUrl: ssUrl, parityUrl, - address, - password, -}) - -function generateRandomId(): string { - const id: string = BigNumber.random(64).toString().replace("0.", "") - - // sometimes it only generates 63 digits - return id.length === 63 ? id + "0" : id -} - -describe("SecretStore", () => { - - describe("#encryptDocument()", () => { - it("should encrypt an document", async () => { - - const serverKeyId = generateRandomId() - - const encryptedDocument = await secretStore.encryptDocument(serverKeyId, testDocument) - assert(encryptedDocument) - }) - }) - - describe("#decryptDocument()", () => { - it("should decrypt an document", async () => { - - const serverKeyId = generateRandomId() - - const encryptedDocument: string = await secretStore.encryptDocument(serverKeyId, testDocument) - assert(encryptedDocument) - - const decryptedDocument: any = await secretStore.decryptDocument(serverKeyId, encryptedDocument) - assert(decryptedDocument) - - assert(testDocument.soWow === decryptedDocument.soWow) - }) - }) -}) diff --git a/test/secretstore/keys/GeneratedKey.json b/test/secretstore/keys/GeneratedKey.json deleted file mode 100644 index a0469fe..0000000 --- a/test/secretstore/keys/GeneratedKey.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "commonPoint": "0xba52313ef585265b52434b1c45a7aa19cf59e371b8d4f5d5f3ef45863e51341b9648dc83ce11b7158347b2cfb2613f92689d6d3704e84dee4eafd38abd0c7ca6", - "encryptedKey": "0x04e77b1d4b3919354550900d871c8ee698ca592e45ee715dad607c408fc18982bae479b3c752dec27eebbe00b102b512e6454e747138f4d882a2fa3dbe84bb3851518766c01e216fc5b01f7a4eb2e18ea2f159063801b0e43f5f632089a80ab982520707ee9e3f4980931a8814e44febdd960b366336ee35b26bfe523950d28bb6bdc0a65240c43b999cae3cd8258a06cb8dd52b2a2516bf15ad4d00d8c50f4e5f8bc48cf7173db5cce77a182093404402", - "encryptedPoint": "0x1697d31ba17eb819177004618f2a5e00fceb355b12ceb4a476ade59adfc9f6579f9b951ef0695eb852f1ff1deff1f12205760b8d1c5a46ba44cce7d54571200a" -} \ No newline at end of file diff --git a/test/secretstore/keys/RetrievedKey.json b/test/secretstore/keys/RetrievedKey.json deleted file mode 100644 index b84eda5..0000000 --- a/test/secretstore/keys/RetrievedKey.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "commonPoint": "0xba52313ef585265b52434b1c45a7aa19cf59e371b8d4f5d5f3ef45863e51341b69b7237c31ee48ea7cb84d304d9ec06d976292c8fb17b211b1502c7442f37f89", - "decryptedSecret": "0x7b6bee06bd00dc825d2c99f324b47e4aee9219d5453076a735cfc3d55c730df285c6e0117ceb90805aee7cfb86e0574d04c17aa09cdff9957b4a91a2af79a3d3", - "decryptShadows": [ - "0x0429f62a48a25306bb64d8a5b74b0d6ee01f062fe1f7238f6b5078e3e7726751b46dd8834c5346bca3d6059ddc923747ecfea545579210db09f8a6708ab05f452ace3956408afddcb3b8796637198109fa046af23c6bcd6da5424cf8d7165d805c6265ea4e358731e4a71d32760d0423d12cf117d9b401bd2d7c321a4b9d47a79d383adce06c45352e23f2bec3262d637b", - "0x045fdbbb9782c046f3023e1d699ee9ae80413e44162ecf4f5ac6ace369f7e0604035abb3b7aed9d087293561ef75eb9296a6582cbefb1af7f449a97bcb5282f9b6cbb1059d595b2e2ec6cef40fceacf228462bebe985b8738e22c6ec196b25e408b7cbb608a74a167a2b5d4e12182e2942ded30d18a6b99b243395d4a4cabe25168560946ce3dd5d77b48b5148c78491e1" - ] -} \ No newline at end of file diff --git a/test/secretstore/keys/ServerKey.json b/test/secretstore/keys/ServerKey.json deleted file mode 100644 index 17e92d3..0000000 --- a/test/secretstore/keys/ServerKey.json +++ /dev/null @@ -1 +0,0 @@ -"0x92c18be2b3f6aea31fc1e58f833936f16f635c0657bf03c3b05a0e3f5809ffec64736f0774b9be536e65a125b05fd21c0ae32a03c1338dcbe6ddb1ce2cd5b95a" \ No newline at end of file From 10d5f4bc68b8294fd741f08156f8dc4645771d0f Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Mon, 22 Oct 2018 14:39:52 +0200 Subject: [PATCH 08/38] updated packages --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2c5913..a1193c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -125,9 +125,9 @@ "integrity": "sha512-UVt9m9WmFm4mTDWmMekT8lhBh2hWr2baEVnF0dEN3OL5BDAWoynFQeeKtUqTepVuOVgNy5bHYKLiHkCWzbOEqA==" }, "@oceanprotocol/secret-store-client": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.1.tgz", - "integrity": "sha512-WFqpT6Am6ptFiLrBDAyGzCNMpT1iJM/yq4eRHZX9GbWrDbvmR3lbjxbQiQaepFqMSDATKrBp4oFGE0x2m6hQIA==", + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.2.tgz", + "integrity": "sha512-UzUth2YUldSgFHjAgWrHNwC9qxmhnvd+o5v6gjuzLbT/Hekz8eibG1F4KiMr9yKlLjkro3/sS725EN0Vr8cHEA==", "requires": { "jayson": "^2.0.6", "node-fetch": "^2.2.0" @@ -1802,7 +1802,7 @@ }, "es6-promisify": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "requires": { "es6-promise": "^4.0.3" diff --git a/package.json b/package.json index 8e3d577..3d16338 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ }, "dependencies": { "@oceanprotocol/keeper-contracts": "^0.3.3", - "@oceanprotocol/secret-store-client": "0.0.1", + "@oceanprotocol/secret-store-client": "^0.0.2", "bignumber.js": "^7.2.1", "eth-crypto": "^1.2.4", "eth-ecies": "^1.0.3", From e82a06410b9c3d69387cdc4cd5010aacef25f07c Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Tue, 23 Oct 2018 10:37:36 +0200 Subject: [PATCH 09/38] secret-store 0.0.3 --- package-lock.json | 8 ++++---- package.json | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index a1193c0..c5f3d4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -125,9 +125,9 @@ "integrity": "sha512-UVt9m9WmFm4mTDWmMekT8lhBh2hWr2baEVnF0dEN3OL5BDAWoynFQeeKtUqTepVuOVgNy5bHYKLiHkCWzbOEqA==" }, "@oceanprotocol/secret-store-client": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.2.tgz", - "integrity": "sha512-UzUth2YUldSgFHjAgWrHNwC9qxmhnvd+o5v6gjuzLbT/Hekz8eibG1F4KiMr9yKlLjkro3/sS725EN0Vr8cHEA==", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.3.tgz", + "integrity": "sha512-B1rJ7zk24qP1HW+L3MkgietEWDy2aEuXUagFYfsGBt3iilixc8qTm8U+nphsuVDp1Lgf7BQpIpXED81S7HAwOA==", "requires": { "jayson": "^2.0.6", "node-fetch": "^2.2.0" @@ -1802,7 +1802,7 @@ }, "es6-promisify": { "version": "5.0.0", - "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "requires": { "es6-promise": "^4.0.3" diff --git a/package.json b/package.json index 3d16338..33ebfa3 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,10 @@ "main": "dist/squid.js", "scripts": { "test": "mocha", - "test:watch": "mocha -w --watch-extensions js,ts", + "test:watch": "mocha -w --watch-extensions js,ts,json", "test:cover": "nyc mocha", "lint": "tslint -c tslint.json 'src/**/*.ts'", - "start": "npm link @oceanprotocol/keeper-contracts && npm run build:watch", + "start": "npm link @oceanprotocol/keeper-contracts @oceanprotocol/secret-store-client && npm run build:watch", "build": "npm run lint && tsc && npm run doc", "build:watch": "tsc -w", "doc": "typedoc --mode modules --out ./doc/ src/", @@ -50,7 +50,7 @@ }, "dependencies": { "@oceanprotocol/keeper-contracts": "^0.3.3", - "@oceanprotocol/secret-store-client": "^0.0.2", + "@oceanprotocol/secret-store-client": "^0.0.3", "bignumber.js": "^7.2.1", "eth-crypto": "^1.2.4", "eth-ecies": "^1.0.3", From baa4adf2697b40bda0a1016066d96c7b41303960 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Tue, 23 Oct 2018 11:49:32 +0200 Subject: [PATCH 10/38] moved access token to json file --- test/ocean/AccessToken.json | 1 + test/ocean/Order.test.ts | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 test/ocean/AccessToken.json diff --git a/test/ocean/AccessToken.json b/test/ocean/AccessToken.json new file mode 100644 index 0000000..242922b --- /dev/null +++ b/test/ocean/AccessToken.json @@ -0,0 +1 @@ +"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1Mzk3ODcxMDEsImV4cCI6NDcyNjk5NjcwNCwiYXVkIjoiIiwic3ViIjoiIiwic2VydmljZV9lbmRwb2ludCI6Imh0dHA6Ly9hZGFzZCIsInJlc291cmNlX2lkIjoiMTIzNDUifQ.2H3TRC3CAToVE9divSckwHi_HNvgOHKrtJPo8128qrKBHTk7YYb0UNfVCuYqwhGR" \ No newline at end of file diff --git a/test/ocean/Order.test.ts b/test/ocean/Order.test.ts index d03c72c..6caebbf 100644 --- a/test/ocean/Order.test.ts +++ b/test/ocean/Order.test.ts @@ -7,12 +7,12 @@ import Asset from "../../src/ocean/Asset" import Ocean from "../../src/ocean/Ocean" import Order from "../../src/ocean/Order" import config from "../config" +import * as AccessToken from "./AccessToken.json" const testName = "Order Test Asset" const testDescription = "This asset is pure owange" const testPrice = 100 const timeout = 1000000 -const accessToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1Mzk3ODcxMDEsImV4cCI6NDcyNjk5NjcwNCwiYXVkIjoiIiwic3ViIjoiIiwic2VydmljZV9lbmRwb2ludCI6Imh0dHA6Ly9hZGFzZCIsInJlc291cmNlX2lkIjoiMTIzNDUifQ.2H3TRC3CAToVE9divSckwHi_HNvgOHKrtJPo8128qrKBHTk7YYb0UNfVCuYqwhGR" let ocean: Ocean let testAsset: Asset @@ -41,7 +41,7 @@ describe("Order", () => { const order: Order = await testAsset.purchase(testConsumer, timeout) assert(order) - await order.commit(accessToken) + await order.commit(AccessToken.toString()) await testConsumer.requestTokens(testAsset.price) const paymentId: string = await order.pay(testConsumer) assert(paymentId) @@ -56,7 +56,7 @@ describe("Order", () => { const order: Order = await testAsset.purchase(testConsumer, timeout) assert(order) - await order.commit(accessToken) + await order.commit(AccessToken.toString()) }) }) @@ -76,7 +76,7 @@ describe("Order", () => { const order: Order = await testAsset.purchase(testConsumer, timeout) assert(order) - await order.commit(accessToken) + await order.commit(AccessToken.toString()) const status: AccessStatus = await order.getStatus() assert(status === AccessStatus.Delivered) @@ -91,7 +91,7 @@ describe("Order", () => { // place order - consumer const order: Order = await testAsset.purchase(consumerAccount, timeout) // commit order - provider - await order.commit(accessToken) + await order.commit(AccessToken.toString()) // pay order - consumer await order.pay(consumerAccount) const url = await order.consume(consumerAccount) From 794b57ecd51d4c211b4482d53de61750573bd3cc Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 25 Oct 2018 17:17:24 +0200 Subject: [PATCH 11/38] added config needed for the secret store --- src/models/Config.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/models/Config.ts b/src/models/Config.ts index 4207965..1de88c6 100644 --- a/src/models/Config.ts +++ b/src/models/Config.ts @@ -1,5 +1,23 @@ export default class Config { - public providerUri: string + /* Aquarius Config */ + // the url to the aquarius + public aquariusUri: string + + /* Keeper Config */ + // the uri to the node we want to connect to, not need if web3Provider is set public nodeUri: string + // from outside eg. metamask public web3Provider: any + + /* Secret Store Config */ + // the uri of the secret store to connect to + public secretStoreUri: string + // the uri of the parity node to connect to + public parityUri: string + // the password of the account in the local parity node to sign the serverKeyId + public password: string + // the address of the account in the local parity node to sign the serverKeyId + public address: string + // the number of nodes in the secret store that have to agree on changes + public threshold: number } From 28fe11e6716d695708cf7cba3e4cf710e9fedd80 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 25 Oct 2018 17:18:33 +0200 Subject: [PATCH 12/38] adapt test config --- test/config.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/config.ts b/test/config.ts index 6c85b26..29ddde4 100644 --- a/test/config.ts +++ b/test/config.ts @@ -2,4 +2,9 @@ import Config from "../src/models/Config" export default { nodeUri: "http://localhost:8545", + parityUri: "http://localhost:9545", + secretStoreUri: "https://secret-store.dev-ocean.com", + threshold: 2, + password: "unittest", + address: "0xed243adfb84a6626eba46178ccb567481c6e655d", } as Config From 7eae00014ebf0cf5c8b7aa67bc6d27a74a8bcc09 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 25 Oct 2018 17:18:57 +0200 Subject: [PATCH 13/38] added secret store --- package-lock.json | 8 ++++---- package.json | 2 +- src/ocean/Ocean.ts | 20 ++++++++++++++++++-- src/secretstore/SecretStoreProvider.ts | 24 ++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 src/secretstore/SecretStoreProvider.ts diff --git a/package-lock.json b/package-lock.json index c5f3d4b..6c97dc7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -125,9 +125,9 @@ "integrity": "sha512-UVt9m9WmFm4mTDWmMekT8lhBh2hWr2baEVnF0dEN3OL5BDAWoynFQeeKtUqTepVuOVgNy5bHYKLiHkCWzbOEqA==" }, "@oceanprotocol/secret-store-client": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.3.tgz", - "integrity": "sha512-B1rJ7zk24qP1HW+L3MkgietEWDy2aEuXUagFYfsGBt3iilixc8qTm8U+nphsuVDp1Lgf7BQpIpXED81S7HAwOA==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.4.tgz", + "integrity": "sha512-VHzcBkZ5ZKVdLKERshvT48jlWeZTX1x1tDgbqhc1x0nH8H6HC8SZ+Ak834S2t8XTswgTVWygxn8g51jtPy5+BQ==", "requires": { "jayson": "^2.0.6", "node-fetch": "^2.2.0" @@ -1802,7 +1802,7 @@ }, "es6-promisify": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "requires": { "es6-promise": "^4.0.3" diff --git a/package.json b/package.json index 33ebfa3..b637cff 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ }, "dependencies": { "@oceanprotocol/keeper-contracts": "^0.3.3", - "@oceanprotocol/secret-store-client": "^0.0.3", + "@oceanprotocol/secret-store-client": "^0.0.4", "bignumber.js": "^7.2.1", "eth-crypto": "^1.2.4", "eth-ecies": "^1.0.3", diff --git a/src/ocean/Ocean.ts b/src/ocean/Ocean.ts index 8798d8e..175ae09 100644 --- a/src/ocean/Ocean.ts +++ b/src/ocean/Ocean.ts @@ -1,8 +1,10 @@ import ConfigProvider from "../ConfigProvider" import Keeper from "../keeper/Keeper" import Web3Provider from "../keeper/Web3Provider" +import Config from "../models/Config" import Provider from "../provider/Provider" import ProviderProvider from "../provider/ProviderProvider" +import SecretStoreProvider from "../secretstore/SecretStoreProvider" import Logger from "../utils/Logger" import Account from "./Account" import Asset from "./Asset" @@ -10,10 +12,11 @@ import Order from "./Order" export default class Ocean { - public static async getInstance(config) { + public static async getInstance(config: Config) { if (!Ocean.instance) { ConfigProvider.configure(config) + SecretStoreProvider.configure(config) ProviderProvider.setProvider(Provider) Ocean.instance = new Ocean(await Keeper.getInstance()) } @@ -39,8 +42,21 @@ export default class Ocean { public async register(asset: Asset): Promise { const {market} = this.keeper + const secretStore = SecretStoreProvider.getSecretStore() + + const id = Math.random().toString(10) + Logger.log("id", id) + + const assetId = (await market.generateId(id)).replace("0x", "") + + Logger.log(assetId.length) + const encryptedDocument = await secretStore.encryptDocument(assetId, asset) + + const decryptedDocument = await secretStore.decryptDocument(assetId, encryptedDocument) + + Logger.log(decryptedDocument, encryptedDocument) + // generate an id - const assetId = await market.generateId(asset.name + asset.description) Logger.log(`Registering: ${assetId} with price ${asset.price} for ${asset.publisher.getId()}`) asset.setId(assetId) const isAssetActive = await market.isAssetActive(assetId) diff --git a/src/secretstore/SecretStoreProvider.ts b/src/secretstore/SecretStoreProvider.ts new file mode 100644 index 0000000..3226436 --- /dev/null +++ b/src/secretstore/SecretStoreProvider.ts @@ -0,0 +1,24 @@ +import SecretStore from "@oceanprotocol/secret-store-client" + +export default class SecretStoreProvider { + + public static getSecretStore() { + + if (!SecretStoreProvider.secretStore) { + SecretStoreProvider.secretStore = new SecretStore(SecretStoreProvider.config) + } + + return SecretStoreProvider.secretStore + } + + public static configure(config: { + secretStoreUri: string, parityUri: string, + address: string, password: string, threshold?: number, + }) { + + SecretStoreProvider.config = config + } + + private static config: any + private static secretStore: SecretStore +} From 300918e687f01c0f0b620e762079606f08c9392e Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Fri, 26 Oct 2018 10:48:53 +0200 Subject: [PATCH 14/38] merge develop --- src/ocean/Ocean.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ocean/Ocean.ts b/src/ocean/Ocean.ts index 70d269b..d006466 100644 --- a/src/ocean/Ocean.ts +++ b/src/ocean/Ocean.ts @@ -4,8 +4,6 @@ import ConfigProvider from "../ConfigProvider" import Keeper from "../keeper/Keeper" import Web3Provider from "../keeper/Web3Provider" import Config from "../models/Config" -import Provider from "../provider/Provider" -import ProviderProvider from "../provider/ProviderProvider" import SecretStoreProvider from "../secretstore/SecretStoreProvider" import Logger from "../utils/Logger" import Account from "./Account" @@ -17,7 +15,7 @@ export default class Ocean { public static async getInstance(config: Config) { if (!Ocean.instance) { - ConfigProvider.configure(config) + ConfigProvider.setConfig(config) SecretStoreProvider.configure(config) AquariusProvider.setAquarius(Aquarius) Ocean.instance = new Ocean(await Keeper.getInstance()) From 33b642c2c368a13e2f526fa30e55ff94dabb78a2 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Fri, 26 Oct 2018 10:57:40 +0200 Subject: [PATCH 15/38] resolve merge conflicts --- src/ocean/Ocean.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ocean/Ocean.ts b/src/ocean/Ocean.ts index d006466..c133f8e 100644 --- a/src/ocean/Ocean.ts +++ b/src/ocean/Ocean.ts @@ -15,7 +15,7 @@ export default class Ocean { public static async getInstance(config: Config) { if (!Ocean.instance) { - ConfigProvider.setConfig(config) + ConfigProvider.configure(config) SecretStoreProvider.configure(config) AquariusProvider.setAquarius(Aquarius) Ocean.instance = new Ocean(await Keeper.getInstance()) From dd227e74ed4a76aa54f3d1799849edb92dab4822 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Fri, 26 Oct 2018 12:16:40 +0200 Subject: [PATCH 16/38] merge --- src/ocean/Ocean.ts | 1 - test/ocean/Asset.test.ts | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ocean/Ocean.ts b/src/ocean/Ocean.ts index f2305c0..914c0ff 100644 --- a/src/ocean/Ocean.ts +++ b/src/ocean/Ocean.ts @@ -16,7 +16,6 @@ export default class Ocean { if (!Ocean.instance) { ConfigProvider.setConfig(config) SecretStoreProvider.configure(config) - AquariusProvider.setAquarius(Aquarius) Ocean.instance = new Ocean(await Keeper.getInstance()) } diff --git a/test/ocean/Asset.test.ts b/test/ocean/Asset.test.ts index 2785352..1554a03 100644 --- a/test/ocean/Asset.test.ts +++ b/test/ocean/Asset.test.ts @@ -38,9 +38,10 @@ describe("Asset", () => { it("should purchase an asset", async () => { - // todo - const consumerAccount = accounts[5] - const order: Order = await testAsset.purchase(consumerAccount, timeout) - assert(order) + // todo + const consumerAccount = accounts[5] + const order: Order = await testAsset.purchase(consumerAccount, timeout) + assert(order) + }) }) }) From fb5dcaf52200bc55ab881e6b2ceea74f9c36178b Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Fri, 26 Oct 2018 13:37:09 +0200 Subject: [PATCH 17/38] added secret store --- package-lock.json | 34 ++++++++++++------- package.json | 3 +- src/aquarius/AquariusConnectorProvider.ts | 1 - src/keeper/Auth.ts | 2 +- src/keeper/Market.ts | 6 ++-- src/keeper/Web3Provider.ts | 3 -- src/ocean/IdGenerator.ts | 8 +++++ src/ocean/Ocean.ts | 8 ++--- src/secretstore/SecretStoreProvider.ts | 17 ++++------ test/aquarius/Aquarius.test.ts | 40 ++++++++++++----------- test/mocks/SecretStore.mock.ts | 16 +++++++++ test/ocean/IdGenerator.test.ts | 26 +++++++++++++++ test/ocean/Ocean.test.ts | 8 +++-- 13 files changed, 114 insertions(+), 58 deletions(-) create mode 100644 src/ocean/IdGenerator.ts create mode 100644 test/mocks/SecretStore.mock.ts create mode 100644 test/ocean/IdGenerator.test.ts diff --git a/package-lock.json b/package-lock.json index 87b0a17..45e0a19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -125,9 +125,9 @@ "integrity": "sha512-UVt9m9WmFm4mTDWmMekT8lhBh2hWr2baEVnF0dEN3OL5BDAWoynFQeeKtUqTepVuOVgNy5bHYKLiHkCWzbOEqA==" }, "@oceanprotocol/secret-store-client": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.4.tgz", - "integrity": "sha512-VHzcBkZ5ZKVdLKERshvT48jlWeZTX1x1tDgbqhc1x0nH8H6HC8SZ+Ak834S2t8XTswgTVWygxn8g51jtPy5+BQ==", + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.6.tgz", + "integrity": "sha512-dJQ7rWQdAkrM79gvLYrT8vm5ZOrjW7XbQR/d2IBIQNS6t09826wZW3Y9kwaiQvKBUIOI9LhbwVuD4Hc0IuXJnQ==", "requires": { "jayson": "^2.0.6", "node-fetch": "^2.2.0" @@ -2002,6 +2002,11 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "uuid": { + "version": "2.0.1", + "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" } } }, @@ -3644,11 +3649,6 @@ "version": "10.12.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.0.tgz", "integrity": "sha512-3TUHC3jsBAB7qVRGxT6lWyYo2v96BMmD2PTcl47H25Lu7UXtFH/2qqmKiVrnel6Ne//0TFYf6uvNX+HW2FRkLQ==" - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" } } }, @@ -7411,9 +7411,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "2.0.1", - "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "v8-compile-cache": { "version": "2.0.2", @@ -7602,6 +7602,13 @@ "setimmediate": "1.0.4", "uuid": "2.0.1", "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "uuid": { + "version": "2.0.1", + "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" + } } }, "hash.js": { @@ -7641,6 +7648,11 @@ "elliptic": "^6.4.0", "xhr-request-promise": "^0.1.2" } + }, + "uuid": { + "version": "2.0.1", + "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" } } }, diff --git a/package.json b/package.json index f787cfa..905d722 100644 --- a/package.json +++ b/package.json @@ -50,13 +50,14 @@ }, "dependencies": { "@oceanprotocol/keeper-contracts": "^0.3.3", - "@oceanprotocol/secret-store-client": "^0.0.4", + "@oceanprotocol/secret-store-client": "^0.0.6", "bignumber.js": "^7.2.1", "eth-crypto": "^1.2.4", "eth-ecies": "^1.0.3", "ethereumjs-util": "^6.0.0", "jsonwebtoken": "^8.3.0", "node-fetch": "^2.2.0", + "uuid": "^3.3.2", "web3": "1.0.0-beta.36", "web3-utils": "1.0.0-beta.36" }, diff --git a/src/aquarius/AquariusConnectorProvider.ts b/src/aquarius/AquariusConnectorProvider.ts index edc9d1f..997e659 100644 --- a/src/aquarius/AquariusConnectorProvider.ts +++ b/src/aquarius/AquariusConnectorProvider.ts @@ -15,7 +15,6 @@ export default class AquariusConnectorProvider { if (!AquariusConnectorProvider.connector) { AquariusConnectorProvider.connector = new AquariusConnector() } - Logger.log("getting", typeof AquariusConnectorProvider.connector.constructor.name) return AquariusConnectorProvider.connector } diff --git a/src/keeper/Auth.ts b/src/keeper/Auth.ts index f771947..b4d9d14 100644 --- a/src/keeper/Auth.ts +++ b/src/keeper/Auth.ts @@ -27,7 +27,7 @@ export default class OceanAuth extends ContractBase { public async initiateAccessRequest(asset: Asset, publicKey: string, timeout: number, buyerAddress: string): Promise { - const args = [asset.getId(), asset.publisher.getId(), publicKey, timeout] + const args = ["0x" + asset.getId(), asset.publisher.getId(), publicKey, timeout] return this.sendTransaction("initiateAccessRequest", buyerAddress, args) } diff --git a/src/keeper/Market.ts b/src/keeper/Market.ts index 2a18de1..b99fa57 100644 --- a/src/keeper/Market.ts +++ b/src/keeper/Market.ts @@ -13,7 +13,7 @@ export default class OceanMarket extends ContractBase { // call functions (costs no gas) public async isAssetActive(assetId: string): Promise { - return this.call("checkAsset", [assetId]) + return this.call("checkAsset", ["0x" + assetId]) } public async verifyOrderPayment(orderId: string): Promise { @@ -21,7 +21,7 @@ export default class OceanMarket extends ContractBase { } public async getAssetPrice(assetId: string): Promise { - return this.call("getAssetPrice", [assetId]) + return this.call("getAssetPrice", ["0x" + assetId]) .then((price: string) => new BigNumber(price).toNumber()) } @@ -34,7 +34,7 @@ export default class OceanMarket extends ContractBase { } public async register(assetId: string, price: number, publisherAddress: string): Promise { - return this.sendTransaction("register", publisherAddress, [assetId, price]) + return this.sendTransaction("register", publisherAddress, ["0x" + assetId, price]) } public async payOrder(order: Order, publisherAddress: string, diff --git a/src/keeper/Web3Provider.ts b/src/keeper/Web3Provider.ts index 6bc5901..5f92759 100644 --- a/src/keeper/Web3Provider.ts +++ b/src/keeper/Web3Provider.ts @@ -1,8 +1,5 @@ import * as Web3 from "web3" import ConfigProvider from "../ConfigProvider" -import Logger from "../utils/Logger" - -Logger.log("using web3", Web3.version) export default class Web3Provider { diff --git a/src/ocean/IdGenerator.ts b/src/ocean/IdGenerator.ts new file mode 100644 index 0000000..24a555b --- /dev/null +++ b/src/ocean/IdGenerator.ts @@ -0,0 +1,8 @@ +import * as v4 from "uuid/v4" + +export default class IdGenerator { + public static generateId(): string { + const id = `${v4()}${v4()}` + return id.replace(/-/g, "") + } +} diff --git a/src/ocean/Ocean.ts b/src/ocean/Ocean.ts index 914c0ff..d4dbad7 100644 --- a/src/ocean/Ocean.ts +++ b/src/ocean/Ocean.ts @@ -8,6 +8,7 @@ import Logger from "../utils/Logger" import Account from "./Account" import Asset from "./Asset" import Order from "./Order" +import IdGenerator from "./IdGenerator" export default class Ocean { @@ -15,7 +16,6 @@ export default class Ocean { if (!Ocean.instance) { ConfigProvider.setConfig(config) - SecretStoreProvider.configure(config) Ocean.instance = new Ocean(await Keeper.getInstance()) } @@ -42,12 +42,8 @@ export default class Ocean { const secretStore = SecretStoreProvider.getSecretStore() - const id = Math.random().toString(10) - Logger.log("id", id) + const assetId = IdGenerator.generateId() - const assetId = (await market.generateId(id)).replace("0x", "") - - Logger.log(assetId.length) const encryptedDocument = await secretStore.encryptDocument(assetId, asset) const decryptedDocument = await secretStore.decryptDocument(assetId, encryptedDocument) diff --git a/src/secretstore/SecretStoreProvider.ts b/src/secretstore/SecretStoreProvider.ts index 3226436..45007cb 100644 --- a/src/secretstore/SecretStoreProvider.ts +++ b/src/secretstore/SecretStoreProvider.ts @@ -1,24 +1,21 @@ import SecretStore from "@oceanprotocol/secret-store-client" +import ConfigProvider from "../ConfigProvider" export default class SecretStoreProvider { + public static setSecretStore(secretStore: SecretStore) { + + SecretStoreProvider.secretStore = secretStore + } + public static getSecretStore() { if (!SecretStoreProvider.secretStore) { - SecretStoreProvider.secretStore = new SecretStore(SecretStoreProvider.config) + SecretStoreProvider.secretStore = new SecretStore(ConfigProvider.getConfig()) } return SecretStoreProvider.secretStore } - public static configure(config: { - secretStoreUri: string, parityUri: string, - address: string, password: string, threshold?: number, - }) { - - SecretStoreProvider.config = config - } - - private static config: any private static secretStore: SecretStore } diff --git a/test/aquarius/Aquarius.test.ts b/test/aquarius/Aquarius.test.ts index 9a4529e..5509b5d 100644 --- a/test/aquarius/Aquarius.test.ts +++ b/test/aquarius/Aquarius.test.ts @@ -4,30 +4,32 @@ import AquariusConnectorProvider from "../../src/aquarius/AquariusConnectorProvi import config from "../config" import AquariusConnectorMock from "../mocks/AquariusConnector.mock" -before(() => { - AquariusConnectorProvider.setConnector(new AquariusConnectorMock()) -}) - describe("Aquarius", () => { - describe("#queryMetadata()", async () => { + before(() => { + AquariusConnectorProvider.setConnector(new AquariusConnectorMock()) + }) - const aquarius: Aquarius = new Aquarius(config) + describe("#queryMetadata()", () => { - const query = { - offset: 100, - page: 0, - query: { - value: 1, - }, - sort: { - value: 1, - }, - text: "Office", - } + it("should query metadata", async () => { + const aquarius: Aquarius = new Aquarius(config) - const result: any[] = await aquarius.queryMetadata(query) - assert(result) + const query = { + offset: 100, + page: 0, + query: { + value: 1, + }, + sort: { + value: 1, + }, + text: "Office", + } + + const result: any[] = await aquarius.queryMetadata(query) + assert(result) + }) }) }) diff --git a/test/mocks/SecretStore.mock.ts b/test/mocks/SecretStore.mock.ts new file mode 100644 index 0000000..8b6ca6e --- /dev/null +++ b/test/mocks/SecretStore.mock.ts @@ -0,0 +1,16 @@ +import SecretStore from "@oceanprotocol/secret-store-client" + +export default class SecretStoreMock extends SecretStore { + + public async encryptDocument(documentId, document: any) { + + return "0x283asdgahd1t371t23h" + } + + public async decryptDocument(documentId, encryptedDocument: any) { + + return { + doc: "test", + } + } +} diff --git a/test/ocean/IdGenerator.test.ts b/test/ocean/IdGenerator.test.ts new file mode 100644 index 0000000..2154bee --- /dev/null +++ b/test/ocean/IdGenerator.test.ts @@ -0,0 +1,26 @@ +import * as assert from "assert" +import IdGenerator from "../../src/ocean/IdGenerator" + +describe("IdGenerator", () => { + + describe("#generateId()", () => { + + it("should generate an id", async () => { + + const id = IdGenerator.generateId() + assert(id) + }) + + it("should generate an id that is 64 chars long", async () => { + + const id: string = IdGenerator.generateId() + assert(id.length === 64, id) + }) + + it("should not contain -", async () => { + + const id: string = IdGenerator.generateId() + assert(id.indexOf("-") === -1) + }) + }) +}) diff --git a/test/ocean/Ocean.test.ts b/test/ocean/Ocean.test.ts index 905a0ef..7a9df7f 100644 --- a/test/ocean/Ocean.test.ts +++ b/test/ocean/Ocean.test.ts @@ -6,8 +6,10 @@ import Account from "../../src/ocean/Account" import Asset from "../../src/ocean/Asset" import Ocean from "../../src/ocean/Ocean" import Order from "../../src/ocean/Order" +import SecretStoreProvider from "../../src/secretstore/SecretStoreProvider" import config from "../config" import AquariusMock from "../mocks/Aquarius.mock" +import SecretStoreMock from "../mocks/SecretStore.mock" let ocean: Ocean let accounts: Account[] @@ -24,6 +26,7 @@ describe("Ocean", () => { before(async () => { ConfigProvider.setConfig(config) AquariusProvider.setAquarius(new AquariusMock(config)) + SecretStoreProvider.setSecretStore(new SecretStoreMock(config)) await ContractHandler.deployContracts() ocean = await Ocean.getInstance(config) accounts = await ocean.getAccounts() @@ -62,10 +65,9 @@ describe("Ocean", () => { const assetId: string = await ocean.register(testAsset) - assert(assetId.length === 66) - assert(assetId.startsWith("0x")) + assert(assetId.length === 64) + assert(!assetId.startsWith("0x")) }) - }) describe("#getOrdersByConsumer()", () => { From 61d27e082edce4fe8178291957e26a42a8b04ac2 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Fri, 26 Oct 2018 13:46:47 +0200 Subject: [PATCH 18/38] optimize import --- src/ocean/Ocean.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ocean/Ocean.ts b/src/ocean/Ocean.ts index d4dbad7..dcd275b 100644 --- a/src/ocean/Ocean.ts +++ b/src/ocean/Ocean.ts @@ -7,8 +7,8 @@ import SecretStoreProvider from "../secretstore/SecretStoreProvider" import Logger from "../utils/Logger" import Account from "./Account" import Asset from "./Asset" -import Order from "./Order" import IdGenerator from "./IdGenerator" +import Order from "./Order" export default class Ocean { From 4629c6f4ccf0b429bb0be92f3ee63ce9b45b9fd7 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Fri, 26 Oct 2018 13:53:57 +0200 Subject: [PATCH 19/38] added secret store mock --- test/ocean/Asset.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/ocean/Asset.test.ts b/test/ocean/Asset.test.ts index 1554a03..e7e41cd 100644 --- a/test/ocean/Asset.test.ts +++ b/test/ocean/Asset.test.ts @@ -8,6 +8,8 @@ import Ocean from "../../src/ocean/Ocean" import Order from "../../src/ocean/Order" import config from "../config" import AquariusMock from "../mocks/Aquarius.mock" +import SecretStoreProvider from "../../src/secretstore/SecretStoreProvider" +import SecretStoreMock from "../mocks/SecretStore.mock" const testName = "Test Asset 2" const testDescription = "This asset is pure owange" @@ -24,7 +26,7 @@ describe("Asset", () => { before(async () => { ConfigProvider.setConfig(config) AquariusProvider.setAquarius(new AquariusMock(config)) - + SecretStoreProvider.setSecretStore(new SecretStoreMock(config)) await ContractHandler.deployContracts() ocean = await Ocean.getInstance(config) accounts = await ocean.getAccounts() From bb6de972eb2091fd9e1100373c479d4ad43be758 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Mon, 29 Oct 2018 10:53:22 +0100 Subject: [PATCH 20/38] added business objects form DIDRegistry and ServieAgreement, Added tests for DIDRegistry --- src/keeper/ContractHandler.ts | 2 + src/keeper/Keeper.ts | 9 +- src/keeper/{ => contracts}/Auth.ts | 12 +-- src/keeper/{ => contracts}/ContractBase.ts | 9 +- src/keeper/contracts/DIDRegistry.ts | 37 ++++++++ src/keeper/{ => contracts}/Market.ts | 8 +- src/keeper/contracts/ServiceAgreement.ts | 10 ++ src/keeper/{ => contracts}/Token.ts | 2 +- src/models/ValueType.ts | 8 ++ test/keeper/DIDRegistry.test.ts | 101 +++++++++++++++++++++ test/mocks/ContractBase.Mock.ts | 4 +- 11 files changed, 182 insertions(+), 20 deletions(-) rename src/keeper/{ => contracts}/Auth.ts (79%) rename src/keeper/{ => contracts}/ContractBase.ts (91%) create mode 100644 src/keeper/contracts/DIDRegistry.ts rename src/keeper/{ => contracts}/Market.ts (84%) create mode 100644 src/keeper/contracts/ServiceAgreement.ts rename src/keeper/{ => contracts}/Token.ts (88%) create mode 100644 src/models/ValueType.ts create mode 100644 test/keeper/DIDRegistry.test.ts diff --git a/src/keeper/ContractHandler.ts b/src/keeper/ContractHandler.ts index 06eed98..07fd85f 100644 --- a/src/keeper/ContractHandler.ts +++ b/src/keeper/ContractHandler.ts @@ -50,6 +50,8 @@ export default class ContractHandler { const market = await ContractHandler.deployContract("OceanMarket", deployerAddress, { args: [token.options.address], }) + await ContractHandler.deployContract("ServiceAgreement", deployerAddress, {}) + await ContractHandler.deployContract("DIDRegistry", deployerAddress, {}) /* not part of trilobite const dispute = await ContractHandler.deployContract("OceanDispute", deployerAddress, { args: [market.options.address, registry.options.address, plcrVoting.options.address], diff --git a/src/keeper/Keeper.ts b/src/keeper/Keeper.ts index 2af79aa..26383e9 100644 --- a/src/keeper/Keeper.ts +++ b/src/keeper/Keeper.ts @@ -1,6 +1,7 @@ -import OceanAuth from "./Auth" -import OceanMarket from "./Market" -import OceanToken from "./Token" +import OceanAuth from "./contracts/Auth" +import OceanMarket from "./contracts/Market" +import ServiceAgreement from "./contracts/ServiceAgreement" +import OceanToken from "./contracts/Token" import Web3Provider from "./Web3Provider" export default class Keeper { @@ -13,6 +14,7 @@ export default class Keeper { Keeper.instance.market = await OceanMarket.getInstance() Keeper.instance.auth = await OceanAuth.getInstance() Keeper.instance.token = await OceanToken.getInstance() + Keeper.instance.serviceAgreement = await ServiceAgreement.getInstance() } return Keeper.instance } @@ -22,6 +24,7 @@ export default class Keeper { public token: OceanToken public market: OceanMarket public auth: OceanAuth + public serviceAgreement: ServiceAgreement public async getNetworkName(): Promise { return Web3Provider.getWeb3().eth.net.getId() diff --git a/src/keeper/Auth.ts b/src/keeper/contracts/Auth.ts similarity index 79% rename from src/keeper/Auth.ts rename to src/keeper/contracts/Auth.ts index b4d9d14..92d8b58 100644 --- a/src/keeper/Auth.ts +++ b/src/keeper/contracts/Auth.ts @@ -1,7 +1,7 @@ import {Receipt} from "web3-utils" -import AccessStatus from "../models/AccessStatus" -import Asset from "../ocean/Asset" -import Order from "../ocean/Order" +import AccessStatus from "../../models/AccessStatus" +import Asset from "../../ocean/Asset" +import Order from "../../ocean/Order" import ContractBase from "./ContractBase" export default class OceanAuth extends ContractBase { @@ -28,12 +28,12 @@ export default class OceanAuth extends ContractBase { public async initiateAccessRequest(asset: Asset, publicKey: string, timeout: number, buyerAddress: string): Promise { const args = ["0x" + asset.getId(), asset.publisher.getId(), publicKey, timeout] - return this.sendTransaction("initiateAccessRequest", buyerAddress, args) + return this.send("initiateAccessRequest", buyerAddress, args) } public async commitAccessRequest(order: Order, publisherAddress: string) { const args = [order.getId(), true, 9999999999, "discovery", "read", "slaLink", "slaType"] - return this.sendTransaction("commitAccessRequest", publisherAddress, args) + return this.send("commitAccessRequest", publisherAddress, args) } public async getTempPubKey(orderId: string) { @@ -41,7 +41,7 @@ export default class OceanAuth extends ContractBase { } public async deliverAccessToken(orderId: string, accessToken: string, publisherAddress: string) { - return this.sendTransaction("deliverAccessToken", publisherAddress, [orderId, accessToken]) + return this.send("deliverAccessToken", publisherAddress, [orderId, accessToken]) } } diff --git a/src/keeper/ContractBase.ts b/src/keeper/contracts/ContractBase.ts similarity index 91% rename from src/keeper/ContractBase.ts rename to src/keeper/contracts/ContractBase.ts index 6b43717..e8c92a9 100644 --- a/src/keeper/ContractBase.ts +++ b/src/keeper/contracts/ContractBase.ts @@ -1,7 +1,8 @@ import Event from "web3" import Contract from "web3-eth-contract" -import Logger from "../utils/Logger" -import ContractHandler from "./ContractHandler" +import {Receipt} from "web3-utils" +import Logger from "../../utils/Logger" +import ContractHandler from "../ContractHandler" export default abstract class ContractBase { @@ -45,7 +46,7 @@ export default abstract class ContractBase { this.contract = await ContractHandler.get(this.contractName) } - protected async sendTransaction(name: string, from: string, args: any[]) { + protected async send(name: string, from: string, args: any[]): Promise { if (!this.contract.methods[name]) { throw new Error(`Method ${name} is not part of contract ${this.contractName}`) } @@ -66,7 +67,7 @@ export default abstract class ContractBase { } } - protected async call(name: string, args: any[], from?: string) { + protected async call(name: string, args: any[], from?: string): Promise { if (!this.contract.methods[name]) { throw new Error(`Method ${name} is not part of contract ${this.contractName}`) } diff --git a/src/keeper/contracts/DIDRegistry.ts b/src/keeper/contracts/DIDRegistry.ts new file mode 100644 index 0000000..05c23c6 --- /dev/null +++ b/src/keeper/contracts/DIDRegistry.ts @@ -0,0 +1,37 @@ +import {Receipt} from "web3-utils" +import ValueType from "../../models/ValueType" +import ContractBase from "./ContractBase" + +export default class DIDRegistry extends ContractBase { + + public static async getInstance(): Promise { + const didRegistry: DIDRegistry = new DIDRegistry("DIDRegistry") + await didRegistry.init() + return didRegistry + } + + public async registerAttribute(did: string, type: ValueType, key: string, + value: string, ownerAddress: string): Promise { + + return this.send("registerAttribute", + ownerAddress, ["0x" + did, type, key, value], + ) + } + + public async getOwner(did: string): Promise { + + return this.call("getOwner", + ["0x" + did], + ) + } + + public async getUpdateAt(did: string): Promise { + + const blockNum = await this.call("getUpdateAt", + ["0x" + did], + ) + + return parseInt(blockNum, 10) + } + +} diff --git a/src/keeper/Market.ts b/src/keeper/contracts/Market.ts similarity index 84% rename from src/keeper/Market.ts rename to src/keeper/contracts/Market.ts index b99fa57..bee7d32 100644 --- a/src/keeper/Market.ts +++ b/src/keeper/contracts/Market.ts @@ -1,6 +1,6 @@ import BigNumber from "bignumber.js" import {Receipt} from "web3-utils" -import Order from "../ocean/Order" +import Order from "../../ocean/Order" import ContractBase from "./ContractBase" export default class OceanMarket extends ContractBase { @@ -26,7 +26,7 @@ export default class OceanMarket extends ContractBase { } public async requestTokens(amount: number, receiverAddress: string): Promise { - return this.sendTransaction("requestTokens", receiverAddress, [amount]) + return this.send("requestTokens", receiverAddress, [amount]) } public async generateId(input: string): Promise { @@ -34,13 +34,13 @@ export default class OceanMarket extends ContractBase { } public async register(assetId: string, price: number, publisherAddress: string): Promise { - return this.sendTransaction("register", publisherAddress, ["0x" + assetId, price]) + return this.send("register", publisherAddress, ["0x" + assetId, price]) } public async payOrder(order: Order, publisherAddress: string, price: number, consumerAddress: string, timeout: number): Promise { - return this.sendTransaction("sendPayment", consumerAddress, [ + return this.send("sendPayment", consumerAddress, [ order.getId(), publisherAddress, price, timeout, ]) } diff --git a/src/keeper/contracts/ServiceAgreement.ts b/src/keeper/contracts/ServiceAgreement.ts new file mode 100644 index 0000000..1f3a8c9 --- /dev/null +++ b/src/keeper/contracts/ServiceAgreement.ts @@ -0,0 +1,10 @@ +import ContractBase from "./ContractBase" + +export default class ServiceAgreement extends ContractBase { + + public static async getInstance(): Promise { + const serviceAgreement: ServiceAgreement = new ServiceAgreement("ServiceAgreement") + await serviceAgreement.init() + return serviceAgreement + } +} diff --git a/src/keeper/Token.ts b/src/keeper/contracts/Token.ts similarity index 88% rename from src/keeper/Token.ts rename to src/keeper/contracts/Token.ts index 52e1bc3..1b04255 100644 --- a/src/keeper/Token.ts +++ b/src/keeper/contracts/Token.ts @@ -11,7 +11,7 @@ export default class OceanToken extends ContractBase { } public async approve(marketAddress: string, price: number, buyerAddress: string): Promise { - return this.sendTransaction("approve", buyerAddress, [marketAddress, price]) + return this.send("approve", buyerAddress, [marketAddress, price]) } public async balanceOf(address: string): Promise { diff --git a/src/models/ValueType.ts b/src/models/ValueType.ts new file mode 100644 index 0000000..4310234 --- /dev/null +++ b/src/models/ValueType.ts @@ -0,0 +1,8 @@ +enum ValueType { + DID, // DID string e.g. 'did:op:xxx' + DIDRef, // hash of DID same as in parameter (bytes32 _did) in text 0x0123abc.. or 0123abc.. + URL, // URL string e.g. 'http(s)://xx' + DDO, // DDO string in JSON e.g. '{ "id": "did:op:xxx"... +} + +export default ValueType diff --git a/test/keeper/DIDRegistry.test.ts b/test/keeper/DIDRegistry.test.ts new file mode 100644 index 0000000..86e8469 --- /dev/null +++ b/test/keeper/DIDRegistry.test.ts @@ -0,0 +1,101 @@ +import {assert} from "chai" +import ConfigProvider from "../../src/ConfigProvider" +import ContractHandler from "../../src/keeper/ContractHandler" +import DIDRegistry from "../../src/keeper/contracts/DIDRegistry" +import Web3Provider from "../../src/keeper/Web3Provider" +import ValueType from "../../src/models/ValueType" +import Account from "../../src/ocean/Account" +import IdGenerator from "../../src/ocean/IdGenerator" +import Ocean from "../../src/ocean/Ocean" +import Logger from "../../src/utils/Logger" +import config from "../config" + +let ocean: Ocean +let didRegistry: DIDRegistry + +describe("DIDRegistry", () => { + + before(async () => { + ConfigProvider.setConfig(config) + await ContractHandler.deployContracts() + ocean = await Ocean.getInstance(config) + didRegistry = await DIDRegistry.getInstance() + }) + + describe("#registerAttribute()", () => { + + it("should register an attribute in a new did", async () => { + const ownerAccount: Account = (await ocean.getAccounts())[0] + const did = IdGenerator.generateId() + const providerKey = Web3Provider.getWeb3().utils.fromAscii("provider") + const data = "my nice provider, is nice" + const receipt = await didRegistry.registerAttribute(did, ValueType.DID, providerKey, + data, ownerAccount.getId()) + assert(receipt.status) + assert(receipt.events.DIDAttributeRegistered) + }) + + it("should register another attribute in the same did", async () => { + const ownerAccount: Account = (await ocean.getAccounts())[0] + const did = IdGenerator.generateId() + { + // register the first attribute + const providerKey = Web3Provider.getWeb3().utils.fromAscii("provider") + const data = "my nice provider, is nice" + await didRegistry.registerAttribute(did, ValueType.DID, providerKey, + data, ownerAccount.getId()) + } + { + // register the second attribute with the same did + const providerKey = Web3Provider.getWeb3().utils.fromAscii("provider2") + const data = "asdsad" + const receipt = await didRegistry.registerAttribute(did, ValueType.DID, providerKey, + data, ownerAccount.getId()) + assert(receipt.status) + assert(receipt.events.DIDAttributeRegistered) + } + }) + + }) + + describe("#getOwner()", () => { + + it("should get the owner of a did properly", async () => { + const ownerAccount: Account = (await ocean.getAccounts())[0] + const did = IdGenerator.generateId() + const providerKey = Web3Provider.getWeb3().utils.fromAscii("provider") + const data = "my nice provider, is nice" + await didRegistry.registerAttribute(did, ValueType.DID, providerKey, + data, ownerAccount.getId()) + + const owner = await didRegistry.getOwner(did) + + assert(owner === ownerAccount.getId(), `Got ${owner} but expected ${ownerAccount.getId()}`) + }) + + it("should get 0x00.. for a not registered did", async () => { + const owner = await didRegistry.getOwner("1234") + assert(owner === "0x0000000000000000000000000000000000000000") + }) + + }) + + describe("#getUpdateAt()", () => { + + it("should the block number of the last update of the did attribute", async () => { + const ownerAccount: Account = (await ocean.getAccounts())[0] + const did = IdGenerator.generateId() + const providerKey = Web3Provider.getWeb3().utils.fromAscii("provider") + const data = "my nice provider, is nice" + await didRegistry.registerAttribute(did, ValueType.DID, providerKey, + data, ownerAccount.getId()) + + const updatedAt: number = await didRegistry.getUpdateAt(did) + + assert(updatedAt > 0) + Logger.log(typeof updatedAt) + }) + + }) + +}) diff --git a/test/mocks/ContractBase.Mock.ts b/test/mocks/ContractBase.Mock.ts index e956ef5..1dbef96 100644 --- a/test/mocks/ContractBase.Mock.ts +++ b/test/mocks/ContractBase.Mock.ts @@ -1,4 +1,4 @@ -import ContractBase from "../../src/keeper/ContractBase" +import ContractBase from "../../src/keeper/contracts/ContractBase" export default class ContractBaseMock extends ContractBase { public async initMock() { @@ -10,6 +10,6 @@ export default class ContractBaseMock extends ContractBase { } public async sendMock(name: string, from: string, args: any[]) { - return this.sendTransaction(name, from, args) + return this.send(name, from, args) } } From df56556e87d3e93acca78636b173eaf30b5a7ec3 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Mon, 29 Oct 2018 17:28:40 +0100 Subject: [PATCH 21/38] added serviceAgreementTemplates, wip --- package-lock.json | 8 +- package.json | 2 +- src/keeper/ContractHandler.ts | 14 +++- src/keeper/contracts/ContractBase.ts | 23 +++++- src/keeper/contracts/ServiceAgreement.ts | 23 ++++++ .../contracts/conditions/AccessConditions.ts | 10 +++ .../contracts/conditions/PaymentConditions.ts | 10 +++ src/ocean/ServiceAgreement.ts | 73 +++++++++++++++++++ src/ocean/ServiceAgreementTemplate.ts | 67 +++++++++++++++++ test/keeper/ContractBase.test.ts | 31 +++++++- test/mocks/ContractBase.Mock.ts | 2 +- test/ocean/ServiceAgreement.test.ts | 56 ++++++++++++++ test/ocean/ServiceAgreementTemplate.test.ts | 34 +++++++++ 13 files changed, 341 insertions(+), 12 deletions(-) create mode 100644 src/keeper/contracts/conditions/AccessConditions.ts create mode 100644 src/keeper/contracts/conditions/PaymentConditions.ts create mode 100644 src/ocean/ServiceAgreement.ts create mode 100644 src/ocean/ServiceAgreementTemplate.ts create mode 100644 test/ocean/ServiceAgreement.test.ts create mode 100644 test/ocean/ServiceAgreementTemplate.test.ts diff --git a/package-lock.json b/package-lock.json index 45e0a19..c26eb70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -120,9 +120,9 @@ } }, "@oceanprotocol/keeper-contracts": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.3.3.tgz", - "integrity": "sha512-UVt9m9WmFm4mTDWmMekT8lhBh2hWr2baEVnF0dEN3OL5BDAWoynFQeeKtUqTepVuOVgNy5bHYKLiHkCWzbOEqA==" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.4.1.tgz", + "integrity": "sha512-UmgPsJul9ZJb5BPIa1qfMpokJWzdROni/wisd4Dnm+wwHUA7/ymsr34zVn+4v+uAcMLHAYPKbsROBT5xlbiKAQ==" }, "@oceanprotocol/secret-store-client": { "version": "0.0.6", @@ -1802,7 +1802,7 @@ }, "es6-promisify": { "version": "5.0.0", - "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "requires": { "es6-promise": "^4.0.3" diff --git a/package.json b/package.json index 905d722..8e19883 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "node": ">=8 <10" }, "dependencies": { - "@oceanprotocol/keeper-contracts": "^0.3.3", + "@oceanprotocol/keeper-contracts": "^0.4.1", "@oceanprotocol/secret-store-client": "^0.0.6", "bignumber.js": "^7.2.1", "eth-crypto": "^1.2.4", diff --git a/src/keeper/ContractHandler.ts b/src/keeper/ContractHandler.ts index 07fd85f..29e3eae 100644 --- a/src/keeper/ContractHandler.ts +++ b/src/keeper/ContractHandler.ts @@ -50,7 +50,19 @@ export default class ContractHandler { const market = await ContractHandler.deployContract("OceanMarket", deployerAddress, { args: [token.options.address], }) - await ContractHandler.deployContract("ServiceAgreement", deployerAddress, {}) + + const sa = await ContractHandler.deployContract("ServiceAgreement", deployerAddress, { + args: [], + + }) + await ContractHandler.deployContract("AccessConditions", deployerAddress, { + args: [sa.options.address], + }) + + await ContractHandler.deployContract("PaymentConditions", deployerAddress, { + args: [sa.options.address, token.options.address], + }) + await ContractHandler.deployContract("DIDRegistry", deployerAddress, {}) /* not part of trilobite const dispute = await ContractHandler.deployContract("OceanDispute", deployerAddress, { diff --git a/src/keeper/contracts/ContractBase.ts b/src/keeper/contracts/ContractBase.ts index e8c92a9..d53e79a 100644 --- a/src/keeper/contracts/ContractBase.ts +++ b/src/keeper/contracts/ContractBase.ts @@ -33,7 +33,7 @@ export default abstract class ContractBase { public async getEventData(eventName: any, options: any): Promise { if (!this.contract.events[eventName]) { - throw new Error(`Event ${eventName} not found on contract ${this.contractName}`) + throw new Error(`Event "${eventName}" not found on contract "${this.contractName}"`) } return this.contract.getPastEvents(eventName, options) } @@ -42,13 +42,28 @@ export default abstract class ContractBase { return this.contract.options.address } + public getSignatureOfMethod(methodName: string): string { + + const foundMethod = this.contract.options.jsonInterface.find((method) => { + if (method.name === methodName) { + return method + } + }) + + if (!foundMethod) { + throw new Error(`Method "${methodName}" is not part of contract "${this.contractName}"`) + } + + return foundMethod.signature + } + protected async init() { this.contract = await ContractHandler.get(this.contractName) } protected async send(name: string, from: string, args: any[]): Promise { if (!this.contract.methods[name]) { - throw new Error(`Method ${name} is not part of contract ${this.contractName}`) + throw new Error(`Method "${name}" is not part of contract "${this.contractName}"`) } try { const tx = this.contract.methods[name](...args) @@ -61,7 +76,7 @@ export default abstract class ContractBase { }) } catch (err) { const argString = JSON.stringify(args, null, 2) - Logger.error(`Sending transaction ${name} on contract ${this.contractName} failed.`) + Logger.error(`Sending transaction "${name}" on contract "${this.contractName}" failed.`) Logger.error(`Args: ${argString} From: ${from}`) throw err } @@ -75,7 +90,7 @@ export default abstract class ContractBase { const method = this.contract.methods[name](...args) return method.call(from ? {from} : null) } catch (err) { - Logger.error(`Calling method ${name} on contract ${this.contractName} failed. Args: ${args}`, err) + Logger.error(`Calling method "${name}" on contract "${this.contractName}" failed. Args: ${args}`, err) throw err } } diff --git a/src/keeper/contracts/ServiceAgreement.ts b/src/keeper/contracts/ServiceAgreement.ts index 1f3a8c9..b110574 100644 --- a/src/keeper/contracts/ServiceAgreement.ts +++ b/src/keeper/contracts/ServiceAgreement.ts @@ -1,3 +1,4 @@ +import {Receipt} from "web3-utils" import ContractBase from "./ContractBase" export default class ServiceAgreement extends ContractBase { @@ -7,4 +8,26 @@ export default class ServiceAgreement extends ContractBase { await serviceAgreement.init() return serviceAgreement } + + public async setupAgreementTemplate(contractAddresses: any[], contractFunctionSignatures: string[], + depencyMatrix: number[], name: any, ownerAddress: string): Promise { + + return this.send("setupAgreementTemplate", ownerAddress, [ + contractAddresses, contractFunctionSignatures, depencyMatrix, name, + ]) + } + + public async getAgreementStatus(agreementId: string) { + + return this.call("getAgreementStatus", [agreementId]) + } + + public async executeAgreement(templateId: string, signature: string, consumerAddress: string, valueHashes: string[], + timeoutValues: number[], serviceDefinitionId: string, did: string, + publisherAddress: string): Promise { + + return this.send("executeAgreement", publisherAddress, [ + templateId, signature, consumerAddress, valueHashes, timeoutValues, serviceDefinitionId, "0x" + did, + ]) + } } diff --git a/src/keeper/contracts/conditions/AccessConditions.ts b/src/keeper/contracts/conditions/AccessConditions.ts new file mode 100644 index 0000000..973287a --- /dev/null +++ b/src/keeper/contracts/conditions/AccessConditions.ts @@ -0,0 +1,10 @@ +import ContractBase from "../ContractBase" + +export default class AccessConditions extends ContractBase { + + public static async getInstance(): Promise { + const accessConditions: AccessConditions = new AccessConditions("AccessConditions") + await accessConditions.init() + return accessConditions + } +} diff --git a/src/keeper/contracts/conditions/PaymentConditions.ts b/src/keeper/contracts/conditions/PaymentConditions.ts new file mode 100644 index 0000000..75d7960 --- /dev/null +++ b/src/keeper/contracts/conditions/PaymentConditions.ts @@ -0,0 +1,10 @@ +import ContractBase from "../ContractBase" + +export default class PaymentConditions extends ContractBase { + + public static async getInstance(): Promise { + const paymentConditions: PaymentConditions = new PaymentConditions("PaymentConditions") + await paymentConditions.init() + return paymentConditions + } +} diff --git a/src/ocean/ServiceAgreement.ts b/src/ocean/ServiceAgreement.ts new file mode 100644 index 0000000..7862d91 --- /dev/null +++ b/src/ocean/ServiceAgreement.ts @@ -0,0 +1,73 @@ +import ServiceAgreementContract from "../keeper/contracts/ServiceAgreement" +import Web3Provider from "../keeper/Web3Provider" +import Account from "./Account" +import OceanBase from "./OceanBase" +import ServiceAgreementTemplate from "./ServiceAgreementTemplate" + +export default class ServiceAgreement extends OceanBase { + + public static async executeServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, + did: string, consumer: Account): Promise { + + const valHashList = [ + ServiceAgreement.valueHash("bool", true), + ServiceAgreement.valueHash("bool", false), + ServiceAgreement.valueHash("uint", 120), + // asset Id: 797FD5B9045B841FDFF72 + ServiceAgreement.valueHash("string", "797FD5B9045B841FDFF72"), + ] + + const serviceDefinitionId = "0x515f158c3a5d81d15b0160cf8929916089218bdb4aa78c3ecd16633afd44b894" + + const timeoutValues = [0, 0, 0, 3] // timeout 5 blocks @ condition 4 + + const saMerkleRoot = ServiceAgreement.merkelizeServiceAgreement(serviceAgreementTemplate, valHashList, + timeoutValues, serviceDefinitionId, did) + const saMerkleRootSignature = await Web3Provider.getWeb3().eth.sign(saMerkleRoot, consumer.getId()) + + const serviceAgreement: ServiceAgreementContract = await ServiceAgreementContract.getInstance() + + const receipt = await serviceAgreement.executeAgreement( + serviceAgreementTemplate.getId(), saMerkleRootSignature, consumer.getId(), valHashList, timeoutValues, + serviceDefinitionId, did, serviceAgreementTemplate.getPublisher().getId()) + + const id = receipt.events.ExecuteAgreement.returnValues.serviceId + return new ServiceAgreement( + id, + receipt.events.ExecuteAgreement.returnValues.templateId, + receipt.events.ExecuteAgreement.returnValues.templateOwner, + receipt.events.ExecuteAgreement.returnValues.consumer, + receipt.events.ExecuteAgreement.returnValues.state, + receipt.events.ExecuteAgreement.returnValues.status, + ) + } + + protected static valueHash(type: string, value: any) { + const args = {type, value} + return Web3Provider.getWeb3().utils.soliditySha3(args).toString("hex") + } + + private static merkelizeServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, valueHashes: string[], + timeouts: number[], serviceDefinitionId: string, did: string) { + const args = [ + {type: "bytes32", value: serviceAgreementTemplate.getId()}, + {type: "bytes32[]", value: serviceAgreementTemplate.getConditionKeys()}, + {type: "bytes32[]", value: valueHashes}, + {type: "uint256[]", value: timeouts}, + {type: "bytes32", value: serviceDefinitionId}, + {type: "bytes32", value: did}, + ] + return Web3Provider.getWeb3().utils.soliditySha3(...args).toString("hex") + } + + private constructor(id: string, templateId: string, templateOwnerId: string, + consumerId: string, state: boolean, status: boolean) { + super(id) + } + + public async getStatus() { + const sa = await ServiceAgreementContract.getInstance() + + return sa.getAgreementStatus(this.getId()) + } +} diff --git a/src/ocean/ServiceAgreementTemplate.ts b/src/ocean/ServiceAgreementTemplate.ts new file mode 100644 index 0000000..4f14c7b --- /dev/null +++ b/src/ocean/ServiceAgreementTemplate.ts @@ -0,0 +1,67 @@ +import AccessConditions from "../keeper/contracts/conditions/AccessConditions" +import PaymentConditions from "../keeper/contracts/conditions/PaymentConditions" +import ServiceAgreement from "../keeper/contracts/ServiceAgreement" +import Web3Provider from "../keeper/Web3Provider" +import Account from "./Account" +import OceanBase from "./OceanBase" + +export default class ServiceAgreementTemplate extends OceanBase { + + public static async registerServiceAgreementsTemplate(resourceName: string, publisher: Account): + Promise { + + const paymentConditions: PaymentConditions = await PaymentConditions.getInstance() + const accessConditions: AccessConditions = await AccessConditions.getInstance() + + const contractAddresses = [ + await paymentConditions.getAddress(), + await accessConditions.getAddress(), + await paymentConditions.getAddress(), + await paymentConditions.getAddress(), + ] + const functionSignatures = [ + await paymentConditions.getSignatureOfMethod("lockPayment"), + await accessConditions.getSignatureOfMethod("grantAccess"), + await paymentConditions.getSignatureOfMethod("releasePayment"), + await paymentConditions.getSignatureOfMethod("refundPayment"), + ] + + const dependencies = [0, 1, 4, 1 | 2 ** 4 | 2 ** 5] // dependency bit | timeout bit + + const serviceAgreement: ServiceAgreement = await ServiceAgreement.getInstance() + + const receipt = await serviceAgreement.setupAgreementTemplate( + contractAddresses, functionSignatures, dependencies, + Web3Provider.getWeb3().utils.fromAscii(resourceName), publisher.getId()) + + const id = receipt.events.SetupAgreementTemplate.returnValues.serviceTemplateId + + return new ServiceAgreementTemplate( + id, + ServiceAgreementTemplate.generateConditionsKeys(id, contractAddresses, functionSignatures), + publisher) + } + + private static generateConditionsKeys(serviceAgreementTemplateId: string, contractAddresses: string[], + functionSignatures: string[]): string[] { + const conditions = [] + for (let i = 0; i < contractAddresses.length; i++) { + const types = ["bytes32", "address", "bytes4"] + const values = [serviceAgreementTemplateId, contractAddresses[i], functionSignatures[i]] + conditions.push(Web3Provider.getWeb3().utils.soliditySha3(...types, ...values).toString("hex")) + } + return conditions + } + + private constructor(id, private conditionKeys: string[], private publisher: Account) { + super(id) + } + + public getPublisher(): Account { + return this.publisher + } + + public getConditionKeys(): string[] { + return this.conditionKeys + } +} diff --git a/test/keeper/ContractBase.test.ts b/test/keeper/ContractBase.test.ts index b620dda..2506356 100644 --- a/test/keeper/ContractBase.test.ts +++ b/test/keeper/ContractBase.test.ts @@ -1,16 +1,22 @@ +import {assert} from "chai" import ConfigProvider from "../../src/ConfigProvider" import ContractHandler from "../../src/keeper/ContractHandler" +import Account from "../../src/ocean/Account" +import Ocean from "../../src/ocean/Ocean" import config from "../config" import ContractBaseMock from "../mocks/ContractBase.Mock" const wrappedContract = new ContractBaseMock("OceanToken") +let accounts: Account[] describe("ContractWrapperBase", () => { before(async () => { ConfigProvider.setConfig(config) await ContractHandler.deployContracts() - wrappedContract.initMock() + await wrappedContract.initMock() + const ocean: Ocean = await Ocean.getInstance(config) + accounts = await ocean.getAccounts() }) describe("#call()", () => { @@ -52,6 +58,29 @@ describe("ContractWrapperBase", () => { }) }) + describe("#send()", () => { + + it("should fail to call on an unknown contract function", (done) => { + + wrappedContract.sendMock("transferxxx", accounts[0].getId(), []) + .catch(() => { + + done() + }) + }) + }) + + describe("#getSignatureOfMethod()", () => { + + it("should a signature of the function", async () => { + + const sig = wrappedContract.getSignatureOfMethod("name") + assert(sig) + assert(typeof sig === "string") + assert(sig.startsWith("0x")) + }) + }) + describe("#getEventData()", () => { it("should fail on unknown event", (done) => { diff --git a/test/mocks/ContractBase.Mock.ts b/test/mocks/ContractBase.Mock.ts index 1dbef96..7d756f8 100644 --- a/test/mocks/ContractBase.Mock.ts +++ b/test/mocks/ContractBase.Mock.ts @@ -2,7 +2,7 @@ import ContractBase from "../../src/keeper/contracts/ContractBase" export default class ContractBaseMock extends ContractBase { public async initMock() { - this.init() + await this.init() } public async callMock(name: string, args: any[], from?: string) { diff --git a/test/ocean/ServiceAgreement.test.ts b/test/ocean/ServiceAgreement.test.ts new file mode 100644 index 0000000..56e6ce2 --- /dev/null +++ b/test/ocean/ServiceAgreement.test.ts @@ -0,0 +1,56 @@ +import {assert} from "chai" +import ConfigProvider from "../../src/ConfigProvider" +import ContractHandler from "../../src/keeper/ContractHandler" +import Account from "../../src/ocean/Account" +import IdGenerator from "../../src/ocean/IdGenerator" +import Ocean from "../../src/ocean/Ocean" +import ServiceAgreement from "../../src/ocean/ServiceAgreement" +import ServiceAgreementTemplate from "../../src/ocean/ServiceAgreementTemplate" +import config from "../config" +import Logger from "../../src/utils/Logger" + +let ocean: Ocean +let accounts: Account[] +let testServiceAgreementTemplate: ServiceAgreementTemplate + +describe("ServiceAgreement", () => { + + before(async () => { + ConfigProvider.setConfig(config) + await ContractHandler.deployContracts() + ocean = await Ocean.getInstance(config) + accounts = await ocean.getAccounts() + + const publisherAccount = accounts[0] + const resourceName = "superb car data" + testServiceAgreementTemplate = + await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, publisherAccount) + + }) + + describe("#executeServiceAgreement()", () => { + it("should execture an service agreement", async () => { + + const consumerAccount = accounts[0] + const did: string = IdGenerator.generateId() + const serviceAgreement: ServiceAgreement = + await ServiceAgreement.executeServiceAgreement(testServiceAgreementTemplate, did, consumerAccount) + + assert(serviceAgreement) + assert(serviceAgreement.getId().startsWith("0x")) + }) + }) + + describe("#getStatus()", () => { + it("should execture an service agreement", async () => { + + const consumerAccount = accounts[0] + const did: string = IdGenerator.generateId() + const serviceAgreement: ServiceAgreement = + await ServiceAgreement.executeServiceAgreement(testServiceAgreementTemplate, did, consumerAccount) + + const status = await serviceAgreement.getStatus() + Logger.log(status) + }) + }) +}) diff --git a/test/ocean/ServiceAgreementTemplate.test.ts b/test/ocean/ServiceAgreementTemplate.test.ts new file mode 100644 index 0000000..2fc4f87 --- /dev/null +++ b/test/ocean/ServiceAgreementTemplate.test.ts @@ -0,0 +1,34 @@ +import {assert} from "chai" +import ConfigProvider from "../../src/ConfigProvider" +import ContractHandler from "../../src/keeper/ContractHandler" +import Account from "../../src/ocean/Account" +import Ocean from "../../src/ocean/Ocean" +import ServiceAgreementTemplate from "../../src/ocean/ServiceAgreementTemplate" +import config from "../config" + +let ocean: Ocean +let accounts: Account[] + +describe("ServiceAgreementTemplate", () => { + + before(async () => { + ConfigProvider.setConfig(config) + await ContractHandler.deployContracts() + ocean = await Ocean.getInstance(config) + accounts = await ocean.getAccounts() + }) + + describe("#registerServiceAgreementsTemplate()", () => { + it("should setup an agreement template", async () => { + + const publisherAccount = accounts[0] + const resourceName = "test data" + const serviceAgreementTemplate: ServiceAgreementTemplate = + await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, publisherAccount) + assert(serviceAgreementTemplate) + assert(serviceAgreementTemplate.getId()) + assert(serviceAgreementTemplate.getPublisher().getId() === publisherAccount.getId()) + }) + }) + +}) From 123157a30545d8095d8c4ee48500faface676ac6 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Mon, 29 Oct 2018 17:50:06 +0100 Subject: [PATCH 22/38] fix package lock --- package-lock.json | 135 +++++++++++++++++++++++++++++++++------------- package.json | 2 +- 2 files changed, 100 insertions(+), 37 deletions(-) diff --git a/package-lock.json b/package-lock.json index df293a6..4caf40e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/squid", - "version": "0.1.0-beta.16", + "version": "0.1.0-beta.17", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -124,10 +124,19 @@ "resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.4.1.tgz", "integrity": "sha512-UmgPsJul9ZJb5BPIa1qfMpokJWzdROni/wisd4Dnm+wwHUA7/ymsr34zVn+4v+uAcMLHAYPKbsROBT5xlbiKAQ==" }, + "@oceanprotocol/secret-store-client": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.6.tgz", + "integrity": "sha512-dJQ7rWQdAkrM79gvLYrT8vm5ZOrjW7XbQR/d2IBIQNS6t09826wZW3Y9kwaiQvKBUIOI9LhbwVuD4Hc0IuXJnQ==", + "requires": { + "jayson": "^2.0.6", + "node-fetch": "^2.2.0" + } + }, "@types/chai": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.6.tgz", - "integrity": "sha512-CBk7KTZt3FhPsEkYioG6kuCIpWISw+YI8o+3op4+NXwTpvAPxE1ES8+PY8zfaK2L98b1z5oq03UHa4VYpeUxnw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", + "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", "dev": true }, "@types/events": { @@ -382,6 +391,15 @@ "long": "^3.2.0" } }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -1782,6 +1800,21 @@ "resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", + "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==" + } + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1969,6 +2002,11 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "uuid": { + "version": "2.0.1", + "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" } } }, @@ -2240,6 +2278,11 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -2494,13 +2537,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2513,18 +2554,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -2627,8 +2665,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -2638,7 +2675,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2651,20 +2687,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.2.4", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -2681,7 +2714,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -2754,8 +2786,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -2765,7 +2796,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -2871,7 +2901,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3601,6 +3630,28 @@ "is-object": "^1.0.1" } }, + "jayson": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-2.1.0.tgz", + "integrity": "sha512-WQhCph4BgSDbRUPdZYqGMojKMxjzPqCCKmWYMsRWX/Bvh1oP+Irs2upeEJy8flU3ZAZzm68TjuL1X8u9Rt4wWQ==", + "requires": { + "@types/node": "^10.3.5", + "JSONStream": "^1.3.1", + "commander": "^2.12.2", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.10", + "uuid": "^3.2.1" + }, + "dependencies": { + "@types/node": { + "version": "10.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.0.tgz", + "integrity": "sha512-3TUHC3jsBAB7qVRGxT6lWyYo2v96BMmD2PTcl47H25Lu7UXtFH/2qqmKiVrnel6Ne//0TFYf6uvNX+HW2FRkLQ==" + } + } + }, "js-sha3": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", @@ -3667,6 +3718,11 @@ "graceful-fs": "^4.1.6" } }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, "jsonwebtoken": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz", @@ -4336,7 +4392,6 @@ "version": "0.1.4", "bundled": true, "dev": true, - "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -4661,8 +4716,7 @@ "is-buffer": { "version": "1.1.6", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "is-builtin-module": { "version": "1.0.0", @@ -4746,7 +4800,6 @@ "version": "3.2.2", "bundled": true, "dev": true, - "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -4793,8 +4846,7 @@ "longest": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "lru-cache": { "version": "4.1.3", @@ -5060,8 +5112,7 @@ "repeat-string": { "version": "1.6.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "require-directory": { "version": "2.1.1", @@ -7360,9 +7411,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "2.0.1", - "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "v8-compile-cache": { "version": "2.0.2", @@ -7551,6 +7602,13 @@ "setimmediate": "1.0.4", "uuid": "2.0.1", "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "uuid": { + "version": "2.0.1", + "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" + } } }, "hash.js": { @@ -7590,6 +7648,11 @@ "elliptic": "^6.4.0", "xhr-request-promise": "^0.1.2" } + }, + "uuid": { + "version": "2.0.1", + "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" } } }, diff --git a/package.json b/package.json index 8e19883..1183ee0 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "web3-utils": "1.0.0-beta.36" }, "devDependencies": { - "@types/chai": "^4.1.6", + "@types/chai": "^4.1.7", "@types/mocha": "^5.2.5", "@types/node": "^8.10.36", "chai": "^4.2.0", From 9a099ae4039e2b8c4d36572a8eb8a5dd91719934 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Mon, 29 Oct 2018 17:52:46 +0100 Subject: [PATCH 23/38] v0.1.0-beta.18 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4caf40e..f3d217a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/squid", - "version": "0.1.0-beta.17", + "version": "0.1.0-beta.18", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1183ee0..757acf3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/squid", - "version": "0.1.0-beta.17", + "version": "0.1.0-beta.18", "description": "JavaScript client library for Ocean Protocol", "main": "dist/squid.js", "scripts": { From 8b83b29c822ae5e0f88770e663a3571c597fdcb5 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Tue, 30 Oct 2018 08:10:04 +0100 Subject: [PATCH 24/38] ignore line with bitwise operator --- src/ocean/ServiceAgreementTemplate.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ocean/ServiceAgreementTemplate.ts b/src/ocean/ServiceAgreementTemplate.ts index 4f14c7b..22598e1 100644 --- a/src/ocean/ServiceAgreementTemplate.ts +++ b/src/ocean/ServiceAgreementTemplate.ts @@ -26,6 +26,7 @@ export default class ServiceAgreementTemplate extends OceanBase { await paymentConditions.getSignatureOfMethod("refundPayment"), ] + // tslint:disable const dependencies = [0, 1, 4, 1 | 2 ** 4 | 2 ** 5] // dependency bit | timeout bit const serviceAgreement: ServiceAgreement = await ServiceAgreement.getInstance() From 733d93cfbaf15a85795e07410d44ea5d5af9bda3 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Tue, 30 Oct 2018 08:30:05 +0100 Subject: [PATCH 25/38] fix codacy issues --- test/ocean/Asset.test.ts | 2 +- test/ocean/ServiceAgreement.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ocean/Asset.test.ts b/test/ocean/Asset.test.ts index e7e41cd..5118184 100644 --- a/test/ocean/Asset.test.ts +++ b/test/ocean/Asset.test.ts @@ -6,9 +6,9 @@ import Account from "../../src/ocean/Account" import Asset from "../../src/ocean/Asset" import Ocean from "../../src/ocean/Ocean" import Order from "../../src/ocean/Order" +import SecretStoreProvider from "../../src/secretstore/SecretStoreProvider" import config from "../config" import AquariusMock from "../mocks/Aquarius.mock" -import SecretStoreProvider from "../../src/secretstore/SecretStoreProvider" import SecretStoreMock from "../mocks/SecretStore.mock" const testName = "Test Asset 2" diff --git a/test/ocean/ServiceAgreement.test.ts b/test/ocean/ServiceAgreement.test.ts index 56e6ce2..ad89343 100644 --- a/test/ocean/ServiceAgreement.test.ts +++ b/test/ocean/ServiceAgreement.test.ts @@ -6,8 +6,8 @@ import IdGenerator from "../../src/ocean/IdGenerator" import Ocean from "../../src/ocean/Ocean" import ServiceAgreement from "../../src/ocean/ServiceAgreement" import ServiceAgreementTemplate from "../../src/ocean/ServiceAgreementTemplate" -import config from "../config" import Logger from "../../src/utils/Logger" +import config from "../config" let ocean: Ocean let accounts: Account[] From c8fa39b3960093ed9318db56b2d4c13547dc62e0 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Tue, 30 Oct 2018 08:37:30 +0100 Subject: [PATCH 26/38] try to fix codacy problem --- test/ocean/AccessToken.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ocean/AccessToken.json b/test/ocean/AccessToken.json index 242922b..27824c1 100644 --- a/test/ocean/AccessToken.json +++ b/test/ocean/AccessToken.json @@ -1 +1 @@ -"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1Mzk3ODcxMDEsImV4cCI6NDcyNjk5NjcwNCwiYXVkIjoiIiwic3ViIjoiIiwic2VydmljZV9lbmRwb2ludCI6Imh0dHA6Ly9hZGFzZCIsInJlc291cmNlX2lkIjoiMTIzNDUifQ.2H3TRC3CAToVE9divSckwHi_HNvgOHKrtJPo8128qrKBHTk7YYb0UNfVCuYqwhGR" \ No newline at end of file +"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1Mzk3ODcxMDEsImV4cCI6NDcyNjk5NjcwNCwiYXVkIjoiIiwic3ViIjoiIiwic2VydmljZV9lbmRwb2ludCI6Imh0dHA6Ly9hZGFzZCIsInJlc291cmNlX2lkIjoiMTIzNDUifQ.2H3TRC3CAToVE9divSckwHi_HNvgOHKrtJPo8128qrKBHTk7YYb0UNfVCuYqwhGR" From 693be5dc9129874aba658a0aa7b9870e64e6ad92 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Tue, 30 Oct 2018 12:00:50 +0100 Subject: [PATCH 27/38] update secret store client dep --- package-lock.json | 65 +++-------------------------------------------- package.json | 4 +-- 2 files changed, 6 insertions(+), 63 deletions(-) diff --git a/package-lock.json b/package-lock.json index f3d217a..d59f74a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/squid", - "version": "0.1.0-beta.18", + "version": "0.1.0-beta.19", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -125,11 +125,10 @@ "integrity": "sha512-UmgPsJul9ZJb5BPIa1qfMpokJWzdROni/wisd4Dnm+wwHUA7/ymsr34zVn+4v+uAcMLHAYPKbsROBT5xlbiKAQ==" }, "@oceanprotocol/secret-store-client": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.6.tgz", - "integrity": "sha512-dJQ7rWQdAkrM79gvLYrT8vm5ZOrjW7XbQR/d2IBIQNS6t09826wZW3Y9kwaiQvKBUIOI9LhbwVuD4Hc0IuXJnQ==", + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@oceanprotocol/secret-store-client/-/secret-store-client-0.0.7.tgz", + "integrity": "sha512-NaqJJ0AlgIbV4WIIRbetjd6PCXux8sT2kZgw1GGmky9b7PZvG4AWm/rPN/1lmJJ2ccx3gwUpQTPrP2SLHRBTuw==", "requires": { - "jayson": "^2.0.6", "node-fetch": "^2.2.0" } }, @@ -391,15 +390,6 @@ "long": "^3.2.0" } }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -1800,21 +1790,6 @@ "resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "^4.0.3" - }, - "dependencies": { - "es6-promise": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", - "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==" - } - } - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -2278,11 +2253,6 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, - "eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" - }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -3630,28 +3600,6 @@ "is-object": "^1.0.1" } }, - "jayson": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/jayson/-/jayson-2.1.0.tgz", - "integrity": "sha512-WQhCph4BgSDbRUPdZYqGMojKMxjzPqCCKmWYMsRWX/Bvh1oP+Irs2upeEJy8flU3ZAZzm68TjuL1X8u9Rt4wWQ==", - "requires": { - "@types/node": "^10.3.5", - "JSONStream": "^1.3.1", - "commander": "^2.12.2", - "es6-promisify": "^5.0.0", - "eyes": "^0.1.8", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.10", - "uuid": "^3.2.1" - }, - "dependencies": { - "@types/node": { - "version": "10.12.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.0.tgz", - "integrity": "sha512-3TUHC3jsBAB7qVRGxT6lWyYo2v96BMmD2PTcl47H25Lu7UXtFH/2qqmKiVrnel6Ne//0TFYf6uvNX+HW2FRkLQ==" - } - } - }, "js-sha3": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", @@ -3718,11 +3666,6 @@ "graceful-fs": "^4.1.6" } }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" - }, "jsonwebtoken": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz", diff --git a/package.json b/package.json index 757acf3..d300737 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/squid", - "version": "0.1.0-beta.18", + "version": "0.1.0-beta.19", "description": "JavaScript client library for Ocean Protocol", "main": "dist/squid.js", "scripts": { @@ -50,7 +50,7 @@ }, "dependencies": { "@oceanprotocol/keeper-contracts": "^0.4.1", - "@oceanprotocol/secret-store-client": "^0.0.6", + "@oceanprotocol/secret-store-client": "^0.0.7", "bignumber.js": "^7.2.1", "eth-crypto": "^1.2.4", "eth-ecies": "^1.0.3", From bf824caa17ab9fa52b70b6ead4d378cce011e9d5 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Tue, 30 Oct 2018 12:09:51 +0100 Subject: [PATCH 28/38] provider is now aquarius --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 77f9dd5..a0da3fb 100644 --- a/README.md +++ b/README.md @@ -46,10 +46,13 @@ import { Ocean, Logger } from '@oceanprotocol/squid' const { Ocean, Logger } = require('@oceanprotocol/squid') ``` -You can then connect to a running [Keeper](https://github.com/oceanprotocol/keeper-contracts) & [Provider](https://github.com/oceanprotocol/provider) instance, e.g.: +You can then connect to a running [Keeper](https://github.com/oceanprotocol/keeper-contracts) & [Aquarius](https://github.com/oceanprotocol/aquarius) instance, e.g.: ```js -const ocean = await new Ocean({nodeUri: 'http://localhost:8545', network: 'development', providerUri: 'http://localhost:5000'}) +const ocean = await new Ocean({ + nodeUri: 'http://localhost:8545', + aquariusUri: 'http://localhost:5000' +}) ``` ## Development From cf86f5af0d6e3eb9d610e748ac9f928a4550314a Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 1 Nov 2018 08:31:21 +0100 Subject: [PATCH 29/38] first steps towards service agreements implementation --- package-lock.json | 6 +- package.json | 2 +- src/keeper/ContractHandler.ts | 18 ++-- src/keeper/ContractReflector.ts | 17 ++++ src/keeper/contracts/GenericContract.ts | 14 ++++ src/keeper/contracts/ServiceAgreement.ts | 26 ++++-- .../contracts/conditions/AccessConditions.ts | 8 ++ src/models/MethodReflection.ts | 6 ++ src/ocean/ServiceAgreement.ts | 83 +++++++++++-------- src/ocean/ServiceAgreementTemplate.ts | 67 ++++++++------- test/ocean/ServiceAgreement.test.ts | 57 ++++++++++--- test/ocean/ServiceAgreementTemplate.test.ts | 19 ++++- 12 files changed, 221 insertions(+), 102 deletions(-) create mode 100644 src/keeper/ContractReflector.ts create mode 100644 src/keeper/contracts/GenericContract.ts create mode 100644 src/models/MethodReflection.ts diff --git a/package-lock.json b/package-lock.json index d59f74a..2784b99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -120,9 +120,9 @@ } }, "@oceanprotocol/keeper-contracts": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.4.1.tgz", - "integrity": "sha512-UmgPsJul9ZJb5BPIa1qfMpokJWzdROni/wisd4Dnm+wwHUA7/ymsr34zVn+4v+uAcMLHAYPKbsROBT5xlbiKAQ==" + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.3.7.tgz", + "integrity": "sha512-Yx+ucPIjLsn/Rvs0G8sPpjKWmmUQv5x9YBdO6pHutSGO82PkVBCydV4mB5Wx3Pqr3KmW0S34ve07KmUN3qtc7A==" }, "@oceanprotocol/secret-store-client": { "version": "0.0.7", diff --git a/package.json b/package.json index d300737..0c9dc24 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "node": ">=8 <10" }, "dependencies": { - "@oceanprotocol/keeper-contracts": "^0.4.1", + "@oceanprotocol/keeper-contracts": "^0.3.7", "@oceanprotocol/secret-store-client": "^0.0.7", "bignumber.js": "^7.2.1", "eth-crypto": "^1.2.4", diff --git a/src/keeper/ContractHandler.ts b/src/keeper/ContractHandler.ts index 29e3eae..9760f87 100644 --- a/src/keeper/ContractHandler.ts +++ b/src/keeper/ContractHandler.ts @@ -3,14 +3,12 @@ import Logger from "../utils/Logger" import Keeper from "./Keeper" import Web3Provider from "./Web3Provider" -const contracts: Map = new Map() - export default class ContractHandler { public static async get(what: string): Contract { const where = (await (await Keeper.getInstance()).getNetworkName()).toLowerCase() try { - return contracts.get(what) || await ContractHandler.load(what, where) + return ContractHandler.contracts.get(what) || await ContractHandler.load(what, where) } catch (err) { Logger.error("Failed to load", what, "from", where, err) throw err @@ -53,8 +51,8 @@ export default class ContractHandler { const sa = await ContractHandler.deployContract("ServiceAgreement", deployerAddress, { args: [], - }) + await ContractHandler.deployContract("AccessConditions", deployerAddress, { args: [sa.options.address], }) @@ -74,6 +72,8 @@ export default class ContractHandler { }) } + private static contracts: Map = new Map() + private static async load(what: string, where: string): Promise { const web3 = Web3Provider.getWeb3() // Logger.log("Loading", what, "from", where) @@ -87,8 +87,8 @@ export default class ContractHandler { // Logger.log("Getting instance of", what, "from", where, "at", artifact.address) const contract = new web3.eth.Contract(artifact.abi, artifact.address) Logger.log("Loaded", what, "from", where) - contracts.set(what, contract) - return contracts.get(what) + ContractHandler.contracts.set(what, contract) + return ContractHandler.contracts.get(what) } // todo: reactivate for tethys @@ -108,8 +108,8 @@ export default class ContractHandler { private static async deployContract(name: string, from: string, params?): Promise { // dont redeploy if there is already something loaded - if (contracts.has(name)) { - return contracts.get(name) + if (ContractHandler.contracts.has(name)) { + return ContractHandler.contracts.get(name) } const web3 = Web3Provider.getWeb3() @@ -130,7 +130,7 @@ export default class ContractHandler { gas: 3000000, gasPrice: 10000000000, }) - contracts.set(name, contractInstance) + ContractHandler.contracts.set(name, contractInstance) // Logger.log("Deployed", name, "at", contractInstance.options.address); } catch (err) { Logger.error("Deployment failed for", name, "with params", JSON.stringify(params, null, 2), err.message) diff --git a/src/keeper/ContractReflector.ts b/src/keeper/ContractReflector.ts new file mode 100644 index 0000000..0f4e651 --- /dev/null +++ b/src/keeper/ContractReflector.ts @@ -0,0 +1,17 @@ +import MethodReflection from "../models/MethodReflection" +import GenericContract from "./contracts/GenericContract" + +export default class ContractReflector { + + public static async reflectContractMethod(pathToMethod: string): Promise { + const parts: string[] = pathToMethod.split(".") + + const contract = await GenericContract.getInstance(parts[0]) + return { + contractName: parts[0], + methodName: parts[1], + address: contract.getAddress(), + signature: contract.getSignatureOfMethod(parts[1]), + } as MethodReflection + } +} diff --git a/src/keeper/contracts/GenericContract.ts b/src/keeper/contracts/GenericContract.ts new file mode 100644 index 0000000..59445a4 --- /dev/null +++ b/src/keeper/contracts/GenericContract.ts @@ -0,0 +1,14 @@ +import ContractBase from "./ContractBase" + +export default class GenericContract extends ContractBase { + + public static async getInstance(contractName: string) { + const contract: GenericContract = new GenericContract(contractName) + await contract.init() + return contract + } + + private constructor(contractName: string) { + super(contractName) + } +} diff --git a/src/keeper/contracts/ServiceAgreement.ts b/src/keeper/contracts/ServiceAgreement.ts index b110574..4eaa7dd 100644 --- a/src/keeper/contracts/ServiceAgreement.ts +++ b/src/keeper/contracts/ServiceAgreement.ts @@ -1,4 +1,5 @@ import {Receipt} from "web3-utils" +import MethodReflection from "../../models/MethodReflection" import ContractBase from "./ContractBase" export default class ServiceAgreement extends ContractBase { @@ -9,25 +10,32 @@ export default class ServiceAgreement extends ContractBase { return serviceAgreement } - public async setupAgreementTemplate(contractAddresses: any[], contractFunctionSignatures: string[], - depencyMatrix: number[], name: any, ownerAddress: string): Promise { + public async setupAgreementTemplate(methodReflections: MethodReflection[], dependencyMatrix: number[], name: any, + ownerAddress: string): Promise { return this.send("setupAgreementTemplate", ownerAddress, [ - contractAddresses, contractFunctionSignatures, depencyMatrix, name, + methodReflections.map((r) => r.address), methodReflections.map((r) => r.signature), + dependencyMatrix, name, ]) } - public async getAgreementStatus(agreementId: string) { + public async getTemplateStatus(templateId: string) { - return this.call("getAgreementStatus", [agreementId]) + return this.call("getTemplateStatus", [templateId]) } - public async executeAgreement(templateId: string, signature: string, consumerAddress: string, valueHashes: string[], - timeoutValues: number[], serviceDefinitionId: string, did: string, - publisherAddress: string): Promise { + public async getAgreementStatus(serviceAgreementId: string) { + + return this.call("getAgreementStatus", ["0x" + serviceAgreementId]) + } + + public async executeAgreement(serviceAgreementTemplateId: string, serviceAgreementSignatureHash: string, + consumerAddress: string, valueHashes: string[], timeoutValues: number[], + serviceAgreementId: string, did: string, publisherAddress: string): Promise { return this.send("executeAgreement", publisherAddress, [ - templateId, signature, consumerAddress, valueHashes, timeoutValues, serviceDefinitionId, "0x" + did, + serviceAgreementTemplateId, serviceAgreementSignatureHash, consumerAddress, valueHashes, + timeoutValues, "0x" + serviceAgreementId, "0x" + did, ]) } } diff --git a/src/keeper/contracts/conditions/AccessConditions.ts b/src/keeper/contracts/conditions/AccessConditions.ts index 973287a..1d4c790 100644 --- a/src/keeper/contracts/conditions/AccessConditions.ts +++ b/src/keeper/contracts/conditions/AccessConditions.ts @@ -1,3 +1,4 @@ +import {Receipt} from "web3-utils" import ContractBase from "../ContractBase" export default class AccessConditions extends ContractBase { @@ -7,4 +8,11 @@ export default class AccessConditions extends ContractBase { await accessConditions.init() return accessConditions } + + public async grantAccess(serviceAgreementId: any, assetId: any, documentKeyId: any, publisherAddress: string) + : Promise { + return this.send("grantAccess", publisherAddress, [ + "0x" + serviceAgreementId, "0x" + assetId, "0x" + documentKeyId, + ]) + } } diff --git a/src/models/MethodReflection.ts b/src/models/MethodReflection.ts new file mode 100644 index 0000000..3ac4ac6 --- /dev/null +++ b/src/models/MethodReflection.ts @@ -0,0 +1,6 @@ +export default class MethodReflection { + public contractName: string + public methodName: string + public address: string + public signature: string +} diff --git a/src/ocean/ServiceAgreement.ts b/src/ocean/ServiceAgreement.ts index 7862d91..d2b1cec 100644 --- a/src/ocean/ServiceAgreement.ts +++ b/src/ocean/ServiceAgreement.ts @@ -1,73 +1,88 @@ +import AccessConditions from "../keeper/contracts/conditions/AccessConditions" import ServiceAgreementContract from "../keeper/contracts/ServiceAgreement" import Web3Provider from "../keeper/Web3Provider" import Account from "./Account" +import IdGenerator from "./IdGenerator" import OceanBase from "./OceanBase" import ServiceAgreementTemplate from "./ServiceAgreementTemplate" export default class ServiceAgreement extends OceanBase { - public static async executeServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, - did: string, consumer: Account): Promise { + public static async signServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, publisher: Account, + did: string, assetId: string, consumer: Account): + Promise { - const valHashList = [ - ServiceAgreement.valueHash("bool", true), - ServiceAgreement.valueHash("bool", false), - ServiceAgreement.valueHash("uint", 120), - // asset Id: 797FD5B9045B841FDFF72 - ServiceAgreement.valueHash("string", "797FD5B9045B841FDFF72"), + const serviceAgreementId = IdGenerator.generateId() + + const valueHashes = [ + ServiceAgreement.hashSingleValue("bool", true), + ServiceAgreement.hashSingleValue("bool", false), + ServiceAgreement.hashSingleValue("uint", 120), + // assetId + ServiceAgreement.hashSingleValue("string", assetId), ] - const serviceDefinitionId = "0x515f158c3a5d81d15b0160cf8929916089218bdb4aa78c3ecd16633afd44b894" + const timeoutValues = [0, 0, 0, 500] // timeout 500 blocks @ condition 4 - const timeoutValues = [0, 0, 0, 3] // timeout 5 blocks @ condition 4 - - const saMerkleRoot = ServiceAgreement.merkelizeServiceAgreement(serviceAgreementTemplate, valHashList, - timeoutValues, serviceDefinitionId, did) - const saMerkleRootSignature = await Web3Provider.getWeb3().eth.sign(saMerkleRoot, consumer.getId()) + const serviceAgreementHash = ServiceAgreement.hashServiceAgreement(serviceAgreementTemplate, valueHashes, + timeoutValues, serviceAgreementId) + const serviceAgreementHashSignature = + await Web3Provider.getWeb3().eth.sign(serviceAgreementHash, consumer.getId()) const serviceAgreement: ServiceAgreementContract = await ServiceAgreementContract.getInstance() - const receipt = await serviceAgreement.executeAgreement( - serviceAgreementTemplate.getId(), saMerkleRootSignature, consumer.getId(), valHashList, timeoutValues, - serviceDefinitionId, did, serviceAgreementTemplate.getPublisher().getId()) + const executeAgreementReceipt = await serviceAgreement.executeAgreement( + serviceAgreementTemplate.getId(), serviceAgreementHashSignature, consumer.getId(), valueHashes, + timeoutValues, serviceAgreementId, did, publisher.getId()) + + if (executeAgreementReceipt.events.ExecuteAgreement.returnValues.state === false) { + throw new Error("signing service agreement failed.") + } - const id = receipt.events.ExecuteAgreement.returnValues.serviceId return new ServiceAgreement( - id, - receipt.events.ExecuteAgreement.returnValues.templateId, - receipt.events.ExecuteAgreement.returnValues.templateOwner, - receipt.events.ExecuteAgreement.returnValues.consumer, - receipt.events.ExecuteAgreement.returnValues.state, - receipt.events.ExecuteAgreement.returnValues.status, + serviceAgreementId, + publisher, + serviceAgreementTemplate, + consumer, + executeAgreementReceipt.events.ExecuteAgreement.returnValues.state, + executeAgreementReceipt.events.ExecuteAgreement.returnValues.status, ) } - protected static valueHash(type: string, value: any) { + protected static hashSingleValue(type: string, value: any): string { const args = {type, value} return Web3Provider.getWeb3().utils.soliditySha3(args).toString("hex") } - private static merkelizeServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, valueHashes: string[], - timeouts: number[], serviceDefinitionId: string, did: string) { + private static hashServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, valueHashes: string[], + timeouts: number[], serviceAgreementId: string) { const args = [ {type: "bytes32", value: serviceAgreementTemplate.getId()}, {type: "bytes32[]", value: serviceAgreementTemplate.getConditionKeys()}, {type: "bytes32[]", value: valueHashes}, {type: "uint256[]", value: timeouts}, - {type: "bytes32", value: serviceDefinitionId}, - {type: "bytes32", value: did}, + {type: "bytes32", value: "0x" + serviceAgreementId}, ] + return Web3Provider.getWeb3().utils.soliditySha3(...args).toString("hex") } - private constructor(id: string, templateId: string, templateOwnerId: string, - consumerId: string, state: boolean, status: boolean) { + private constructor(id: string, private publisher: Account, serviceAgreementTemplate: ServiceAgreementTemplate, + consumer: Account, state: boolean, status: boolean) { super(id) } - public async getStatus() { - const sa = await ServiceAgreementContract.getInstance() + public async grantAccess(assetId: string, documentId: string): Promise { + const accessConditions: AccessConditions = await AccessConditions.getInstance() - return sa.getAgreementStatus(this.getId()) + const grantAccessReceipt = + await accessConditions.grantAccess(this.getId(), assetId, documentId, this.publisher.getId()) + + return grantAccessReceipt.status + } + + public async getStatus() { + const serviceAgreement = await ServiceAgreementContract.getInstance() + return serviceAgreement.getAgreementStatus(this.getId()) } } diff --git a/src/ocean/ServiceAgreementTemplate.ts b/src/ocean/ServiceAgreementTemplate.ts index 22598e1..da3d004 100644 --- a/src/ocean/ServiceAgreementTemplate.ts +++ b/src/ocean/ServiceAgreementTemplate.ts @@ -1,65 +1,70 @@ -import AccessConditions from "../keeper/contracts/conditions/AccessConditions" -import PaymentConditions from "../keeper/contracts/conditions/PaymentConditions" +import ContractReflector from "../keeper/ContractReflector" import ServiceAgreement from "../keeper/contracts/ServiceAgreement" import Web3Provider from "../keeper/Web3Provider" +import MethodReflection from "../models/MethodReflection" import Account from "./Account" import OceanBase from "./OceanBase" export default class ServiceAgreementTemplate extends OceanBase { - public static async registerServiceAgreementsTemplate(resourceName: string, publisher: Account): + public static async registerServiceAgreementsTemplate(serviceName: string, templateOwner: Account): Promise { - const paymentConditions: PaymentConditions = await PaymentConditions.getInstance() - const accessConditions: AccessConditions = await AccessConditions.getInstance() - - const contractAddresses = [ - await paymentConditions.getAddress(), - await accessConditions.getAddress(), - await paymentConditions.getAddress(), - await paymentConditions.getAddress(), - ] - const functionSignatures = [ - await paymentConditions.getSignatureOfMethod("lockPayment"), - await accessConditions.getSignatureOfMethod("grantAccess"), - await paymentConditions.getSignatureOfMethod("releasePayment"), - await paymentConditions.getSignatureOfMethod("refundPayment"), + const methodReflections: MethodReflection[] = [ + await ContractReflector.reflectContractMethod("PaymentConditions.lockPayment"), + await ContractReflector.reflectContractMethod("AccessConditions.grantAccess"), + await ContractReflector.reflectContractMethod("PaymentConditions.releasePayment"), + await ContractReflector.reflectContractMethod("PaymentConditions.refundPayment"), ] // tslint:disable - const dependencies = [0, 1, 4, 1 | 2 ** 4 | 2 ** 5] // dependency bit | timeout bit + const dependencyMatrix = [0, 1, 4, 1 | 2 ** 4 | 2 ** 5] // dependency bit | timeout bit const serviceAgreement: ServiceAgreement = await ServiceAgreement.getInstance() const receipt = await serviceAgreement.setupAgreementTemplate( - contractAddresses, functionSignatures, dependencies, - Web3Provider.getWeb3().utils.fromAscii(resourceName), publisher.getId()) + methodReflections, dependencyMatrix, + Web3Provider.getWeb3().utils.fromAscii(serviceName), + templateOwner.getId()) const id = receipt.events.SetupAgreementTemplate.returnValues.serviceTemplateId return new ServiceAgreementTemplate( id, - ServiceAgreementTemplate.generateConditionsKeys(id, contractAddresses, functionSignatures), - publisher) + ServiceAgreementTemplate.generateConditionsKeys(id, methodReflections), + templateOwner) } - private static generateConditionsKeys(serviceAgreementTemplateId: string, contractAddresses: string[], - functionSignatures: string[]): string[] { + /** + * gets the status of a service agreement template + */ + public async getStatus(): Promise { + + const serviceAgreement: ServiceAgreement = await ServiceAgreement.getInstance() + + return serviceAgreement.getTemplateStatus(this.getId()) + } + + private static generateConditionsKeys(serviceAgreementTemplateId: string, methodReflections: MethodReflection[]): + string[] { const conditions = [] - for (let i = 0; i < contractAddresses.length; i++) { - const types = ["bytes32", "address", "bytes4"] - const values = [serviceAgreementTemplateId, contractAddresses[i], functionSignatures[i]] - conditions.push(Web3Provider.getWeb3().utils.soliditySha3(...types, ...values).toString("hex")) + for (let i = 0; i < methodReflections.length; i++) { + const values = [ + {type: "bytes32", value: serviceAgreementTemplateId}, + {type: "address", value: methodReflections[i].address}, + {type: "bytes4", value: methodReflections[i].signature}, + ] + conditions.push(Web3Provider.getWeb3().utils.soliditySha3(...values).toString("hex")) } return conditions } - private constructor(id, private conditionKeys: string[], private publisher: Account) { + private constructor(id, private conditionKeys: string[], private owner: Account) { super(id) } - public getPublisher(): Account { - return this.publisher + public getOwner(): Account { + return this.owner } public getConditionKeys(): string[] { diff --git a/test/ocean/ServiceAgreement.test.ts b/test/ocean/ServiceAgreement.test.ts index ad89343..a9e1b8b 100644 --- a/test/ocean/ServiceAgreement.test.ts +++ b/test/ocean/ServiceAgreement.test.ts @@ -6,11 +6,14 @@ import IdGenerator from "../../src/ocean/IdGenerator" import Ocean from "../../src/ocean/Ocean" import ServiceAgreement from "../../src/ocean/ServiceAgreement" import ServiceAgreementTemplate from "../../src/ocean/ServiceAgreementTemplate" -import Logger from "../../src/utils/Logger" import config from "../config" let ocean: Ocean let accounts: Account[] +let publisherAccount: Account +let templateOwnerAccount: Account +let consumerAccount: Account + let testServiceAgreementTemplate: ServiceAgreementTemplate describe("ServiceAgreement", () => { @@ -21,36 +24,66 @@ describe("ServiceAgreement", () => { ocean = await Ocean.getInstance(config) accounts = await ocean.getAccounts() - const publisherAccount = accounts[0] + templateOwnerAccount = accounts[0] + publisherAccount = accounts[1] + consumerAccount = accounts[2] + const resourceName = "superb car data" testServiceAgreementTemplate = - await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, publisherAccount) + await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, templateOwnerAccount) }) describe("#executeServiceAgreement()", () => { - it("should execture an service agreement", async () => { + it("should execute an service agreement", async () => { - const consumerAccount = accounts[0] const did: string = IdGenerator.generateId() + const assetId: string = IdGenerator.generateId() + const serviceAgreement: ServiceAgreement = - await ServiceAgreement.executeServiceAgreement(testServiceAgreementTemplate, did, consumerAccount) + await ServiceAgreement.signServiceAgreement(testServiceAgreementTemplate, publisherAccount, + did, assetId, consumerAccount) assert(serviceAgreement) - assert(serviceAgreement.getId().startsWith("0x")) + const id = serviceAgreement.getId() + assert(id) + assert(id !== did) }) }) describe("#getStatus()", () => { - it("should execture an service agreement", async () => { + it("should get the status of a newly created service agreement", async () => { - const consumerAccount = accounts[0] const did: string = IdGenerator.generateId() - const serviceAgreement: ServiceAgreement = - await ServiceAgreement.executeServiceAgreement(testServiceAgreementTemplate, did, consumerAccount) + const assetId: string = IdGenerator.generateId() + const serviceAgreement: ServiceAgreement = + await ServiceAgreement.signServiceAgreement(testServiceAgreementTemplate, publisherAccount, + did, assetId, consumerAccount) + + assert(serviceAgreement) const status = await serviceAgreement.getStatus() - Logger.log(status) + assert(status === false) + }) + }) + + describe("#grantAccess()", () => { + it("should grant access in that service agreement", async () => { + + const did: string = IdGenerator.generateId() + const assetId: string = IdGenerator.generateId() + + const resourceName = "nice service" + const serviceAgreementTemplate = + await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, templateOwnerAccount) + + const serviceAgreement: ServiceAgreement = + await ServiceAgreement.signServiceAgreement(serviceAgreementTemplate, publisherAccount, + did, assetId, consumerAccount) + assert(serviceAgreement) + + const fulfilled: boolean = await serviceAgreement.grantAccess(did, IdGenerator.generateId()) + assert(fulfilled) }) }) }) diff --git a/test/ocean/ServiceAgreementTemplate.test.ts b/test/ocean/ServiceAgreementTemplate.test.ts index 2fc4f87..719a9f0 100644 --- a/test/ocean/ServiceAgreementTemplate.test.ts +++ b/test/ocean/ServiceAgreementTemplate.test.ts @@ -21,13 +21,26 @@ describe("ServiceAgreementTemplate", () => { describe("#registerServiceAgreementsTemplate()", () => { it("should setup an agreement template", async () => { - const publisherAccount = accounts[0] + const templateOwner = accounts[0] const resourceName = "test data" const serviceAgreementTemplate: ServiceAgreementTemplate = - await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, publisherAccount) + await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, templateOwner) assert(serviceAgreementTemplate) assert(serviceAgreementTemplate.getId()) - assert(serviceAgreementTemplate.getPublisher().getId() === publisherAccount.getId()) + assert(serviceAgreementTemplate.getOwner().getId() === templateOwner.getId()) + }) + }) + + describe("#getStatus()", () => { + it("should get the status of a newly deployed agreement template", async () => { + + const publisherAccount = accounts[0] + const resourceName = "template status" + const serviceAgreementTemplate: ServiceAgreementTemplate = + await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, publisherAccount) + + const templateStatus = await serviceAgreementTemplate.getStatus() + assert(templateStatus === true) }) }) From 076c2eb7887cac8ee167c2dc6c996198e926dbde Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 1 Nov 2018 09:18:34 +0100 Subject: [PATCH 30/38] make templates and service agreements configurable --- src/ocean/ServiceAgreement.ts | 61 +++++++++++++++------ src/ocean/ServiceAgreementTemplate.ts | 18 +++--- test/ocean/ServiceAgreement.test.ts | 31 ++++++----- test/ocean/ServiceAgreementTemplate.test.ts | 21 +++++-- 4 files changed, 88 insertions(+), 43 deletions(-) diff --git a/src/ocean/ServiceAgreement.ts b/src/ocean/ServiceAgreement.ts index d2b1cec..e836781 100644 --- a/src/ocean/ServiceAgreement.ts +++ b/src/ocean/ServiceAgreement.ts @@ -8,26 +8,35 @@ import ServiceAgreementTemplate from "./ServiceAgreementTemplate" export default class ServiceAgreement extends OceanBase { - public static async signServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, publisher: Account, - did: string, assetId: string, consumer: Account): - Promise { + public static async createServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, assetId: string, + did: string, consumer: Account, publisher: Account) { + // todo: this should come from ddo const serviceAgreementId = IdGenerator.generateId() - - const valueHashes = [ - ServiceAgreement.hashSingleValue("bool", true), - ServiceAgreement.hashSingleValue("bool", false), - ServiceAgreement.hashSingleValue("uint", 120), - // assetId - ServiceAgreement.hashSingleValue("string", assetId), + const timeoutValues = [0, 0, 0, 500] // timeout 500 blocks @ condition 4 + const values = [ + {type: "bool", value: true}, + {type: "bool", value: false}, + {type: "uint", value: 120}, + {type: "string", value: assetId}, ] - const timeoutValues = [0, 0, 0, 500] // timeout 500 blocks @ condition 4 + const saHashSig = await ServiceAgreement.createSAHashSignature(serviceAgreementTemplate, serviceAgreementId, + values, timeoutValues, consumer) - const serviceAgreementHash = ServiceAgreement.hashServiceAgreement(serviceAgreementTemplate, valueHashes, - timeoutValues, serviceAgreementId) - const serviceAgreementHashSignature = - await Web3Provider.getWeb3().eth.sign(serviceAgreementHash, consumer.getId()) + const serviceAgreement: ServiceAgreement = await ServiceAgreement.signServiceAgreement(serviceAgreementTemplate, + serviceAgreementId, assetId, did, values, timeoutValues, saHashSig, consumer, publisher) + + return serviceAgreement + } + + private static async signServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, + serviceAgreementId: string, assetId: string, did: string, values: any[], + timeoutValues: number[], serviceAgreementHashSignature: string, + consumer: Account, publisher: Account): + Promise { + + const valueHashes = ServiceAgreement.createValueHashes(values) const serviceAgreement: ServiceAgreementContract = await ServiceAgreementContract.getInstance() @@ -49,11 +58,31 @@ export default class ServiceAgreement extends OceanBase { ) } - protected static hashSingleValue(type: string, value: any): string { + private static createValueHashes(values: any[]): any[] { + return values.map((value) => { + return ServiceAgreement.hashSingleValue(value.type, value.value) + }) + } + + private static hashSingleValue(type: string, value: any): string { const args = {type, value} return Web3Provider.getWeb3().utils.soliditySha3(args).toString("hex") } + private static async createSAHashSignature(serviceAgreementTemplate: ServiceAgreementTemplate, + serviceAgreementId: string, values: any[], timeoutValues: number[], + consumer: Account): Promise { + + const valueHashes = ServiceAgreement.createValueHashes(values) + + const serviceAgreementHash = ServiceAgreement.hashServiceAgreement(serviceAgreementTemplate, valueHashes, + timeoutValues, serviceAgreementId) + const serviceAgreementHashSignature = + await Web3Provider.getWeb3().eth.sign(serviceAgreementHash, consumer.getId()) + + return serviceAgreementHashSignature + } + private static hashServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, valueHashes: string[], timeouts: number[], serviceAgreementId: string) { const args = [ diff --git a/src/ocean/ServiceAgreementTemplate.ts b/src/ocean/ServiceAgreementTemplate.ts index da3d004..330ac76 100644 --- a/src/ocean/ServiceAgreementTemplate.ts +++ b/src/ocean/ServiceAgreementTemplate.ts @@ -7,18 +7,16 @@ import OceanBase from "./OceanBase" export default class ServiceAgreementTemplate extends OceanBase { - public static async registerServiceAgreementsTemplate(serviceName: string, templateOwner: Account): + public static async registerServiceAgreementsTemplate(serviceName: string, methods: string[], + dependencyMatrix: number[], templateOwner: Account): Promise { - const methodReflections: MethodReflection[] = [ - await ContractReflector.reflectContractMethod("PaymentConditions.lockPayment"), - await ContractReflector.reflectContractMethod("AccessConditions.grantAccess"), - await ContractReflector.reflectContractMethod("PaymentConditions.releasePayment"), - await ContractReflector.reflectContractMethod("PaymentConditions.refundPayment"), - ] - - // tslint:disable - const dependencyMatrix = [0, 1, 4, 1 | 2 ** 4 | 2 ** 5] // dependency bit | timeout bit + const methodReflections: MethodReflection[] = + await Promise.all(methods.map(async (method) => { + const methodReflection = await + ContractReflector.reflectContractMethod(method) + return methodReflection + })) const serviceAgreement: ServiceAgreement = await ServiceAgreement.getInstance() diff --git a/test/ocean/ServiceAgreement.test.ts b/test/ocean/ServiceAgreement.test.ts index a9e1b8b..15ed40d 100644 --- a/test/ocean/ServiceAgreement.test.ts +++ b/test/ocean/ServiceAgreement.test.ts @@ -29,20 +29,29 @@ describe("ServiceAgreement", () => { consumerAccount = accounts[2] const resourceName = "superb car data" - testServiceAgreementTemplate = - await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, templateOwnerAccount) + const methods: string[] = [ + "PaymentConditions.lockPayment", + "AccessConditions.grantAccess", + "PaymentConditions.releasePayment", + "PaymentConditions.refundPayment", + ] + // tslint:disable + const dependencyMatrix = [0, 1, 4, 1 | 2 ** 4 | 2 ** 5] // dependency bit | timeout bit + testServiceAgreementTemplate = + await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, methods, + dependencyMatrix, templateOwnerAccount) }) - describe("#executeServiceAgreement()", () => { + describe("#createServiceAgreement()", () => { it("should execute an service agreement", async () => { const did: string = IdGenerator.generateId() const assetId: string = IdGenerator.generateId() const serviceAgreement: ServiceAgreement = - await ServiceAgreement.signServiceAgreement(testServiceAgreementTemplate, publisherAccount, - did, assetId, consumerAccount) + await ServiceAgreement.createServiceAgreement(testServiceAgreementTemplate, assetId, did, + consumerAccount, publisherAccount) assert(serviceAgreement) const id = serviceAgreement.getId() @@ -58,8 +67,8 @@ describe("ServiceAgreement", () => { const assetId: string = IdGenerator.generateId() const serviceAgreement: ServiceAgreement = - await ServiceAgreement.signServiceAgreement(testServiceAgreementTemplate, publisherAccount, - did, assetId, consumerAccount) + await ServiceAgreement.createServiceAgreement(testServiceAgreementTemplate, assetId, did, + consumerAccount, publisherAccount) assert(serviceAgreement) const status = await serviceAgreement.getStatus() @@ -73,13 +82,9 @@ describe("ServiceAgreement", () => { const did: string = IdGenerator.generateId() const assetId: string = IdGenerator.generateId() - const resourceName = "nice service" - const serviceAgreementTemplate = - await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, templateOwnerAccount) - const serviceAgreement: ServiceAgreement = - await ServiceAgreement.signServiceAgreement(serviceAgreementTemplate, publisherAccount, - did, assetId, consumerAccount) + await ServiceAgreement.createServiceAgreement(testServiceAgreementTemplate, assetId, did, + consumerAccount, publisherAccount) assert(serviceAgreement) const fulfilled: boolean = await serviceAgreement.grantAccess(did, IdGenerator.generateId()) diff --git a/test/ocean/ServiceAgreementTemplate.test.ts b/test/ocean/ServiceAgreementTemplate.test.ts index 719a9f0..d44c7b4 100644 --- a/test/ocean/ServiceAgreementTemplate.test.ts +++ b/test/ocean/ServiceAgreementTemplate.test.ts @@ -8,6 +8,14 @@ import config from "../config" let ocean: Ocean let accounts: Account[] +const methods: string[] = [ + "PaymentConditions.lockPayment", + "AccessConditions.grantAccess", + "PaymentConditions.releasePayment", + "PaymentConditions.refundPayment", +] +// tslint:disable +const dependencyMatrix = [0, 1, 4, 1 | 2 ** 4 | 2 ** 5] // dependency bit | timeout bit describe("ServiceAgreementTemplate", () => { @@ -22,9 +30,11 @@ describe("ServiceAgreementTemplate", () => { it("should setup an agreement template", async () => { const templateOwner = accounts[0] - const resourceName = "test data" + const resourceName = "consume" const serviceAgreementTemplate: ServiceAgreementTemplate = - await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, templateOwner) + await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, methods, + dependencyMatrix, templateOwner) + assert(serviceAgreementTemplate) assert(serviceAgreementTemplate.getId()) assert(serviceAgreementTemplate.getOwner().getId() === templateOwner.getId()) @@ -35,9 +45,12 @@ describe("ServiceAgreementTemplate", () => { it("should get the status of a newly deployed agreement template", async () => { const publisherAccount = accounts[0] - const resourceName = "template status" + const resourceName = "consume" + const serviceAgreementTemplate: ServiceAgreementTemplate = - await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, publisherAccount) + await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, methods, + dependencyMatrix, publisherAccount) + assert(serviceAgreementTemplate) const templateStatus = await serviceAgreementTemplate.getStatus() assert(templateStatus === true) From db910aaaa288de92c2cddf232049a4a6c707cb53 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 1 Nov 2018 09:28:17 +0100 Subject: [PATCH 31/38] optimize --- src/ocean/ServiceAgreementTemplate.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/ocean/ServiceAgreementTemplate.ts b/src/ocean/ServiceAgreementTemplate.ts index 330ac76..c0ac0aa 100644 --- a/src/ocean/ServiceAgreementTemplate.ts +++ b/src/ocean/ServiceAgreementTemplate.ts @@ -33,24 +33,14 @@ export default class ServiceAgreementTemplate extends OceanBase { templateOwner) } - /** - * gets the status of a service agreement template - */ - public async getStatus(): Promise { - - const serviceAgreement: ServiceAgreement = await ServiceAgreement.getInstance() - - return serviceAgreement.getTemplateStatus(this.getId()) - } - private static generateConditionsKeys(serviceAgreementTemplateId: string, methodReflections: MethodReflection[]): string[] { const conditions = [] - for (let i = 0; i < methodReflections.length; i++) { + for (const methodReflection of methodReflections) { const values = [ {type: "bytes32", value: serviceAgreementTemplateId}, - {type: "address", value: methodReflections[i].address}, - {type: "bytes4", value: methodReflections[i].signature}, + {type: "address", value: methodReflection.address}, + {type: "bytes4", value: methodReflection.signature}, ] conditions.push(Web3Provider.getWeb3().utils.soliditySha3(...values).toString("hex")) } @@ -61,6 +51,16 @@ export default class ServiceAgreementTemplate extends OceanBase { super(id) } + /** + * gets the status of a service agreement template + */ + public async getStatus(): Promise { + + const serviceAgreement: ServiceAgreement = await ServiceAgreement.getInstance() + + return serviceAgreement.getTemplateStatus(this.getId()) + } + public getOwner(): Account { return this.owner } From 4dfaf6dae74ac553a3de1e053c1e5327bf85650f Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 1 Nov 2018 09:31:30 +0100 Subject: [PATCH 32/38] v0.1.0-beta.20 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2784b99..8481e98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/squid", - "version": "0.1.0-beta.19", + "version": "0.1.0-beta.20", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0c9dc24..307dcdc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oceanprotocol/squid", - "version": "0.1.0-beta.19", + "version": "0.1.0-beta.20", "description": "JavaScript client library for Ocean Protocol", "main": "dist/squid.js", "scripts": { From b3f3a3547f525fe8be5b70c67a5350c4eb559a17 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 1 Nov 2018 09:34:32 +0100 Subject: [PATCH 33/38] added clean job --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 307dcdc..1ed198a 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,10 @@ "test": "mocha", "test:watch": "mocha -w --watch-extensions js,ts,json", "test:cover": "nyc mocha", + "clean": "rm -rf ./dist/ ./doc/ ./coverage ./.nyc_output", "lint": "tslint -c tslint.json 'src/**/*.ts'", "start": "npm link @oceanprotocol/keeper-contracts @oceanprotocol/secret-store-client && npm run build:watch", - "build": "npm run lint && tsc && npm run doc", + "build": "npm run clean && npm run lint && tsc && npm run doc", "build:watch": "tsc -w", "doc": "typedoc --mode modules --out ./doc/ src/", "release": "./node_modules/release-it/bin/release-it.js --src.tagName='v%s' --github.release --npm.publish --non-interactive", From 63e8452d69ed9faac30b7214dee1275a8cd11224 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 1 Nov 2018 11:04:59 +0100 Subject: [PATCH 34/38] added ddo business objects --- src/ddo/AdditionalInformation.ts | 15 ++ src/ddo/Authentication.ts | 4 + src/ddo/Curation.ts | 5 + src/ddo/DDO.ts | 35 +++++ src/ddo/MetaData.ts | 59 +++++++ src/ddo/MetaDataBase.ts | 31 ++++ src/ddo/PublicKey.ts | 7 + src/ddo/Service.ts | 8 + src/ddo/StructuredMarkup.ts | 4 + test/ddo/DDO.test.ts | 183 ++++++++++++++++++++++ test/ocean/Order.test.ts | 2 +- test/{ocean => testdata}/AccessToken.json | 0 test/testdata/ddo.json | 133 ++++++++++++++++ 13 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 src/ddo/AdditionalInformation.ts create mode 100644 src/ddo/Authentication.ts create mode 100644 src/ddo/Curation.ts create mode 100644 src/ddo/DDO.ts create mode 100644 src/ddo/MetaData.ts create mode 100644 src/ddo/MetaDataBase.ts create mode 100644 src/ddo/PublicKey.ts create mode 100644 src/ddo/Service.ts create mode 100644 src/ddo/StructuredMarkup.ts create mode 100644 test/ddo/DDO.test.ts rename test/{ocean => testdata}/AccessToken.json (100%) create mode 100644 test/testdata/ddo.json diff --git a/src/ddo/AdditionalInformation.ts b/src/ddo/AdditionalInformation.ts new file mode 100644 index 0000000..f1212ce --- /dev/null +++ b/src/ddo/AdditionalInformation.ts @@ -0,0 +1,15 @@ +import StructuredMarkup from "./StructuredMarkup" + +export default class AdditionalInformation { + public updateFrecuency: string = "yearly" + public structuredMarkup: StructuredMarkup[] = [ + { + uri: "http://skos.um.es/unescothes/C01194/jsonld", + mediaType: "application/ld+json", + } as StructuredMarkup, + { + uri: "http://skos.um.es/unescothes/C01194/turtle", + mediaType: "text/turtle", + }as StructuredMarkup, + ] +} diff --git a/src/ddo/Authentication.ts b/src/ddo/Authentication.ts new file mode 100644 index 0000000..bd4689a --- /dev/null +++ b/src/ddo/Authentication.ts @@ -0,0 +1,4 @@ +export default class Authentication { + public type: string = "RsaSignatureAuthentication2018" + public publicKey: string = "did:op:123456789abcdefghi#keys-1" +} diff --git a/src/ddo/Curation.ts b/src/ddo/Curation.ts new file mode 100644 index 0000000..bc40e86 --- /dev/null +++ b/src/ddo/Curation.ts @@ -0,0 +1,5 @@ +export default class Curation { + public rating: number = 0.93 + public numVotes: number = 123 + public schema: string = "Binary Votting" +} diff --git a/src/ddo/DDO.ts b/src/ddo/DDO.ts new file mode 100644 index 0000000..d0febe6 --- /dev/null +++ b/src/ddo/DDO.ts @@ -0,0 +1,35 @@ +import Authentication from "./Authentication" +import PublicKey from "./PublicKey" +import Service from "./Service" + +export default class DDO { + + public static serialize(ddo: DDO): string { + return JSON.stringify(ddo, null, 2) + } + + public static deserialize(ddoString: string): DDO { + const ddo = JSON.parse(ddoString) + + return ddo as DDO + } + + public "@context": string = "https://w3id.org/future-method/v1" + public id: string + public publicKey: PublicKey[] + public authentication: Authentication[] + public service: Service[] + + // @ts-ignore + private assa: string + + public constructor(ddo: { + publicKey: PublicKey[], + authentication: Authentication[], + service: Service[], + }) { + this.publicKey = ddo.publicKey + this.authentication = ddo.authentication + this.service = ddo.service + } +} diff --git a/src/ddo/MetaData.ts b/src/ddo/MetaData.ts new file mode 100644 index 0000000..e1abd25 --- /dev/null +++ b/src/ddo/MetaData.ts @@ -0,0 +1,59 @@ +import Curation from "./Curation" +import StructuredMarkup from "./StructuredMarkup" +import AdditionalInformation from "./AdditionalInformation" +import MetaDataBase from "./MetaDataBase" + +export default class MetaData { + + public base: MetaDataBase = { + name: "UK Weather information 2011", + type: "dataset", + description: "Weather information of UK including temperature and humidity", + size: "3.1gb", + dateCreated: "2012-10-10T17:00:000Z", + author: "Met Office", + license: "CC-BY", + copyrightHolder: "Met Office", + encoding: "UTF-8", + compression: "zip", + contentType: "text/csv", + workExample: "423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68", + contentUrls: [ + "https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip", + ], + links: [ + { + sample1: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-daily/", + }, + { + sample2: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-averages-25km/", + }, + { + fieldsDescription: "http://data.ceda.ac.uk/badc/ukcp09/", + }, + ], + inLanguage: "en", + tags: "weather, uk, 2011, temperature, humidity", + price: 10, + } as MetaDataBase + + public curation: Curation = { + rating: 0.93, + numVotes: 123, + schema: "Binary Votting", + } as Curation + + public additionalInformation: AdditionalInformation = { + updateFrecuency: "yearly", + structuredMarkup: [ + { + uri: "http://skos.um.es/unescothes/C01194/jsonld", + mediaType: "application/ld+json", + } as StructuredMarkup, + { + uri: "http://skos.um.es/unescothes/C01194/turtle", + mediaType: "text/turtle", + } as StructuredMarkup, + ], + } as AdditionalInformation +} diff --git a/src/ddo/MetaDataBase.ts b/src/ddo/MetaDataBase.ts new file mode 100644 index 0000000..212c4e8 --- /dev/null +++ b/src/ddo/MetaDataBase.ts @@ -0,0 +1,31 @@ +export default class MetaDataBase { + public name: string = "UK Weather information 2011" + public type: string = "dataset" + public description: string = "Weather information of UK including temperature and humidity" + public size: string = "3.1gb" + public dateCreated: string = "2012-10-10T17:00:000Z" + public author: string = "Met Office" + public license: string = "CC-BY" + public copyrightHolder: string = "Met Office" + public encoding: string = "UTF-8" + public compression: string = "zip" + public contentType: string = "text/csv" + public workExample: string = "423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68" + public contentUrls: string[] = [ + "https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip", + ] + public links: any[] = [ + { + sample1: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-daily/", + }, + { + sample2: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-averages-25km/", + }, + { + fieldsDescription: "http://data.ceda.ac.uk/badc/ukcp09/", + }, + ] + public inLanguage: string = "en" + public tags: string = "weather, uk, 2011, temperature, humidity" + public price: number = 10 +} diff --git a/src/ddo/PublicKey.ts b/src/ddo/PublicKey.ts new file mode 100644 index 0000000..4de771c --- /dev/null +++ b/src/ddo/PublicKey.ts @@ -0,0 +1,7 @@ +export default class PublicKey { + public id: string = "did:op:123456789abcdefghi#keys-1" + public type: string = "RsaVerificationKey2018" + public owner: string = "did:op:123456789abcdefghi" + public publicKeyPem?: string = "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n" + public publicKeyBase58?: string = "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV" +} diff --git a/src/ddo/Service.ts b/src/ddo/Service.ts new file mode 100644 index 0000000..b02192c --- /dev/null +++ b/src/ddo/Service.ts @@ -0,0 +1,8 @@ +import MetaData from "./MetaData" + +export default class Service { + public type: string = "OpenIdConnectVersion1.0Service" + public serviceEndpoint: string = "https://openid.example.com/" + public description?: string = "My public social inbox" + public metadata?: MetaData = {} as MetaData +} diff --git a/src/ddo/StructuredMarkup.ts b/src/ddo/StructuredMarkup.ts new file mode 100644 index 0000000..acf0c16 --- /dev/null +++ b/src/ddo/StructuredMarkup.ts @@ -0,0 +1,4 @@ +export default class StructuredMarkup { + public uri: string = "http://skos.um.es/unescothes/C01194/jsonld" + public mediaType: string = "application/ld+json" +} diff --git a/test/ddo/DDO.test.ts b/test/ddo/DDO.test.ts new file mode 100644 index 0000000..b729182 --- /dev/null +++ b/test/ddo/DDO.test.ts @@ -0,0 +1,183 @@ +import {assert} from "chai" +import AdditionalInformation from "../../src/ddo/AdditionalInformation" +import Authentication from "../../src/ddo/Authentication" +import Curation from "../../src/ddo/Curation" +import DDO from "../../src/ddo/DDO" +import MetaData from "../../src/ddo/MetaData" +import MetaDataBase from "../../src/ddo/MetaDataBase" +import PublicKey from "../../src/ddo/PublicKey" +import Service from "../../src/ddo/Service" +import StructuredMarkup from "../../src/ddo/StructuredMarkup" +import Logger from "../../src/utils/Logger" +import * as jsonDDO from "../testdata/ddo.json" + +describe("DDO", () => { + + const testDDO: DDO = new DDO({ + publicKey: [ + { + id: "did:op:123456789abcdefghi#keys-1", + type: "RsaVerificationKey2018", + owner: "did:op:123456789abcdefghi", + publicKeyPem: "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n", + } as PublicKey, + { + id: "did:op:123456789abcdefghi#keys-2", + type: "Ed25519VerificationKey2018", + owner: "did:op:123456789abcdefghi", + publicKeyBase58: "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV", + } as PublicKey, + { + id: "did:op:123456789abcdefghi#keys-3", + type: "RsaPublicKeyExchangeKey2018", + owner: "did:op:123456789abcdefghi", + publicKeyPem: "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n", + } as PublicKey, + ], + authentication: [ + { + type: "RsaSignatureAuthentication2018", + publicKey: "did:op:123456789abcdefghi#keys-1", + } as Authentication, + { + type: "ieee2410Authentication2018", + publicKey: "did:op:123456789abcdefghi#keys-2", + } as Authentication, + ], + service: [ + { + type: "OpenIdConnectVersion1.0Service", + serviceEndpoint: "https://openid.example.com/", + } as Service, + { + type: "CredentialRepositoryService", + serviceEndpoint: "https://repository.example.com/service/8377464", + } as Service, + { + type: "XdiService", + serviceEndpoint: "https://xdi.example.com/8377464", + } as Service, + { + type: "HubService", + serviceEndpoint: "https://hub.example.com/.identity/did:op:0123456789abcdef/", + } as Service, + { + type: "MessagingService", + serviceEndpoint: "https://example.com/messages/8377464", + } as Service, + { + type: "SocialWebInboxService", + serviceEndpoint: "https://social.example.com/83hfh37dj", + description: "My public social inbox", + spamCost: { + amount: "0.50", + currency: "USD", + }, + } as Service, + { + id: "did:op:123456789abcdefghi;bops", + type: "BopsService", + serviceEndpoint: "https://bops.example.com/enterprise/", + } as Service, + { + type: "Consume", + // tslint:disable + serviceEndpoint: "http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}", + } as Service, + { + type: "Compute", + serviceEndpoint: "http://mybrizo.org/api/v1/brizo/services/compute?pubKey=${pubKey}&serviceId={serviceId}&algo={algo}&container={container}", + } as Service, + { + type: "Metadata", + serviceEndpoint: "http://myaquarius.org/api/v1/provider/assets/metadata/{did}", + metadata: { + base: { + name: "UK Weather information 2011", + type: "dataset", + description: "Weather information of UK including temperature and humidity", + size: "3.1gb", + dateCreated: "2012-10-10T17:00:000Z", + author: "Met Office", + license: "CC-BY", + copyrightHolder: "Met Office", + encoding: "UTF-8", + compression: "zip", + contentType: "text/csv", + workExample: "423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68", + contentUrls: [ + "https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip" + ], + links: [ + { + sample1: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-daily/" + }, + { + sample2: "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-averages-25km/" + }, + { + fieldsDescription: "http://data.ceda.ac.uk/badc/ukcp09/" + } + ], + inLanguage: "en", + tags: "weather, uk, 2011, temperature, humidity", + price: 10 + } as MetaDataBase, + curation: { + "rating": 0.93, + "numVotes": 123, + "schema": "Binary Votting" + } as Curation, + additionalInformation: { + updateFrecuency: "yearly", + structuredMarkup: [ + { + "uri": "http://skos.um.es/unescothes/C01194/jsonld", + "mediaType": "application/ld+json" + } as StructuredMarkup, + { + "uri": "http://skos.um.es/unescothes/C01194/turtle", + "mediaType": "text/turtle" + } as StructuredMarkup + ] + } as AdditionalInformation + } as MetaData + } + ] + }) + + describe("#serialize()", () => { + + it("should properly serialize", async () => { + + const ddoString = DDO.serialize(testDDO) + Logger.log(ddoString) + assert(ddoString) + assert(ddoString.startsWith("{")) + }) + }) + + describe("#deserialize()", () => { + + it("should properly deserialize from serialized object", async () => { + + const ddoString = DDO.serialize(testDDO) + assert(ddoString) + + const ddo: DDO = DDO.deserialize(ddoString) + assert(ddo) + + assert(ddo.id == testDDO.id) + assert(ddo.publicKey[0].publicKeyPem == testDDO.publicKey[0].publicKeyPem) + }) + + it("should properly deserialize from json file", async () => { + + const ddo: DDO = DDO.deserialize(JSON.stringify(jsonDDO)) + assert(ddo) + + assert(ddo.id == jsonDDO.id) + assert(ddo.publicKey[0].publicKeyPem == jsonDDO.publicKey[0].publicKeyPem) + }) + }) +}) diff --git a/test/ocean/Order.test.ts b/test/ocean/Order.test.ts index a0bd013..75b0136 100644 --- a/test/ocean/Order.test.ts +++ b/test/ocean/Order.test.ts @@ -9,7 +9,7 @@ import Ocean from "../../src/ocean/Ocean" import Order from "../../src/ocean/Order" import config from "../config" import AquariusMock from "../mocks/Aquarius.mock" -import * as AccessToken from "./AccessToken.json" +import * as AccessToken from "../testdata/AccessToken.json" const testName = "Order Test Asset" const testDescription = "This asset is pure owange" diff --git a/test/ocean/AccessToken.json b/test/testdata/AccessToken.json similarity index 100% rename from test/ocean/AccessToken.json rename to test/testdata/AccessToken.json diff --git a/test/testdata/ddo.json b/test/testdata/ddo.json new file mode 100644 index 0000000..a52b407 --- /dev/null +++ b/test/testdata/ddo.json @@ -0,0 +1,133 @@ +{ + "@context": "https://w3id.org/future-method/v1", + "id": "did:op:123456789abcdefghi", + "publicKey": [ + { + "id": "did:op:123456789abcdefghi#keys-1", + "type": "RsaVerificationKey2018", + "owner": "did:op:123456789abcdefghi", + "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n" + }, + { + "id": "did:op:123456789abcdefghi#keys-2", + "type": "Ed25519VerificationKey2018", + "owner": "did:op:123456789abcdefghi", + "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV" + }, + { + "id": "did:op:123456789abcdefghi#keys-3", + "type": "RsaPublicKeyExchangeKey2018", + "owner": "did:op:123456789abcdefghi", + "publicKeyPem": "-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n" + } + ], + "authentication": [ + { + "type": "RsaSignatureAuthentication2018", + "publicKey": "did:op:123456789abcdefghi#keys-1" + }, + { + "type": "ieee2410Authentication2018", + "publicKey": "did:op:123456789abcdefghi#keys-2" + } + ], + "service": [ + { + "type": "OpenIdConnectVersion1.0Service", + "serviceEndpoint": "https://openid.example.com/" + }, + { + "type": "CredentialRepositoryService", + "serviceEndpoint": "https://repository.example.com/service/8377464" + }, + { + "type": "XdiService", + "serviceEndpoint": "https://xdi.example.com/8377464" + }, + { + "type": "HubService", + "serviceEndpoint": "https://hub.example.com/.identity/did:op:0123456789abcdef/" + }, + { + "type": "MessagingService", + "serviceEndpoint": "https://example.com/messages/8377464" + }, + { + "type": "SocialWebInboxService", + "serviceEndpoint": "https://social.example.com/83hfh37dj", + "description": "My public social inbox", + "spamCost": { + "amount": "0.50", + "currency": "USD" + } + }, + { + "id": "did:op:123456789abcdefghi;bops", + "type": "BopsService", + "serviceEndpoint": "https://bops.example.com/enterprise/" + }, + { + "type": "Consume", + "serviceEndpoint": "http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}" + }, + { + "type": "Compute", + "serviceEndpoint": "http://mybrizo.org/api/v1/brizo/services/compute?pubKey=${pubKey}&serviceId={serviceId}&algo={algo}&container={container}" + }, + { + "type": "Metadata", + "serviceEndpoint": "http://myaquarius.org/api/v1/provider/assets/metadata/{did}", + "metadata": { + "base": { + "name": "UK Weather information 2011", + "type": "dataset", + "description": "Weather information of UK including temperature and humidity", + "size": "3.1gb", + "dateCreated": "2012-10-10T17:00:000Z", + "author": "Met Office", + "license": "CC-BY", + "copyrightHolder": "Met Office", + "encoding": "UTF-8", + "compression": "zip", + "contentType": "text/csv", + "workExample": "423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68", + "contentUrls": [ + "https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip" + ], + "links": [ + { + "sample1": "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-daily/" + }, + { + "sample2": "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-averages-25km/" + }, + { + "fieldsDescription": "http://data.ceda.ac.uk/badc/ukcp09/" + } + ], + "inLanguage": "en", + "tags": "weather, uk, 2011, temperature, humidity", + "price": 10 + }, + "curation": { + "rating": 0.93, + "numVotes": 123, + "schema": "Binary Votting" + }, + "additionalInformation": { + "updateFrecuency": "yearly", + "structuredMarkup": [ + { + "uri": "http://skos.um.es/unescothes/C01194/jsonld", + "mediaType": "application/ld+json" + }, + { + "uri": "http://skos.um.es/unescothes/C01194/turtle", + "mediaType": "text/turtle" + } + ] + } + } + } + ] +} From 56fc8e6f231faec1a19040dc9cef835ceae9ca1c Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 1 Nov 2018 11:05:29 +0100 Subject: [PATCH 35/38] fixed lint error --- src/ddo/MetaData.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ddo/MetaData.ts b/src/ddo/MetaData.ts index e1abd25..9613b2a 100644 --- a/src/ddo/MetaData.ts +++ b/src/ddo/MetaData.ts @@ -1,7 +1,7 @@ -import Curation from "./Curation" -import StructuredMarkup from "./StructuredMarkup" import AdditionalInformation from "./AdditionalInformation" +import Curation from "./Curation" import MetaDataBase from "./MetaDataBase" +import StructuredMarkup from "./StructuredMarkup" export default class MetaData { From 787ed9dcf39a1bb5e10a3e4053848b349ff57be1 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 1 Nov 2018 11:22:00 +0100 Subject: [PATCH 36/38] made ddo business object more versatile --- src/ddo/DDO.ts | 14 +++++++------- test/ddo/DDO.test.ts | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/ddo/DDO.ts b/src/ddo/DDO.ts index d0febe6..1cca7f8 100644 --- a/src/ddo/DDO.ts +++ b/src/ddo/DDO.ts @@ -23,13 +23,13 @@ export default class DDO { // @ts-ignore private assa: string - public constructor(ddo: { - publicKey: PublicKey[], - authentication: Authentication[], - service: Service[], + public constructor(ddo?: { + publicKey?: PublicKey[], + authentication?: Authentication[], + service?: Service[], }) { - this.publicKey = ddo.publicKey - this.authentication = ddo.authentication - this.service = ddo.service + this.publicKey = ddo ? ddo.publicKey ? ddo.publicKey : [] : [] + this.authentication = ddo ? ddo.authentication ? ddo.authentication : [] : [] + this.service = ddo ? ddo.service ? ddo.service : [] : [] } } diff --git a/test/ddo/DDO.test.ts b/test/ddo/DDO.test.ts index b729182..f57fad0 100644 --- a/test/ddo/DDO.test.ts +++ b/test/ddo/DDO.test.ts @@ -8,7 +8,6 @@ import MetaDataBase from "../../src/ddo/MetaDataBase" import PublicKey from "../../src/ddo/PublicKey" import Service from "../../src/ddo/Service" import StructuredMarkup from "../../src/ddo/StructuredMarkup" -import Logger from "../../src/utils/Logger" import * as jsonDDO from "../testdata/ddo.json" describe("DDO", () => { @@ -151,12 +150,43 @@ describe("DDO", () => { it("should properly serialize", async () => { const ddoString = DDO.serialize(testDDO) - Logger.log(ddoString) assert(ddoString) assert(ddoString.startsWith("{")) }) }) + describe("#constructor()", () => { + + it("should create an empty ddo", async () => { + + const ddo = new DDO() + assert(ddo) + + assert(ddo.service.length === 0) + assert(ddo.authentication.length === 0) + assert(ddo.publicKey.length === 0) + }) + + it("should create an predefined ddo", async () => { + + const service: Service = { + serviceEndpoint: "http://", + description: "nice service" + } as Service + + const ddo = new DDO({ + service: [service] + }) + assert(ddo) + + assert(ddo.service.length === 1) + assert(ddo.service[0].description === service.description) + + assert(ddo.authentication.length === 0) + assert(ddo.publicKey.length === 0) + }) + }) + describe("#deserialize()", () => { it("should properly deserialize from serialized object", async () => { From 093a6ea4af9f9315049f8c66d52d618db3d13b32 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 1 Nov 2018 12:47:48 +0100 Subject: [PATCH 37/38] added ddo handling --- src/aquarius/Aquarius.ts | 58 +++++++++++++--- src/aquarius/AquariusConnector.ts | 28 +++++--- src/aquarius/AquariusConnectorProvider.ts | 3 - src/aquarius/query/Query.ts | 3 + src/aquarius/query/SearchQuery.ts | 14 ++++ src/aquarius/query/Sort.ts | 3 + src/ddo/DDO.ts | 2 + test/aquarius/Aquarius.test.ts | 85 +++++++++++++++++++++-- test/mocks/AquariusConnector.mock.ts | 25 ++++--- 9 files changed, 182 insertions(+), 39 deletions(-) create mode 100644 src/aquarius/query/Query.ts create mode 100644 src/aquarius/query/SearchQuery.ts create mode 100644 src/aquarius/query/Sort.ts diff --git a/src/aquarius/Aquarius.ts b/src/aquarius/Aquarius.ts index 2e14c4b..331187c 100644 --- a/src/aquarius/Aquarius.ts +++ b/src/aquarius/Aquarius.ts @@ -1,6 +1,9 @@ +import {URL} from "url" +import DDO from "../ddo/DDO" import Config from "../models/Config" import Logger from "../utils/Logger" import AquariusConnectorProvider from "./AquariusConnectorProvider" +import SearchQuery from "./query/SearchQuery" export default class Aquarius { @@ -11,7 +14,7 @@ export default class Aquarius { this.url = config.aquariusUri } - public async getAccessUrl(accessToken: any, payload: any): Promise { + public async getAccessUrl(accessToken: any, payload: any): Promise { const accessUrl = await AquariusConnectorProvider.getConnector().post( `${accessToken.service_endpoint}/${accessToken.resource_id}`, @@ -33,11 +36,10 @@ export default class Aquarius { return accessUrl } - public async queryMetadata(query): Promise { + public async queryMetadata(query: SearchQuery): Promise { - const result = await AquariusConnectorProvider.getConnector().post( - this.url + "/api/v1/aquarius/assets/ddo/query", - JSON.stringify(query)) + const result = await AquariusConnectorProvider.getConnector() + .post(this.url + "/api/v1/aquarius/assets/ddo/query", JSON.stringify(query)) .then((response: any) => { if (response.ok) { return response.json() @@ -51,11 +53,15 @@ export default class Aquarius { return result } - public async queryMetadataByText(query): Promise { + public async queryMetadataByText(query: SearchQuery): Promise { - const result = await AquariusConnectorProvider.getConnector().get( - this.url + "/api/v1/aquarius/assets/ddo/query", - JSON.stringify(query)) + const fullUrl = new URL(this.url + "/api/v1/aquarius/assets/ddo/query") + fullUrl.searchParams.append("text", query.text) + fullUrl.searchParams.append("sort", JSON.stringify(query.sort)) + fullUrl.searchParams.append("offset", query.offset.toString()) + fullUrl.searchParams.append("page", query.page.toString()) + const result = await AquariusConnectorProvider.getConnector() + .get(fullUrl) .then((response: any) => { if (response.ok) { return response.json() @@ -68,4 +74,38 @@ export default class Aquarius { return result } + + public async storeDDO(ddo: DDO): Promise { + const fullUrl = this.url + `/api/v1/aquarius/assets/ddo` + const result = await AquariusConnectorProvider.getConnector() + .post(fullUrl, DDO.serialize(ddo)) + .then((response: any) => { + if (response.ok) { + return response.json() + } + Logger.log("Failed:", response.status, response.statusText) + }) + .catch((error) => { + Logger.error("Error fetching querying metadata: ", error) + }) + + return result + } + + public async retrieveDDO(did: string): Promise { + const fullUrl = this.url + `/api/v1/aquarius/assets/ddo/${did}` + const result = await AquariusConnectorProvider.getConnector() + .get(fullUrl) + .then((response: any) => { + if (response.ok) { + return response.json() + } + Logger.log("Failed:", response.status, response.statusText) + }) + .catch((error) => { + Logger.error("Error fetching querying metadata: ", error) + }) + + return result + } } diff --git a/src/aquarius/AquariusConnector.ts b/src/aquarius/AquariusConnector.ts index 243bd23..d4e0ad3 100644 --- a/src/aquarius/AquariusConnector.ts +++ b/src/aquarius/AquariusConnector.ts @@ -1,10 +1,9 @@ import fetch from "node-fetch" -import { URL } from "url" export default class AquariusConnector { - public post(url, payload) { - return fetch(url, { + public async post(url, payload): Promise { + return this.fetch(url, { method: "POST", body: payload, headers: { @@ -13,17 +12,26 @@ export default class AquariusConnector { }) } - public get(url, payload) { - const fullUrl = new URL(url) - for (const key of Object.keys(payload)) { - fullUrl.searchParams.append(key, payload[key]) - } - return fetch(fullUrl, { + public async get(url): Promise { + return this.fetch(url, { method: "GET", - body: null, headers: { "Content-type": "application/json", }, }) } + + public async put(url, payload): Promise { + return this.fetch(url, { + method: "PUT", + body: payload, + headers: { + "Content-type": "application/json", + }, + }) + } + + private async fetch(url, opts): Promise { + return fetch(url, opts) + } } diff --git a/src/aquarius/AquariusConnectorProvider.ts b/src/aquarius/AquariusConnectorProvider.ts index 997e659..5c2bbd5 100644 --- a/src/aquarius/AquariusConnectorProvider.ts +++ b/src/aquarius/AquariusConnectorProvider.ts @@ -1,12 +1,9 @@ -import Logger from "../utils/Logger" import AquariusConnector from "./AquariusConnector" export default class AquariusConnectorProvider { public static setConnector(connector: AquariusConnector) { - Logger.log("setting", typeof connector.constructor.name) - AquariusConnectorProvider.connector = connector } diff --git a/src/aquarius/query/Query.ts b/src/aquarius/query/Query.ts new file mode 100644 index 0000000..2bf1b66 --- /dev/null +++ b/src/aquarius/query/Query.ts @@ -0,0 +1,3 @@ +export default class Query { + public value: number = 1 +} \ No newline at end of file diff --git a/src/aquarius/query/SearchQuery.ts b/src/aquarius/query/SearchQuery.ts new file mode 100644 index 0000000..16eea31 --- /dev/null +++ b/src/aquarius/query/SearchQuery.ts @@ -0,0 +1,14 @@ +import Query from "./Query" +import Sort from "./Sort" + +export default class SearchQuery { + public offset: number = 100 + public page: number = 0 + public query: Query = { + value: 1, + } as Query + public sort: Sort = { + value: 1, + } as Sort + public text: string = "Office" +} diff --git a/src/aquarius/query/Sort.ts b/src/aquarius/query/Sort.ts new file mode 100644 index 0000000..3aa3fd9 --- /dev/null +++ b/src/aquarius/query/Sort.ts @@ -0,0 +1,3 @@ +export default class Sort { + public value: number = 1 +} diff --git a/src/ddo/DDO.ts b/src/ddo/DDO.ts index 1cca7f8..4682f28 100644 --- a/src/ddo/DDO.ts +++ b/src/ddo/DDO.ts @@ -24,10 +24,12 @@ export default class DDO { private assa: string public constructor(ddo?: { + id?: string, publicKey?: PublicKey[], authentication?: Authentication[], service?: Service[], }) { + this.id = ddo ? ddo.id ? ddo.id : null : null this.publicKey = ddo ? ddo.publicKey ? ddo.publicKey : [] : [] this.authentication = ddo ? ddo.authentication ? ddo.authentication : [] : [] this.service = ddo ? ddo.service ? ddo.service : [] : [] diff --git a/test/aquarius/Aquarius.test.ts b/test/aquarius/Aquarius.test.ts index d5ed2aa..421a081 100644 --- a/test/aquarius/Aquarius.test.ts +++ b/test/aquarius/Aquarius.test.ts @@ -1,21 +1,20 @@ import * as assert from "assert" import Aquarius from "../../src/aquarius/Aquarius" import AquariusConnectorProvider from "../../src/aquarius/AquariusConnectorProvider" +import SearchQuery from "../../src/aquarius/query/SearchQuery" +import DDO from "../../src/ddo/DDO" +import IdGenerator from "../../src/ocean/IdGenerator" import config from "../config" import AquariusConnectorMock from "../mocks/AquariusConnector.mock" +// import * as jsonDDO from "../testdata/ddo.json" describe("Aquarius", () => { - before(() => { - AquariusConnectorProvider.setConnector(new AquariusConnectorMock()) - }) - + const aquarius: Aquarius = new Aquarius(config) describe("#queryMetadata()", () => { it("should query metadata", async () => { - const aquarius: Aquarius = new Aquarius(config) - const query = { offset: 100, page: 0, @@ -26,12 +25,84 @@ describe("Aquarius", () => { value: 1, }, text: "Office", - } + } as SearchQuery + + // @ts-ignore + AquariusConnectorProvider.setConnector(new AquariusConnectorMock()) const result: any[] = await aquarius.queryMetadata(query) assert(result) + assert(result.length !== null) }) }) + describe("#queryMetadataByText()", () => { + + it("should query metadata by text", async () => { + + const query = { + offset: 100, + page: 0, + query: { + value: 1, + }, + sort: { + value: 1, + }, + text: "Office", + } as SearchQuery + + // @ts-ignore + AquariusConnectorProvider.setConnector(new AquariusConnectorMock()) + + const result: any[] = await aquarius.queryMetadataByText(query) + assert(result) + assert(result.length !== null) + }) + + }) + + describe("#storeDDO()", () => { + + it("should store a ddo", async () => { + + const did: string = `did:op:${IdGenerator.generateId()}` + const ddo: DDO = new DDO({ + id: did, + }) + + // @ts-ignore + AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo)) + + const result: DDO = await aquarius.storeDDO(ddo) + assert(result) + assert(result.id === ddo.id) + }) + }) + + describe("#retrieveDDO()", () => { + + it("should store a ddo", async () => { + + const did: string = `did:op:${IdGenerator.generateId()}` + const ddo: DDO = new DDO({ + id: did, + }) + + // @ts-ignore + AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo)) + + const storageResult: DDO = await aquarius.storeDDO(ddo) + assert(storageResult) + + assert(storageResult.id === did) + + const restrieveResult: DDO = await aquarius.retrieveDDO(did) + assert(restrieveResult) + + assert(restrieveResult.id === did) + assert(restrieveResult.id === storageResult.id) + }) + }) }) diff --git a/test/mocks/AquariusConnector.mock.ts b/test/mocks/AquariusConnector.mock.ts index 5e0db38..3326ece 100644 --- a/test/mocks/AquariusConnector.mock.ts +++ b/test/mocks/AquariusConnector.mock.ts @@ -1,17 +1,22 @@ import AquariusConnector from "../../src/aquarius/AquariusConnector" +// @ts-ignore export default class AquariusConnectorMock extends AquariusConnector { - public async post(url: string, payload: any) { + constructor(private returnData: any) { + super() + } - return { - ok: true, - json: () => { - return [] - }, - text: () => { - return "" - }, - } + // @ts-ignore + private async fetch(url, opts): Promise { + + return new Promise((resolve, reject) => { + resolve({ + ok: true, + json: () => { + return this.returnData ? this.returnData : [] + }, + }) + }) } } From 1d9754fba68e47413347a9bc5ed49de5a9807fd5 Mon Sep 17 00:00:00 2001 From: Sebastian Gerske Date: Thu, 1 Nov 2018 13:24:41 +0100 Subject: [PATCH 38/38] make lint more solid --- package.json | 2 +- src/aquarius/Aquarius.ts | 16 ++++++++-------- src/aquarius/AquariusConnectorProvider.ts | 2 +- src/aquarius/query/Query.ts | 2 +- test/mocks/AquariusConnector.mock.ts | 3 +++ test/ocean/Ocean.test.ts | 1 - 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 1ed198a..9e2172f 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "test:watch": "mocha -w --watch-extensions js,ts,json", "test:cover": "nyc mocha", "clean": "rm -rf ./dist/ ./doc/ ./coverage ./.nyc_output", - "lint": "tslint -c tslint.json 'src/**/*.ts'", + "lint": "tslint -c tslint.json 'src/**/*.ts' 'test/**/*.ts'", "start": "npm link @oceanprotocol/keeper-contracts @oceanprotocol/secret-store-client && npm run build:watch", "build": "npm run clean && npm run lint && tsc && npm run doc", "build:watch": "tsc -w", diff --git a/src/aquarius/Aquarius.ts b/src/aquarius/Aquarius.ts index 331187c..0f1d3ad 100644 --- a/src/aquarius/Aquarius.ts +++ b/src/aquarius/Aquarius.ts @@ -14,23 +14,23 @@ export default class Aquarius { this.url = config.aquariusUri } - public async getAccessUrl(accessToken: any, payload: any): Promise { + public async getAccessUrl(accessToken: any, payload: any): Promise { - const accessUrl = await AquariusConnectorProvider.getConnector().post( - `${accessToken.service_endpoint}/${accessToken.resource_id}`, - payload) - .then((response: any) => { + const accessUrl: string = await AquariusConnectorProvider.getConnector() + .post(`${accessToken.service_endpoint}/${accessToken.resource_id}`, payload) + .then((response: any): string => { if (response.ok) { return response.text() } - Logger.log("Failed: ", response.status, response.statusText) + Logger.error("Failed: ", response.status, response.statusText) }) - .then((consumptionUrl: string) => { + .then((consumptionUrl: string): string => { Logger.log("Success accessing consume endpoint: ", consumptionUrl) return consumptionUrl }) .catch((error) => { Logger.error("Error fetching the data asset consumption url: ", error) + return null }) return accessUrl @@ -77,7 +77,7 @@ export default class Aquarius { public async storeDDO(ddo: DDO): Promise { const fullUrl = this.url + `/api/v1/aquarius/assets/ddo` - const result = await AquariusConnectorProvider.getConnector() + const result: DDO = await AquariusConnectorProvider.getConnector() .post(fullUrl, DDO.serialize(ddo)) .then((response: any) => { if (response.ok) { diff --git a/src/aquarius/AquariusConnectorProvider.ts b/src/aquarius/AquariusConnectorProvider.ts index 5c2bbd5..5b00b31 100644 --- a/src/aquarius/AquariusConnectorProvider.ts +++ b/src/aquarius/AquariusConnectorProvider.ts @@ -7,7 +7,7 @@ export default class AquariusConnectorProvider { AquariusConnectorProvider.connector = connector } - public static getConnector() { + public static getConnector(): AquariusConnector { if (!AquariusConnectorProvider.connector) { AquariusConnectorProvider.connector = new AquariusConnector() diff --git a/src/aquarius/query/Query.ts b/src/aquarius/query/Query.ts index 2bf1b66..1c5c892 100644 --- a/src/aquarius/query/Query.ts +++ b/src/aquarius/query/Query.ts @@ -1,3 +1,3 @@ export default class Query { public value: number = 1 -} \ No newline at end of file +} diff --git a/test/mocks/AquariusConnector.mock.ts b/test/mocks/AquariusConnector.mock.ts index 3326ece..ccf0168 100644 --- a/test/mocks/AquariusConnector.mock.ts +++ b/test/mocks/AquariusConnector.mock.ts @@ -16,6 +16,9 @@ export default class AquariusConnectorMock extends AquariusConnector { json: () => { return this.returnData ? this.returnData : [] }, + text: () => { + return this.returnData ? this.returnData.toString() : "" + }, }) }) } diff --git a/test/ocean/Ocean.test.ts b/test/ocean/Ocean.test.ts index 7a9df7f..a7ef21e 100644 --- a/test/ocean/Ocean.test.ts +++ b/test/ocean/Ocean.test.ts @@ -84,7 +84,6 @@ describe("Ocean", () => { assert(orders.length === 1) assert(orders[0].getId() === order.getId()) - }) })