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:
parent
b172a245b1
commit
717ca1d07c
9
package-lock.json
generated
9
package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import KeyBase from "./KeyBase"
|
||||
|
||||
export default class GeneratedKey extends KeyBase {
|
||||
public encryptedKey: string
|
||||
public encryptedPoint: string
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export default class KeyBase {
|
||||
public commonPoint: string
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import KeyBase from "./KeyBase"
|
||||
|
||||
export default class RetrievedKey extends KeyBase {
|
||||
public decryptedSecret: string
|
||||
public decryptShadows: string[]
|
||||
}
|
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"commonPoint": "0xba52313ef585265b52434b1c45a7aa19cf59e371b8d4f5d5f3ef45863e51341b9648dc83ce11b7158347b2cfb2613f92689d6d3704e84dee4eafd38abd0c7ca6",
|
||||
"encryptedKey": "0x04e77b1d4b3919354550900d871c8ee698ca592e45ee715dad607c408fc18982bae479b3c752dec27eebbe00b102b512e6454e747138f4d882a2fa3dbe84bb3851518766c01e216fc5b01f7a4eb2e18ea2f159063801b0e43f5f632089a80ab982520707ee9e3f4980931a8814e44febdd960b366336ee35b26bfe523950d28bb6bdc0a65240c43b999cae3cd8258a06cb8dd52b2a2516bf15ad4d00d8c50f4e5f8bc48cf7173db5cce77a182093404402",
|
||||
"encryptedPoint": "0x1697d31ba17eb819177004618f2a5e00fceb355b12ceb4a476ade59adfc9f6579f9b951ef0695eb852f1ff1deff1f12205760b8d1c5a46ba44cce7d54571200a"
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"commonPoint": "0xba52313ef585265b52434b1c45a7aa19cf59e371b8d4f5d5f3ef45863e51341b69b7237c31ee48ea7cb84d304d9ec06d976292c8fb17b211b1502c7442f37f89",
|
||||
"decryptedSecret": "0x7b6bee06bd00dc825d2c99f324b47e4aee9219d5453076a735cfc3d55c730df285c6e0117ceb90805aee7cfb86e0574d04c17aa09cdff9957b4a91a2af79a3d3",
|
||||
"decryptShadows": [
|
||||
"0x0429f62a48a25306bb64d8a5b74b0d6ee01f062fe1f7238f6b5078e3e7726751b46dd8834c5346bca3d6059ddc923747ecfea545579210db09f8a6708ab05f452ace3956408afddcb3b8796637198109fa046af23c6bcd6da5424cf8d7165d805c6265ea4e358731e4a71d32760d0423d12cf117d9b401bd2d7c321a4b9d47a79d383adce06c45352e23f2bec3262d637b",
|
||||
"0x045fdbbb9782c046f3023e1d699ee9ae80413e44162ecf4f5ac6ace369f7e0604035abb3b7aed9d087293561ef75eb9296a6582cbefb1af7f449a97bcb5282f9b6cbb1059d595b2e2ec6cef40fceacf228462bebe985b8738e22c6ec196b25e408b7cbb608a74a167a2b5d4e12182e2942ded30d18a6b99b243395d4a4cabe25168560946ce3dd5d77b48b5148c78491e1"
|
||||
]
|
||||
}
|
@ -1 +0,0 @@
|
||||
"0x92c18be2b3f6aea31fc1e58f833936f16f635c0657bf03c3b05a0e3f5809ffec64736f0774b9be536e65a125b05fd21c0ae32a03c1338dcbe6ddb1ce2cd5b95a"
|
Loading…
Reference in New Issue
Block a user