mirror of
https://github.com/oceanprotocol/ocean.js.git
synced 2024-11-26 20:39:05 +01:00
Feature/credentials support in asset (#787)
* [KianYee] Add credentials in DDO Co-authored-by: alexcos20 <alex.coseru@gmail.com>
This commit is contained in:
parent
9f0b5dd6ff
commit
0f46959dfa
@ -7,6 +7,7 @@ import Web3Provider from '../datatokens/Web3Provider'
|
||||
import { BestPrice } from './interfaces/BestPrice'
|
||||
import { DataTokenInfo } from './interfaces/DataTokenInfo'
|
||||
import { PurgatoryData } from './interfaces/PurgatoryData'
|
||||
import { Credentials } from './interfaces/Credentials'
|
||||
/**
|
||||
* DID Descriptor Object.
|
||||
* Contains all the data related to an asset.
|
||||
@ -62,6 +63,8 @@ export class DDO {
|
||||
|
||||
public dataTokenInfo?: DataTokenInfo
|
||||
|
||||
public credentials?: Credentials
|
||||
|
||||
public constructor(ddo: Partial<DDO> = {}) {
|
||||
Object.assign(this, ddo, {
|
||||
created: (ddo && ddo.created) || new Date().toISOString().replace(/\.[0-9]{3}/, '')
|
||||
|
16
src/ddo/interfaces/Credentials.ts
Normal file
16
src/ddo/interfaces/Credentials.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export enum CredentialType {
|
||||
address = 'address',
|
||||
credential3Box = 'credential3Box'
|
||||
}
|
||||
|
||||
export type CredentialAction = 'allow' | 'deny'
|
||||
|
||||
export interface Credential {
|
||||
type: CredentialType
|
||||
value: string[]
|
||||
}
|
||||
|
||||
export interface Credentials {
|
||||
allow?: Credential[]
|
||||
deny?: Credential[]
|
||||
}
|
@ -13,3 +13,4 @@ export * from './PublicKey'
|
||||
export * from './Service'
|
||||
export * from './ServicePrices'
|
||||
export * from './PurgatoryData'
|
||||
export * from './Credentials'
|
||||
|
@ -13,6 +13,12 @@ import { Provider } from '../provider/Provider'
|
||||
import { isAddress } from 'web3-utils'
|
||||
import { MetadataMain } from '../ddo/interfaces'
|
||||
import { TransactionReceipt } from 'web3-core'
|
||||
import {
|
||||
CredentialType,
|
||||
CredentialAction,
|
||||
Credentials
|
||||
} from '../ddo/interfaces/Credentials'
|
||||
import { updateCredentialDetail, removeCredentialDetail } from './AssetsCredential'
|
||||
import { Consumable } from '../ddo/interfaces/Consumable'
|
||||
|
||||
export enum CreateProgressStep {
|
||||
@ -285,6 +291,63 @@ export class Assets extends Instantiable {
|
||||
return ddo
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Credentials attribute in DDO
|
||||
* @param {ddo} DDO
|
||||
* @param {credentialType} CredentialType e.g. address / credentail3Box
|
||||
* @param {allowList} string[] List of allow credential
|
||||
* @param {denyList} string[] List of deny credential
|
||||
* @return {Promise<DDO>} Updated DDO
|
||||
*/
|
||||
public async updateCredentials(
|
||||
ddo: DDO,
|
||||
credentialType: CredentialType,
|
||||
allowList: string[],
|
||||
denyList: string[]
|
||||
): Promise<DDO> {
|
||||
if (allowList && allowList.length > 0) {
|
||||
ddo = updateCredentialDetail(ddo, credentialType, allowList, 'allow')
|
||||
} else {
|
||||
ddo = removeCredentialDetail(ddo, credentialType, 'allow')
|
||||
}
|
||||
|
||||
if (denyList && denyList.length > 0) {
|
||||
ddo = updateCredentialDetail(ddo, credentialType, denyList, 'deny')
|
||||
} else {
|
||||
ddo = removeCredentialDetail(ddo, credentialType, 'deny')
|
||||
}
|
||||
return ddo
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a credential can consume a dataset
|
||||
* @param {ddo} DDO
|
||||
* @param {credentialType} CredentialType e.g. address / credentail3Box
|
||||
* @param {value} string credential
|
||||
* @return {boolean} allowed ?
|
||||
*/
|
||||
public checkCredential(
|
||||
ddo: DDO,
|
||||
credentialType: CredentialType,
|
||||
value: string
|
||||
): boolean {
|
||||
let allowed = true
|
||||
if (!ddo.credentials) return allowed
|
||||
if (ddo.credentials.allow && ddo.credentials.allow.length > 0) {
|
||||
const allowList = ddo.credentials.allow.find(
|
||||
(credentail) => credentail.type === credentialType
|
||||
)
|
||||
if (allowList && !allowList.value.includes(value)) allowed = false
|
||||
}
|
||||
if (ddo.credentials.deny && ddo.credentials.deny.length > 0) {
|
||||
const denyList = ddo.credentials.deny.find(
|
||||
(credentail) => credentail.type === credentialType
|
||||
)
|
||||
if (denyList && denyList.value.includes(value)) allowed = false
|
||||
}
|
||||
return allowed
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish DDO on chain.
|
||||
* @param {ddo} DDO
|
||||
|
169
src/ocean/AssetsCredential.ts
Normal file
169
src/ocean/AssetsCredential.ts
Normal file
@ -0,0 +1,169 @@
|
||||
import { DDO } from '../ddo/DDO'
|
||||
import {
|
||||
Credentials,
|
||||
Credential,
|
||||
CredentialType,
|
||||
CredentialAction
|
||||
} from '../ddo/interfaces/Credentials'
|
||||
|
||||
/**
|
||||
* checks if a credential list exists for a specific action
|
||||
* @param {credentials} Credentials list of crentials from ddo
|
||||
* @param {credentialType} CredentialType e.g. address / credential3Box
|
||||
* @param {credentialAction} CredentialAction allow or deny
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function checkCredentialExist(
|
||||
credentials: Credentials,
|
||||
credentialType: CredentialType,
|
||||
credentialAction: CredentialAction
|
||||
): boolean {
|
||||
let isExist = false
|
||||
if (credentialAction === 'allow') {
|
||||
if (credentials && credentials.allow) {
|
||||
const allowList = credentials.allow.find(
|
||||
(credential) => credential.type === credentialType
|
||||
)
|
||||
isExist = allowList && allowList.value.length > 0
|
||||
}
|
||||
return isExist
|
||||
} else {
|
||||
if (credentials && credentials.deny) {
|
||||
const dennyList = credentials.deny.find(
|
||||
(credential) => credential.type === credentialType
|
||||
)
|
||||
isExist = dennyList && dennyList.value.length > 0
|
||||
}
|
||||
return isExist
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all credentials of a certain type for a specific action
|
||||
* @param {ddo} DDO
|
||||
* @param {credentialType} CredentialType e.g. address / credential3Box
|
||||
* @param {credentialAction} CredentialAction allow or deny
|
||||
* @return {DDO}
|
||||
*/
|
||||
export function removeCredentialDetail(
|
||||
ddo: DDO,
|
||||
credentialType: CredentialType,
|
||||
credentialAction: CredentialAction
|
||||
): DDO {
|
||||
const exists = this.checkCredentialExist(
|
||||
ddo.credentials,
|
||||
credentialType,
|
||||
credentialAction
|
||||
)
|
||||
if (credentialAction === 'allow') {
|
||||
if (exists) {
|
||||
ddo.credentials.allow = ddo.credentials.allow.filter(
|
||||
(credential) => credential.type !== credentialType
|
||||
)
|
||||
}
|
||||
if (!ddo.credentials.allow) {
|
||||
ddo.credentials = {
|
||||
deny: ddo.credentials.deny
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (exists) {
|
||||
ddo.credentials.deny = ddo.credentials.deny.filter(
|
||||
(credential) => credential.type !== credentialType
|
||||
)
|
||||
}
|
||||
if (!ddo.credentials.deny) {
|
||||
ddo.credentials = {
|
||||
allow: ddo.credentials.allow
|
||||
}
|
||||
}
|
||||
}
|
||||
return ddo
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates credentials of a certain type for a specific action
|
||||
* @param {ddo} DDO
|
||||
* @param {credentialType} CredentialType e.g. address / credential3Box
|
||||
* @param {list} string[] list of values
|
||||
* @param {credentialAction} CredentialAction allow or deny
|
||||
* @return {DDO}
|
||||
*/
|
||||
|
||||
export function updateCredentialDetail(
|
||||
ddo: DDO,
|
||||
credentialType: CredentialType,
|
||||
list: string[],
|
||||
credentialAction: CredentialAction
|
||||
): DDO {
|
||||
const exists = this.checkCredentialExist(
|
||||
ddo.credentials,
|
||||
credentialType,
|
||||
credentialAction
|
||||
)
|
||||
if (credentialAction === 'allow') {
|
||||
if (exists) {
|
||||
ddo.credentials.allow.find((credential) => {
|
||||
if (credential.type === credentialType) {
|
||||
credential.value = list
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return this.addCredentialDetail(ddo, credentialType, list, credentialAction)
|
||||
}
|
||||
} else {
|
||||
if (exists) {
|
||||
ddo.credentials.deny.find((credential) => {
|
||||
if (credential.type === credentialType) {
|
||||
credential.value = list
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return this.addCredentialDetail(ddo, credentialType, list, credentialAction)
|
||||
}
|
||||
}
|
||||
return ddo
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds values to credentials of a certain type for a specific action
|
||||
* @param {ddo} DDO
|
||||
* @param {credentialType} CredentialType e.g. address / credential3Box
|
||||
* @param {list} string[] list of values
|
||||
* @param {credentialAction} CredentialAction allow or deny
|
||||
* @return {DDO}
|
||||
*/
|
||||
|
||||
export function addCredentialDetail(
|
||||
ddo: DDO,
|
||||
credentialType: CredentialType,
|
||||
list: string[],
|
||||
credentialAction: CredentialAction
|
||||
) {
|
||||
const newCredentialDetail: Credential = {
|
||||
type: credentialType,
|
||||
value: list
|
||||
}
|
||||
if (credentialAction === 'allow') {
|
||||
if (ddo.credentials && ddo.credentials.allow) {
|
||||
ddo.credentials.allow.push(newCredentialDetail)
|
||||
} else {
|
||||
const newCredentials: Credentials = {
|
||||
allow: [newCredentialDetail],
|
||||
deny: ddo.credentials && ddo.credentials.deny
|
||||
}
|
||||
ddo.credentials = newCredentials
|
||||
}
|
||||
} else {
|
||||
if (ddo.credentials && ddo.credentials.deny) {
|
||||
ddo.credentials.deny.push(newCredentialDetail)
|
||||
} else {
|
||||
const newCredential: Credentials = {
|
||||
allow: ddo.credentials && ddo.credentials.allow,
|
||||
deny: [newCredentialDetail]
|
||||
}
|
||||
ddo.credentials = newCredential
|
||||
}
|
||||
}
|
||||
return ddo
|
||||
}
|
@ -5,7 +5,14 @@ import spies from 'chai-spies'
|
||||
import Web3 from 'web3'
|
||||
import { AbiItem } from 'web3-utils/types'
|
||||
import { DataTokens } from '../../src/datatokens/Datatokens'
|
||||
import { Account, EditableMetadata, Service, ServiceAccess, DID } from '../../src/lib'
|
||||
import {
|
||||
Account,
|
||||
EditableMetadata,
|
||||
Service,
|
||||
ServiceAccess,
|
||||
DID,
|
||||
CredentialType
|
||||
} from '../../src/lib'
|
||||
import { noDidPrefixed } from '../../src/utils/'
|
||||
import { Ocean } from '../../src/ocean/Ocean'
|
||||
import { ConfigHelper } from '../../src/utils/ConfigHelper'
|
||||
|
@ -3,19 +3,40 @@ import spies from 'chai-spies'
|
||||
|
||||
import { SearchQuery, MetadataCache } from '../../../src/metadatacache/MetadataCache'
|
||||
import { Ocean } from '../../../src/ocean/Ocean'
|
||||
import config from '../config'
|
||||
import { DDO } from '../../../src/lib'
|
||||
import Web3 from 'web3'
|
||||
import { Account, DDO, CredentialType, ConfigHelper } from '../../../src/lib'
|
||||
import { responsify, getSearchResults } from '../helpers'
|
||||
|
||||
const web3 = new Web3('http://127.0.0.1:8545')
|
||||
use(spies)
|
||||
|
||||
describe('Assets', () => {
|
||||
let ocean: Ocean
|
||||
let metadataCache: MetadataCache
|
||||
|
||||
let asset: any
|
||||
let owner: Account
|
||||
let alice: Account
|
||||
let bob: Account
|
||||
let charlie: Account
|
||||
let ddo: DDO
|
||||
let ddoWithAddressAnd3Box: DDO
|
||||
const addressType = CredentialType.address
|
||||
const threeBoxType = CredentialType.credential3Box
|
||||
let walletA: string
|
||||
let walletB: string
|
||||
let walletC: string
|
||||
const threeBoxValue = 'did:3:bafyre'
|
||||
beforeEach(async () => {
|
||||
const config = new ConfigHelper().getConfig('development')
|
||||
config.web3Provider = web3
|
||||
ocean = await Ocean.getInstance(config)
|
||||
metadataCache = ocean.metadataCache // eslint-disable-line prefer-destructuring
|
||||
owner = (await ocean.accounts.list())[0]
|
||||
alice = (await ocean.accounts.list())[1]
|
||||
walletA = alice.getId()
|
||||
bob = (await ocean.accounts.list())[2]
|
||||
walletB = bob.getId()
|
||||
charlie = (await ocean.accounts.list())[3]
|
||||
walletC = charlie.getId()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@ -57,4 +78,125 @@ describe('Assets', () => {
|
||||
assert.isDefined(assets.results[0].findServiceById)
|
||||
})
|
||||
})
|
||||
it('Generates metadata', async () => {
|
||||
asset = {
|
||||
main: {
|
||||
type: 'dataset',
|
||||
name: 'test-dataset',
|
||||
dateCreated: new Date(Date.now()).toISOString().split('.')[0] + 'Z', // remove milliseconds
|
||||
author: 'oceanprotocol-team',
|
||||
license: 'MIT',
|
||||
files: [
|
||||
{
|
||||
url: 'https://s3.amazonaws.com/testfiles.oceanprotocol.com/info.0.json',
|
||||
checksum: 'efb2c764274b745f5fc37f97c6b0e761',
|
||||
contentLength: '4535431',
|
||||
contentType: 'text/csv',
|
||||
encoding: 'UTF-8',
|
||||
compression: 'zip'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Alice creates a DDO', async () => {
|
||||
const price = '10' // in datatoken
|
||||
const publishedDate = new Date(Date.now()).toISOString().split('.')[0] + 'Z'
|
||||
const timeout = 0
|
||||
const service1 = await ocean.assets.createAccessServiceAttributes(
|
||||
alice,
|
||||
price,
|
||||
publishedDate,
|
||||
timeout
|
||||
)
|
||||
ddo = await ocean.assets.create(asset, alice, [service1], null)
|
||||
})
|
||||
|
||||
it('should add allow credential', async () => {
|
||||
assert(ocean.assets.checkCredential(ddo, addressType, walletA) === true)
|
||||
assert(ocean.assets.checkCredential(ddo, addressType, walletC) === true)
|
||||
const allowWalletAddressList = [walletA, walletB]
|
||||
console.error(JSON.stringify(ddo.credentials))
|
||||
const newDdo = await ocean.assets.updateCredentials(
|
||||
ddo,
|
||||
addressType,
|
||||
allowWalletAddressList,
|
||||
[]
|
||||
)
|
||||
assert(newDdo.credentials.allow.length === 1)
|
||||
assert(ocean.assets.checkCredential(ddo, addressType, walletA) === true)
|
||||
assert(ocean.assets.checkCredential(ddo, addressType, walletC) === false)
|
||||
})
|
||||
|
||||
it('should append allow credential', async () => {
|
||||
const allowWalletAddressList = [walletA, walletB]
|
||||
const allow3BoxList = [threeBoxValue]
|
||||
ddoWithAddressAnd3Box = await ocean.assets.updateCredentials(
|
||||
ddo,
|
||||
addressType,
|
||||
allowWalletAddressList,
|
||||
[]
|
||||
)
|
||||
ddoWithAddressAnd3Box = await ocean.assets.updateCredentials(
|
||||
ddo,
|
||||
threeBoxType,
|
||||
allow3BoxList,
|
||||
[]
|
||||
)
|
||||
assert(ddoWithAddressAnd3Box.credentials.allow.length === 2)
|
||||
})
|
||||
|
||||
it('should add deny credential', async () => {
|
||||
const denyWalletAddressList = [walletC]
|
||||
const newDdo = await ocean.assets.updateCredentials(
|
||||
ddo,
|
||||
addressType,
|
||||
[],
|
||||
denyWalletAddressList
|
||||
)
|
||||
assert(newDdo.credentials.deny.length === 1)
|
||||
assert(ocean.assets.checkCredential(ddo, addressType, walletA) === true)
|
||||
assert(ocean.assets.checkCredential(ddo, addressType, walletC) === false)
|
||||
})
|
||||
|
||||
it('should append deny credential', async () => {
|
||||
const denyWalletAddressList = [walletC]
|
||||
const deny3BoxList = [threeBoxValue]
|
||||
let newDdo = await ocean.assets.updateCredentials(
|
||||
ddo,
|
||||
addressType,
|
||||
[],
|
||||
denyWalletAddressList
|
||||
)
|
||||
newDdo = await ocean.assets.updateCredentials(ddo, threeBoxType, [], deny3BoxList)
|
||||
assert(newDdo.credentials.deny.length === 2)
|
||||
})
|
||||
|
||||
it('should only remove allow credential by credential type', async () => {
|
||||
const allowWalletAddressList = [walletA, walletB]
|
||||
const allow3BoxList = [threeBoxValue]
|
||||
let newDdo = await ocean.assets.updateCredentials(
|
||||
ddo,
|
||||
addressType,
|
||||
allowWalletAddressList,
|
||||
[]
|
||||
)
|
||||
newDdo = await ocean.assets.updateCredentials(
|
||||
ddoWithAddressAnd3Box,
|
||||
threeBoxType,
|
||||
allow3BoxList,
|
||||
[]
|
||||
)
|
||||
assert(newDdo.credentials.allow.length === 2)
|
||||
newDdo = await ocean.assets.updateCredentials(
|
||||
ddoWithAddressAnd3Box,
|
||||
threeBoxType,
|
||||
[],
|
||||
[]
|
||||
)
|
||||
assert(newDdo.credentials.allow.length === 1)
|
||||
assert(ocean.assets.checkCredential(ddo, addressType, walletA) === true)
|
||||
assert(ocean.assets.checkCredential(ddo, addressType, walletC) === false)
|
||||
})
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user