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

moved secret store to secret-store-client-js

This commit is contained in:
Sebastian Gerske 2018-10-22 13:39:31 +02:00
parent b172a245b1
commit 717ca1d07c
14 changed files with 10 additions and 460 deletions

9
package-lock.json generated
View File

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

View File

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

View File

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

View File

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

View File

@ -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<string> {
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<any> {
// 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<string> {
// 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<GeneratedKey> {
// generate document key from server key
const documentKeys: GeneratedKey = await this.partiyClient.generateDocumentKeyFromKey(serverKey)
return documentKeys
}
private async storeDocumentKey(serverKeyId: string, documentKeys: GeneratedKey): Promise<boolean> {
// 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<RetrievedKey> {
// 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
}
}

View File

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

View File

@ -1,6 +0,0 @@
import KeyBase from "./KeyBase"
export default class GeneratedKey extends KeyBase {
public encryptedKey: string
public encryptedPoint: string
}

View File

@ -1,3 +0,0 @@
export default class KeyBase {
public commonPoint: string
}

View File

@ -1,6 +0,0 @@
import KeyBase from "./KeyBase"
export default class RetrievedKey extends KeyBase {
public decryptedSecret: string
public decryptShadows: string[]
}

View File

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

View File

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

View File

@ -1,5 +0,0 @@
{
"commonPoint": "0xba52313ef585265b52434b1c45a7aa19cf59e371b8d4f5d5f3ef45863e51341b9648dc83ce11b7158347b2cfb2613f92689d6d3704e84dee4eafd38abd0c7ca6",
"encryptedKey": "0x04e77b1d4b3919354550900d871c8ee698ca592e45ee715dad607c408fc18982bae479b3c752dec27eebbe00b102b512e6454e747138f4d882a2fa3dbe84bb3851518766c01e216fc5b01f7a4eb2e18ea2f159063801b0e43f5f632089a80ab982520707ee9e3f4980931a8814e44febdd960b366336ee35b26bfe523950d28bb6bdc0a65240c43b999cae3cd8258a06cb8dd52b2a2516bf15ad4d00d8c50f4e5f8bc48cf7173db5cce77a182093404402",
"encryptedPoint": "0x1697d31ba17eb819177004618f2a5e00fceb355b12ceb4a476ade59adfc9f6579f9b951ef0695eb852f1ff1deff1f12205760b8d1c5a46ba44cce7d54571200a"
}

View File

@ -1,8 +0,0 @@
{
"commonPoint": "0xba52313ef585265b52434b1c45a7aa19cf59e371b8d4f5d5f3ef45863e51341b69b7237c31ee48ea7cb84d304d9ec06d976292c8fb17b211b1502c7442f37f89",
"decryptedSecret": "0x7b6bee06bd00dc825d2c99f324b47e4aee9219d5453076a735cfc3d55c730df285c6e0117ceb90805aee7cfb86e0574d04c17aa09cdff9957b4a91a2af79a3d3",
"decryptShadows": [
"0x0429f62a48a25306bb64d8a5b74b0d6ee01f062fe1f7238f6b5078e3e7726751b46dd8834c5346bca3d6059ddc923747ecfea545579210db09f8a6708ab05f452ace3956408afddcb3b8796637198109fa046af23c6bcd6da5424cf8d7165d805c6265ea4e358731e4a71d32760d0423d12cf117d9b401bd2d7c321a4b9d47a79d383adce06c45352e23f2bec3262d637b",
"0x045fdbbb9782c046f3023e1d699ee9ae80413e44162ecf4f5ac6ace369f7e0604035abb3b7aed9d087293561ef75eb9296a6582cbefb1af7f449a97bcb5282f9b6cbb1059d595b2e2ec6cef40fceacf228462bebe985b8738e22c6ec196b25e408b7cbb608a74a167a2b5d4e12182e2942ded30d18a6b99b243395d4a4cabe25168560946ce3dd5d77b48b5148c78491e1"
]
}

View File

@ -1 +0,0 @@
"0x92c18be2b3f6aea31fc1e58f833936f16f635c0657bf03c3b05a0e3f5809ffec64736f0774b9be536e65a125b05fd21c0ae32a03c1338dcbe6ddb1ce2cd5b95a"