Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -308,10 +308,27 @@ jobs:
with:
repository: 'oceanprotocol/ocean-cli'
path: 'ocean-cli'
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 'v20.19.0'
- name: Checkout Ocean-js
uses: actions/checkout@v4
with:
repository: 'oceanprotocol/ocean.js'
path: 'ocean.js'
ref: feature/refactor_signatures
- name: Build ocean-js
working-directory: ${{ github.workspace }}/ocean.js
run: |
npm ci
npm run build
npm link
- name: Setup Ocean CLI
working-directory: ${{ github.workspace }}/ocean-cli
run: |
npm ci
npm link @oceanprotocol/lib
npm run build
- name: Run system tests
working-directory: ${{ github.workspace }}/ocean-cli
Expand Down
41 changes: 21 additions & 20 deletions src/@types/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ export interface FindPeerCommand extends Command {
export interface GetP2PPeersCommand extends Command {}
export interface GetP2PNetworkStatsCommand extends Command {}

export interface AdminCommand extends Command {
expiryTimestamp: number
export interface SignedCommand extends Command {
nonce: string
signature: string
address?: string
address: string
}

export interface AdminCollectFeesHandlerResponse {
Expand Down Expand Up @@ -87,7 +87,6 @@ export interface ValidateDDOCommand extends Command {
publisherAddress?: string
nonce?: string
signature?: string
message?: string
}

export interface StatusCommand extends Command {
Expand Down Expand Up @@ -151,38 +150,48 @@ export interface GetFeesCommand extends Command {
policyServer?: any // object to pass to policyServer
}
// admin commands
export interface AdminStopNodeCommand extends AdminCommand {}
export interface AdminReindexTxCommand extends AdminCommand {
export interface AdminStopNodeCommand extends SignedCommand {}
export interface AdminReindexTxCommand extends SignedCommand {
chainId: number
txId: string
}

export interface AdminCollectFeesCommand extends AdminCommand {
export interface AdminCollectFeesCommand extends SignedCommand {
tokenAddress: string
chainId: number
tokenAmount?: number
destinationAddress: string
}

export interface AdminReindexChainCommand extends AdminCommand {
export interface AdminReindexChainCommand extends SignedCommand {
chainId: number
block?: number
}

export interface AdminFetchConfigCommand extends AdminCommand {}
export interface AdminFetchConfigCommand extends SignedCommand {}

export interface AdminPushConfigCommand extends AdminCommand {
export interface AdminPushConfigCommand extends SignedCommand {
config: Record<string, any>
}

export interface AdminGetLogsCommand extends AdminCommand {
export interface AdminGetLogsCommand extends SignedCommand {
logId?: string
startTime?: string
endTime?: string
maxLogs?: number
moduleName?: string
level?: string
page?: number
}
/* eslint-disable no-unused-vars */
export enum IndexingCommand {
STOP_THREAD = 'STOP_THREAD',
START_THREAD = 'START_THREAD'
}
export interface StartStopIndexingCommand extends SignedCommand {
chainId?: number
action: IndexingCommand
}

export interface ICommandHandler {
handle(command: Command): Promise<P2PCommandResponse>
Expand All @@ -194,7 +203,7 @@ export interface IValidateCommandHandler extends ICommandHandler {
}

export interface IValidateAdminCommandHandler extends ICommandHandler {
validate(command: AdminCommand): Promise<ValidateParams>
validate(command: SignedCommand): Promise<ValidateParams>
}

export interface ComputeGetEnvironmentsCommand extends Command {
Expand Down Expand Up @@ -285,14 +294,6 @@ export interface JobStatus {
status: CommandStatus
hash: string
}
export enum IndexingCommand {
STOP_THREAD = 'start',
START_THREAD = 'stop'
}
export interface StartStopIndexingCommand extends AdminCommand {
chainId?: number
action: IndexingCommand
}

export interface PolicyServerPassthroughCommand extends Command {
policyServerPassthrough?: any
Expand Down
6 changes: 3 additions & 3 deletions src/components/Auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface AuthValidation {
address?: string
nonce?: string
signature?: string
message?: string
command?: string
chainId?: string | null
}

Expand Down Expand Up @@ -79,7 +79,7 @@ export class Auth {
async validateAuthenticationOrToken(
authValidation: AuthValidation
): Promise<CommonValidation> {
const { token, address, nonce, signature, message, chainId } = authValidation
const { token, address, nonce, signature, command, chainId } = authValidation
try {
if (signature && address && nonce) {
const oceanNode = OceanNode.getInstance()
Expand All @@ -88,7 +88,7 @@ export class Auth {
address,
parseInt(nonce),
signature,
message,
command,
chainId
)

Expand Down
12 changes: 6 additions & 6 deletions src/components/Indexer/processors/BaseProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ export abstract class BaseEventProcessor {
): Promise<any> {
let ddo
// Log the flag value
INDEXER_LOGGER.logMessage(`decryptDDO: flag=${flag}`)
INDEXER_LOGGER.debug(`decryptDDO: flag=${flag}`)
if ((parseInt(flag) & 2) !== 0) {
INDEXER_LOGGER.logMessage(
`Decrypting DDO from network: ${this.networkId} created by: ${eventCreator} encrypted by: ${decryptorURL}`
Expand All @@ -253,8 +253,6 @@ export abstract class BaseEventProcessor {
const wallet = keyManager.getEthWallet()
const ethAddress = wallet.address

const useTxIdOrContractAddress = txId || contractAddress

if (URLUtils.isValidUrl(decryptorURL)) {
try {
const response = await withRetrial(async () => {
Expand All @@ -264,7 +262,7 @@ export abstract class BaseEventProcessor {
)

const message = String(
useTxIdOrContractAddress + ethAddress + chainId.toString() + nonce
String(ethAddress) + String(nonce) + String(PROTOCOL_COMMANDS.DECRYPT_DDO)
)
const signature = await keyManager.signMessage(message)

Expand Down Expand Up @@ -373,7 +371,7 @@ export abstract class BaseEventProcessor {
)

const message = String(
useTxIdOrContractAddress + ethAddress + chainId.toString() + nonceP2p
String(ethAddress) + String(nonceP2p) + String(PROTOCOL_COMMANDS.DECRYPT_DDO)
)
const signature = await keyManager.signMessage(message)

Expand Down Expand Up @@ -431,7 +429,9 @@ export abstract class BaseEventProcessor {
)

const messageToSign = String(
useTxIdOrContractAddress + ethAddress + chainId.toString() + remoteNonce
String(ethAddress) +
String(remoteNonce) +
String(PROTOCOL_COMMANDS.DECRYPT_DDO)
)
const signature = await keyManager.signMessage(messageToSign)

Expand Down
95 changes: 85 additions & 10 deletions src/components/core/admin/adminHandler.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import { AdminCommand, IValidateAdminCommandHandler } from '../../../@types/commands.js'
import { SignedCommand, IValidateAdminCommandHandler } from '../../../@types/commands.js'
import {
ValidateParams,
validateCommandParameters,
buildInvalidRequestMessage,
buildRateLimitReachedResponse,
buildInvalidParametersResponse
} from '../../httpRoutes/validateCommands.js'
import { validateAdminSignature } from '../../../utils/auth.js'
import { getAdminAddresses } from '../../../utils/auth.js'
import { checkSingleCredential } from '../../../utils/credentials.js'
import { CREDENTIALS_TYPES } from '../../../@types/DDO/Credentials.js'
import { BaseHandler } from '../handler/handler.js'
import { P2PCommandResponse } from '../../../@types/OceanNode.js'
import { ReadableString } from '../../P2P/handleProtocolCommands.js'
import { CommonValidation } from '../../../utils/validators.js'
import { getConfiguration } from '../../../utils/index.js'
import { CORE_LOGGER } from '../../../utils/logging/common.js'

export abstract class AdminCommandHandler
extends BaseHandler
implements IValidateAdminCommandHandler
{
async verifyParamsAndRateLimits(task: AdminCommand): Promise<P2PCommandResponse> {
async verifyParamsAndRateLimits(task: SignedCommand): Promise<P2PCommandResponse> {
if (!(await this.checkRateLimit(task.caller))) {
return buildRateLimitReachedResponse()
}
Expand All @@ -33,22 +37,93 @@ export abstract class AdminCommandHandler
}
}

async validate(command: AdminCommand): Promise<ValidateParams> {
async validateTokenOrSignature(
address: string,
nonce: string,
signature: string,
command: string,
chainId?: string
): Promise<CommonValidation> {
const oceanNode = this.getOceanNode()
const auth = oceanNode.getAuth()
if (!auth) {
return {
valid: false,
error: 'Auth not configured'
}
}
const isAuthRequestValid = await auth.validateAuthenticationOrToken({
token: null,
address,
nonce,
signature,
command,
chainId
})
if (!isAuthRequestValid.valid) {
return {
valid: false,
error: isAuthRequestValid.error
}
}
try {
const config = await getConfiguration()
const allowedAdmins = await getAdminAddresses(config)

const { addresses, accessLists } = allowedAdmins
let allowed = await checkSingleCredential(
{ type: CREDENTIALS_TYPES.ADDRESS, values: addresses },
address,
null
)
if (allowed) {
return { valid: true, error: '' }
}
if (accessLists) {
for (const chainId of Object.keys(accessLists)) {
allowed = await checkSingleCredential(
{
type: CREDENTIALS_TYPES.ACCESS_LIST,
chainId: parseInt(chainId),
accessList: accessLists[chainId]
},
address,
null
)
if (allowed) {
return { valid: true, error: '' }
}
}
}

const errorMsg = `The address which signed the message is not on the allowed admins list. Therefore signature ${signature} is rejected`
CORE_LOGGER.logMessage(errorMsg)
return { valid: false, error: errorMsg }
} catch (e) {
const errorMsg = `Error during signature validation: ${e}`
CORE_LOGGER.error(errorMsg)
return { valid: false, error: errorMsg }
}
}

async validate(command: SignedCommand): Promise<ValidateParams> {
const commandValidation = validateCommandParameters(command, [
'expiryTimestamp',
'nonce',
'address',
'signature'
])
if (!commandValidation.valid) {
return buildInvalidRequestMessage(commandValidation.reason)
}
const signatureValidation: CommonValidation = await validateAdminSignature(
command.expiryTimestamp,
const isAuthRequestValid = await this.validateTokenOrSignature(
command.address,
command.nonce,
command.signature,
command.address
command.command
)
if (!signatureValidation.valid) {
if (!isAuthRequestValid.valid) {
return buildInvalidRequestMessage(
`Signature check failed: ${signatureValidation.error}`
`Signature check failed: ${isAuthRequestValid.error}`
)
}
return { valid: true }
Expand Down
Loading
Loading