1
0
mirror of https://github.com/oceanprotocol-archive/squid-js.git synced 2024-02-02 15:31:51 +01:00

added secret store connection

This commit is contained in:
Sebastian Gerske 2018-10-19 13:42:24 +02:00
parent d777bd9030
commit 2662a7795b
7 changed files with 351 additions and 16 deletions

61
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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<string> {
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())
})
})
}
}

View File

@ -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<string> {
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<string> {
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<string> {
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
}
}

View File

@ -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<string> {
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)
}
}

View File

@ -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)
})
})
})

View File

@ -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)
})
})
})