From 50704a7d242ed922ab368d029a3eef602518fd1e Mon Sep 17 00:00:00 2001 From: KulkarniShashank Date: Fri, 29 Mar 2024 20:28:59 +0530 Subject: [PATCH] feat: out-of-band connection invitation Signed-off-by: KulkarniShashank --- .../src/agent-service.controller.ts | 7 +- .../src/agent-service.service.ts | 18 +- .../src/interface/agent-service.interface.ts | 667 +++++++++--------- .../src/connection/connection.controller.ts | 31 +- .../src/connection/connection.service.ts | 9 +- .../src/connection/dtos/connection.dto.ts | 53 ++ .../src/connection/enums/connections.enum.ts | 5 + .../src/verification/dto/request-proof.dto.ts | 6 + apps/connection/src/connection.controller.ts | 6 + apps/connection/src/connection.service.ts | 153 +++- .../src/interfaces/connection.interfaces.ts | 21 + libs/common/src/common.constant.ts | 2 + 12 files changed, 635 insertions(+), 343 deletions(-) diff --git a/apps/agent-service/src/agent-service.controller.ts b/apps/agent-service/src/agent-service.controller.ts index 10587964c..7b7b65d21 100644 --- a/apps/agent-service/src/agent-service.controller.ts +++ b/apps/agent-service/src/agent-service.controller.ts @@ -1,7 +1,7 @@ import { Controller } from '@nestjs/common'; import { MessagePattern } from '@nestjs/microservices'; import { AgentServiceService } from './agent-service.service'; -import { IAgentStatus, IConnectionDetails, IUserRequestInterface, ISendProofRequestPayload, IAgentSpinUpSatus, IGetCredDefAgentRedirection, IGetSchemaAgentRedirection, IAgentSpinupDto, IIssuanceCreateOffer, ITenantCredDef, ITenantDto, ITenantSchema, IOutOfBandCredentialOffer, IAgentProofRequest, IDidCreate, IWallet, ITenantRecord } from './interface/agent-service.interface'; +import { IAgentStatus, IConnectionDetails, IUserRequestInterface, ISendProofRequestPayload, IAgentSpinUpSatus, IGetCredDefAgentRedirection, IGetSchemaAgentRedirection, IAgentSpinupDto, IIssuanceCreateOffer, ITenantCredDef, ITenantDto, ITenantSchema, IOutOfBandCredentialOffer, IAgentProofRequest, IDidCreate, IWallet, ITenantRecord, ICreateConnectionInvitation } from './interface/agent-service.interface'; import { user } from '@prisma/client'; import { InvitationMessage } from '@credebl/common/interfaces/agent-service.interface'; @@ -246,5 +246,10 @@ export class AgentServiceController { return this.agentServiceService.createSecp256k1KeyPair(payload.orgId); } + + @MessagePattern({ cmd: 'agent-create-connection-invitation' }) + async createConnectionInvitation(payload: { url: string; orgId: string; connectionPayload: ICreateConnectionInvitation }): Promise { + return this.agentServiceService.createConnectionInvitation(payload.url, payload.orgId, payload.connectionPayload); + } } diff --git a/apps/agent-service/src/agent-service.service.ts b/apps/agent-service/src/agent-service.service.ts index eb5cf2e2d..5a595fbf1 100644 --- a/apps/agent-service/src/agent-service.service.ts +++ b/apps/agent-service/src/agent-service.service.ts @@ -46,7 +46,8 @@ import { IDidCreate, IWallet, ITenantRecord, - LedgerListResponse + LedgerListResponse, + ICreateConnectionInvitation } from './interface/agent-service.interface'; import { AgentSpinUpStatus, AgentType, DidMethod, Ledgers, OrgAgentType } from '@credebl/enum/enum'; import { AgentServiceRepository } from './repositories/agent-service.repository'; @@ -1572,6 +1573,21 @@ export class AgentServiceService { this.logger.error(`Error in schema endorsement request in agent service : ${JSON.stringify(error)}`); } } + + async createConnectionInvitation(url: string, orgId: string, connectionPayload: ICreateConnectionInvitation): Promise { + try { + const getApiKey = await this.getOrgAgentApiKey(orgId); + + const createConnectionInvitation = await this.commonService + .httpPost(url, connectionPayload, { headers: { authorization: getApiKey } }) + .then(async (response) => response); + return createConnectionInvitation; + } catch (error) { + this.logger.error(`Error in create connection invitation in agent service : ${JSON.stringify(error)}`); + throw error; + } + } + async natsCall(pattern: object, payload: object): Promise<{ response: string; }> { diff --git a/apps/agent-service/src/interface/agent-service.interface.ts b/apps/agent-service/src/interface/agent-service.interface.ts index 4e3b1a4ed..38f5f9388 100644 --- a/apps/agent-service/src/interface/agent-service.interface.ts +++ b/apps/agent-service/src/interface/agent-service.interface.ts @@ -1,161 +1,161 @@ import { UserRoleOrgPermsDto } from 'apps/api-gateway/src/dtos/user-role-org-perms.dto'; export interface IAgentSpinupDto { - walletName: string; - walletPassword: string; - seed: string; - orgId?: string; - orgName?: string; - ledgerId?: string[]; - keyType: string; - domain?: string; - privatekey?: string; - endpoint?: string; - role?: string; - network?: string - endorserDid?: string - method: string; - did?: string; - agentType?: string; - transactionApproval?: boolean; - clientSocketId?: string - tenant?: boolean; - ledgerName?: string[]; - platformAdminEmail?: string; - apiKey?: string; + walletName: string; + walletPassword: string; + seed: string; + orgId?: string; + orgName?: string; + ledgerId?: string[]; + keyType: string; + domain?: string; + privatekey?: string; + endpoint?: string; + role?: string; + network?: string; + endorserDid?: string; + method: string; + did?: string; + agentType?: string; + transactionApproval?: boolean; + clientSocketId?: string; + tenant?: boolean; + ledgerName?: string[]; + platformAdminEmail?: string; + apiKey?: string; } export interface IOutOfBandCredentialOffer { - emailId: string; - attributes: IAttributes[]; - credentialDefinitionId: string; - comment: string; - protocolVersion?: string; - orgId: string; - goalCode?: string, - parentThreadId?: string, - willConfirm?: boolean, - label?: string + emailId: string; + attributes: IAttributes[]; + credentialDefinitionId: string; + comment: string; + protocolVersion?: string; + orgId: string; + goalCode?: string; + parentThreadId?: string; + willConfirm?: boolean; + label?: string; } export interface ITenantDto { - label: string; - seed?: string; - keyType: string; - ledgerId: string[]; - domain?: string; - privatekey?: string; - endpoint?: string; - role?: string; - network?: string - endorserDid?: string - method: string; - orgId: string; - did?: string; - tenantId?: string; - didDocument?: string; - clientSocketId?: string; + label: string; + seed?: string; + keyType: string; + ledgerId: string[]; + domain?: string; + privatekey?: string; + endpoint?: string; + role?: string; + network?: string; + endorserDid?: string; + method: string; + orgId: string; + did?: string; + tenantId?: string; + didDocument?: string; + clientSocketId?: string; } export interface IWallet { - label: string; - orgId: string; - did?: string; - clientSocketId?: string; + label: string; + orgId: string; + did?: string; + clientSocketId?: string; } export interface IDidCreate { - keyType: KeyType; - seed: string; - domain?: string; - network?: string; - privatekey?: string; - endpoint?: string; - method: string; - did?: string; - role?: string; - endorserDid?: string; + keyType: KeyType; + seed: string; + domain?: string; + network?: string; + privatekey?: string; + endpoint?: string; + method: string; + did?: string; + role?: string; + endorserDid?: string; } export interface ITenantSchema { - tenantId?: string; - attributes: string[]; - version: string; - name: string; - issuerId?: string; - payload?: ITenantSchemaDto; - method?: string; - agentType?: string; - apiKey?: string; - agentEndPoint?: string; - orgId?: string; + tenantId?: string; + attributes: string[]; + version: string; + name: string; + issuerId?: string; + payload?: ITenantSchemaDto; + method?: string; + agentType?: string; + apiKey?: string; + agentEndPoint?: string; + orgId?: string; } export interface ITenantSchemaDto { - attributes: string[]; - version: string; - name: string; - issuerId: string; + attributes: string[]; + version: string; + name: string; + issuerId: string; } export interface IGetSchemaAgentRedirection { - schemaId?: string; - tenantId?: string; - payload?: IGetSchemaFromTenantPayload; - apiKey?: string; - agentEndPoint?: string; - agentType?: string; - method?: string; - orgId?: string; + schemaId?: string; + tenantId?: string; + payload?: IGetSchemaFromTenantPayload; + apiKey?: string; + agentEndPoint?: string; + agentType?: string; + method?: string; + orgId?: string; } export interface IGetSchemaFromTenantPayload { - schemaId: string; + schemaId: string; } export interface ITenantCredDef { - tenantId?: string; - tag?: string; - schemaId?: string; - issuerId?: string; - payload?: ITenantCredDef; - method?: string; - agentType?: string; - apiKey?: string; - agentEndPoint?: string; - orgId?: string; + tenantId?: string; + tag?: string; + schemaId?: string; + issuerId?: string; + payload?: ITenantCredDef; + method?: string; + agentType?: string; + apiKey?: string; + agentEndPoint?: string; + orgId?: string; } export interface IWalletProvision { - orgId: string; - externalIp: string; - walletName: string; - walletPassword: string; - seed: string; - webhookEndpoint: string; - walletStorageHost: string; - walletStoragePort: string; - walletStorageUser: string; - walletStoragePassword: string; - containerName: string; - agentType: string; - orgName: string; - indyLedger: string; - afjVersion: string; - protocol: string; - tenant: boolean; - inboundEndpoint: string; - apiKey?: string; + orgId: string; + externalIp: string; + walletName: string; + walletPassword: string; + seed: string; + webhookEndpoint: string; + walletStorageHost: string; + walletStoragePort: string; + walletStorageUser: string; + walletStoragePassword: string; + containerName: string; + agentType: string; + orgName: string; + indyLedger: string; + afjVersion: string; + protocol: string; + tenant: boolean; + inboundEndpoint: string; + apiKey?: string; } export interface IPlatformConfigDto { - externalIP: string; - genesisURL: string; - adminKey: string; - lastInternalIP: string; - platformTestNetApiKey: string; - sgEmailFrom: string; - apiEndpoint: string; - tailsFileServer: string; + externalIP: string; + genesisURL: string; + adminKey: string; + lastInternalIP: string; + platformTestNetApiKey: string; + sgEmailFrom: string; + apiEndpoint: string; + tailsFileServer: string; } export interface IStoreOrgAgentDetails { @@ -184,335 +184,348 @@ export interface IStoreOrgAgentDetails { } export interface IStoreOrgAgent { - id?: string; - clientSocketId?: string; - agentEndPoint?: string; - apiKey?: string; - seed?: string; - did?: string; - verkey?: string; - isDidPublic?: boolean; - agentSpinUpStatus?: number; - walletName?: string; - agentsTypeId?: string; - orgId?: string; - agentId?: string; - orgAgentTypeId?: string; - tenantId?: string; - ledgerId?: unknown; - agentType?: string; + id?: string; + clientSocketId?: string; + agentEndPoint?: string; + apiKey?: string; + seed?: string; + did?: string; + verkey?: string; + isDidPublic?: boolean; + agentSpinUpStatus?: number; + walletName?: string; + agentsTypeId?: string; + orgId?: string; + agentId?: string; + orgAgentTypeId?: string; + tenantId?: string; + ledgerId?: unknown; + agentType?: string; } - export interface IConnectionDetails { - multiUseInvitation?: boolean; - autoAcceptConnection: boolean; + multiUseInvitation?: boolean; + autoAcceptConnection: boolean; } export interface IUserRequestInterface { - userId?: string; - id?: string; - email: string; - orgId: string; - agentEndPoint?: string; - apiKey?: string; - tenantId?: string; - tenantName?: string; - tenantOrgId?: string; - userRoleOrgPermissions?: UserRoleOrgPermsDto[]; - orgName?: string; - selectedOrg: IOrgInterface; + userId?: string; + id?: string; + email: string; + orgId: string; + agentEndPoint?: string; + apiKey?: string; + tenantId?: string; + tenantName?: string; + tenantOrgId?: string; + userRoleOrgPermissions?: UserRoleOrgPermsDto[]; + orgName?: string; + selectedOrg: IOrgInterface; } export interface IOrgInterface { - id: string; - userId: string; - orgRoleId: string; - orgId: string; - orgRole: object; - organisation: IOrganizationAgentInterface; + id: string; + userId: string; + orgRoleId: string; + orgId: string; + orgRole: object; + organisation: IOrganizationAgentInterface; } export interface IOrganizationAgentInterface { - name: string; - description: string; - org_agents: IOrgAgentInterface[] - + name: string; + description: string; + org_agents: IOrgAgentInterface[]; } export interface IPlatformAgent { - seed: string; - keyType: string; - method: string; - network: string; - role: string; - } - + seed: string; + keyType: string; + method: string; + network: string; + role: string; +} + export interface IOrgAgentInterface { - orgDid: string; - verkey: string; - agentEndPoint: string; - agentOptions: string; - walletName: string; - agentsTypeId: string; - orgId: string; + orgDid: string; + verkey: string; + agentEndPoint: string; + agentOptions: string; + walletName: string; + agentsTypeId: string; + orgId: string; } export interface ITenantCredDefDto { - tag: string; - schemaId: string; - issuerId: string; + tag: string; + schemaId: string; + issuerId: string; } export interface IGetCredDefAgentRedirection { - credentialDefinitionId?: string; - tenantId?: string; - payload?: IGetCredDefFromTenantPayload; - apiKey?: string; - agentEndPoint?: string; - agentType?: string; - method?: string; - orgId?: string; + credentialDefinitionId?: string; + tenantId?: string; + payload?: IGetCredDefFromTenantPayload; + apiKey?: string; + agentEndPoint?: string; + agentType?: string; + method?: string; + orgId?: string; } export interface IGetCredDefFromTenantPayload { - credentialDefinitionId: string; + credentialDefinitionId: string; } export interface IIssuanceCreateOffer { - connectionId: string; - credentialFormats: ICredentialFormats; - autoAcceptCredential: string; - comment: string; + connectionId: string; + credentialFormats: ICredentialFormats; + autoAcceptCredential: string; + comment: string; } export interface ICredentialFormats { - indy: IIndy; - credentialDefinitionId: string; + indy: IIndy; + credentialDefinitionId: string; } export interface IIndy { - attributes: IAttributes[]; + attributes: IAttributes[]; } export interface IAttributes { - name: string; - value: string; + name: string; + value: string; } export interface ISendProofRequestPayload { - comment: string; - connectionId?: string; - proofFormats: IProofFormats; - autoAcceptProof: string; - goalCode?: string; - parentThreadId?: string; - willConfirm?: boolean; - protocolVersion?: string; + comment: string; + connectionId?: string; + proofFormats: IProofFormats; + autoAcceptProof: string; + goalCode?: string; + parentThreadId?: string; + willConfirm?: boolean; + protocolVersion?: string; } export interface IAgentStatus { - label: string; - endpoints: string[]; - isInitialized: boolean; + label: string; + endpoints: string[]; + isInitialized: boolean; } interface IProofFormats { - indy: IndyProof + indy: IndyProof; } interface IndyProof { - name: string; - version: string; - requested_attributes: IRequestedAttributes; - requested_predicates: IRequestedPredicates; + name: string; + version: string; + requested_attributes: IRequestedAttributes; + requested_predicates: IRequestedPredicates; } interface IRequestedAttributes { - [key: string]: IRequestedAttributesName; + [key: string]: IRequestedAttributesName; } interface IRequestedAttributesName { - name: string; - restrictions: IRequestedRestriction[] + name: string; + restrictions: IRequestedRestriction[]; } interface IRequestedPredicates { - [key: string]: IRequestedPredicatesName; + [key: string]: IRequestedPredicatesName; } interface IRequestedPredicatesName { - name: string; - restrictions: IRequestedRestriction[] + name: string; + restrictions: IRequestedRestriction[]; } interface IRequestedRestriction { - cred_def_id?: string; - schema_id?: string; - schema_issuer_did?: string; - schema_name?: string; - issuer_did?: string; + cred_def_id?: string; + schema_id?: string; + schema_issuer_did?: string; + schema_name?: string; + issuer_did?: string; } export interface IAgentSpinUpSatus { - agentSpinupStatus: number; + agentSpinupStatus: number; } interface IWalletConfig { - id: string; - key: string; - keyDerivationMethod: string; + id: string; + key: string; + keyDerivationMethod: string; } interface IConfig { - label: string; - walletConfig: IWalletConfig; + label: string; + walletConfig: IWalletConfig; } export interface ITenantRecord { - _tags: string; - metadata: string; - id: string; - createdAt: string; - config: IConfig; - updatedAt: string; + _tags: string; + metadata: string; + id: string; + createdAt: string; + config: IConfig; + updatedAt: string; } export interface ICreateTenant { - tenantRecord: ITenantRecord; - did: string; - verkey: string; + tenantRecord: ITenantRecord; + did: string; + verkey: string; } - export interface IOrgAgent { - agentSpinUpStatus: number; + agentSpinUpStatus: number; } export interface IOrgLedgers { - id: string; + id: string; } export interface ICreateOrgAgent { - id: string; + id: string; } interface IOrgAgentEndPoint { - agentSpinUpStatus: number; - agentEndPoint: string; - apiKey; + agentSpinUpStatus: number; + agentEndPoint: string; + apiKey; } export interface IOrgAgentsResponse { - org_agents: IOrgAgentEndPoint[]; + org_agents: IOrgAgentEndPoint[]; } export interface IStoreAgent { - id: string; + id: string; } export interface IAcceptCredentials { - credentialRecordId: string; + credentialRecordId: string; } export interface IAgentProofRequest { - metadata: object; - id: string; - createdAt: string; - protocolVersion: string; - state: string; - connectionId: string; - threadId: string; - autoAcceptProof: string; - updatedAt: string; + metadata: object; + id: string; + createdAt: string; + protocolVersion: string; + state: string; + connectionId: string; + threadId: string; + autoAcceptProof: string; + updatedAt: string; } export interface IPresentation { - _tags: ITags; - metadata: object; - id: string; + _tags: ITags; + metadata: object; + id: string; } export interface IStoreAgent { - id: string; + id: string; } export interface IReceiveInvite { - alias?: string; - label?: string; - imageUrl?: string; - autoAcceptConnection?: boolean; - autoAcceptInvitation?: boolean; - reuseConnection?: boolean; - acceptInvitationTimeoutMs?: number; + alias?: string; + label?: string; + imageUrl?: string; + autoAcceptConnection?: boolean; + autoAcceptInvitation?: boolean; + reuseConnection?: boolean; + acceptInvitationTimeoutMs?: number; } export interface IReceiveInvitationUrl extends IReceiveInvite { - invitationUrl: string; + invitationUrl: string; } interface IService { - id: string; - serviceEndpoint: string; - type: string; - recipientKeys: string[]; - routingKeys: string[]; - accept: string[]; + id: string; + serviceEndpoint: string; + type: string; + recipientKeys: string[]; + routingKeys: string[]; + accept: string[]; } interface IInvitation { - '@id': string; - '@type': string; - label: string; - goalCode: string; - goal: string; - accept: string[]; - handshake_protocols: string[]; - services: (IService | string)[]; - imageUrl?: string; + '@id': string; + '@type': string; + label: string; + goalCode: string; + goal: string; + accept: string[]; + handshake_protocols: string[]; + services: (IService | string)[]; + imageUrl?: string; } export interface IReceiveInvitation extends IReceiveInvite { - invitation: IInvitation; + invitation: IInvitation; } export interface IProofPresentation { - createdAt: string; - protocolVersion: string; - state: string; - connectionId: string; - threadId: string; - autoAcceptProof: string; - updatedAt: string; - isVerified: boolean; + createdAt: string; + protocolVersion: string; + state: string; + connectionId: string; + threadId: string; + autoAcceptProof: string; + updatedAt: string; + isVerified: boolean; } interface ITags { - connectionId: string; - state: string; - threadId: string; + connectionId: string; + state: string; + threadId: string; } export interface IValidResponses { - text: string; - } - export interface IQuestionPayload { - detail: string; - validResponses: IValidResponses[]; - question: string; - orgId?: string; - connectionId: string; - tenantId: string; - } + text: string; +} +export interface IQuestionPayload { + detail: string; + validResponses: IValidResponses[]; + question: string; + orgId?: string; + connectionId: string; + tenantId: string; +} interface Ledger { - id: string; - createDateTime: string; - lastChangedDateTime: string; - name: string; - networkType: string; - poolConfig: string; - isActive: boolean; - networkString: string; - registerDIDEndpoint: string; - registerDIDPayload: string; - indyNamespace: string; - networkUrl: string | null; - } - - export interface LedgerListResponse { - response: Ledger[]; - } \ No newline at end of file + id: string; + createDateTime: string; + lastChangedDateTime: string; + name: string; + networkType: string; + poolConfig: string; + isActive: boolean; + networkString: string; + registerDIDEndpoint: string; + registerDIDPayload: string; + indyNamespace: string; + networkUrl: string | null; +} + +export interface LedgerListResponse { + response: Ledger[]; +} + +export interface ICreateConnectionInvitation { + label?: string; + alias?: string; + imageUrl?: string; + goalCode?: string; + goal?: string; + handshake?: boolean; + handshakeProtocols?: object[]; + messages?: object[]; + multiUseInvitation?: boolean; + autoAcceptConnection?: boolean; + routing?: object; + appendedAttachments?: object[]; + orgId?: string; +} diff --git a/apps/api-gateway/src/connection/connection.controller.ts b/apps/api-gateway/src/connection/connection.controller.ts index 9fc45bfb7..d3dad9185 100644 --- a/apps/api-gateway/src/connection/connection.controller.ts +++ b/apps/api-gateway/src/connection/connection.controller.ts @@ -7,7 +7,7 @@ import { User } from '../authz/decorators/user.decorator'; import { ForbiddenErrorDto } from '../dtos/forbidden-error.dto'; import { UnauthorizedErrorDto } from '../dtos/unauthorized-error.dto'; import { ConnectionService } from './connection.service'; -import { ConnectionDto, CreateConnectionDto, ReceiveInvitationDto, ReceiveInvitationUrlDto } from './dtos/connection.dto'; +import { ConnectionDto, CreateConnectionDto, CreateOutOfBandConnectionInvitation, ReceiveInvitationDto, ReceiveInvitationUrlDto } from './dtos/connection.dto'; import { IUserRequestInterface } from './interfaces'; import { Response } from 'express'; import { IUserRequest } from '@credebl/user-request/user-request.interface'; @@ -192,6 +192,35 @@ export class ConnectionController { } + /** + * Create out-of-band connection invitation + * @param connectionDto + * @param res + * @returns Created out-of-band connection invitation url + */ + @Post('/orgs/:orgId/connection-invitation') + @ApiOperation({ summary: 'Create outbound out-of-band connection invitation', description: 'Create outbound out-of-band connection invitation' }) + @UseGuards(AuthGuard('jwt'), OrgRolesGuard) + @Roles(OrgRoles.OWNER, OrgRoles.ADMIN, OrgRoles.ISSUER, OrgRoles.VERIFIER, OrgRoles.MEMBER) + @ApiResponse({ status: HttpStatus.CREATED, description: 'Created', type: ApiResponseDto }) + async createConnectionInvitation( + @Param('orgId') orgId: string, + @Body() createOutOfBandConnectionInvitation: CreateOutOfBandConnectionInvitation, + @User() reqUser: IUserRequestInterface, + @Res() res: Response + ): Promise { + + createOutOfBandConnectionInvitation.orgId = orgId; + const connectionData = await this.connectionService.createConnectionInvitation(createOutOfBandConnectionInvitation, reqUser); + const finalResponse: IResponse = { + statusCode: HttpStatus.CREATED, + message: ResponseMessages.connection.success.create, + data: connectionData + }; + return res.status(HttpStatus.CREATED).json(finalResponse); + + } + @Post('/orgs/:orgId/question-answer/question/:connectionId') @ApiOperation({ summary: '', description: 'send question' }) @UseGuards(AuthGuard('jwt'), OrgRolesGuard) diff --git a/apps/api-gateway/src/connection/connection.service.ts b/apps/api-gateway/src/connection/connection.service.ts index 8938e62b4..3d5e6ac70 100644 --- a/apps/api-gateway/src/connection/connection.service.ts +++ b/apps/api-gateway/src/connection/connection.service.ts @@ -2,7 +2,7 @@ import { IUserRequest } from '@credebl/user-request/user-request.interface'; import { Inject, Injectable} from '@nestjs/common'; import { ClientProxy, RpcException } from '@nestjs/microservices'; import { BaseService } from 'libs/service/base.service'; -import { ConnectionDto, CreateConnectionDto, ReceiveInvitationDto, ReceiveInvitationUrlDto } from './dtos/connection.dto'; +import { ConnectionDto, CreateConnectionDto, CreateOutOfBandConnectionInvitation, ReceiveInvitationDto, ReceiveInvitationUrlDto } from './dtos/connection.dto'; import { IReceiveInvitationRes, IUserRequestInterface } from './interfaces'; import { IConnectionList, ICreateConnectionUrl } from '@credebl/common/interfaces/connection.interface'; import { AgentConnectionSearchCriteria, IConnectionDetailsById, IConnectionSearchCriteria } from '../interfaces/IConnectionSearch.interface'; @@ -149,4 +149,11 @@ export class ConnectionService extends BaseService { } } + createConnectionInvitation( + createOutOfBandConnectionInvitation: CreateOutOfBandConnectionInvitation, + user: IUserRequestInterface + ): Promise { + const payload = { user, createOutOfBandConnectionInvitation }; + return this.sendNatsMessage(this.connectionServiceProxy, 'create-connection-invitation', payload); + } } diff --git a/apps/api-gateway/src/connection/dtos/connection.dto.ts b/apps/api-gateway/src/connection/dtos/connection.dto.ts index 63afc50ee..afe499c6a 100644 --- a/apps/api-gateway/src/connection/dtos/connection.dto.ts +++ b/apps/api-gateway/src/connection/dtos/connection.dto.ts @@ -2,6 +2,59 @@ import { ArrayNotEmpty, IsArray, IsBoolean, IsNotEmpty, IsNumber, IsOptional, Is import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; +import { HandshakeProtocol } from '../enums/connections.enum'; + +export class CreateOutOfBandConnectionInvitation { + @ApiPropertyOptional() + @IsOptional() + label?: string; + + @ApiPropertyOptional() + @IsOptional() + alias?: string; + + @ApiPropertyOptional() + @IsOptional() + imageUrl?: string; + + @ApiPropertyOptional() + @IsOptional() + goalCode?: string; + + @ApiPropertyOptional() + @IsOptional() + goal?: string; + + @ApiPropertyOptional() + @IsOptional() + handshake?: boolean; + + @ApiPropertyOptional() + @IsOptional() + handshakeProtocols?: HandshakeProtocol[]; + + @ApiPropertyOptional() + @IsOptional() + messages?: object[]; + + @ApiPropertyOptional() + @IsOptional() + multiUseInvitation?: boolean; + + @ApiPropertyOptional() + @IsOptional() + autoAcceptConnection?: boolean; + + @ApiPropertyOptional() + @IsOptional() + routing?: object; + + @ApiPropertyOptional() + @IsOptional() + appendedAttachments?: object[]; + + orgId; +} export class CreateConnectionDto { @ApiPropertyOptional() diff --git a/apps/api-gateway/src/connection/enums/connections.enum.ts b/apps/api-gateway/src/connection/enums/connections.enum.ts index 3ea871b2a..1c4a24600 100644 --- a/apps/api-gateway/src/connection/enums/connections.enum.ts +++ b/apps/api-gateway/src/connection/enums/connections.enum.ts @@ -9,4 +9,9 @@ export enum Connections { responseReceived = 'response-received', complete = 'complete', abandoned = 'abandoned' +} + +export declare enum HandshakeProtocol { + Connections = "https://didcomm.org/connections/1.0", + DidExchange = "https://didcomm.org/didexchange/1.0" } \ No newline at end of file diff --git a/apps/api-gateway/src/verification/dto/request-proof.dto.ts b/apps/api-gateway/src/verification/dto/request-proof.dto.ts index 9e1f49174..48479e119 100644 --- a/apps/api-gateway/src/verification/dto/request-proof.dto.ts +++ b/apps/api-gateway/src/verification/dto/request-proof.dto.ts @@ -232,6 +232,12 @@ export class ProofRequestPresentationDefinition { export class SendProofRequestPayload { + @ApiPropertyOptional() + @IsOptional() + @IsNotEmpty({ message: 'Please provide valid goal code' }) + @IsString({ message: 'goal code should be string' }) + goalCode?: string; + @ApiPropertyOptional() @IsString({ message: 'protocolVersion must be in string' }) @IsNotEmpty({ message: 'please provide valid protocol version' }) diff --git a/apps/connection/src/connection.controller.ts b/apps/connection/src/connection.controller.ts index ca67a4149..9b8c5e645 100644 --- a/apps/connection/src/connection.controller.ts +++ b/apps/connection/src/connection.controller.ts @@ -5,6 +5,7 @@ import { GetAllConnections, IConnection, ICreateConnection, + ICreateOutOfbandConnectionInvitation, IFetchConnectionById, IFetchConnections, IReceiveInvitationByOrg, @@ -94,4 +95,9 @@ export class ConnectionController { async getQuestionAnswersRecord(orgId: string): Promise { return this.connectionService.getQuestionAnswersRecord(orgId); } + + @MessagePattern({ cmd: 'create-connection-invitation' }) + async createConnectionInvitation(payload: ICreateOutOfbandConnectionInvitation): Promise { + return this.connectionService.createConnectionInvitation(payload); + } } diff --git a/apps/connection/src/connection.service.ts b/apps/connection/src/connection.service.ts index a2acdda52..737be584a 100644 --- a/apps/connection/src/connection.service.ts +++ b/apps/connection/src/connection.service.ts @@ -12,7 +12,9 @@ import { ICreateConnection, IReceiveInvitation, IReceiveInvitationResponse, - IReceiveInvitationUrl + IReceiveInvitationUrl, + ICreateOutOfbandConnectionInvitation, + ICreateConnectionInvitation } from './interfaces/connection.interfaces'; import { ConnectionRepository } from './connection.repository'; import { ResponseMessages } from '@credebl/common/response-messages'; @@ -143,7 +145,6 @@ export class ConnectionService { const payload = { connectionPayload, url, orgId }; try { - return await this.natsCall(pattern, payload); } catch (error) { this.logger.error(`catch: ${JSON.stringify(error)}`); @@ -397,15 +398,30 @@ export class ConnectionService { * @param referenceId * @returns agent URL */ - async getAgentUrl(orgAgentType: string, agentEndPoint: string, tenantId?: string): Promise { + async getAgentUrl( + orgAgentType: string, + agentEndPoint: string, + tenantId?: string, + connectionInvitationFlag?: string + ): Promise { try { let url; - if (orgAgentType === OrgAgentType.DEDICATED) { - url = `${agentEndPoint}${CommonConstants.URL_CONN_LEGACY_INVITE}`; - } else if (orgAgentType === OrgAgentType.SHARED) { - url = `${agentEndPoint}${CommonConstants.URL_SHAGENT_CREATE_INVITATION}`.replace('#', tenantId); + if ('connection-invitation' === connectionInvitationFlag) { + if (orgAgentType === OrgAgentType.DEDICATED) { + url = `${agentEndPoint}${CommonConstants.URL_CONN_INVITE}`; + } else if (orgAgentType === OrgAgentType.SHARED) { + url = `${agentEndPoint}${CommonConstants.URL_SHAGENT_CREATE_CONNECTION_INVITATION}`.replace('#', tenantId); + } else { + throw new NotFoundException(ResponseMessages.connection.error.agentUrlNotFound); + } } else { - throw new NotFoundException(ResponseMessages.connection.error.agentUrlNotFound); + if (orgAgentType === OrgAgentType.DEDICATED) { + url = `${agentEndPoint}${CommonConstants.URL_CONN_LEGACY_INVITE}`; + } else if (orgAgentType === OrgAgentType.SHARED) { + url = `${agentEndPoint}${CommonConstants.URL_SHAGENT_CREATE_INVITATION}`.replace('#', tenantId); + } else { + throw new NotFoundException(ResponseMessages.connection.error.agentUrlNotFound); + } } return url; } catch (error) { @@ -639,10 +655,7 @@ export class ConnectionService { } } - async storeConnectionObjectAndReturnUrl( - connectionInvitationUrl: string, - persistent: boolean - ): Promise { + async storeConnectionObjectAndReturnUrl(connectionInvitationUrl: string, persistent: boolean): Promise { const storeObj = connectionInvitationUrl; //nats call in agent-service to create an invitation url const pattern = { cmd: 'store-object-return-url' }; @@ -663,6 +676,122 @@ export class ConnectionService { } } + /** + * Create connection invitation URL + * @param orgId + * @param user + * @returns Connection invitation URL + */ + async createConnectionInvitation(payload: ICreateOutOfbandConnectionInvitation): Promise { + try { + const { + alias, + appendedAttachments, + autoAcceptConnection, + goal, + goalCode, + handshake, + handshakeProtocols, + imageUrl, + messages, + multiUseInvitation, + orgId, + routing + } = payload?.createOutOfBandConnectionInvitation; + + const agentDetails = await this.connectionRepository.getAgentEndPoint(payload?.createOutOfBandConnectionInvitation?.orgId); + + const { agentEndPoint, id, organisation } = agentDetails; + const agentId = id; + if (!agentDetails) { + throw new NotFoundException(ResponseMessages.connection.error.agentEndPointNotFound); + } + + const connectionPayload = { + multiUseInvitation: multiUseInvitation ?? true, + autoAcceptConnection: autoAcceptConnection ?? true, + alias: alias || undefined, + imageUrl: organisation.logoUrl || imageUrl || undefined, + label: organisation.name, + goal: goal || undefined, + goalCode: goalCode || undefined, + handshake: handshake || undefined, + handshakeProtocols: handshakeProtocols || undefined, + appendedAttachments: appendedAttachments || undefined, + routing: routing || undefined, + messages: messages || undefined + }; + + const createConnectionInvitationFlag = 'connection-invitation'; + const orgAgentType = await this.connectionRepository.getOrgAgentType(agentDetails?.orgAgentTypeId); + const url = await this.getAgentUrl( + orgAgentType, + agentEndPoint, + agentDetails?.tenantId, + createConnectionInvitationFlag + ); + const createConnectionInvitation = await this._createOutOfBandConnectionInvitation(connectionPayload, url, orgId); + const connectionInvitationUrl = createConnectionInvitation?.response?.invitationUrl; + const shortenedUrl = await this.storeConnectionObjectAndReturnUrl( + connectionInvitationUrl, + connectionPayload.multiUseInvitation + ); + const saveConnectionDetails = await this.connectionRepository.saveAgentConnectionInvitations( + shortenedUrl, + agentId, + orgId, + null + ); + const connectionDetailRecords: ConnectionResponseDetail = { + id: saveConnectionDetails.id, + orgId: saveConnectionDetails.orgId, + agentId: saveConnectionDetails.agentId, + connectionInvitation: saveConnectionDetails.connectionInvitation, + multiUse: saveConnectionDetails.multiUse, + createDateTime: saveConnectionDetails.createDateTime, + createdBy: saveConnectionDetails.createdBy, + lastChangedDateTime: saveConnectionDetails.lastChangedDateTime, + lastChangedBy: saveConnectionDetails.lastChangedBy, + recordId: createConnectionInvitation.response.outOfBandRecord.id, + recipientKey: saveConnectionDetails.recipientKey + }; + return connectionDetailRecords; + } catch (error) { + this.logger.error(`[createConnectionInvitation] - error in connection oob invitation: ${error}`); + this.handleError(error); + } + } + + /** + * Store shortening URL + * @param orgId + * @returns connection invitation URL + */ + async _createOutOfBandConnectionInvitation( + connectionPayload: ICreateConnectionInvitation, + url: string, + orgId: string + ): Promise<{ + response; + }> { + //nats call in agent-service to create an invitation url + const pattern = { cmd: 'agent-create-connection-invitation' }; + const payload = { connectionPayload, url, orgId }; + + try { + return await this.natsCall(pattern, payload); + } catch (error) { + this.logger.error(`catch: ${JSON.stringify(error)}`); + throw new HttpException( + { + status: error.status, + error: error.message + }, + error.status + ); + } + } + async natsCall( pattern: object, payload: object diff --git a/apps/connection/src/interfaces/connection.interfaces.ts b/apps/connection/src/interfaces/connection.interfaces.ts index b49d6ea9e..af3f24a76 100644 --- a/apps/connection/src/interfaces/connection.interfaces.ts +++ b/apps/connection/src/interfaces/connection.interfaces.ts @@ -267,3 +267,24 @@ export interface ConnectionResponseDetail { recordId: string; recipientKey:string; } + +export interface ICreateConnectionInvitation { + label?: string; + alias?: string; + imageUrl?: string; + goalCode?: string; + goal?: string; + handshake?: boolean; + handshakeProtocols?: object[]; + messages?: object[]; + multiUseInvitation?: boolean; + autoAcceptConnection?: boolean; + routing?: object; + appendedAttachments?: object[]; + orgId?: string; +} + +export interface ICreateOutOfbandConnectionInvitation { + user: IUserRequestInterface, + createOutOfBandConnectionInvitation: ICreateConnectionInvitation, +} \ No newline at end of file diff --git a/libs/common/src/common.constant.ts b/libs/common/src/common.constant.ts index a15b61224..ebb8f4171 100644 --- a/libs/common/src/common.constant.ts +++ b/libs/common/src/common.constant.ts @@ -23,6 +23,7 @@ export enum CommonConstants { URL_CONN_REMOVE_CONNECTION_BY_ID = '/connections/#/remove', URL_CONN_METADATA = '/connections/#/metadata', URL_CONN_LEGACY_INVITE = '/oob/create-legacy-invitation', + URL_CONN_INVITE = '/oob/create-invitation', URL_RECEIVE_INVITATION_URL = '/oob/receive-invitation-url', URL_RECEIVE_INVITATION = '/oob/receive-invitation', URL_CONN_INVITATION = '/url', @@ -97,6 +98,7 @@ export enum CommonConstants { URL_SHAGENT_CREATE_CRED_DEF = '/multi-tenancy/credential-definition/#', URL_SHAGENT_GET_CRED_DEF = '/multi-tenancy/credential-definition/@/#', URL_SHAGENT_CREATE_INVITATION = '/multi-tenancy/create-legacy-invitation/#', + URL_SHAGENT_CREATE_CONNECTION_INVITATION = '/multi-tenancy/create-invitation/#', URL_SHAGENT_GET_CREATEED_INVITATIONS = '/multi-tenancy/connections/#', URL_SHAGENT_GET_CREATEED_INVITATION_BY_CONNECTIONID = '/multi-tenancy/connections/#/@', URL_SHAGENT_CREATE_OFFER = '/multi-tenancy/credentials/create-offer/#',