openwallet-foundation / credo-ts

Typescript framework for building decentralized identity and verifiable credential solutions
https://credo.js.org
Apache License 2.0
247 stars 186 forks source link

Unable to send or recieve PerformMessage with params #1785

Open BlackLight54 opened 4 months ago

BlackLight54 commented 4 months ago

When sending or recieving a message which is compliant with Aries RFC 0509: Action Menu Protocol which contains a valid params dictionary:

Recieved Message

``` INFO: Received message with type 'https://didcomm.org/action-menu/1.0/perform', recipient key /**/and sender key /**/{ "@type": "https://didcomm.org/action-menu/1.0/perform", "@id": "/**//", "name": "echo", "params": { "message-text": "asd" }, "~thread": { "thid": "85e0a4a3-c4c8-4832-81da-79fd7820fc21" } } ```

There is an unexpected validation error, stating that an eachconstraint is not satisfied, specifically each value in params must be a string .

Error

``` ERROR: Error validating message undefined { "errors": { "name": "ClassValidationError", "message": "PerformMessage: Failed to validate class. An instance of PerformMessage has failed the validation: - property params has failed the following constraints: each value in params must be a string", "stack": "ClassValidationError: PerformMessage: Failed to validate class. An instance of PerformMessage has failed the validation: - property params has failed the following constraints: each value in params must be a string at Function.validateSync (.../node_modules/@credo-ts/core/src/utils/MessageValidator.ts:19:13) at Function.fromJSON (.../node_modules/@credo-ts/core/src/utils/JsonTransformer.ts:35:22) at MessageReceiver.transformMessage (.../node_modules/@credo-ts/core/src/agent/MessageReceiver.ts:255:44) at MessageReceiver.transformAndValidate (.../node_modules/@credo-ts/core/src/agent/MessageReceiver.ts:212:28) at MessageReceiver.receiveEncryptedMessage (.../node_modules/@credo-ts/core/src/agent/MessageReceiver.ts:133:32) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at MessageReceiver.receiveMessage (.../node_modules/@credo-ts/core/src/agent/MessageReceiver.ts:96:9) at (...node_modules/@credo-ts/node/src/transport/HttpInboundTransport.ts:55:9)", "validationErrors": [ { "target": { "@type": "https://didcomm.org/action-menu/1.0/perform", "@id": "/**/", "name": "echo", "params": { "message-text": "asd" }, "~thread": { "thid": "85e0a4a3-c4c8-4832-81da-79fd7820fc21" } }, "value": { "message-text": "asd" }, "property": "params", "children": [], "constraints": { "isString": "each value in params must be a string" } } ] }, "message": "{\"@type\":\"https://didcomm.org/action-menu/1.0/perform\",\"@id\":\"/**/\",\"name\":\"echo\",\"params\":{\"message-text\":\"asd\"},\"~thread\":{\"thid\":\"85e0a4a3-c4c8-4832-81da-79fd7820fc21\"}}" } ```

The same doesn't happen with an empty params field.

This probably originates from the validation in packages/action-menu/src/messages/PerformMessage.ts

export class PerformMessage extends AgentMessage {
  /* ... */
  @IsString({ each: true })
  @IsOptional()
  public params?: Record<string, string>
}

I suspect that because Record<string,string> is not a class, only a simple object, the validator doesn't work as expected, or that the each validator option only works with arrays not records. I think a solution would fall along the lines of this issue.

PS: This issue may become irrelevant if class-validator is replaced by zod #1777

GJanos commented 1 month ago

I was able to recreate this issue, when I tried to perform an action of a requested action menu with params included.

The data that I tried to submit: {name: "echo", params: { message-text: "test message :)" }} And the error message that was automatically logged from credo's side: I beleive it is related to this issue.

MessageSendingError: Message is undeliverable to connection 60fb89be-2f84-415e-9a23-dbce0fb9d4c5 (SupportOffice)
    at MessageSender.sendMessage (/usr/src/app/node_modules/@credo-ts/core/build/agent/MessageSender.js:302:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async ActionMenuApi.performAction (/usr/src/app/node_modules/@credo-ts/action-menu/build/ActionMenuApi.js:98:9)
    at async ActionMenuRequesterService.performAction (/usr/src/app/dist/apps/credo-api/main.js:222:16)
    at async ActionMenuController.sendActionMenuPerformMessage (/usr/src/app/dist/apps/credo-api/main.js:108:16)
    at async /usr/src/app/node_modules/@nestjs/core/router/router-execution-context.js:46:28
    at async /usr/src/app/node_modules/@nestjs/core/router/router-proxy.js:9:17 {
  outboundMessageContext: OutboundMessageContext {
    message: PerformMessage {
      allowDidSovPrefix: false,
      allowQueueTransport: true,
      type: 'https://didcomm.org/action-menu/1.0/perform',
      id: '498f241a-2849-4043-93fe-e84f43806029',
      name: 'echo',
      params: [Object],
      thread: [ThreadDecorator]
    },
    connection: ConnectionRecord {
      _tags: [Object],
      type: 'ConnectionRecord',
      metadata: [Metadata],
      connectionTypes: [],
      previousDids: [],
      previousTheirDids: [],
      id: '60fb89be-2f84-415e-9a23-dbce0fb9d4c5',
      createdAt: 2024-05-20T11:56:51.098Z,
      did: 'did:peer:1zQmQ8w87wHNULLnQuXorGZmi6GE93JPjbatf2XrfH5tp7yr',
      invitationDid: 'did:peer:2.Vz6MkvBRdeUiJpKd5PDbiiJRxL1r3p4aMJQfrdALPiFuQ95B1.Ez6LSboiaz3wKeSgCN9TAoBqsmaLNcfeTNsVg4g8udiFuUJxg.SeyJzIjoiaHR0cDovL3N1cHBvcnQtb2ZmaWNlOjQwMDEiLCJ0IjoiZGlkLWNvbW11bmljYXRpb24iLCJwcmlvcml0eSI6MCwicmVjaXBpZW50S2V5cyI6WyIja2V5LTEiXSwiciI6W119',
      theirLabel: 'SupportOffice',
      state: 'completed',
      role: 'requester',
      autoAcceptConnection: true,
      threadId: '4997f79d-26f3-436c-995a-1c64d3fea454',
      protocol: 'https://didcomm.org/didexchange/1.x',
      outOfBandId: 'e0148cc7-649e-4182-b510-79e3179f0754',
      updatedAt: 2024-05-20T11:56:51.249Z,
      theirDid: 'did:peer:1zQmX51xQkgS8ge1rQMzmgq2e8gQfijFpcKxeK9Njj6LKQkS'
    },
    sessionId: undefined,
    outOfBand: undefined,
    serviceParams: undefined,
    associatedRecord: ActionMenuRecord {
      _tags: [Object],
      type: 'ActionMenuRecord',
      metadata: [Metadata],
      id: '83bb3288-2a7d-4bcf-b43c-70450eed3217',
      createdAt: 2024-05-20T11:56:56.776Z,
      connectionId: '60fb89be-2f84-415e-9a23-dbce0fb9d4c5',
      threadId: 'd5cf05da-a1cc-4a63-ad6d-385bbe39750f',
      state: 'done',
      role: 'requester',
      updatedAt: 2024-05-20T17:17:01.362Z,
menu: [ActionMenu],
      performedAction: [Object]
    },
    inboundMessageContext: undefined,
    agentContext: AgentContext {
      dependencyManager: [DependencyManager],
      contextCorrelationId: 'default'
    }
  },
  [cause]: undefined
}