diff --git a/.env.example b/.env.example index d6ee9609c4882af81c7703abd3fbdd06c298a295..e66463c709c7879153166b641d2f3b764b076bc2 100644 --- a/.env.example +++ b/.env.example @@ -1,18 +1,35 @@ -AGENT_PEER_URL="http://localhost:4000" -AGENT_NAME=DExcVasd_AGENT_45 -AGENT_KEY=HwNJroKHTSSj3XvE7ZAnuKiTn2C4QkFvxEqfm5rzhNrh -AGENT_DID_SEED=200000000000000000000000TCuste21 - LEDGERS="BCOVRIN_TEST" -IDUNION_KEY= +IDUNION_KEY=#add if you are using IDUNION as a ledger +AGENT_PEER_URL="http://localhost:4000" +AGENT_NAME=EXAMPLE_AGENT_45 +AGENT_KEY=EXAMPLE_AGENT_45_KEY +AGENT_DID_SEED=200000000000000000000000ExampleT21 #random string min 32 chars AGENT_DB_HOST=0.0.0.0:5432 AGENT_DB_USER=postgres AGENT_DB_PASS=postgres -PORT=3001 +AGENT_PORT=3001 +AGENT_CONSUMER_NAME=agent_1 +AGENT_IS_REST=false +AGENT_MAX_MESSAGES=10 +AGENT_RETE_LIMIT=5 NATS_SERVERS=0.0.0.0:4222 -NATS_STREAM_NAME=ssi -NATS_SUBJECTS="connections.*,proofs.*,credentials.*" -AGENT_CONSUMER_NAME=agent -AGENT_IS_REST=true +NATS_STREAM_NAME=ssi_stream +NATS_SUBJECTS="connections.*,proofs.*,credentials.*,schemas.*" + +GATEWAY_HTTP_PORT=8081 +GATEWAY_TCP_PORT=8881 +GATEWAY_SOCKET_EVENT_NAME=message +GATEWAY_MESSAGE_PATTERN=webhook +GATEWAY_HOST=0.0.0.0 + +CONNECTION_SERVICE_TCP_PORT=8882 +CONNECTION_SERVICE_HOST=0.0.0.0 + +ATTESTATION_SERVICE_TCP_PORT=8883 +ATTESTATION_SERVICE_HOST=0.0.0.0 + +PROOF_SERVICE_TCP_PORT=8884 +PROOF_SERVICE_HOST=0.0.0.0 + diff --git a/README.md b/README.md index b9ed0fb71b3046c899821895e559799d601d841f..16287d32eb8061a5a8ace8e78a945bec88274128 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,9 @@ -# OcmEngine +# Ocm Engine <a alt="Nx logo" href="https://nx.dev" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-logo.png" width="45"></a> ✨ **This workspace has been generated by [Nx, a Smart, fast and extensible build system.](https://nx.dev)** ✨ -## Development server - -Run `nx serve agent` for a dev server. Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files. - -## Understand this workspace - -Run `nx graph` to see a diagram of the dependencies of the projects. - -## Remote caching - -Run `npx nx connect-to-nx-cloud` to enable [remote caching](https://nx.app) and make CI faster. - ## Further help Visit the [Nx Documentation](https://nx.dev) to learn more. diff --git a/apps/attestation-manager/src/app/app.controller.ts b/apps/attestation-manager/src/app/app.controller.ts index 3c778ceaf87f265b48165656ea5320f0ef4d7fb3..667407051f8d6570e9a874631f3122a79660b0a2 100644 --- a/apps/attestation-manager/src/app/app.controller.ts +++ b/apps/attestation-manager/src/app/app.controller.ts @@ -1,16 +1,14 @@ -import { Body, Controller, Get, Logger } from "@nestjs/common"; +import { Body, Controller, Logger } from "@nestjs/common"; -import { AppService } from "./app.service"; import { MessagePattern, RpcException } from "@nestjs/microservices"; import { CloudEventDto, - ConnectionEvent, CreateCredentialDefinitionRequsetDto, - CreateInvitationResponseDto, CreateSchemaRequestDto, CredentialEvent, - GetConnectionRequestDto, + GatewayAcceptedResponseDto, IssueCredentialRequestDto, + makeEvent, SchemaEvent, } from "@ocm-engine/dtos"; import { ProducerService } from "@ocm-engine/nats"; @@ -19,10 +17,7 @@ import { ProducerService } from "@ocm-engine/nats"; export class AppController { private readonly logger: Logger = new Logger(AppController.name); - constructor( - private readonly producerService: ProducerService, - private readonly appService: AppService, - ) {} + constructor(private readonly producerService: ProducerService) {} @MessagePattern("schemas") async create( @@ -36,14 +31,17 @@ export class AppController { this.logger.debug(JSON.stringify(payload, null, 2)); try { - const event = this.appService.toEvent(payload); + const event = makeEvent(payload); this.logger.debug(JSON.stringify(event, null, 2)); await this.producerService.publish<typeof payload.data>( payload.type, event as CloudEventDto<typeof payload.data>, ); - return { id: event.id }; + const response = new GatewayAcceptedResponseDto(); + response.id = event.id; + + return response; } catch (e) { this.logger.debug(JSON.stringify(e, null, 2)); if (e instanceof Error) { @@ -69,14 +67,17 @@ export class AppController { this.logger.debug(JSON.stringify(payload, null, 2)); try { - const event = this.appService.toEvent(payload); + const event = makeEvent(payload); this.logger.debug(JSON.stringify(event, null, 2)); await this.producerService.publish<typeof payload.data>( payload.type, event as CloudEventDto<typeof payload.data>, ); - return { id: event.id }; + const response = new GatewayAcceptedResponseDto(); + response.id = event.id; + + return response; } catch (e) { this.logger.debug(JSON.stringify(e, null, 2)); if (e instanceof Error) { diff --git a/apps/attestation-manager/src/app/app.module.ts b/apps/attestation-manager/src/app/app.module.ts index 5fbe1f9a3d38d356789cb2985914f5f1fe66386e..337144b3609b0e9ed5a489bb54a7c3b61f807688 100644 --- a/apps/attestation-manager/src/app/app.module.ts +++ b/apps/attestation-manager/src/app/app.module.ts @@ -1,7 +1,6 @@ import { Module } from "@nestjs/common"; import { AppController } from "./app.controller"; -import { AppService } from "./app.service"; import { ConfigModule } from "@nestjs/config"; import { amConfig, amSchema, natsConfig, natsSchema } from "@ocm-engine/config"; import { ProducerService } from "@ocm-engine/nats"; @@ -21,6 +20,6 @@ const validationSchema = Joi.object({ }), ], controllers: [AppController], - providers: [ProducerService, AppService], + providers: [ProducerService], }) export class AppModule {} diff --git a/apps/attestation-manager/src/app/app.service.ts b/apps/attestation-manager/src/app/app.service.ts deleted file mode 100644 index bb195327d59df12ccbb3cdb032316c8592f1da71..0000000000000000000000000000000000000000 --- a/apps/attestation-manager/src/app/app.service.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Injectable } from "@nestjs/common"; -import { - ALL_EVENTS, - CloudEventDto, - ConnectionUnsupportedTypeError, - CreateCredentialDefinitionRequsetDto, - CreateSchemaRequestDto, - CredentialEvent, - IssueCredentialRequestDto, - SchemaEvent, -} from "@ocm-engine/dtos"; - -@Injectable() -export class AppService { - toEvent = (payload: { - data: - | null - | CreateSchemaRequestDto - | CreateSchemaRequestDto - | CreateCredentialDefinitionRequsetDto - | IssueCredentialRequestDto; - type: SchemaEvent | CredentialEvent; - source: string; - }) => { - if (ALL_EVENTS.includes(payload.type)) { - throw new ConnectionUnsupportedTypeError(); - } - - const event = new CloudEventDto<typeof payload.data>(); - event.subject = payload.type; - event.source = payload.source; - event.type = payload.type; - event.data = payload.data; - - return event; - }; -} diff --git a/apps/attestation-manager/src/main.ts b/apps/attestation-manager/src/main.ts index b9c9619988ba69898f38e48f5d5b77b109bcf043..f2abf774009b2ad0cad82a22546cc6b527965dd1 100644 --- a/apps/attestation-manager/src/main.ts +++ b/apps/attestation-manager/src/main.ts @@ -31,7 +31,7 @@ async function bootstrap() { app.enableShutdownHooks(); - Logger.log("Application is running"); + Logger.log(`Application is running ${am.host}:${am.port} TCP`); } bootstrap(); diff --git a/apps/connection-manager/src/app/app.controller.ts b/apps/connection-manager/src/app/app.controller.ts index 5ae534df4ca00a903f41388bfdd326287754e861..8001d35a53d9570173cb7ea75b0d24fe399b421c 100644 --- a/apps/connection-manager/src/app/app.controller.ts +++ b/apps/connection-manager/src/app/app.controller.ts @@ -2,21 +2,20 @@ import { Body, Controller, Logger } from "@nestjs/common"; import { ProducerService } from "@ocm-engine/nats"; import { MessagePattern, RpcException } from "@nestjs/microservices"; -import { AppService } from "./app.service"; import { + CloudEventDto, ConnectionEvent, CreateInvitationResponseDto, + GatewayAcceptedResponseDto, GetConnectionRequestDto, + makeEvent, } from "@ocm-engine/dtos"; @Controller() export class AppController { private readonly logger: Logger = new Logger(AppController.name); - constructor( - private readonly producerService: ProducerService, - private readonly appService: AppService, - ) {} + constructor(private readonly producerService: ProducerService) {} @MessagePattern("connections") async create( @@ -30,14 +29,18 @@ export class AppController { this.logger.debug(JSON.stringify(payload, null, 2)); try { - const event = this.appService.toEvent(payload); + const event = makeEvent(payload); this.logger.debug(JSON.stringify(event, null, 2)); + await this.producerService.publish<typeof payload.data>( payload.type, - event, + event as CloudEventDto<typeof payload.data>, ); - return { id: event.id }; + const response = new GatewayAcceptedResponseDto(); + response.id = event.id; + + return response; } catch (e) { this.logger.debug(JSON.stringify(e, null, 2)); if (e instanceof Error) { diff --git a/apps/connection-manager/src/app/app.module.ts b/apps/connection-manager/src/app/app.module.ts index 0dcb44fbf478df8ec6a6c56d11f17bb180d38e15..5370512cf996efd2ca3d54f0d8a01b2c370b5b33 100644 --- a/apps/connection-manager/src/app/app.module.ts +++ b/apps/connection-manager/src/app/app.module.ts @@ -5,7 +5,6 @@ import { ProducerService } from "@ocm-engine/nats"; import { ConfigModule } from "@nestjs/config"; import { cmConfig, cmSchema, natsConfig, natsSchema } from "@ocm-engine/config"; import Joi from "joi"; -import { AppService } from "./app.service"; const validationSchema = Joi.object({ nats: natsSchema, @@ -21,6 +20,6 @@ const validationSchema = Joi.object({ }), ], controllers: [AppController], - providers: [ProducerService, AppService], + providers: [ProducerService], }) export class AppModule {} diff --git a/apps/connection-manager/src/app/app.service.ts b/apps/connection-manager/src/app/app.service.ts deleted file mode 100644 index d649854d330228a5f82be7c449c3e869a9cf16e7..0000000000000000000000000000000000000000 --- a/apps/connection-manager/src/app/app.service.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable } from "@nestjs/common"; -import { - CloudEventDto, - CONNECTION_EVENTS, - ConnectionEvent, - ConnectionUnsupportedTypeError, - CreateInvitationResponseDto, - GetConnectionRequestDto, -} from "@ocm-engine/dtos"; - -@Injectable() -export class AppService { - toEvent = (payload: { - data: null | CreateInvitationResponseDto | GetConnectionRequestDto; - type: ConnectionEvent; - source: string; - }) => { - if (!CONNECTION_EVENTS.includes(payload.type)) { - throw new ConnectionUnsupportedTypeError(); - } - - const event = new CloudEventDto<typeof payload.data>(); - event.subject = payload.type; - event.source = payload.source; - event.type = payload.type; - event.data = payload.data; - - return event; - }; -} diff --git a/apps/gateway/src/app/app.module.ts b/apps/gateway/src/app/app.module.ts index cc91a8cec459825dd035e10bb6d2821339aa9e47..5591b06dad1340a25fe613855cc22e83b289b599 100644 --- a/apps/gateway/src/app/app.module.ts +++ b/apps/gateway/src/app/app.module.ts @@ -10,35 +10,46 @@ import { cmSchema, gatewayConfig, gatewaySchema, + pmConfig, + pmSchema, } from "@ocm-engine/config"; import { AttestationManagerClient, ConnectionManagerClient, + ProofManagerClient, } from "@ocm-engine/clients"; import Joi from "joi"; import { ConnectionController } from "./managers/connection.controller"; import { APP_PIPE } from "@nestjs/core"; import { AttestationController } from "./managers/attestation.controller"; +import { ProofController } from "./managers/proof.controller"; const validationSchema = Joi.object({ gateway: gatewaySchema, cm: cmSchema, am: amSchema, + pm: pmSchema, }); @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, - load: [gatewayConfig, cmConfig, amConfig], + load: [gatewayConfig, cmConfig, amConfig, pmConfig], validationSchema, }), ], - controllers: [AppController, ConnectionController, AttestationController], + controllers: [ + AppController, + ConnectionController, + AttestationController, + ProofController, + ], providers: [ EventsGateway, ConnectionManagerClient, AttestationManagerClient, + ProofManagerClient, { provide: APP_PIPE, useValue: new ValidationPipe({ diff --git a/apps/gateway/src/app/managers/attestation.controller.ts b/apps/gateway/src/app/managers/attestation.controller.ts index f4f4d47b36a47d1db5ec9fface825d82157020c0..c1e290fb6dc510e1d635beebe54970485f2062cc 100644 --- a/apps/gateway/src/app/managers/attestation.controller.ts +++ b/apps/gateway/src/app/managers/attestation.controller.ts @@ -11,7 +11,6 @@ import { AllExceptionsHandler } from "../exception.handler"; import { AttestationManagerClient } from "@ocm-engine/clients"; import { AcceptCredentialOfferRequestDto, - CONNECTION_ACCEPT, CreateCredentialDefinitionRequsetDto, CreateSchemaRequestDto, CRED_DEF_CREATE, @@ -140,7 +139,7 @@ export class AttestationController { }); } - @Post("credential/definition") + @Post("credentials/definition") @ApiResponse({ status: 201, description: @@ -176,7 +175,7 @@ export class AttestationController { }); } - @Post("credential/issue") + @Post("credentials/issue") @ApiResponse({ status: 201, description: @@ -194,9 +193,9 @@ export class AttestationController { description: "Unknown error", }) @ApiOperation({ - summary: "Issue credential definition", + summary: "Issue credential", description: - "Method issue credential definition. The id of the response will be matched when you receive event from the websocket", + "Method issue credential, it will create an offer and send it to specified receiver (connectionId). The id of the response will be matched when you receive event from the websocket", tags: ["Credentials"], }) issueCredential(@Body() issueCredentialDto: IssueCredentialRequestDto) { @@ -244,7 +243,7 @@ export class AttestationController { }); } - @Get("/credential/offers") + @Get("/credentials/offers") @ApiResponse({ status: 200, description: @@ -262,10 +261,10 @@ export class AttestationController { description: "Unknown error", }) @ApiOperation({ - summary: "List all credential offers", + summary: "List unaccepted credential offers", description: - "Method list offers that are sent, but not accepted. The id of the response will be matched when you receive event from the websocket", - tags: ["Credentials"], + "Method list offers that are received, but not accepted. The id of the response will be matched when you receive event from the websocket", + tags: ["Credentials Offers"], }) getCredentialOffers() { return this.amClient.sendPayload({ @@ -278,7 +277,7 @@ export class AttestationController { }); } - @Post("/credential/offers/:credential_record_id/accept") + @Post("/credentials/offers/:credential_record_id/accept") @ApiResponse({ status: 200, description: @@ -299,7 +298,7 @@ export class AttestationController { summary: "Accept credential offers", description: "Method list accept credential offer. The id of the response will be matched when you receive event from the websocket", - tags: ["Credentials"], + tags: ["Credentials Offers"], }) acceptCredential(@Param("credential_record_id") credentialRecordId: string) { const data = new AcceptCredentialOfferRequestDto(); diff --git a/apps/gateway/src/app/managers/connection.controller.ts b/apps/gateway/src/app/managers/connection.controller.ts index 52c86c6940baa9896c050e026b81306b68733349..6fd64d9afea73b55ee887ab25da785ec6dfca2ad 100644 --- a/apps/gateway/src/app/managers/connection.controller.ts +++ b/apps/gateway/src/app/managers/connection.controller.ts @@ -1,10 +1,10 @@ import { - Controller, + BadRequestException, Body, - Post, + Controller, Get, Param, - BadRequestException, + Post, UseFilters, } from "@nestjs/common"; import { ConnectionManagerClient } from "@ocm-engine/clients"; @@ -20,11 +20,9 @@ import { import { AllExceptionsHandler } from "../exception.handler"; import { ApiBadRequestResponse, - ApiBody, ApiInternalServerErrorResponse, ApiOperation, ApiResponse, - ApiTags, } from "@nestjs/swagger"; @UseFilters(AllExceptionsHandler) @@ -32,7 +30,7 @@ import { export class ConnectionController { constructor(private readonly cmClient: ConnectionManagerClient) {} - @Post("/invitation") + @Post("/invitations") @ApiResponse({ status: 201, description: @@ -66,7 +64,7 @@ export class ConnectionController { }); } - @Post("/invitation/accept") + @Post("/invitations/accept") @ApiResponse({ status: 201, description: diff --git a/apps/gateway/src/app/managers/proof.controller.ts b/apps/gateway/src/app/managers/proof.controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..cc7f4e02f361f7e616f0ba5ba48661310509e155 --- /dev/null +++ b/apps/gateway/src/app/managers/proof.controller.ts @@ -0,0 +1,137 @@ +import { + BadRequestException, + Body, + Controller, + Get, + Param, + Post, + UseFilters, +} from "@nestjs/common"; +import { + AcceptProofRequestDto, + GatewayAcceptedResponseDto, + GetSchemaRequestDto, + IssueProofRequestDto, + PROOF_ACCEPT, + PROOF_ISSUE, + PROOF_LIST, +} from "@ocm-engine/dtos"; +import { AllExceptionsHandler } from "../exception.handler"; +import { ProofManagerClient } from "@ocm-engine/clients"; +import { + ApiBadRequestResponse, + ApiInternalServerErrorResponse, + ApiOperation, + ApiResponse, +} from "@nestjs/swagger"; + +@UseFilters(AllExceptionsHandler) +@Controller("v1") +export class ProofController { + constructor(private readonly pmClient: ProofManagerClient) {} + + @Get("/credentials/proof") + @ApiResponse({ + status: 200, + description: + "Request is accepted for execution, the response id will match the event id received from the web socket", + type: GatewayAcceptedResponseDto, + }) + @ApiBadRequestResponse({ + status: 400, + description: + "Error in sending data to proof manager. This error shows that proof manager could not convert request to event or proof manager could not send the event to the broker.", + type: BadRequestException, + }) + @ApiInternalServerErrorResponse({ + status: 500, + description: "Unknown error", + }) + @ApiOperation({ + summary: "List received unaccepted proofs", + description: + "Method list all received unaccepted proofs. Status - request-receive. The id of the response will be matched when you receive event from the websocket", + tags: ["Credentials Proof"], + }) + proofs() { + return this.pmClient.sendPayload<GetSchemaRequestDto>({ + pattern: "proofs", + payload: { + source: "/credential/proofs", + data: null, + type: PROOF_LIST, + }, + }); + } + + @Post("/credentials/proof/issue") + @ApiResponse({ + status: 201, + description: + "Request is accepted for execution, the response id will match the event id received from the web socket", + type: GatewayAcceptedResponseDto, + }) + @ApiBadRequestResponse({ + status: 400, + description: + "Error in sending data to proof manager. This error shows that proof manager could not convert request to event or proof manager could not send the event to the broker.", + type: BadRequestException, + }) + @ApiInternalServerErrorResponse({ + status: 500, + description: "Unknown error", + }) + @ApiOperation({ + summary: "Issue proof for credential", + description: + "Method will issue proof. If connection id is not passed, the proof will be OOB. The id of the response will be matched when you receive event from the websocket", + tags: ["Credentials Proof"], + }) + issueProof(@Body() issueProofDto: IssueProofRequestDto) { + return this.pmClient.sendPayload<IssueProofRequestDto>({ + pattern: "proofs", + payload: { + source: "/credentials/proof/issue", + data: issueProofDto, + type: PROOF_ISSUE, + }, + }); + } + + @Post(`/credentials/proof/:proof_record_id/accept`) + @ApiResponse({ + status: 201, + description: + "Request is accepted for execution, the response id will match the event id received from the web socket", + type: GatewayAcceptedResponseDto, + }) + @ApiBadRequestResponse({ + status: 400, + description: + "Error in sending data to proof manager. This error shows that proof manager could not convert request to event or proof manager could not send the event to the broker.", + type: BadRequestException, + }) + @ApiInternalServerErrorResponse({ + status: 500, + description: "Unknown error", + }) + @ApiOperation({ + summary: "Accept credential proof", + description: + "Method accept credential proof. The id of the response will be matched when you receive event from the websocket", + tags: ["Credentials Proof"], + }) + acceptProof(@Param("proof_record_id") proofRecordId: string) { + const data = new AcceptProofRequestDto(); + data.proofRecordId = proofRecordId; + + return this.pmClient.sendPayload<AcceptProofRequestDto>({ + pattern: "proofs", + payload: { + source: "/credentials/proofs/:id/accept", + data, + type: PROOF_ACCEPT, + }, + }); + } +} diff --git a/apps/proof-manager/.eslintrc.json b/apps/proof-manager/.eslintrc.json new file mode 100644 index 0000000000000000000000000000000000000000..9d9c0db55bb1e91c5f2e7b64a02bc6bf69fc7cb5 --- /dev/null +++ b/apps/proof-manager/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/apps/proof-manager/deployment/Dockerfile b/apps/proof-manager/deployment/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..8c740efc99871407d03be48922d4a533808f51ce --- /dev/null +++ b/apps/proof-manager/deployment/Dockerfile @@ -0,0 +1,15 @@ +FROM node:18.16.0-buster-slim + +RUN apt update -y && apt install python3 git make build-essential -y + +WORKDIR app + +COPY ./dist/apps/proof-manager . +COPY package.json yarn.lock ./ + +RUN yarn install + + +EXPOSE 8882 + +CMD ["node", "main.js"] diff --git a/apps/proof-manager/jest.config.ts b/apps/proof-manager/jest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..946e79d227e86c9c81908c6977f4c55cdc43a213 --- /dev/null +++ b/apps/proof-manager/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: "proof-manager", + preset: "../../jest.preset.js", + testEnvironment: "node", + transform: { + "^.+\\.[tj]s$": ["ts-jest", { tsconfig: "<rootDir>/tsconfig.spec.json" }], + }, + moduleFileExtensions: ["ts", "js", "html"], + coverageDirectory: "../../coverage/apps/proof-manager", +}; diff --git a/apps/proof-manager/project.json b/apps/proof-manager/project.json new file mode 100644 index 0000000000000000000000000000000000000000..18af77b9b98812800594f1d6e5c4aec8885a777a --- /dev/null +++ b/apps/proof-manager/project.json @@ -0,0 +1,63 @@ +{ + "name": "proof-manager", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/proof-manager/src", + "projectType": "application", + "targets": { + "build": { + "executor": "@nx/webpack:webpack", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "target": "node", + "compiler": "tsc", + "outputPath": "dist/apps/proof-manager", + "main": "apps/proof-manager/src/main.ts", + "tsConfig": "apps/proof-manager/tsconfig.app.json", + "isolatedConfig": true, + "webpackConfig": "apps/proof-manager/webpack.config.js" + }, + "configurations": { + "development": {}, + "production": {} + } + }, + "serve": { + "executor": "@nx/js:node", + "defaultConfiguration": "development", + "options": { + "buildTarget": "proof-manager:build" + }, + "configurations": { + "development": { + "buildTarget": "proof-manager:build:development" + }, + "production": { + "buildTarget": "proof-manager:build:production" + } + } + }, + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["apps/proof-manager/**/*.ts"] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "apps/proof-manager/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + }, + "tags": [] +} diff --git a/apps/proof-manager/src/app/app.controller.ts b/apps/proof-manager/src/app/app.controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..b7e41ea0dda88da0b3225d4bdacb1ba6b9af0f2c --- /dev/null +++ b/apps/proof-manager/src/app/app.controller.ts @@ -0,0 +1,51 @@ +import { Body, Controller, Logger } from "@nestjs/common"; + +import { ProducerService } from "@ocm-engine/nats"; +import { MessagePattern, RpcException } from "@nestjs/microservices"; +import { + CloudEventDto, + GatewayAcceptedResponseDto, + makeEvent, + ProofEvent, +} from "@ocm-engine/dtos"; + +@Controller() +export class AppController { + private readonly logger: Logger = new Logger(AppController.name); + + constructor(private readonly producerService: ProducerService) {} + + @MessagePattern("proofs") + async create( + @Body() + payload: { + data: null; + type: ProofEvent; + source: string; + }, + ): Promise<GatewayAcceptedResponseDto> { + this.logger.debug(JSON.stringify(payload, null, 2)); + + try { + const event = makeEvent(payload); + this.logger.debug(JSON.stringify(event, null, 2)); + + await this.producerService.publish<typeof payload.data>( + payload.type, + event as CloudEventDto<typeof payload.data>, + ); + + const response = new GatewayAcceptedResponseDto(); + response.id = event.id; + + return response; + } catch (e) { + this.logger.debug(JSON.stringify(e, null, 2)); + if (e instanceof Error) { + throw new RpcException(e.message); + } + + throw new RpcException("Internal server error"); + } + } +} diff --git a/apps/proof-manager/src/app/app.module.ts b/apps/proof-manager/src/app/app.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..b3d4f05d6caa93f5ef53e0d1ad2d60583f7908f9 --- /dev/null +++ b/apps/proof-manager/src/app/app.module.ts @@ -0,0 +1,25 @@ +import { Module } from "@nestjs/common"; + +import { AppController } from "./app.controller"; +import Joi from "joi"; +import { natsConfig, natsSchema, pmConfig, pmSchema } from "@ocm-engine/config"; +import { ConfigModule } from "@nestjs/config"; +import { ProducerService } from "@ocm-engine/nats"; + +const validationSchema = Joi.object({ + nats: natsSchema, + pm: pmSchema, +}); + +@Module({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + load: [natsConfig, pmConfig], + validationSchema, + }), + ], + controllers: [AppController], + providers: [ProducerService], +}) +export class AppModule {} diff --git a/apps/proof-manager/src/main.ts b/apps/proof-manager/src/main.ts new file mode 100644 index 0000000000000000000000000000000000000000..c963b20348b863becc1d96abf65b0dd0b7f15300 --- /dev/null +++ b/apps/proof-manager/src/main.ts @@ -0,0 +1,37 @@ +/** + * This is not a production server yet! + * This is only a minimal backend to get started. + */ + +import { Logger } from "@nestjs/common"; +import { NestFactory } from "@nestjs/core"; + +import { AppModule } from "./app/app.module"; +import { ConfigService } from "@nestjs/config"; +import { MicroserviceOptions, Transport } from "@nestjs/microservices"; +import { IProofManagerConfig } from "@ocm-engine/config"; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + + const configService = app.get(ConfigService); + const pm = configService.get<IProofManagerConfig>("pm")!; + + app.enableShutdownHooks(); + + const microservice = app.connectMicroservice<MicroserviceOptions>({ + transport: Transport.TCP, + options: { + host: pm.host, + port: pm.port, + }, + }); + + await app.startAllMicroservices(); + + app.enableShutdownHooks(); + + Logger.log(`Application is running ${pm.host}:${pm.port}`); +} + +bootstrap(); diff --git a/apps/proof-manager/tsconfig.app.json b/apps/proof-manager/tsconfig.app.json new file mode 100644 index 0000000000000000000000000000000000000000..954f3ad1c11170724606b4b020297567c518a86b --- /dev/null +++ b/apps/proof-manager/tsconfig.app.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["node"], + "emitDecoratorMetadata": true, + "target": "es2015" + }, + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/apps/proof-manager/tsconfig.json b/apps/proof-manager/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..c1e2dd4e8be6f4fe3dca35d044fd912ff41b1c18 --- /dev/null +++ b/apps/proof-manager/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "compilerOptions": { + "esModuleInterop": true + } +} diff --git a/apps/proof-manager/tsconfig.spec.json b/apps/proof-manager/tsconfig.spec.json new file mode 100644 index 0000000000000000000000000000000000000000..9b2a121d114b68dcdb5b834ebca032814b499a74 --- /dev/null +++ b/apps/proof-manager/tsconfig.spec.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/apps/proof-manager/webpack.config.js b/apps/proof-manager/webpack.config.js new file mode 100644 index 0000000000000000000000000000000000000000..0ab513e830c33d6687ae9e14f62f69df7c0df36b --- /dev/null +++ b/apps/proof-manager/webpack.config.js @@ -0,0 +1,8 @@ +const { composePlugins, withNx } = require("@nx/webpack"); + +// Nx plugins for webpack. +module.exports = composePlugins(withNx(), (config) => { + // Update the webpack config as needed here. + // e.g. `config.plugins.push(new MyPlugin())` + return config; +}); diff --git a/compose/docker-compose.infra.yml b/compose/docker-compose.infra.yml new file mode 100644 index 0000000000000000000000000000000000000000..dcc23f575f2088184ebdc566b7c027b15c03afcd --- /dev/null +++ b/compose/docker-compose.infra.yml @@ -0,0 +1,23 @@ +version: '3.8' + +services: + pg_db: + image: 'postgres:latest' + ports: + - '5432:5432' + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + volumes: + - ./data/db/:/var/lib/postgresql/data/ + + broker: + command: ["-js", "-sd", "/data", "-m","8222", "-D"] + container_name: broker + image: 'nats:latest' + ports: + - '4222:4222' #Nats server port + - '8222:8222' #Nats server Monitering port + volumes: + - ./data/nats/:/data/ + diff --git a/compose/docker-compose.yml b/compose/docker-compose.yml index 2a0c5fb5ac8a488ffac5bb6ce7a9b9a4777c8def..abf7679292621ae38c6de4292f6a5ddbcc710b92 100644 --- a/compose/docker-compose.yml +++ b/compose/docker-compose.yml @@ -1,37 +1,52 @@ version: '3.8' services: + + #===================== ISSUER =========================# + agent-issuer: + labels: + - "traefik.http.routers.agent-issuer.rule=Host(`agent-issuer.local`)" + - "traefik.http.routers.agent-issuer.entrypoints=web" + profiles: + - issuer container_name: agent-issuer build: context: "../" dockerfile: "./apps/agent/deployment/Dockerfile" env_file: - ./env/issuer.env - ports: - - "8080:8080" - - "8001:8001" +# ports: +# - "8080:8080" +# - "8001:8001" depends_on: pg_db: condition: service_started - broker: + broker-issuer: condition: service_started gateway-issuer: + labels: + - "traefik.http.routers.gateway-issuer.rule=Host(`gateway-issuer.local`)" + - "traefik.http.routers.gateway-issuer.entrypoints=web" + profiles: + - issuer container_name: gateway-issuer build: context: "../" dockerfile: "./apps/gateway/deployment/Dockerfile" env_file: - ./env/issuer.env - ports: - - "8081:8081" - - "8881:8881" +# ports: +# - "8081:8081" +# - "8881:8881" depends_on: cm-issuer: condition: service_started cm-issuer: + profiles: + - issuer container_name: cm-issuer build: context: "../" @@ -41,10 +56,12 @@ services: ports: - "8882" depends_on: - broker: + broker-issuer: condition: service_started am-issuer: + profiles: + - issuer container_name: am-issuer build: context: "../" @@ -54,10 +71,114 @@ services: ports: - "8883" depends_on: - broker: + broker-issuer: + condition: service_started + + pm-issuer: + profiles: + - issuer + container_name: pm-issuer + build: + context: "../" + dockerfile: "./apps/proof-manager/deployment/Dockerfile" + env_file: + - ./env/issuer.env + ports: + - "8884" + depends_on: + broker-issuer: + condition: service_started + +#===================== holder =========================# + + agent-holder: + labels: + - "traefik.http.routers.agent-issuer.rule=Host(`agent-holder.local`)" + - "traefik.http.routers.agent-issuer.entrypoints=web" + profiles: + - holder + container_name: agent-holder + build: + context: "../" + dockerfile: "./apps/agent/deployment/Dockerfile" + env_file: + - ./env/holder.env +# ports: +# - "8080:8080" +# - "8001:8001" + depends_on: + pg_db: + condition: service_started + broker-holder: + condition: service_started + + gateway-holder: + labels: + - "traefik.http.routers.gateway-issuer.rule=Host(`gateway-holder.local`)" + - "traefik.http.routers.gateway-issuer.entrypoints=web" + profiles: + - holder + container_name: gateway-holder + build: + context: "../" + dockerfile: "./apps/gateway/deployment/Dockerfile" + env_file: + - ./env/holder.env +# ports: +# - "8081:8081" +# - "8881:8881" + depends_on: + cm-holder: + condition: service_started + + cm-holder: + profiles: + - holder + container_name: cm-holder + build: + context: "../" + dockerfile: "./apps/connection-manager/deployment/Dockerfile" + env_file: + - ./env/holder.env + ports: + - "8882" + depends_on: + broker-holder: + condition: service_started + + am-holder: + profiles: + - holder + container_name: am-holder + build: + context: "../" + dockerfile: "./apps/attestation-manager/deployment/Dockerfile" + env_file: + - ./env/holder.env + ports: + - "8883" + depends_on: + broker-holder: + condition: service_started + + pm-holder: + profiles: + - holder + container_name: pm-holder + build: + context: "../" + dockerfile: "./apps/proof-manager/deployment/Dockerfile" + env_file: + - ./env/holder.env + ports: + - "8884" + depends_on: + broker-holder: condition: service_started + #===================== INFRA =========================# + pg_db: image: 'postgres:latest' ports: @@ -68,12 +189,41 @@ services: volumes: - ./data/db/:/var/lib/postgresql/data/ - broker: + broker-issuer: + profiles: + - issuer command: ["-js", "-sd", "/data", "-m","8222", "-D"] - container_name: broker + container_name: broker-issuer image: 'nats:latest' ports: - - '4222:4222' #Nats server port + - '4222' #Nats server port - '8222:8222' #Nats server Monitering port volumes: - - ./data/nats/:/data/ + - ./data/issuer/nats/:/data/ + + + broker-holder: + profiles: + - holder + command: ["-js", "-sd", "/data", "-m","8222", "-D"] + container_name: broker-holder + image: 'nats:latest' + ports: + - '4222' #Nats server port + - '8223:8222' #Nats server Monitering port + volumes: + - ./data/holder/nats/:/data/ + + reverse-proxy: + image: traefik:v2.10.1 + command: + - "--api.insecure=true" + - "--providers.docker=true" + - "--entrypoints.web.address=:80" + - "--entrypoints.webextra.address=:8001" + ports: + - "80:80" + - "8001:8001" + - "8080:8080" + volumes: + - ./data/var/run/docker.sock:/var/run/docker.sock diff --git a/compose/env/holder.env b/compose/env/holder.env index fc16d0a33eccd568942e1f6f0876f0b228a025f5..b5be92bcc0e72363f3a9b9102873ebc8b1dd63e8 100644 --- a/compose/env/holder.env +++ b/compose/env/holder.env @@ -1,12 +1,34 @@ -AGENT_PEER_URL="http://holder:6000" -AGENT_NAME=HOLDER_LOCAL -AGENT_KEY=HwNJroKHTSSJ3XvE7ZAnuKiTn2C4QkFvxEqfm5rzhNrh -AGENT_DID_SEED=900000000000000000000000TCUste21 - LEDGERS="BCOVRIN_TEST" -IDUNION_KEY="a" +IDUNION_KEY= +AGENT_PEER_URL="http://agent-holder:8001" +AGENT_NAME=DEV_AGENT_HOLDER_OCM # this should be changed to company name +AGENT_KEY=HwNJroKHTSSj3XvE7ZAnuKiTn2C4QkFvxEqfm5rzhNrh #example random string +AGENT_DID_SEED=200000000000000000000000TCuste21 #did private key seed min lenght 32 AGENT_DB_HOST=pg_db:5432 AGENT_DB_USER=postgres AGENT_DB_PASS=postgres -PORT=5001 +AGENT_PORT=8081 +AGENT_CONSUMER_NAME=agent_1 +AGENT_IS_REST=false +AGENT_MAX_MESSAGES=10 +AGENT_RETE_LIMIT=5 + +NATS_SERVERS=broker-holder:4222 +NATS_STREAM_NAME=ssi_holder_stream +NATS_SUBJECTS="connections.*,proofs.*,credentials.*,schemas.*" + +GATEWAY_HTTP_PORT=8081 +GATEWAY_TCP_PORT=8881 +GATEWAY_SOCKET_EVENT_NAME=message +GATEWAY_MESSAGE_PATTERN=webhook +GATEWAY_HOST=gateway-holder + +CONNECTION_SERVICE_TCP_PORT=8882 +CONNECTION_SERVICE_HOST=cm-holder + +ATTESTATION_SERVICE_TCP_PORT=8883 +ATTESTATION_SERVICE_HOST=ap-holder + +PROOF_SERVICE_TCP_PORT=8884 +PROOF_SERVICE_HOST=pm-holder diff --git a/compose/env/issuer.env b/compose/env/issuer.env index aa7308f2eb4a20dcd44f71819f828b9083907c69..9fb7f25f5fc4d7d4dbd5da2728b1468333f2848a 100644 --- a/compose/env/issuer.env +++ b/compose/env/issuer.env @@ -1,10 +1,10 @@ LEDGERS="BCOVRIN_TEST" IDUNION_KEY= -AGENT_PEER_URL="http://0.0.0.0:8001" -AGENT_NAME=DExcVasd_AGENT_45 -AGENT_KEY=HwNJroKHTSSj3XvE7ZAnuKiTn2C4QkFvxEqfm5rzhNrh -AGENT_DID_SEED=200000000000000000000000TCuste21 +AGENT_PEER_URL="http://agent-issuer:8001" +AGENT_NAME=DEV_AGENT_ISSUER_OCM # this should be changed to company name +AGENT_KEY=HwNJroKHTSSj3XvE7ZAnuKiTn2C4QkFvxEqfm5rzhNrh #example random string +AGENT_DID_SEED=200000000000000000000000TCuste21 #did private key seed min lenght 32 AGENT_DB_HOST=pg_db:5432 AGENT_DB_USER=postgres AGENT_DB_PASS=postgres @@ -14,8 +14,8 @@ AGENT_IS_REST=false AGENT_MAX_MESSAGES=10 AGENT_RETE_LIMIT=5 -NATS_SERVERS=broker:4222 -NATS_STREAM_NAME=ssi_12 +NATS_SERVERS=broker-issuer:4222 +NATS_STREAM_NAME=ssi_issuer_stream NATS_SUBJECTS="connections.*,proofs.*,credentials.*,schemas.*" GATEWAY_HTTP_PORT=8081 @@ -27,5 +27,8 @@ GATEWAY_HOST=gateway-issuer CONNECTION_SERVICE_TCP_PORT=8882 CONNECTION_SERVICE_HOST=cm-issuer -CONNECTION_SERVICE_TCP_PORT=8883 -CONNECTION_SERVICE_HOST=am-issuer +ATTESTATION_SERVICE_TCP_PORT=8883 +ATTESTATION_SERVICE_HOST=ap-issuer + +PROOF_SERVICE_TCP_PORT=8884 +PROOF_SERVICE_HOST=pm-issuer diff --git a/gateway-swagger.json b/gateway-swagger.json index 7abc420082b25e60f8ce051ad2a4245f400c9f58..2c80f9140e94b31c739be461eb9efbe49a070d93 100644 --- a/gateway-swagger.json +++ b/gateway-swagger.json @@ -1 +1 @@ -{"openapi":"3.0.0","paths":{"/api/v1/invitation":{"post":{"operationId":"ConnectionController_createInvitation","summary":"Create invitation for connection","description":"Method will create invitation url. The id of the response will be matched when you receive event from the websocket","tags":["Connections"],"parameters":[],"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that connection manager could not convert request to event or connection manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/invitation/accept":{"post":{"operationId":"ConnectionController_acceptInvitation","summary":"Accept invitation for connection","description":"Method will accept the invitation and will return connection thought the websocket. The id of the response will be matched when you receive event from the websocket","tags":["Connections"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInvitationResponseDto"}}}},"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that connection manager could not convert request to event or connection manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/connections":{"get":{"operationId":"ConnectionController_list","summary":"List all connections","description":"The id of the response will be matched when you receive event from the websocket","tags":["Connections"],"parameters":[],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that connection manager could not convert request to event or connection manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/connections/{id}":{"get":{"operationId":"ConnectionController_getById","summary":"Get connection by id","description":"The method will search for connection id, if not found null will be returned. The id of the response will be matched when you receive event from the websocket","tags":["Connections"],"parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that connection manager could not convert request to event or connection manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/schemas":{"post":{"operationId":"AttestationController_createSchema","summary":"Create schema","description":"Method will create schema. The id of the response will be matched when you receive event from the websocket","tags":["Schema"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSchemaRequestDto"}}}},"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}},"get":{"operationId":"AttestationController_listSchema","summary":"List all schemas","description":"Method will fetch all schemas. The id of the response will be matched when you receive event from the websocket","tags":["Schema"],"parameters":[],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/schemas-by-id":{"post":{"operationId":"AttestationController_getSchemaById","summary":"Get schema by id","description":"Method will fetch specific schema or return null. The id of the response will be matched when you receive event from the websocket","tags":["Schema"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSchemaRequestDto"}}}},"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credential/definition":{"post":{"operationId":"AttestationController_createCredentialDefinition","summary":"Create credential definition","description":"Method create credential definition. The id of the response will be matched when you receive event from the websocket","tags":["Credentials"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCredentialDefinitionRequsetDto"}}}},"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credential/issue":{"post":{"operationId":"AttestationController_issueCredential","summary":"Issue credential definition","description":"Method issue credential definition. The id of the response will be matched when you receive event from the websocket","tags":["Credentials"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueCredentialRequestDto"}}}},"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credentials":{"get":{"operationId":"AttestationController_credentials","summary":"List all credential","description":"Method list credential definition no filters applied. The id of the response will be matched when you receive event from the websocket","tags":["Credentials"],"parameters":[],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credential/offers":{"get":{"operationId":"AttestationController_getCredentialOffers","summary":"List all credential offers","description":"Method list offers that are sent, but not accepted. The id of the response will be matched when you receive event from the websocket","tags":["Credentials"],"parameters":[],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credential/offers/{credential_record_id}/accept":{"post":{"operationId":"AttestationController_acceptCredential","summary":"Accept credential offers","description":"Method list accept credential offer. The id of the response will be matched when you receive event from the websocket","tags":["Credentials"],"parameters":[{"name":"credential_record_id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"201":{"description":""},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}}},"info":{"title":"Gateway","description":"OCM ENGINE GATEWAY API","version":"1.0","contact":{}},"tags":[],"servers":[{"url":"http://0.0.0.0:8081"}],"components":{"schemas":{"CloudEventDto":{"type":"object","properties":{}},"GatewayAcceptedResponseDto":{"type":"object","properties":{"id":{"type":"string","example":"80633e6d-c606-4539-a3df-287fedd09253"}},"required":["id"]},"BadRequestException":{"type":"object","properties":{}},"CreateInvitationResponseDto":{"type":"object","properties":{"invitationUrl":{"type":"string","description":"A list of user's roles","example":"http://0.0.0.0:8001?oob=eyJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvb3V0LW9mLWJhbmQvMS4xL2ludml0YXRpb24iLCJAaWQiOiIzYWExNGIzNC04YTk5LTQxY2UtYTY3NC1jODUxYmVhMTIxMWEiLCJsYWJlbCI6IkRFeGNWYXNkX0FHRU5UXzQ1IiwiYWNjZXB0IjpbImRpZGNvbW0vYWlwMSIsImRpZGNvbW0vYWlwMjtlbnY9cmZjMTkiXSwiaGFuZHNoYWtlX3Byb3RvY29scyI6WyJodHRwczovL2RpZGNvbW0ub3JnL2RpZGV4Y2hhbmdlLzEuMCIsImh0dHBzOi8vZGlkY29tbS5vcmcvY29ubmVjdGlvbnMvMS4wIl0sInNlcnZpY2VzIjpbeyJpZCI6IiNpbmxpbmUtMCIsInNlcnZpY2VFbmRwb2ludCI6Imh0dHA6Ly8wLjAuMC4wOjgwMDEiLCJ0eXBlIjoiZGlkLWNvbW11bmljYXRpb24iLCJyZWNpcGllbnRLZXlzIjpbImRpZDprZXk6ejZNa3VFcHllc1pNa3k0a1BpQzhEOEplZERlcm55YTFuaTREMUF3ZmdnWWt6YmR4Il0sInJvdXRpbmdLZXlzIjpbXX1dfQ"}},"required":["invitationUrl"]},"CreateSchemaRequestDto":{"type":"object","properties":{"name":{"type":"string","example":"my test schema"},"attributes":{"example":["first_name, last_name"],"type":"array","items":{"type":"string"}},"version":{"type":"string","example":"1.0.2","pattern":"/^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$/"}},"required":["name","attributes","version"]},"GetSchemaRequestDto":{"type":"object","properties":{"schemaId":{"type":"string","example":"did:indy:LEDNGER:SXM76gQwRnjkgoz2oBnGjd/anoncreds/v0/SCHEMA/test schema/1.0.2"}},"required":["schemaId"]},"CreateCredentialDefinitionRequsetDto":{"type":"object","properties":{"schemaId":{"type":"string"},"tag":{"type":"string"}},"required":["schemaId","tag"]},"IssueCredentialAttributes":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"}},"required":["name","value"]},"IssueCredentialRequestDto":{"type":"object","properties":{"connectionId":{"type":"string"},"credentialDefinitionId":{"type":"string"},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/IssueCredentialAttributes"}}},"required":["connectionId","credentialDefinitionId","attributes"]}}}} \ No newline at end of file +{"openapi":"3.0.0","paths":{"/api/v1/invitations":{"post":{"operationId":"ConnectionController_createInvitation","summary":"Create invitation for connection","description":"Method will create invitation url. The id of the response will be matched when you receive event from the websocket","tags":["Connections"],"parameters":[],"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that connection manager could not convert request to event or connection manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/invitations/accept":{"post":{"operationId":"ConnectionController_acceptInvitation","summary":"Accept invitation for connection","description":"Method will accept the invitation and will return connection thought the websocket. The id of the response will be matched when you receive event from the websocket","tags":["Connections"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInvitationResponseDto"}}}},"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that connection manager could not convert request to event or connection manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/connections":{"get":{"operationId":"ConnectionController_list","summary":"List all connections","description":"The id of the response will be matched when you receive event from the websocket","tags":["Connections"],"parameters":[],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that connection manager could not convert request to event or connection manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/connections/{id}":{"get":{"operationId":"ConnectionController_getById","summary":"Get connection by id","description":"The method will search for connection id, if not found null will be returned. The id of the response will be matched when you receive event from the websocket","tags":["Connections"],"parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that connection manager could not convert request to event or connection manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/schemas":{"post":{"operationId":"AttestationController_createSchema","summary":"Create schema","description":"Method will create schema. The id of the response will be matched when you receive event from the websocket","tags":["Schema"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSchemaRequestDto"}}}},"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}},"get":{"operationId":"AttestationController_listSchema","summary":"List all schemas","description":"Method will fetch all schemas. The id of the response will be matched when you receive event from the websocket","tags":["Schema"],"parameters":[],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/schemas-by-id":{"post":{"operationId":"AttestationController_getSchemaById","summary":"Get schema by id","description":"Method will fetch specific schema or return null. The id of the response will be matched when you receive event from the websocket","tags":["Schema"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSchemaRequestDto"}}}},"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to connection manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credentials/definition":{"post":{"operationId":"AttestationController_createCredentialDefinition","summary":"Create credential definition","description":"Method create credential definition. The id of the response will be matched when you receive event from the websocket","tags":["Credentials"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCredentialDefinitionRequsetDto"}}}},"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credentials/issue":{"post":{"operationId":"AttestationController_issueCredential","summary":"Issue credential","description":"Method issue credential, it will create an offer and send it to specified receiver (connectionId). The id of the response will be matched when you receive event from the websocket","tags":["Credentials"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueCredentialRequestDto"}}}},"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credentials":{"get":{"operationId":"AttestationController_credentials","summary":"List all credential","description":"Method list credential definition no filters applied. The id of the response will be matched when you receive event from the websocket","tags":["Credentials"],"parameters":[],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credentials/offers":{"get":{"operationId":"AttestationController_getCredentialOffers","summary":"List unaccepted credential offers","description":"Method list offers that are received, but not accepted. The id of the response will be matched when you receive event from the websocket","tags":["Credentials Offers"],"parameters":[],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credentials/offers/{credential_record_id}/accept":{"post":{"operationId":"AttestationController_acceptCredential","summary":"Accept credential offers","description":"Method list accept credential offer. The id of the response will be matched when you receive event from the websocket","tags":["Credentials Offers"],"parameters":[{"name":"credential_record_id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"201":{"description":""},"400":{"description":"Error in sending data to attestation manager. This error shows that attestation manager could not convert request to event or attestation manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credentials/proof":{"get":{"operationId":"ProofController_proofs","summary":"List received unaccepted proofs","description":"Method list all received unaccepted proofs. Status - request-receive. The id of the response will be matched when you receive event from the websocket","tags":["Credentials Proof"],"parameters":[],"responses":{"200":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to proof manager. This error shows that proof manager could not convert request to event or proof manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credentials/proof/issue":{"post":{"operationId":"ProofController_issueProof","summary":"Issue proof for credential","description":"Method will issue proof. If connection id is not passed, the proof will be OOB. The id of the response will be matched when you receive event from the websocket","tags":["Credentials Proof"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueProofRequestDto"}}}},"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to proof manager. This error shows that proof manager could not convert request to event or proof manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}},"/api/v1/credentials/proof/{proof_record_id}/accept":{"post":{"operationId":"ProofController_acceptProof","summary":"Accept credential proof","description":"Method accept credential proof. The id of the response will be matched when you receive event from the websocket","tags":["Credentials Proof"],"parameters":[{"name":"proof_record_id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"Request is accepted for execution, the response id will match the event id received from the web socket","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayAcceptedResponseDto"}}}},"400":{"description":"Error in sending data to proof manager. This error shows that proof manager could not convert request to event or proof manager could not send the event to the broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BadRequestException"}}}},"500":{"description":"Unknown error"}}}}},"info":{"title":"Gateway","description":"OCM ENGINE GATEWAY API","version":"1.0","contact":{}},"tags":[],"servers":[{"url":"http://0.0.0.0:8081"}],"components":{"schemas":{"CloudEventDto":{"type":"object","properties":{}},"GatewayAcceptedResponseDto":{"type":"object","properties":{"id":{"type":"string","example":"80633e6d-c606-4539-a3df-287fedd09253"}},"required":["id"]},"BadRequestException":{"type":"object","properties":{}},"CreateInvitationResponseDto":{"type":"object","properties":{"invitationUrl":{"type":"string","description":"A list of user's roles","example":"http://0.0.0.0:8001?oob=eyJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvb3V0LW9mLWJhbmQvMS4xL2ludml0YXRpb24iLCJAaWQiOiIzYWExNGIzNC04YTk5LTQxY2UtYTY3NC1jODUxYmVhMTIxMWEiLCJsYWJlbCI6IkRFeGNWYXNkX0FHRU5UXzQ1IiwiYWNjZXB0IjpbImRpZGNvbW0vYWlwMSIsImRpZGNvbW0vYWlwMjtlbnY9cmZjMTkiXSwiaGFuZHNoYWtlX3Byb3RvY29scyI6WyJodHRwczovL2RpZGNvbW0ub3JnL2RpZGV4Y2hhbmdlLzEuMCIsImh0dHBzOi8vZGlkY29tbS5vcmcvY29ubmVjdGlvbnMvMS4wIl0sInNlcnZpY2VzIjpbeyJpZCI6IiNpbmxpbmUtMCIsInNlcnZpY2VFbmRwb2ludCI6Imh0dHA6Ly8wLjAuMC4wOjgwMDEiLCJ0eXBlIjoiZGlkLWNvbW11bmljYXRpb24iLCJyZWNpcGllbnRLZXlzIjpbImRpZDprZXk6ejZNa3VFcHllc1pNa3k0a1BpQzhEOEplZERlcm55YTFuaTREMUF3ZmdnWWt6YmR4Il0sInJvdXRpbmdLZXlzIjpbXX1dfQ"}},"required":["invitationUrl"]},"CreateSchemaRequestDto":{"type":"object","properties":{"name":{"type":"string","example":"my test schema"},"attributes":{"example":["first_name, last_name"],"type":"array","items":{"type":"string"}},"version":{"type":"string","example":"1.0.2","pattern":"/^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$/"}},"required":["name","attributes","version"]},"GetSchemaRequestDto":{"type":"object","properties":{"schemaId":{"type":"string","example":"did:indy:LEDNGER:SXM76gQwRnjkgoz2oBnGjd/anoncreds/v0/SCHEMA/test schema/1.0.2"}},"required":["schemaId"]},"CreateCredentialDefinitionRequsetDto":{"type":"object","properties":{"schemaId":{"type":"string"},"tag":{"type":"string"}},"required":["schemaId","tag"]},"IssueCredentialAttributes":{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"string"}},"required":["name","value"]},"IssueCredentialRequestDto":{"type":"object","properties":{"connectionId":{"type":"string"},"credentialDefinitionId":{"type":"string"},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/IssueCredentialAttributes"}}},"required":["connectionId","credentialDefinitionId","attributes"]},"IssueProofAttribute":{"type":"object","properties":{"attributeName":{"type":"string"},"credentialDefinitionId":{"type":"string"},"schemaId":{"type":"string"}},"required":["attributeName","credentialDefinitionId","schemaId"]},"IssueProofRequestDto":{"type":"object","properties":{"connectionId":{"type":"string"},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/IssueProofAttribute"}}},"required":["attributes"]}}}} \ No newline at end of file diff --git a/libs/asker/src/agent.utils.ts b/libs/asker/src/agent.utils.ts index bd70e69be3016f47afb6aacc7644dbb5e1d09990..3eae5e959a039310952d4bdaadd5e631d6e54827 100644 --- a/libs/asker/src/agent.utils.ts +++ b/libs/asker/src/agent.utils.ts @@ -11,6 +11,7 @@ import { TypedArrayEncoder, V2CredentialProtocol, V2ProofProtocol, + WalletError, WalletKeyExistsError, } from "@aries-framework/core"; import { @@ -62,7 +63,7 @@ export const generateKey = async ({ try { return await agent.wallet.createKey({ - privateKey, + seed: privateKey, keyType: KeyType.Ed25519, }); } catch (e) { @@ -75,8 +76,11 @@ export const generateKey = async ({ return Key.fromPublicKey(c.publicBytes, KeyType.Ed25519); } - console.log(JSON.stringify(e, null, 2)); - throw new Error("Failed to create key"); + if (e instanceof WalletError) { + throw new Error(`Failed to create key - ${e.message}`); + } + + throw new Error("Unknown"); } }; diff --git a/libs/asker/src/asker-nats/agent.consumer.service.ts b/libs/asker/src/asker-nats/agent.consumer.service.ts index 1a333e3a5d238661a53c3087b36b7213cf98be2f..ee23e0288b5071d52a79d0ebe7b356a522b82306 100644 --- a/libs/asker/src/asker-nats/agent.consumer.service.ts +++ b/libs/asker/src/asker-nats/agent.consumer.service.ts @@ -11,6 +11,7 @@ import { IConfAgent } from "@ocm-engine/config"; import { GatewayClient } from "@ocm-engine/clients"; import { AcceptCredentialOfferRequestDto, + AcceptProofRequestDto, CONNECTION_ACCEPT, CONNECTION_CREATE, CONNECTION_GET, @@ -26,6 +27,10 @@ import { GetConnectionRequestDto, GetSchemaRequestDto, IssueCredentialRequestDto, + IssueProofRequestDto, + PROOF_ACCEPT, + PROOF_ISSUE, + PROOF_LIST, SCHEMA_CREATE, SCHEMA_GET, SCHEMA_LIST, @@ -111,6 +116,21 @@ export class AgentConsumerService implements OnModuleInit, OnModuleDestroy { data = await this.agentService.acceptCredential( dto.credentialRecordId, ); + break; + + case PROOF_ISSUE: + dto = event.data as IssueProofRequestDto; + data = await this.agentService.issueProof(dto); + break; + + case PROOF_LIST: + data = await this.agentService.proofs(); + break; + + case PROOF_ACCEPT: + dto = event.data as AcceptProofRequestDto; + data = await this.agentService.acceptProof(dto.proofRecordId); + break; } event.data = data; diff --git a/libs/asker/src/asker/asker.service.ts b/libs/asker/src/asker/asker.service.ts index 6e37b3fa4055d24bf65e2ad065be3d209fd08a8b..6bf5e577778e22fffc70c406d8d9287769fb314d 100644 --- a/libs/asker/src/asker/asker.service.ts +++ b/libs/asker/src/asker/asker.service.ts @@ -55,7 +55,6 @@ export class AskerService implements OnModuleInit, OnModuleDestroy { }, id: this.agentConfig.agentName, key: this.agentConfig.agentKey, - keyDerivationMethod: KeyDerivationMethod.Raw, }, endpoints: [this.agentConfig.agentPeerAddress], } satisfies InitConfig; diff --git a/libs/clients/src/index.ts b/libs/clients/src/index.ts index 76a58bf05b250a6fda72297b742165eddd0e54a9..7413a83117f8d8fb22835ec890fc93b77b8a3b67 100644 --- a/libs/clients/src/index.ts +++ b/libs/clients/src/index.ts @@ -1,3 +1,4 @@ export * from "./lib/gateway.client"; export * from "./lib/connection.manager.client"; export * from "./lib/attestation.manager.client"; +export * from "./lib/proof.manager.client"; diff --git a/libs/clients/src/lib/proof.manager.client.ts b/libs/clients/src/lib/proof.manager.client.ts new file mode 100644 index 0000000000000000000000000000000000000000..3619eca4d3af21187959dd01742cc3de4786f8df --- /dev/null +++ b/libs/clients/src/lib/proof.manager.client.ts @@ -0,0 +1,62 @@ +import { + BadRequestException, + Injectable, + InternalServerErrorException, + Logger, +} from "@nestjs/common"; +import { + ClientProxy, + ClientProxyFactory, + Transport, +} from "@nestjs/microservices"; +import { ConfigService } from "@nestjs/config"; +import { + IConnectionManagerConfig, + IProofManagerConfig, +} from "@ocm-engine/config"; +import { lastValueFrom } from "rxjs"; + +@Injectable() +export class ProofManagerClient { + private client: ClientProxy; + private pmConfig: IProofManagerConfig; + private readonly logger: Logger = new Logger(ProofManagerClient.name); + + constructor(configService: ConfigService) { + this.pmConfig = configService.get<IProofManagerConfig>("pm")!; + + this.client = ClientProxyFactory.create({ + transport: Transport.TCP, + options: { + host: this.pmConfig.host, + port: this.pmConfig.port, + }, + }); + } + + async sendPayload<T>({ + pattern, + payload, + }: { + pattern: string; + payload: { + data: T; + type: string; + source: string; + }; + }): Promise<{ + id: string; + }> { + this.logger.debug( + `sending payload to proof manager ${JSON.stringify(payload, null, 2)}`, + ); + + return lastValueFrom(this.client.send(pattern, payload)).catch((e) => { + if (e.message === "Internal server error") { + throw new InternalServerErrorException(); + } + + throw new BadRequestException(e.message); + }); + } +} diff --git a/libs/config/src/config/proof.manager.ts b/libs/config/src/config/proof.manager.ts new file mode 100644 index 0000000000000000000000000000000000000000..71b21783c377a3025ecea6d99f429cf839060614 --- /dev/null +++ b/libs/config/src/config/proof.manager.ts @@ -0,0 +1,11 @@ +import { registerAs } from "@nestjs/config"; +import * as process from "process"; +import { IAttestationManagerConfig } from "../interfaces/attestation.manager.config.interface"; + +export const pmConfig = registerAs( + "pm", + (): IAttestationManagerConfig => ({ + host: process.env["PROOF_SERVICE_HOST"]!, + port: parseInt(process.env["PROOF_SERVICE_TCP_PORT"]!), + }), +); diff --git a/libs/config/src/index.ts b/libs/config/src/index.ts index 6ecbe3f4fe991891573fd5590d29998ecfef8bbe..1a892f81c2d70405d0b7b4392bf5a9f1cf4913e7 100644 --- a/libs/config/src/index.ts +++ b/libs/config/src/index.ts @@ -4,6 +4,7 @@ export * from "./config/ledgers.config"; export * from "./config/gateway.config"; export * from "./config/connection.manager.config"; export * from "./config/attestation.manager"; +export * from "./config/proof.manager"; export * from "./interfaces/nats.config.interface"; export * from "./interfaces/agent.config.interface"; @@ -11,6 +12,7 @@ export * from "./interfaces/ledgers.config.interface"; export * from "./interfaces/gateway.config.interface"; export * from "./interfaces/connection.manager.config.interface"; export * from "./interfaces/attestation.manager.config.interface"; +export * from "./interfaces/proof.manager.config.interface"; export * from "./schemas/nats.schema"; export * from "./schemas/agent.schema"; @@ -18,3 +20,4 @@ export * from "./schemas/ledgers.schema"; export * from "./schemas/gateway.schema"; export * from "./schemas/connection.manager.schema"; export * from "./schemas/attestation.manager.schema"; +export * from "./schemas/proof.manager.schema"; diff --git a/libs/config/src/interfaces/proof.manager.config.interface.ts b/libs/config/src/interfaces/proof.manager.config.interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..81f9d92b8b4e9dab8c2fcc98cb23ae354a52581b --- /dev/null +++ b/libs/config/src/interfaces/proof.manager.config.interface.ts @@ -0,0 +1,4 @@ +export interface IProofManagerConfig { + host: string; + port: number; +} diff --git a/libs/config/src/schemas/proof.manager.schema.ts b/libs/config/src/schemas/proof.manager.schema.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ba6164249949d5d29e562159809d8399b65334f --- /dev/null +++ b/libs/config/src/schemas/proof.manager.schema.ts @@ -0,0 +1,6 @@ +import Joi from "joi"; + +export const pmSchema = Joi.object({ + PROOF_SERVICE_TCP_PORT: Joi.string().required(), + PROOF_SERVICE_HOST: Joi.string().required(), +}); diff --git a/libs/dtos/src/dtos/requests/accept.proof.request.dto.ts b/libs/dtos/src/dtos/requests/accept.proof.request.dto.ts new file mode 100644 index 0000000000000000000000000000000000000000..848258238ee20537fbefc58b906bbcf2d7119cc8 --- /dev/null +++ b/libs/dtos/src/dtos/requests/accept.proof.request.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from "class-validator"; + +export class AcceptProofRequestDto { + @IsString() + @IsNotEmpty() + proofRecordId: string; +} diff --git a/libs/dtos/src/events/dtoToEventTransformer.ts b/libs/dtos/src/events/dtoToEventTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..0bb08689e7c55f0f0aa6d399465145eaa4c02174 --- /dev/null +++ b/libs/dtos/src/events/dtoToEventTransformer.ts @@ -0,0 +1,43 @@ +import { + ALL_EVENTS, + ConnectionEvent, + CredentialEvent, + ProofEvent, + SchemaEvent, +} from "./types"; +import { CloudEventDto } from "./event"; +import { ConnectionUnsupportedTypeError } from "../errors/connection.unsupported.type.error"; +import { CreateCredentialDefinitionRequsetDto } from "../dtos/requests/create.credential.definition.requset.dto"; +import { CreateInvitationResponseDto } from "../dtos/responses/create.invitation.response.dto"; +import { CreateSchemaRequestDto } from "../dtos/requests/create.schema.request.dto"; +import { GetConnectionRequestDto } from "../dtos/requests/get.connection.request.dto"; +import { IssueCredentialRequestDto } from "../dtos/requests/issue.credential.request.dto"; +import { IssueProofRequestDto } from "../dtos/requests/issue.proof.request.dto"; +import { AcceptCredentialOfferRequestDto } from "../dtos/requests/accept.credential.offer.request.dto"; + +export const makeEvent = (payload: { + data: + | null + | IssueProofRequestDto + | AcceptCredentialOfferRequestDto + | CreateInvitationResponseDto + | GetConnectionRequestDto + | CreateSchemaRequestDto + | CreateSchemaRequestDto + | CreateCredentialDefinitionRequsetDto + | IssueCredentialRequestDto; + type: SchemaEvent | CredentialEvent | ProofEvent | ConnectionEvent; + source: string; +}) => { + if (ALL_EVENTS.includes(payload.type)) { + throw new ConnectionUnsupportedTypeError(); + } + + const event = new CloudEventDto<typeof payload.data>(); + event.subject = payload.type; + event.source = payload.source; + event.type = payload.type; + event.data = payload.data; + + return event; +}; diff --git a/libs/dtos/src/events/types.ts b/libs/dtos/src/events/types.ts index 128a81f8437f29e263fb89fed01201f4319401e7..e4fc183d6890f20fc15ca9a293bd15d718f5a912 100644 --- a/libs/dtos/src/events/types.ts +++ b/libs/dtos/src/events/types.ts @@ -28,17 +28,17 @@ export const SCHEMA_EVENTS: SchemaEvent[] = [ ]; export type CredentialEvent = - | "credential.definition.create" - | "credential.issue" - | "credential.list" - | "credential.offer.list" - | "credential.offer.accept"; - -export const CRED_DEF_CREATE = "credential.definition.create"; -export const CRED_ISSUE = "credential.issue"; -export const CRED_LIST = "credential.list"; -export const CRED_OFFER_LIST = "credential.offer.list"; -export const CRED_OFFER_ACCEPT = "credential.offer.accept"; + | "credentials.definition.create" + | "credentials.issue" + | "credentials.list" + | "credentials.offer.list" + | "credentials.offer.accept"; + +export const CRED_DEF_CREATE = "credentials.definition.create"; +export const CRED_ISSUE = "credentials.issue"; +export const CRED_LIST = "credentials.list"; +export const CRED_OFFER_LIST = "credentials.offer.list"; +export const CRED_OFFER_ACCEPT = "credentials.offer.accept"; export const CRED_EVENTS: CredentialEvent[] = [ CRED_DEF_CREATE, @@ -48,4 +48,21 @@ export const CRED_EVENTS: CredentialEvent[] = [ CRED_OFFER_ACCEPT, ]; -export const ALL_EVENTS = [...SCHEMA_EVENTS, ...CRED_EVENTS]; +export type ProofEvent = "proofs.list" | "proofs.accept" | "proofs.issue"; + +export const PROOF_LIST = "proofs.list"; +export const PROOF_ACCEPT = "proofs.accept"; +export const PROOF_ISSUE = "proofs.issue"; + +export const PROOF_EVENTS: ProofEvent[] = [ + PROOF_ACCEPT, + PROOF_LIST, + PROOF_ISSUE, +]; + +export const ALL_EVENTS = [ + ...SCHEMA_EVENTS, + ...CRED_EVENTS, + ...PROOF_EVENTS, + ...CONNECTION_EVENTS, +]; diff --git a/libs/dtos/src/index.ts b/libs/dtos/src/index.ts index cf82a2c82268d0c6c5fddb9d53da6e2654418885..1cb5460a67fe1c16bcb98d09e905e4ea796e88ec 100644 --- a/libs/dtos/src/index.ts +++ b/libs/dtos/src/index.ts @@ -6,6 +6,7 @@ export * from "./dtos/requests/issue.proof.request.dto"; export * from "./dtos/requests/get.connection.request.dto"; export * from "./dtos/requests/get.schema.request.dto"; export * from "./dtos/requests/accept.credential.offer.request.dto"; +export * from "./dtos/requests/accept.proof.request.dto"; export * from "./dtos/responses/create.invitation.response.dto"; export * from "./dtos/responses/accept.invitation.response.dto"; @@ -23,3 +24,4 @@ export * from "./errors/connection.unsupported.type.error"; export * from "./events/event"; export * from "./events/types"; +export * from "./events/dtoToEventTransformer"; diff --git a/package.json b/package.json index 64b865808a8ece2b1c15acaf67bcdb22df0b52c7..92245c61c7c3a9034741acef77d3a47a4403c81d 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,35 @@ { "name": "ocm-engine", "version": "0.0.0", - "license": "MIT", - "scripts": {}, + "license": "Apache-2.0", + "scripts": { + "build:all": "yarn build:agent && yarn build:cm && yarn build:am && yarn build:pm && yarn build:gateway", + "build:agent": "nx run agent:build:development", + "build:agent:production": "nx run agent:build:production", + "build:cm": "nx run connection-manager:build:development", + "build:cm:production": "nx run connection-manager:build:production", + "build:am": "nx run attestation-manager:build:development", + "build:am:production": "nx run attestation-manager:build:production", + "build:pm": "nx run proof-manager:build:development", + "build:pm:production": "nx run proof-manager:build:production", + "build:gateway": "nx run gateway:build:development", + "build:gateway:production": "nx run gateway:build:production", + + "serve:all": "concurrently \"yarn serve:agent\" \"yarn serve:cm\" \"yarn serve:am\" \"yarn serve:pm\" \"yarn serve:gateway\"", + "serve:agent": "nx run agent:serve:development", + "serve:cm": "nx run connection-manager:serve:development", + "serve:am": "nx run attestation-manager:serve:development", + "serve:pm": "nx run proof-manager:serve:development", + "serve:gateway": "nx run gateway:serve:development", + + "infra": "cd compose && docker-compose --profile issuer --profile holder up -d", + "infra:issuer": "cd compose && docker-compose --profile issuer up -d", + "infra:holder": "cd compose && docker-compose --profile holder up -d", + "infra:issuer:stop": "cd compose && docker-compose --profile issuer stop", + "infra:holder:stop": "cd compose && docker-compose --profile holder stop", + "infra:local": "cd compose && docker-compose -f=docker-compose.infra.yml up -d", + "infra:local:stop": "cd compose && docker-compose -f=docker-compose.infra.yml stop" + }, "private": true, "dependencies": { "@hyperledger/anoncreds-nodejs": "^0.1.0-dev.15", @@ -56,6 +83,7 @@ "@types/node": "~18.7.1", "@typescript-eslint/eslint-plugin": "^5.58.0", "@typescript-eslint/parser": "^5.58.0", + "concurrently": "^8.2.0", "conventional-changelog-conventionalcommits": "^5.0.0", "eslint": "~8.15.0", "eslint-config-prettier": "8.1.0", diff --git a/yarn.lock b/yarn.lock index 281a5c16601be3312293b605bff199a7c245a706..0f299dbcc2da94cc0314db682c0894db12f078c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1116,6 +1116,13 @@ dependencies: regenerator-runtime "^0.13.11" +"@babel/runtime@^7.21.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.5.tgz#8564dd588182ce0047d55d7a75e93921107b57ec" + integrity sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA== + dependencies: + regenerator-runtime "^0.13.11" + "@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.21.9", "@babel/template@^7.3.3": version "7.21.9" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.21.9.tgz#bf8dad2859130ae46088a99c1f265394877446fb" @@ -4453,6 +4460,21 @@ concat-stream@^1.5.2: readable-stream "^2.2.2" typedarray "^0.0.6" +concurrently@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.2.0.tgz#cdc9f621a4d913366600355d68254df2c5e782f3" + integrity sha512-nnLMxO2LU492mTUj9qX/az/lESonSZu81UznYDoXtz1IQf996ixVqPAgHXwvHiHCAef/7S8HIK+fTFK7Ifk8YA== + dependencies: + chalk "^4.1.2" + date-fns "^2.30.0" + lodash "^4.17.21" + rxjs "^7.8.1" + shell-quote "^1.8.1" + spawn-command "0.0.2" + supports-color "^8.1.1" + tree-kill "^1.2.2" + yargs "^17.7.2" + config-chain@^1.1.11: version "1.1.13" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" @@ -4837,6 +4859,13 @@ data-uri-to-buffer@^3.0.1: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== +date-fns@^2.30.0: + version "2.30.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" + integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== + dependencies: + "@babel/runtime" "^7.21.0" + dateformat@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" @@ -9917,7 +9946,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@7.8.1, rxjs@^7.0.0, rxjs@^7.2.0: +rxjs@7.8.1, rxjs@^7.0.0, rxjs@^7.2.0, rxjs@^7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== @@ -10152,7 +10181,7 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.7.3: +shell-quote@^1.7.3, shell-quote@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== @@ -10324,6 +10353,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +spawn-command@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" + integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== + spawn-error-forwarder@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz#1afd94738e999b0346d7b9fc373be55e07577029" @@ -10640,7 +10674,7 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0: +supports-color@^8.0.0, supports-color@^8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== @@ -10838,7 +10872,7 @@ traverse@~0.6.6: resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.7.tgz#46961cd2d57dd8706c36664acde06a248f1173fe" integrity sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg== -tree-kill@1.2.2: +tree-kill@1.2.2, tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== @@ -11556,7 +11590,7 @@ yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.3.1, yargs@^17.5.1, yargs@^17.6.2: +yargs@^17.3.1, yargs@^17.5.1, yargs@^17.6.2, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==