Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
f06accb
add some access/credentials tests + emit events if unauthorized
paulo-ocean Mar 12, 2025
a439c3d
debug it
paulo-ocean Mar 12, 2025
f0a73d1
try fix test
paulo-ocean Mar 12, 2025
121aece
try fix test
paulo-ocean Mar 12, 2025
cf34fd7
try fix test
paulo-ocean Mar 12, 2025
d091629
try fix test
paulo-ocean Mar 12, 2025
74d36e9
try fix test, fix order
paulo-ocean Mar 12, 2025
2b1aed4
try fix test, fix order
paulo-ocean Mar 12, 2025
96d5f27
add generic function for unauthprized events
paulo-ocean Mar 12, 2025
8da9c6a
try something
paulo-ocean Mar 12, 2025
9d9b2eb
try something
paulo-ocean Mar 12, 2025
03eb479
restor hooks
paulo-ocean Mar 12, 2025
ffa8898
try another approach
paulo-ocean Mar 12, 2025
d73c962
debug
paulo-ocean Mar 12, 2025
337b7d7
try global list to save deployments info
paulo-ocean Mar 12, 2025
ee3fa08
try global list to save deployments info
paulo-ocean Mar 12, 2025
e958e3e
deploy 3 accessLists, test config
paulo-ocean Mar 13, 2025
2133281
deploy 3 accessLists, test config, fix import
paulo-ocean Mar 13, 2025
4fd6606
some refactor + debug
paulo-ocean Mar 13, 2025
67c9e3d
some refactor + debug
paulo-ocean Mar 13, 2025
4cbd05d
refactor
paulo-ocean Mar 13, 2025
cef5ce4
more tests
paulo-ocean Mar 13, 2025
181cadc
add 2 ore tests
paulo-ocean Mar 13, 2025
a78ef74
fix test... we want the NON authorized here
paulo-ocean Mar 13, 2025
e895dfc
fix explanation
paulo-ocean Mar 13, 2025
cb5615f
bigger refactor, emit event on auth specific emitter
paulo-ocean Mar 13, 2025
3b3f08d
fix linter
paulo-ocean Mar 13, 2025
936c369
fix import
paulo-ocean Mar 13, 2025
d98ff09
Merge branch 'main' into issue-840-accessTests
paulo-ocean Mar 14, 2025
77bd70e
restore package & debug more
paulo-ocean Mar 14, 2025
ab3a4d0
undo prior changes
paulo-ocean Mar 14, 2025
fba597b
small fix
paulo-ocean Mar 14, 2025
601a1f4
cleanup
paulo-ocean Mar 14, 2025
a7b18ef
refactor check on ddo handler
paulo-ocean Mar 17, 2025
ec946f0
refactor check on processor, for auth publishers list, use common fn
paulo-ocean Mar 17, 2025
4842299
cleanup
paulo-ocean Mar 17, 2025
8b16dbe
Merge branch 'main' into issue-840-accessTests
giurgiur99 Apr 9, 2025
1aea215
debug faiing credential test
giurgiur99 Apr 11, 2025
08dee37
fix undefined access to .ddo in test
giurgiur99 Apr 11, 2025
6834d13
remove unauthorized events
giurgiur99 Apr 16, 2025
03f18d7
remove AUTH_CREDENTIALS_EVENT_EMITTER
giurgiur99 Apr 16, 2025
f615729
Remove unused listeners
giurgiur99 Apr 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 12 additions & 25 deletions src/components/Indexer/processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import ERC721Template from '@oceanprotocol/contracts/artifacts/contracts/templat
import ERC20Template from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC20TemplateEnterprise.sol/ERC20TemplateEnterprise.json' assert { type: 'json' }
import Dispenser from '@oceanprotocol/contracts/artifacts/contracts/pools/dispenser/Dispenser.sol/Dispenser.json' assert { type: 'json' }
import FixedRateExchange from '@oceanprotocol/contracts/artifacts/contracts/pools/fixedRate/FixedRateExchange.sol/FixedRateExchange.json' assert { type: 'json' }
import AccessListContract from '@oceanprotocol/contracts/artifacts/contracts/accesslists/AccessList.sol/AccessList.json' assert { type: 'json' }
import { getDatabase } from '../../utils/database.js'
import {
PROTOCOL_COMMANDS,
Expand Down Expand Up @@ -52,6 +51,7 @@ import { create256Hash } from '../../utils/crypt.js'
import { URLUtils } from '../../utils/url.js'
import { makeDid } from '../core/utils/validateDdoHandler.js'
import { PolicyServer } from '../policyServer/index.js'
import { checkCredentialOnAccessList } from '../../utils/credentials.js'
class BaseEventProcessor {
protected networkId: number

Expand Down Expand Up @@ -458,30 +458,17 @@ export class MetadataEventProcessor extends BaseEventProcessor {
}
if (authorizedPublishersList) {
// check accessList
const chainsListed = Object.keys(authorizedPublishersList)
const chain = String(chainId)
// check the access lists for this chain
if (chainsListed.length > 0 && chainsListed.includes(chain)) {
let isAuthorized = false
for (const accessListAddress of authorizedPublishersList[chain]) {
const accessListContract = new ethers.Contract(
accessListAddress,
AccessListContract.abi,
signer
)
// if has at least 1 token than is is authorized
const balance = await accessListContract.balanceOf(owner)
if (Number(balance) > 0) {
isAuthorized = true
break
}
}
if (!isAuthorized) {
INDEXER_LOGGER.error(
`DDO owner ${owner} is NOT part of the ${ENVIRONMENT_VARIABLES.AUTHORIZED_PUBLISHERS_LIST.name} access group.`
)
return
}
const isAuthorized = await checkCredentialOnAccessList(
authorizedPublishersList,
String(chainId),
owner,
signer
)
if (!isAuthorized) {
INDEXER_LOGGER.error(
`DDO owner ${owner} is NOT part of the ${ENVIRONMENT_VARIABLES.AUTHORIZED_PUBLISHERS_LIST.name} access group.`
)
return
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/components/Indexer/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,9 @@ export const processChunkLogs = async (
isAllowed = true // no rules for this specific chain, so ignore this
}
// move on to the next (do not process this event)
if (isAllowed === false) continue
if (isAllowed === false) {
continue
}
} // end if (allowedValidatorsList) {
} // end if if (checkMetadataValidated) {
}
Expand Down
56 changes: 19 additions & 37 deletions src/components/core/handler/ddoHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { CORE_LOGGER } from '../../../utils/logging/common.js'
import { Blockchain } from '../../../utils/blockchain.js'
import { ethers, isAddress } from 'ethers'
import ERC721Template from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC721Template.sol/ERC721Template.json' assert { type: 'json' }
import AccessListContract from '@oceanprotocol/contracts/artifacts/contracts/accesslists/AccessList.sol/AccessList.json' assert { type: 'json' }
// import lzma from 'lzma-native'
import lzmajs from 'lzma-purejs-requirejs'
import {
Expand All @@ -44,6 +43,7 @@ import {
wasNFTDeployedByOurFactory
} from '../../Indexer/utils.js'
import { deleteIndexedMetadataIfExists, validateDDOHash } from '../../../utils/asset.js'
import { checkCredentialOnAccessList } from '../../../utils/credentials.js'

const MAX_NUM_PROVIDERS = 5
// after 60 seconds it returns whatever info we have available
Expand Down Expand Up @@ -200,44 +200,25 @@ export class DecryptDdoHandler extends CommandHandler {
}
}

// access lit checks, needs blockchain connection
// access list checks, needs blockchain connection
const { authorizedDecryptersList } = config
if (authorizedDecryptersList && Object.keys(authorizedDecryptersList).length > 0) {
// check accessList
const chainsListed = Object.keys(authorizedDecryptersList)
// check the access lists for this chain
if (chainsListed.length > 0 && chainsListed.includes(chainId)) {
let isAllowed = false
for (const accessListAddress of authorizedDecryptersList[chainId]) {
// instantiate contract and check balanceOf
const accessListContract = new ethers.Contract(
accessListAddress,
AccessListContract.abi,
blockchain.getSigner()
)

// check access list contract
const balance = await accessListContract.balanceOf(
await blockchain.getSigner().getAddress()
)
if (Number(balance) > 0) {
isAllowed = true
break
}
}

if (!isAllowed) {
CORE_LOGGER.logMessage(
'Decrypt DDO: Decrypter not authorized per access list',
true
)
return {
stream: null,
status: {
httpStatus: 403,
error: 'Decrypt DDO: Decrypter not authorized per access list'
}
}
const isAllowed = await checkCredentialOnAccessList(
authorizedDecryptersList,
chainId,
decrypterAddress,
signer
)
if (!isAllowed) {
CORE_LOGGER.logMessage(
'Decrypt DDO: Decrypter not authorized per access list',
true
)
return {
stream: null,
status: {
httpStatus: 403,
error: `Decrypt DDO: Decrypter ${decrypterAddress} not authorized per access list`
}
}
}
Expand Down Expand Up @@ -282,6 +263,7 @@ export class DecryptDdoHandler extends CommandHandler {
try {
encryptedDocument = ethers.getBytes(task.encryptedDocument)
flags = Number(task.flags)
// eslint-disable-next-line prefer-destructuring
documentHash = task.documentHash
} catch (error) {
CORE_LOGGER.logMessage(`Decrypt DDO: error ${error}`, true)
Expand Down
201 changes: 201 additions & 0 deletions src/test/integration/accessLists.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import {
buildEnvOverrideConfig,
getMockSupportedNetworks,
OverrideEnvConfig,
setupEnvironment,
tearDownEnvironment,
TEST_ENV_CONFIG_FILE
} from '../utils/utils.js'
import { JsonRpcProvider, Signer } from 'ethers'
import { Blockchain } from '../../utils/blockchain.js'
import { RPCS, SupportedNetwork } from '../../@types/blockchain.js'
import { DEVELOPMENT_CHAIN_ID } from '../../utils/address.js'
import { ENVIRONMENT_VARIABLES } from '../../utils/constants.js'
import { deployAndGetAccessListConfig, EXISTING_ACCESSLISTS } from '../utils/contracts.js'
import { AccessListContract, OceanNodeConfig } from '../../@types/OceanNode.js'
import { homedir } from 'os'
import { getConfiguration } from '../../utils/config.js'
import { assert, expect } from 'chai'
import { findAccessListCredentials } from '../../utils/credentials.js'

describe('Should deploy some accessLists before all other tests.', () => {
let config: OceanNodeConfig
let provider: JsonRpcProvider
const mockSupportedNetworks: RPCS = getMockSupportedNetworks()

let previousConfiguration: OverrideEnvConfig[]

let blockchain: Blockchain
// let contractAcessList: Contract
let owner: Signer

let wallets: Signer[] = []

let allAccessListsDefinitions: AccessListContract[] = []

before(async () => {
provider = new JsonRpcProvider('http://127.0.0.1:8545')
config = await getConfiguration() // Force reload the configuration

wallets = [
(await provider.getSigner(0)) as Signer,
(await provider.getSigner(1)) as Signer,
(await provider.getSigner(2)) as Signer,
(await provider.getSigner(3)) as Signer
]

const rpcs: RPCS = config.supportedNetworks
const chain: SupportedNetwork = rpcs[String(DEVELOPMENT_CHAIN_ID)]
blockchain = new Blockchain(
chain.rpc,
chain.network,
chain.chainId,
chain.fallbackRPCs
)

owner = blockchain.getSigner()

// ENVIRONMENT_VARIABLES.AUTHORIZED_PUBLISHERS_LIST
const accessListPublishers = await deployAndGetAccessListConfig(
owner,
provider,
wallets
)
EXISTING_ACCESSLISTS.set(
ENVIRONMENT_VARIABLES.AUTHORIZED_PUBLISHERS_LIST.name,
accessListPublishers
)
const accessListValidators = await deployAndGetAccessListConfig(
owner,
provider,
wallets
)
// ENVIRONMENT_VARIABLES.ALLOWED_VALIDATORS_LIST
EXISTING_ACCESSLISTS.set(
ENVIRONMENT_VARIABLES.ALLOWED_VALIDATORS_LIST.name,
accessListValidators
)

const accessListDecrypters = await deployAndGetAccessListConfig(
owner,
provider,
wallets
)
// ENVIRONMENT_VARIABLES.AUTHORIZED_DECRYPTERS_LIST
EXISTING_ACCESSLISTS.set(
ENVIRONMENT_VARIABLES.AUTHORIZED_DECRYPTERS_LIST.name,
accessListDecrypters
)

// put them all here
allAccessListsDefinitions = [
accessListPublishers,
accessListValidators,
accessListDecrypters
]

// override and save configuration (always before calling getConfig())
previousConfiguration = await setupEnvironment(
TEST_ENV_CONFIG_FILE,
buildEnvOverrideConfig(
[
ENVIRONMENT_VARIABLES.RPCS,
ENVIRONMENT_VARIABLES.INDEXER_NETWORKS,
ENVIRONMENT_VARIABLES.PRIVATE_KEY,
ENVIRONMENT_VARIABLES.AUTHORIZED_DECRYPTERS,
ENVIRONMENT_VARIABLES.ALLOWED_ADMINS,
ENVIRONMENT_VARIABLES.AUTHORIZED_PUBLISHERS,
ENVIRONMENT_VARIABLES.ADDRESS_FILE,
// ACCESS_LISTS
ENVIRONMENT_VARIABLES.AUTHORIZED_PUBLISHERS_LIST,
ENVIRONMENT_VARIABLES.ALLOWED_VALIDATORS_LIST,
ENVIRONMENT_VARIABLES.AUTHORIZED_DECRYPTERS_LIST
],
[
JSON.stringify(mockSupportedNetworks),
JSON.stringify([8996]),
'0xc594c6e5def4bab63ac29eed19a134c130388f74f019bc74b8f4389df2837a58',
JSON.stringify(['0xe2DD09d719Da89e5a3D0F2549c7E24566e947260']),
JSON.stringify(['0xe2DD09d719Da89e5a3D0F2549c7E24566e947260']),
JSON.stringify([
await owner.getAddress() // the node
]),
`${homedir}/.ocean/ocean-contracts/artifacts/address.json`,
JSON.stringify(
EXISTING_ACCESSLISTS.get(
ENVIRONMENT_VARIABLES.AUTHORIZED_PUBLISHERS_LIST.name
)
),
JSON.stringify(
EXISTING_ACCESSLISTS.get(ENVIRONMENT_VARIABLES.ALLOWED_VALIDATORS_LIST.name)
),
JSON.stringify(
EXISTING_ACCESSLISTS.get(
ENVIRONMENT_VARIABLES.AUTHORIZED_DECRYPTERS_LIST.name
)
)
]
)
)

config = await getConfiguration()
})

it('should have some access lists', () => {
expect(EXISTING_ACCESSLISTS.size > 0, 'Should have at least 1 accessList')
})

it(`should have ${ENVIRONMENT_VARIABLES.AUTHORIZED_PUBLISHERS_LIST.name} access lists`, () => {
assert(
config.authorizedPublishersList !== null,
`${ENVIRONMENT_VARIABLES.AUTHORIZED_PUBLISHERS_LIST.name} accessList is not defined`
)
console.log(config.authorizedPublishersList)
})

it(`should have ${ENVIRONMENT_VARIABLES.ALLOWED_VALIDATORS_LIST.name} access lists`, () => {
assert(
config.allowedValidatorsList !== null,
`${ENVIRONMENT_VARIABLES.ALLOWED_VALIDATORS_LIST.name} accessList is not defined`
)
console.log(config.allowedValidatorsList)
})

it(`should have ${ENVIRONMENT_VARIABLES.AUTHORIZED_DECRYPTERS_LIST.name} access lists`, () => {
assert(
config.authorizedPublishersList !== null,
`${ENVIRONMENT_VARIABLES.AUTHORIZED_DECRYPTERS_LIST.name} accessList is not defined`
)
console.log(config.authorizedPublishersList)
})

it('should check if wallets are on accessList (with Access)', async function () {
for (let z = 0; z < allAccessListsDefinitions.length; z++) {
const accessListAddress = allAccessListsDefinitions[z][DEVELOPMENT_CHAIN_ID][0] // we have only 1 accesslist per config
for (let i = 0; i < wallets.length; i++) {
const account = await wallets[i].getAddress()
expect(
(await findAccessListCredentials(owner, account, accessListAddress)) === true,
`Address ${account} has no balance on Access List ${accessListAddress}, so its not Authorized`
)
}
}
})

it('should check that wallets are NOT on accessList (without Access)', async function () {
for (let z = 0; z < allAccessListsDefinitions.length; z++) {
const accessListAddress = allAccessListsDefinitions[z][DEVELOPMENT_CHAIN_ID][0] // we have only 1 accesslist per config
for (let i = wallets.length; i < 4; i++) {
const account = await (await provider.getSigner(i)).getAddress()
expect(
(await findAccessListCredentials(owner, account, accessListAddress)) === false,
`Address ${account} should not be part Access List ${accessListAddress}, therefore its not Authorized`
)
}
}
})

after(async () => {
await tearDownEnvironment(previousConfiguration)
})
})
Loading
Loading