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

encrypt contentUrls at once instead separate, move generation of serviceAgreementId outside of signAgreement and executeAgreement in ocean object, hardened sign and execute of service agreements, wrote unit tests

This commit is contained in:
Sebastian Gerske 2018-11-12 12:09:42 +01:00
parent 86d1621046
commit 0c46763095
16 changed files with 208 additions and 85 deletions

View File

@ -19,6 +19,7 @@ const base: MetaDataBase = {
workExample: "stationId,latitude,longitude,datetime,temperature,humidity423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68",
contentUrls: [
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip",
"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/"},

View File

@ -11,7 +11,8 @@ export default class MetaDataBase {
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[] = [
public contentUrls: string | string[] = [
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip",
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip",
]
public links: any[] = [

View File

@ -1,6 +1,7 @@
import DDO from "../ddo/DDO"
import MetaData from "../ddo/MetaData"
import MetaDataBase from "../ddo/MetaDataBase"
import IdGenerator from "../ocean/IdGenerator"
import {Account, Logger, Ocean, ServiceAgreement} from "../squid"
(async () => {
@ -35,6 +36,7 @@ import {Account, Logger, Ocean, ServiceAgreement} from "../squid"
workExample: "stationId,latitude,longitude,datetime,temperature,humidity423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68",
contentUrls: [
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip",
"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/"},
@ -48,12 +50,14 @@ import {Account, Logger, Ocean, ServiceAgreement} from "../squid"
} as MetaData)
const ddo: DDO = await ocean.registerAsset(metaData, publisher)
Logger.log(ddo.id)
Logger.log("did", ddo.id)
const serviceAgreementSignature: string = await ocean.signServiceAgreement(ddo.id, consumer)
Logger.log(serviceAgreementSignature)
const serviceAgreementId: string = IdGenerator.generateId()
const serviceAgreementSignature: string = await ocean.signServiceAgreement(ddo.id, serviceAgreementId, consumer)
Logger.log("ServiceAgreement Signature:", serviceAgreementSignature)
const serviceAgreement: ServiceAgreement = await ocean.executeServiceAgreement(ddo.id, serviceAgreementId,
serviceAgreementSignature, consumer, publisher)
Logger.log("ServiceAgreement Id:", serviceAgreement.getId())
const serviceAgreement: ServiceAgreement = await ocean.executeServiceAgreement(ddo.id, serviceAgreementSignature,
consumer, publisher)
Logger.log(serviceAgreement)
})()

View File

@ -34,6 +34,7 @@ import {Account, Logger, Ocean} from "../squid"
workExample: "stationId,latitude,longitude,datetime,temperature,humidity423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68",
contentUrls: [
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip",
"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/"},

View File

@ -0,0 +1,22 @@
import {Account, Logger, Ocean, ServiceAgreementTemplate, Templates} from "../squid"
(async () => {
const ocean: Ocean = await Ocean.getInstance({
nodeUri: "http://localhost:8545",
aquariusUri: "http://localhost:5000",
brizoUri: "https://localhost:8030",
parityUri: "http://localhost:9545",
secretStoreUri: "https://secret-store.dev-ocean.com",
threshold: 2,
password: "unittest",
address: "0xed243adfb84a6626eba46178ccb567481c6e655d",
})
const templateOwner: Account = (await ocean.getAccounts())[5]
const serviceAgreementTemplate: ServiceAgreementTemplate = new ServiceAgreementTemplate(new Templates.Access())
const serviceAgreementRegistered: boolean = await serviceAgreementTemplate.register(templateOwner.getId())
Logger.log("ServiceAgreement registered:", serviceAgreementRegistered,
"templateId:", serviceAgreementTemplate.getId())
})()

View File

@ -14,9 +14,12 @@ import {Logger, Ocean} from "../squid"
})
const result: DDO[] = await ocean.searchAssetsByText("Office Humidity")
const dids = result.map((res: DDO) => {
return res.id
const names: string[] = result.map((res: DDO): string => {
const service = res.service.find((srv) => srv.type === "Metadata")
if (service && service.metadata) {
return service.metadata.base.name
}
})
Logger.log(dids.length, JSON.stringify(dids, null, 2))
Logger.log(names.length, names)
})()

View File

@ -1,6 +1,6 @@
import MetaData from "../../test/testdata/MetaData"
import DDO from "../ddo/DDO"
import MetaData from "../ddo/MetaData"
import MetaDataBase from "../ddo/MetaDataBase"
import IdGenerator from "../ocean/IdGenerator"
import {Account, Logger, Ocean} from "../squid"
(async () => {
@ -18,38 +18,10 @@ import {Account, Logger, Ocean} from "../squid"
const publisher: Account = (await ocean.getAccounts())[0]
const consumer: Account = (await ocean.getAccounts())[1]
const metaData = new MetaData({
base: {
name: "Office Humidity",
type: "dataset",
description: "Weather information of UK including temperature and humidity",
size: "3.1gb",
dateCreated: "2012-02-01T10:55:11+00:00",
author: "Met Office",
license: "CC-BY",
copyrightHolder: "Met Office",
encoding: "UTF-8",
compression: "zip",
contentType: "text/csv",
// tslint:disable-next-line
workExample: "stationId,latitude,longitude,datetime,temperature,humidity423432fsd,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,
} as MetaData)
const ddo: DDO = await ocean.registerAsset(MetaData, publisher)
Logger.log("did", ddo.id)
const ddo: DDO = await ocean.registerAsset(metaData, publisher)
Logger.log(ddo.id)
const serviceAgreementSignature = await ocean.signServiceAgreement(ddo.id, consumer)
Logger.log(serviceAgreementSignature)
const serviceAgreementId: string = IdGenerator.generateId()
const serviceAgreementSignature = await ocean.signServiceAgreement(ddo.id, serviceAgreementId, consumer)
Logger.log("ServiceAgreement Signature:", serviceAgreementSignature)
})()

View File

@ -1,7 +1,5 @@
import Aquarius from "../aquarius/Aquarius"
import AquariusProvider from "../aquarius/AquariusProvider"
import SearchQuery from "../aquarius/query/SearchQuery"
import Brizo from "../brizo/Brizo"
import BrizoProvider from "../brizo/BrizoProvider"
import ConfigProvider from "../ConfigProvider"
import Authentication from "../ddo/Authentication"
@ -16,6 +14,7 @@ import Config from "../models/Config"
import ValuePair from "../models/ValuePair"
import ValueType from "../models/ValueType"
import SecretStoreProvider from "../secretstore/SecretStoreProvider"
import Logger from "../utils/Logger"
import Account from "./Account"
import IdGenerator from "./IdGenerator"
import Condition from "./ServiceAgreements/Condition"
@ -31,8 +30,6 @@ export default class Ocean {
ConfigProvider.setConfig(config)
Ocean.instance = new Ocean()
Ocean.instance.keeper = await Keeper.getInstance()
Ocean.instance.aquarius = await AquariusProvider.getAquarius()
Ocean.instance.brizo = await BrizoProvider.getBrizo()
}
return Ocean.instance
@ -41,8 +38,6 @@ export default class Ocean {
private static instance = null
private keeper: Keeper
private aquarius: Aquarius
private brizo: Brizo
private constructor() {
}
@ -58,17 +53,15 @@ export default class Ocean {
public async registerAsset(metadata: MetaData, publisher: Account): Promise<DDO> {
const {didRegistry} = this.keeper
const aquarius = AquariusProvider.getAquarius()
const brizo = BrizoProvider.getBrizo()
const id: string = IdGenerator.generateId()
const did: string = `did:op:${id}`
const serviceDefinitionId: string = IdGenerator.generatePrefixedId()
metadata.base.contentUrls = await Promise.all(metadata.base.contentUrls.map(async (contentUrl) => {
const encryptedUrl: string = await SecretStoreProvider.getSecretStore().encryptDocument(id, contentUrl)
return encryptedUrl
}))
metadata.base.contentUrls =
await SecretStoreProvider.getSecretStore().encryptDocument(id, metadata.base.contentUrls)
const template = new Access()
const serviceAgreementTemplate = new ServiceAgreementTemplate(template)
@ -92,7 +85,7 @@ export default class Ocean {
} as DDOCondition
})
const serviceEndpoint = this.aquarius.getServiceEndpoint(did)
const serviceEndpoint = aquarius.getServiceEndpoint(did)
// create ddo itself
const ddo: DDO = new DDO({
@ -118,8 +111,8 @@ export default class Ocean {
service: [
{
type: template.templateName,
purchaseEndpoint: this.brizo.getPurchaseEndpoint(),
serviceEndpoint: this.brizo.getConsumeEndpoint(publisher.getId(),
purchaseEndpoint: brizo.getPurchaseEndpoint(),
serviceEndpoint: brizo.getConsumeEndpoint(publisher.getId(),
serviceDefinitionId, metadata.base.contentUrls[0]),
// the id of the service agreement?
serviceDefinitionId,
@ -128,7 +121,7 @@ export default class Ocean {
conditions: ddoConditions,
} as Service,
{
serviceEndpoint: this.brizo.getComputeEndpoint(publisher.getId(),
serviceEndpoint: brizo.getComputeEndpoint(publisher.getId(),
serviceDefinitionId, "xxx", "xxx"),
type: "Compute",
} as Service,
@ -140,7 +133,7 @@ export default class Ocean {
],
})
const storedDdo = await this.aquarius.storeDDO(ddo)
const storedDdo = await aquarius.storeDDO(ddo)
await didRegistry.registerAttribute(id, ValueType.DID, "Metadata", serviceEndpoint,
publisher.getId())
@ -148,25 +141,27 @@ export default class Ocean {
return storedDdo
}
public async signServiceAgreement(did: string, consumer: Account): Promise<string> {
public async signServiceAgreement(did: string, serviceAgreementId: string, consumer: Account): Promise<string> {
const ddo = await AquariusProvider.getAquarius().retrieveDDO(did)
const id = did.replace("did:op:", "")
const serviceAgreementId: string = IdGenerator.generateId()
const serviceAgrementSignature: string = await ServiceAgreement.signServiceAgreement(id,
ddo, serviceAgreementId, consumer)
try {
const serviceAgrementSignature: string = await ServiceAgreement.signServiceAgreement(id,
ddo, serviceAgreementId, consumer)
return serviceAgrementSignature
} catch (err) {
return serviceAgrementSignature
Logger.error("Signing ServiceAgreement failed!", err)
}
}
public async executeServiceAgreement(did: string, serviceAgreementSignature: string,
public async executeServiceAgreement(did: string, serviceAgreementId: string, serviceAgreementSignature: string,
consumer: Account, publisher: Account): Promise<ServiceAgreement> {
const ddo = await AquariusProvider.getAquarius().retrieveDDO(did)
const id = did.replace("did:op:", "")
const serviceAgreementId: string = IdGenerator.generateId()
const serviceAgrement: ServiceAgreement = await ServiceAgreement.executeServiceAgreement(id,
ddo, serviceAgreementId, serviceAgreementSignature, consumer, publisher)
@ -174,11 +169,11 @@ export default class Ocean {
}
public async searchAssets(query: SearchQuery): Promise<DDO[]> {
return this.aquarius.queryMetadata(query)
return AquariusProvider.getAquarius().queryMetadata(query)
}
public async searchAssetsByText(text: string): Promise<DDO[]> {
return this.aquarius.queryMetadataByText({
return AquariusProvider.getAquarius().queryMetadataByText({
text,
page: 0,
offset: 100,

View File

@ -30,7 +30,7 @@ export default class ServiceAgreement extends OceanBase {
const timeoutValues: number[] = ServiceAgreement.getTimeoutValuesFromDDO(ddo)
const serviceAgreement: ServiceAgreement = await ServiceAgreement.executeAgreement(ddo,
serviceAgreementId, values, valueHashes, timeoutValues, serviceAgreementHashSignature, consumer, publisher)
serviceAgreementId, valueHashes, timeoutValues, serviceAgreementHashSignature, consumer, publisher)
return serviceAgreement
}
@ -39,6 +39,10 @@ export default class ServiceAgreement extends OceanBase {
valueHashes: string[], timeoutValues: number[], consumer: Account):
Promise<string> {
if (!ddo.service[0].templateId) {
throw new Error("TemplateId not found in ddo.")
}
const conditionKeys: string[] = ddo.service[0].conditions.map((condition) => {
return condition.conditionKey
})
@ -52,18 +56,22 @@ export default class ServiceAgreement extends OceanBase {
return serviceAgreementHashSignature
}
private static async executeAgreement(ddo: DDO, serviceAgreementId: string, values: ValuePair[],
valueHashes: string[], timeoutValues: number[],
serviceAgreementHashSignature: string, consumer: Account,
publisher: Account): Promise<ServiceAgreement> {
private static async executeAgreement(ddo: DDO, serviceAgreementId: string, valueHashes: string[],
timeoutValues: number[], serviceAgreementHashSignature: string,
consumer: Account, publisher: Account): Promise<ServiceAgreement> {
const {serviceAgreement} = await Keeper.getInstance()
if (!ddo.service[0].templateId) {
throw new Error("TemplateId not found in ddo.")
}
const executeAgreementReceipt = await serviceAgreement.executeAgreement(
ddo.service[0].templateId, serviceAgreementHashSignature, consumer.getId(), valueHashes,
timeoutValues, serviceAgreementId, ddo.id, publisher.getId())
if (executeAgreementReceipt.events.ExecuteAgreement.returnValues.state === false) {
throw new Error("signing service agreement failed.")
throw new Error("executing service agreement failed.")
}
return new ServiceAgreement(
@ -101,6 +109,7 @@ export default class ServiceAgreement extends OceanBase {
}
private static getTimeoutValuesFromDDO(ddo: DDO): number[] {
const timeoutValues: number[] = ddo.service[0].conditions.map((condition: Condition) => {
return condition.timeout
})

View File

@ -41,8 +41,14 @@ export default class ServiceAgreementTemplate extends OceanBase {
const owner = await this.getOwner()
if (owner.getId() === templateOwnerAddress) {
// tslint:disable-next-line
Logger.error(`Template with id "${this.template.id}" is already registered to your account "${templateOwnerAddress}".`)
return false
}
if (!owner.getId().startsWith("0x0")) {
Logger.error(`Template with id "${this.template.id}" already registered.`)
Logger.error(`Template with id "${this.template.id}" already registered by someone else.`)
return false
}
@ -51,15 +57,20 @@ export default class ServiceAgreementTemplate extends OceanBase {
Web3Provider.getWeb3().utils.fromAscii(this.template.templateName),
templateOwnerAddress)
const templateId = receipt.events.SetupAgreementTemplate.returnValues.serviceTemplateId
const {serviceTemplateId, provider} = receipt.events.SetupAgreementTemplate.returnValues
if (templateId !== this.template.id) {
if (serviceTemplateId !== this.template.id) {
// tslint:disable-next-line
throw new Error(`TemplateId missmatch on ${this.template.templateName}! Should be "${this.template.id}" but is ${templateId}`)
throw new Error(`TemplateId missmatch on ${this.template.templateName}! Should be "${this.template.id}" but is ${serviceTemplateId}`)
}
if (receipt.status) {
Logger.error("Registering template failed")
if (provider !== templateOwnerAddress) {
// tslint:disable-next-line
throw new Error(`Template owner missmatch on ${this.template.templateName}! Should be "${templateOwnerAddress}" but is ${provider}`)
}
if (!receipt.status) {
Logger.error(`Registering template failed, status was "false".`)
}
return receipt.status

View File

@ -1,11 +1,18 @@
import Account from "./ocean/Account"
import Ocean from "./ocean/Ocean"
import ServiceAgreement from "./ocean/ServiceAgreements/ServiceAgreement"
import ServiceAgreementTemplate from "./ocean/ServiceAgreements/ServiceAgreementTemplate"
import Access from "./ocean/ServiceAgreements/Templates/Access"
import FitchainCompute from "./ocean/ServiceAgreements/Templates/FitchainCompute"
import Logger from "./utils/Logger"
const Templates = {Access, FitchainCompute}
export {
Ocean,
ServiceAgreement,
ServiceAgreementTemplate,
Logger,
Templates,
Account,
}

View File

@ -107,6 +107,7 @@ describe("DDO", () => {
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",
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip",
],
links: [
{

View File

@ -1,8 +1,20 @@
import Aquarius from "../../src/aquarius/Aquarius"
import DDO from "../../src/ddo/DDO"
const ddoStore: Map<string, any> = new Map<string, any>()
export default class AquariusMock extends Aquarius {
public async getAccessUrl(accessToken: any, payload: any): Promise<string> {
return "http://test/test"
}
public async storeDDO(ddo: DDO): Promise<DDO> {
ddoStore.set(ddo.id, ddo)
return ddo
}
public async retrieveDDO(did: string): Promise<DDO> {
return ddoStore.get(did)
}
}

View File

@ -14,10 +14,10 @@ export default class AquariusConnectorMock extends AquariusConnector {
resolve({
ok: true,
json: () => {
return this.returnData ? this.returnData : []
return this.returnData ? this.returnData : {}
},
text: () => {
return this.returnData ? this.returnData.toString() : ""
return this.returnData ? JSON.stringify(this.returnData.toString()) : ""
},
})
})

View File

@ -1,15 +1,19 @@
import {assert} from "chai"
import AquariusConnectorProvider from "../../src/aquarius/AquariusConnectorProvider"
import AquariusProvider from "../../src/aquarius/AquariusProvider"
import SearchQuery from "../../src/aquarius/query/SearchQuery"
import ConfigProvider from "../../src/ConfigProvider"
import DDO from "../../src/ddo/DDO"
import MetaData from "../../src/ddo/MetaData"
import Account from "../../src/ocean/Account"
import IdGenerator from "../../src/ocean/IdGenerator"
import Ocean from "../../src/ocean/Ocean"
import ServiceAgreement from "../../src/ocean/ServiceAgreements/ServiceAgreement"
import SecretStoreProvider from "../../src/secretstore/SecretStoreProvider"
import config from "../config"
import TestContractHandler from "../keeper/TestContractHandler"
import AquariusMock from "../mocks/Aquarius.mock"
import AquariusConnectorMock from "../mocks/AquariusConnector.mock"
import SecretStoreMock from "../mocks/SecretStore.mock"
let ocean: Ocean
@ -97,4 +101,50 @@ describe("Ocean", () => {
})
})
describe("#signServiceAgreement()", () => {
it("should sign an service agreement", async () => {
const publisher = accounts[0]
const consumer = accounts[1]
const ddo: DDO = await ocean.registerAsset(new MetaData(), publisher)
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo))
const serviceAgreementId: string = IdGenerator.generateId()
const serviceAgreementSignature: string = await ocean.signServiceAgreement(ddo.id, serviceAgreementId,
consumer)
assert(serviceAgreementSignature)
assert(serviceAgreementSignature.startsWith("0x"))
})
})
describe("#executeServiceAgreement()", () => {
it("should execute an service agreement", async () => {
const publisher = accounts[0]
const consumer = accounts[1]
const ddo: DDO = await ocean.registerAsset(new MetaData(), publisher)
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo))
const serviceAgreementId: string = IdGenerator.generateId()
const serviceAgreementSignature: string = await ocean.signServiceAgreement(ddo.id, serviceAgreementId,
consumer)
const serviceAgreement: ServiceAgreement = await ocean.executeServiceAgreement(ddo.id, serviceAgreementId,
serviceAgreementSignature, consumer, publisher)
assert(serviceAgreement)
})
})
})

34
test/testdata/MetaData.ts vendored Normal file
View File

@ -0,0 +1,34 @@
import MetaDataModel from "../../src/ddo/MetaData"
import MetaDataBase from "../../src/ddo/MetaDataBase"
const MetaData = new MetaDataModel({
base: {
name: "Office Humidity",
type: "dataset",
description: "Weather information of UK including temperature and humidity",
size: "3.1gb",
dateCreated: "2012-02-01T10:55:11+00:00",
author: "Met Office",
license: "CC-BY",
copyrightHolder: "Met Office",
encoding: "UTF-8",
compression: "zip",
contentType: "text/csv",
// tslint:disable-next-line
workExample: "stationId,latitude,longitude,datetime,temperature,humidity423432fsd,51.509865,-0.118092,2011-01-01T10:55:11+00:00,7.2,68",
contentUrls: [
"https://testocnfiles.blob.core.windows.net/testfiles/testzkp.zip",
"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,
} as MetaDataModel)
export default MetaData