From 97daf1a12d814df58ca46dfaae2cc88e20a38ba3 Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Mon, 18 Mar 2024 17:12:23 +0530 Subject: [PATCH 01/18] feat: added w3c schema Signed-off-by: tipusinghaw --- .../src/agent-service.controller.ts | 7 ++ .../src/agent-service.service.ts | 13 ++- .../api-gateway/src/dtos/create-schema.dto.ts | 19 ++++ .../src/schema/schema.controller.ts | 22 ++++- apps/api-gateway/src/schema/schema.service.ts | 5 ++ .../interfaces/schema-payload.interface.ts | 7 ++ apps/ledger/src/schema/schema.controller.ts | 8 +- apps/ledger/src/schema/schema.service.ts | 88 ++++++++++++++++++- libs/common/src/common.constant.ts | 4 + 9 files changed, 168 insertions(+), 5 deletions(-) diff --git a/apps/agent-service/src/agent-service.controller.ts b/apps/agent-service/src/agent-service.controller.ts index 163c7edca..6d035f798 100644 --- a/apps/agent-service/src/agent-service.controller.ts +++ b/apps/agent-service/src/agent-service.controller.ts @@ -34,6 +34,13 @@ export class AgentServiceController { return this.agentServiceService.createSchema(payload); } + //DONE + @MessagePattern({ cmd: 'agent-create-w3c-schema' }) + async createWC3Schema(payload: {url, apiKey, schemaRequestPayload}): Promise { + + return this.agentServiceService.createWC3Schema(payload.url, payload.apiKey, payload.schemaRequestPayload); + } + //DONE @MessagePattern({ cmd: 'agent-get-schema' }) async getSchemaById(payload: IGetSchemaAgentRedirection): Promise { diff --git a/apps/agent-service/src/agent-service.service.ts b/apps/agent-service/src/agent-service.service.ts index 36552d004..4188c7184 100644 --- a/apps/agent-service/src/agent-service.service.ts +++ b/apps/agent-service/src/agent-service.service.ts @@ -1267,7 +1267,6 @@ export class AgentServiceService { let agentApiKey; const orgAgentApiKey = await this.agentServiceRepository.getAgentApiKey(orgId); - const orgAgentId = await this.agentServiceRepository.getOrgAgentTypeDetails(OrgAgentType.SHARED); if (orgAgentApiKey?.orgAgentTypeId === orgAgentId) { const platformAdminSpinnedUp = await this.agentServiceRepository.platformAdminAgent(CommonConstants.PLATFORM_ADMIN_ORG); @@ -1335,5 +1334,17 @@ export class AgentServiceService { } + async createWC3Schema(url: string, apiKey: string, schemaRequestPayload): Promise { + try { + const schemaRequest = await this.commonService + .httpPost(url, schemaRequestPayload, { headers: { 'authorization': apiKey } }) + .then(async response => response); + return schemaRequest; + } catch (error) { + this.logger.error(`Error in schema endorsement request in agent service : ${JSON.stringify(error)}`); + throw error; + } + } + } diff --git a/apps/api-gateway/src/dtos/create-schema.dto.ts b/apps/api-gateway/src/dtos/create-schema.dto.ts index 5ba17afe9..a2f84530c 100644 --- a/apps/api-gateway/src/dtos/create-schema.dto.ts +++ b/apps/api-gateway/src/dtos/create-schema.dto.ts @@ -70,3 +70,22 @@ export class CreateSchemaDto { @IsString({ message: 'orgDid must be a string' }) orgDid: string; } + +export class CreateW3CSchemaDto { + @ApiProperty() + @IsNotEmpty({ message: 'schemaObject is required' }) + schema: object; + + @ApiProperty() + @IsString({ message: 'schemaName must be a string' }) + @Transform(({ value }) => trim(value)) + @IsNotEmpty({ message: 'schemaName is required' }) + schemaName: string; + + @ApiProperty() + @IsString({ message: 'schemaName must be a string' }) + @Transform(({ value }) => trim(value)) + @IsNotEmpty({ message: 'schemaName is required' }) + did: string; + +} diff --git a/apps/api-gateway/src/schema/schema.controller.ts b/apps/api-gateway/src/schema/schema.controller.ts index 596be7c4d..f1c25aab6 100644 --- a/apps/api-gateway/src/schema/schema.controller.ts +++ b/apps/api-gateway/src/schema/schema.controller.ts @@ -17,7 +17,7 @@ import { OrgRoles } from 'libs/org-roles/enums'; import { Roles } from '../authz/decorators/roles.decorator'; import { IUserRequestInterface } from './interfaces'; import { OrgRolesGuard } from '../authz/guards/org-roles.guard'; -import { CreateSchemaDto } from '../dtos/create-schema.dto'; +import { CreateSchemaDto, CreateW3CSchemaDto } from '../dtos/create-schema.dto'; import { CustomExceptionFilter } from 'apps/api-gateway/common/exception-handler'; import { CredDefSortFields, SortFields } from 'apps/ledger/src/schema/enum/schema.enum'; @@ -133,6 +133,26 @@ export class SchemaController { return res.status(HttpStatus.OK).json(finalResponse); } + @Post('/:orgId/polygon-w3c/schemas') + @ApiOperation({ + summary: 'Create and sends a schema to the ledger.', + description: 'Create and sends a schema to the ledger.' + }) + @Roles(OrgRoles.OWNER, OrgRoles.ADMIN) + @UseGuards(AuthGuard('jwt'), OrgRolesGuard) + @ApiResponse({ status: HttpStatus.CREATED, description: 'Success', type: ApiResponseDto }) + async createW3CSchema(@Res() res: Response, @Body() schemaPayload: CreateW3CSchemaDto, @Param('orgId') orgId: string, @User() user: IUserRequestInterface): Promise { + + const schemaDetails = await this.appService.createW3CSchema(schemaPayload, orgId); + + const finalResponse: IResponseType = { + statusCode: HttpStatus.CREATED, + message: ResponseMessages.schema.success.create, + data: schemaDetails + }; + return res.status(HttpStatus.CREATED).json(finalResponse); + } + @Post('/:orgId/schemas') @ApiOperation({ summary: 'Create and sends a schema to the ledger.', diff --git a/apps/api-gateway/src/schema/schema.service.ts b/apps/api-gateway/src/schema/schema.service.ts index a1d0863a3..7432f3c3a 100644 --- a/apps/api-gateway/src/schema/schema.service.ts +++ b/apps/api-gateway/src/schema/schema.service.ts @@ -19,6 +19,11 @@ export class SchemaService extends BaseService { return this.sendNatsMessage(this.schemaServiceProxy, 'create-schema', payload); } + createW3CSchema(schemaPayload: object, orgId: string): Promise { + const payload = { schemaPayload, orgId }; + return this.sendNatsMessage(this.schemaServiceProxy, 'create-w3c-schema', payload); + } + getSchemaById(schemaId: string, orgId: string): Promise<{ response: object; }> { diff --git a/apps/ledger/src/schema/interfaces/schema-payload.interface.ts b/apps/ledger/src/schema/interfaces/schema-payload.interface.ts index fb5a3f37e..42d2d477b 100644 --- a/apps/ledger/src/schema/interfaces/schema-payload.interface.ts +++ b/apps/ledger/src/schema/interfaces/schema-payload.interface.ts @@ -72,3 +72,10 @@ export interface ISchemaExist { version: string; } +export interface SchemaPayload { + schema: object; + schemaName: string; + did: string; + orgId: string; + } + diff --git a/apps/ledger/src/schema/schema.controller.ts b/apps/ledger/src/schema/schema.controller.ts index 68003ac49..723241091 100644 --- a/apps/ledger/src/schema/schema.controller.ts +++ b/apps/ledger/src/schema/schema.controller.ts @@ -5,7 +5,8 @@ import { ISchema, ISchemaCredDeffSearchInterface, ISchemaExist, - ISchemaSearchPayload + ISchemaSearchPayload, + SchemaPayload } from './interfaces/schema-payload.interface'; import { schema } from '@prisma/client'; import { @@ -24,6 +25,11 @@ export class SchemaController { return this.schemaService.createSchema(schema, user, orgId); } + @MessagePattern({ cmd: 'create-w3c-schema' }) + async createW3CSchema(payload: SchemaPayload): Promise { + return this.schemaService.createW3CSchema(payload); + } + @MessagePattern({ cmd: 'get-schema-by-id' }) async getSchemaById(payload: ISchema): Promise { const { schemaId, orgId } = payload; diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index 7d253557b..f02d0092d 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -11,7 +11,7 @@ import { ClientProxy, RpcException } from '@nestjs/microservices'; import { BaseService } from 'libs/service/base.service'; import { SchemaRepository } from './repositories/schema.repository'; import { schema } from '@prisma/client'; -import { ISchema, ISchemaCredDeffSearchInterface, ISchemaExist, ISchemaPayload, ISchemaSearchCriteria } from './interfaces/schema-payload.interface'; +import { ISchema, ISchemaCredDeffSearchInterface, ISchemaExist, ISchemaPayload, ISchemaSearchCriteria, SchemaPayload } from './interfaces/schema-payload.interface'; import { ResponseMessages } from '@credebl/common/response-messages'; import { IUserRequestInterface } from './interfaces/schema.interface'; import { CreateSchemaAgentRedirection, GetSchemaAgentRedirection } from './schema.interface'; @@ -246,6 +246,64 @@ export class SchemaService extends BaseService { } } + async createW3CSchema( + schemaRequestPayload: SchemaPayload + ): Promise { + + const { orgId } = schemaRequestPayload; + let apiKey: string = await this.cacheService.get(CommonConstants.CACHE_APIKEY_KEY); + if (!apiKey || null === apiKey || undefined === apiKey) { + apiKey = await this._getOrgAgentApiKey(orgId); + } + + try { + const agentDetails = await this.schemaRepository.getAgentDetailsByOrgId(orgId); + if (!agentDetails) { + throw new NotFoundException( + ResponseMessages.schema.error.agentDetailsNotFound, + { cause: new Error(), description: ResponseMessages.errorMessages.notFound } + ); + } + const { agentEndPoint } = agentDetails; + + const getAgentDetails = await this.schemaRepository.getAgentType(orgId); + + let url; + const orgAgentType = await this.schemaRepository.getOrgAgentType(getAgentDetails.org_agents[0].orgAgentTypeId); + if (OrgAgentType.DEDICATED === orgAgentType) { + url = `${agentEndPoint}${CommonConstants.DEDICATED_CREATE_POLYGON_W3C_SCHEMA}`; + const schemaPayload = { + url, + apiKey, + schemaRequestPayload + }; + + return this._createW3CSchema(schemaPayload); + } + if (OrgAgentType.SHARED === orgAgentType) { + const { tenantId } = await this.schemaRepository.getAgentDetailsByOrgId(orgId); + + url = `${agentEndPoint}${CommonConstants.SHARED_CREATE_POLYGON_W3C_SCHEMA}${tenantId}`; + const schemaPayload = { + url, + apiKey, + schemaRequestPayload + }; + + return this._createW3CSchema(schemaPayload); + + } + + + } catch (error) { + this.logger.error( + `[createSchema] - outer Error: ${JSON.stringify(error)}` + ); + + throw new RpcException(error.response ? error.response : error); + } + } + async _createSchema(payload: CreateSchemaAgentRedirection): Promise<{ response: string; }> { @@ -272,6 +330,32 @@ export class SchemaService extends BaseService { return schemaResponse; } + async _createW3CSchema(payload: object): Promise<{ + response: string; + }> { + const pattern = { + cmd: 'agent-create-w3c-schema' + }; + const schemaResponse = await this.schemaServiceProxy + .send(pattern, payload) + .pipe( + map((response) => ( + { + response + })) + ).toPromise() + .catch(error => { + this.logger.error(`Error in creating WC3 schema : ${JSON.stringify(error)}`); + throw new HttpException( + { + status: error.statusCode, + error: error.error, + message: error.message + }, error.error); + }); + return schemaResponse; + } + async getSchemaById(schemaId: string, orgId: string): Promise { try { @@ -467,7 +551,7 @@ export class SchemaService extends BaseService { async _getOrgAgentApiKey(orgId: string): Promise { const pattern = { cmd: 'get-org-agent-api-key' }; const payload = { orgId }; - + try { // eslint-disable-next-line @typescript-eslint/no-explicit-any const message = await this.schemaServiceProxy.send(pattern, payload).toPromise(); diff --git a/libs/common/src/common.constant.ts b/libs/common/src/common.constant.ts index 14f7ddc02..4c4dbdc2e 100644 --- a/libs/common/src/common.constant.ts +++ b/libs/common/src/common.constant.ts @@ -84,6 +84,10 @@ export enum CommonConstants { URL_SCHM_GET_CRED_DEF_BY_ID = '/credential-definitions/#', URL_SCHM_GET_CRED_DEF_BY_ATTRB = '/credential-definitions/created', + // POLYGON BASED W3C SCHEMAS + DEDICATED_CREATE_POLYGON_W3C_SCHEMA = '/polygon/create-schema', + SHARED_CREATE_POLYGON_W3C_SCHEMA = '/multi-tenancy/polygon-wc3/schema/', + // SHARED AGENT URL_SHAGENT_CREATE_TENANT = '/multi-tenancy/create-tenant', URL_SHAGENT_WITH_TENANT_AGENT = '/multi-tenancy/with-tenant-agent', From 143e8d9714cfdf33d5f2b0d265ab48d5bd77bdd2 Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Mon, 18 Mar 2024 18:10:49 +0530 Subject: [PATCH 02/18] feat: added interface Signed-off-by: tipusinghaw --- .../src/interfaces/ISchemaSearch.interface.ts | 6 ++ apps/api-gateway/src/schema/schema.service.ts | 4 +- .../interfaces/schema-payload.interface.ts | 23 +++++--- apps/ledger/src/schema/schema.controller.ts | 4 +- apps/ledger/src/schema/schema.service.ts | 57 +++++++------------ 5 files changed, 45 insertions(+), 49 deletions(-) diff --git a/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts b/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts index 2f83d26cb..6266a4e37 100644 --- a/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts +++ b/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts @@ -10,3 +10,9 @@ export interface ISchemaSearchPayload { user?: IUserRequestInterface } + +export interface W3CSchemaPayload { + schema: object; + schemaName: string; + did: string; + } diff --git a/apps/api-gateway/src/schema/schema.service.ts b/apps/api-gateway/src/schema/schema.service.ts index 7432f3c3a..5a5ade975 100644 --- a/apps/api-gateway/src/schema/schema.service.ts +++ b/apps/api-gateway/src/schema/schema.service.ts @@ -2,7 +2,7 @@ import { Injectable, Inject } from '@nestjs/common'; import { ClientProxy } from '@nestjs/microservices'; import { BaseService } from '../../../../libs/service/base.service'; import { CreateSchemaDto } from '../dtos/create-schema.dto'; -import { ISchemaSearchPayload } from '../interfaces/ISchemaSearch.interface'; +import { ISchemaSearchPayload, W3CSchemaPayload } from '../interfaces/ISchemaSearch.interface'; import { IUserRequestInterface } from './interfaces'; import { ICredDefWithPagination, ISchemaData, ISchemasWithPagination } from '@credebl/common/interfaces/schema.interface'; import { GetCredentialDefinitionBySchemaIdDto } from './dtos/get-all-schema.dto'; @@ -19,7 +19,7 @@ export class SchemaService extends BaseService { return this.sendNatsMessage(this.schemaServiceProxy, 'create-schema', payload); } - createW3CSchema(schemaPayload: object, orgId: string): Promise { + createW3CSchema(schemaPayload: W3CSchemaPayload, orgId: string): Promise { const payload = { schemaPayload, orgId }; return this.sendNatsMessage(this.schemaServiceProxy, 'create-w3c-schema', payload); } diff --git a/apps/ledger/src/schema/interfaces/schema-payload.interface.ts b/apps/ledger/src/schema/interfaces/schema-payload.interface.ts index 42d2d477b..5393bdddf 100644 --- a/apps/ledger/src/schema/interfaces/schema-payload.interface.ts +++ b/apps/ledger/src/schema/interfaces/schema-payload.interface.ts @@ -72,10 +72,19 @@ export interface ISchemaExist { version: string; } -export interface SchemaPayload { - schema: object; - schemaName: string; - did: string; - orgId: string; - } - +interface SchemaPayload { + schema: object, + schemaName: string, + did: string + } + +export interface W3CSchemaPayload { + schemaPayload: SchemaPayload, + orgId: string + } + +export interface W3CCreateSchema { + url: string, + apiKey: string, + schemaRequestPayload: SchemaPayload +} diff --git a/apps/ledger/src/schema/schema.controller.ts b/apps/ledger/src/schema/schema.controller.ts index 723241091..dafc53a89 100644 --- a/apps/ledger/src/schema/schema.controller.ts +++ b/apps/ledger/src/schema/schema.controller.ts @@ -6,7 +6,7 @@ import { ISchemaCredDeffSearchInterface, ISchemaExist, ISchemaSearchPayload, - SchemaPayload + W3CSchemaPayload } from './interfaces/schema-payload.interface'; import { schema } from '@prisma/client'; import { @@ -26,7 +26,7 @@ export class SchemaController { } @MessagePattern({ cmd: 'create-w3c-schema' }) - async createW3CSchema(payload: SchemaPayload): Promise { + async createW3CSchema(payload: W3CSchemaPayload): Promise { return this.schemaService.createW3CSchema(payload); } diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index f02d0092d..9f1ae6f1e 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -11,7 +11,7 @@ import { ClientProxy, RpcException } from '@nestjs/microservices'; import { BaseService } from 'libs/service/base.service'; import { SchemaRepository } from './repositories/schema.repository'; import { schema } from '@prisma/client'; -import { ISchema, ISchemaCredDeffSearchInterface, ISchemaExist, ISchemaPayload, ISchemaSearchCriteria, SchemaPayload } from './interfaces/schema-payload.interface'; +import { ISchema, ISchemaCredDeffSearchInterface, ISchemaExist, ISchemaPayload, ISchemaSearchCriteria, W3CCreateSchema, W3CSchemaPayload } from './interfaces/schema-payload.interface'; import { ResponseMessages } from '@credebl/common/response-messages'; import { IUserRequestInterface } from './interfaces/schema.interface'; import { CreateSchemaAgentRedirection, GetSchemaAgentRedirection } from './schema.interface'; @@ -247,16 +247,10 @@ export class SchemaService extends BaseService { } async createW3CSchema( - schemaRequestPayload: SchemaPayload - ): Promise { - - const { orgId } = schemaRequestPayload; - let apiKey: string = await this.cacheService.get(CommonConstants.CACHE_APIKEY_KEY); - if (!apiKey || null === apiKey || undefined === apiKey) { - apiKey = await this._getOrgAgentApiKey(orgId); - } - + schemaRequestPayload: W3CSchemaPayload + ): Promise { try { + const { orgId } = schemaRequestPayload; const agentDetails = await this.schemaRepository.getAgentDetailsByOrgId(orgId); if (!agentDetails) { throw new NotFoundException( @@ -265,44 +259,31 @@ export class SchemaService extends BaseService { ); } const { agentEndPoint } = agentDetails; - + const apiKey: string = await this.cacheService.get(CommonConstants.CACHE_APIKEY_KEY) || await this._getOrgAgentApiKey(orgId); const getAgentDetails = await this.schemaRepository.getAgentType(orgId); - - let url; const orgAgentType = await this.schemaRepository.getOrgAgentType(getAgentDetails.org_agents[0].orgAgentTypeId); + let url; if (OrgAgentType.DEDICATED === orgAgentType) { - url = `${agentEndPoint}${CommonConstants.DEDICATED_CREATE_POLYGON_W3C_SCHEMA}`; - const schemaPayload = { - url, - apiKey, - schemaRequestPayload - }; - - return this._createW3CSchema(schemaPayload); - } - if (OrgAgentType.SHARED === orgAgentType) { + url = `${agentEndPoint}${CommonConstants.DEDICATED_CREATE_POLYGON_W3C_SCHEMA}`; + } else if (OrgAgentType.SHARED === orgAgentType) { const { tenantId } = await this.schemaRepository.getAgentDetailsByOrgId(orgId); - - url = `${agentEndPoint}${CommonConstants.SHARED_CREATE_POLYGON_W3C_SCHEMA}${tenantId}`; - const schemaPayload = { - url, - apiKey, - schemaRequestPayload - }; - - return this._createW3CSchema(schemaPayload); - + url = `${agentEndPoint}${CommonConstants.SHARED_CREATE_POLYGON_W3C_SCHEMA}${tenantId}`; } - - + const schemaPayload = { + url, + apiKey, + schemaRequestPayload: schemaRequestPayload.schemaPayload + }; + return this._createW3CSchema(schemaPayload); } catch (error) { this.logger.error( `[createSchema] - outer Error: ${JSON.stringify(error)}` ); - - throw new RpcException(error.response ? error.response : error); + //need to discuss the multiple error message + throw new RpcException(error.error ? error.error.message : error.message); } } + async _createSchema(payload: CreateSchemaAgentRedirection): Promise<{ response: string; @@ -330,7 +311,7 @@ export class SchemaService extends BaseService { return schemaResponse; } - async _createW3CSchema(payload: object): Promise<{ + async _createW3CSchema(payload: W3CCreateSchema): Promise<{ response: string; }> { const pattern = { From a495d9ae41823331227e9248266a9da10ff5c731 Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Mon, 18 Mar 2024 18:13:56 +0530 Subject: [PATCH 03/18] fix: schema dto Signed-off-by: tipusinghaw --- apps/api-gateway/src/dtos/create-schema.dto.ts | 4 ++-- apps/api-gateway/src/schema/schema.controller.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/api-gateway/src/dtos/create-schema.dto.ts b/apps/api-gateway/src/dtos/create-schema.dto.ts index a2f84530c..65b109a5c 100644 --- a/apps/api-gateway/src/dtos/create-schema.dto.ts +++ b/apps/api-gateway/src/dtos/create-schema.dto.ts @@ -83,9 +83,9 @@ export class CreateW3CSchemaDto { schemaName: string; @ApiProperty() - @IsString({ message: 'schemaName must be a string' }) + @IsString({ message: 'did must be a string' }) @Transform(({ value }) => trim(value)) - @IsNotEmpty({ message: 'schemaName is required' }) + @IsNotEmpty({ message: 'did is required' }) did: string; } diff --git a/apps/api-gateway/src/schema/schema.controller.ts b/apps/api-gateway/src/schema/schema.controller.ts index f1c25aab6..6ca121d2f 100644 --- a/apps/api-gateway/src/schema/schema.controller.ts +++ b/apps/api-gateway/src/schema/schema.controller.ts @@ -135,8 +135,8 @@ export class SchemaController { @Post('/:orgId/polygon-w3c/schemas') @ApiOperation({ - summary: 'Create and sends a schema to the ledger.', - description: 'Create and sends a schema to the ledger.' + summary: 'Create and sends a W3C-schema to the ledger.', + description: 'Create and sends a W3C-schema to the ledger.' }) @Roles(OrgRoles.OWNER, OrgRoles.ADMIN) @UseGuards(AuthGuard('jwt'), OrgRolesGuard) From 5340e31283b51f2594285c37ee7af9bb14645190 Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Mon, 18 Mar 2024 18:33:39 +0530 Subject: [PATCH 04/18] fix: sonar cloud issue Signed-off-by: tipusinghaw --- apps/ledger/src/schema/schema.service.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index 9f1ae6f1e..394797427 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -269,12 +269,12 @@ export class SchemaService extends BaseService { const { tenantId } = await this.schemaRepository.getAgentDetailsByOrgId(orgId); url = `${agentEndPoint}${CommonConstants.SHARED_CREATE_POLYGON_W3C_SCHEMA}${tenantId}`; } - const schemaPayload = { + const W3cSchemaPayload = { url, apiKey, schemaRequestPayload: schemaRequestPayload.schemaPayload }; - return this._createW3CSchema(schemaPayload); + return this._createW3CSchema(W3cSchemaPayload); } catch (error) { this.logger.error( `[createSchema] - outer Error: ${JSON.stringify(error)}` @@ -314,11 +314,11 @@ export class SchemaService extends BaseService { async _createW3CSchema(payload: W3CCreateSchema): Promise<{ response: string; }> { - const pattern = { + const natsPattern = { cmd: 'agent-create-w3c-schema' }; - const schemaResponse = await this.schemaServiceProxy - .send(pattern, payload) + const W3CSchemaResponse = await this.schemaServiceProxy + .send(natsPattern, payload) .pipe( map((response) => ( { @@ -334,7 +334,7 @@ export class SchemaService extends BaseService { message: error.message }, error.error); }); - return schemaResponse; + return W3CSchemaResponse; } From aa377f7c512fe91e0834be9c2b2f3fbf49c16182 Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Mon, 18 Mar 2024 19:34:03 +0530 Subject: [PATCH 05/18] fix: changed the interface of create schema Signed-off-by: tipusinghaw --- apps/api-gateway/src/schema/schema.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api-gateway/src/schema/schema.service.ts b/apps/api-gateway/src/schema/schema.service.ts index 5a5ade975..f0655d307 100644 --- a/apps/api-gateway/src/schema/schema.service.ts +++ b/apps/api-gateway/src/schema/schema.service.ts @@ -19,7 +19,7 @@ export class SchemaService extends BaseService { return this.sendNatsMessage(this.schemaServiceProxy, 'create-schema', payload); } - createW3CSchema(schemaPayload: W3CSchemaPayload, orgId: string): Promise { + createW3CSchema(schemaPayload: W3CSchemaPayload, orgId: string): Promise { const payload = { schemaPayload, orgId }; return this.sendNatsMessage(this.schemaServiceProxy, 'create-w3c-schema', payload); } From 101a38b068414bac44ed6ec2b1df77ff8851c65a Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Tue, 19 Mar 2024 13:03:14 +0530 Subject: [PATCH 06/18] fix: multiple error messages Signed-off-by: tipusinghaw --- apps/ledger/src/schema/schema.service.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index 394797427..4ecf1796d 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -279,7 +279,6 @@ export class SchemaService extends BaseService { this.logger.error( `[createSchema] - outer Error: ${JSON.stringify(error)}` ); - //need to discuss the multiple error message throw new RpcException(error.error ? error.error.message : error.message); } } @@ -327,12 +326,7 @@ export class SchemaService extends BaseService { ).toPromise() .catch(error => { this.logger.error(`Error in creating WC3 schema : ${JSON.stringify(error)}`); - throw new HttpException( - { - status: error.statusCode, - error: error.error, - message: error.message - }, error.error); + throw new RpcException(error.error ? error.error.message : error.message); }); return W3CSchemaResponse; } From 9b1b876959f507198f933142207a5b98de84ede1 Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Wed, 27 Mar 2024 13:50:47 +0530 Subject: [PATCH 07/18] refactor: changed API key fetching logic Signed-off-by: tipusinghaw --- apps/agent-service/src/agent-service.controller.ts | 5 ++--- apps/api-gateway/src/schema/schema.controller.ts | 2 +- .../ledger/src/schema/interfaces/schema-payload.interface.ts | 2 +- apps/ledger/src/schema/schema.service.ts | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/agent-service/src/agent-service.controller.ts b/apps/agent-service/src/agent-service.controller.ts index c630b30c9..10587964c 100644 --- a/apps/agent-service/src/agent-service.controller.ts +++ b/apps/agent-service/src/agent-service.controller.ts @@ -47,9 +47,8 @@ export class AgentServiceController { //DONE @MessagePattern({ cmd: 'agent-create-w3c-schema' }) - async createWC3Schema(payload: {url, apiKey, schemaRequestPayload}): Promise { - - return this.agentServiceService.createWC3Schema(payload.url, payload.apiKey, payload.schemaRequestPayload); + async createW3CSchema(payload: { url, orgId, schemaRequestPayload }): Promise { + return this.agentServiceService.createW3CSchema(payload.url, payload.orgId, payload.schemaRequestPayload); } //DONE diff --git a/apps/api-gateway/src/schema/schema.controller.ts b/apps/api-gateway/src/schema/schema.controller.ts index 6ca121d2f..15335fa03 100644 --- a/apps/api-gateway/src/schema/schema.controller.ts +++ b/apps/api-gateway/src/schema/schema.controller.ts @@ -138,7 +138,7 @@ export class SchemaController { summary: 'Create and sends a W3C-schema to the ledger.', description: 'Create and sends a W3C-schema to the ledger.' }) - @Roles(OrgRoles.OWNER, OrgRoles.ADMIN) + @Roles(OrgRoles.OWNER, OrgRoles.ADMIN, OrgRoles.ISSUER, OrgRoles.VERIFIER, OrgRoles.MEMBER) @UseGuards(AuthGuard('jwt'), OrgRolesGuard) @ApiResponse({ status: HttpStatus.CREATED, description: 'Success', type: ApiResponseDto }) async createW3CSchema(@Res() res: Response, @Body() schemaPayload: CreateW3CSchemaDto, @Param('orgId') orgId: string, @User() user: IUserRequestInterface): Promise { diff --git a/apps/ledger/src/schema/interfaces/schema-payload.interface.ts b/apps/ledger/src/schema/interfaces/schema-payload.interface.ts index 5393bdddf..bd091074e 100644 --- a/apps/ledger/src/schema/interfaces/schema-payload.interface.ts +++ b/apps/ledger/src/schema/interfaces/schema-payload.interface.ts @@ -85,6 +85,6 @@ export interface W3CSchemaPayload { export interface W3CCreateSchema { url: string, - apiKey: string, + orgId: string, schemaRequestPayload: SchemaPayload } diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index 0a2d49dd6..0f65ac7f7 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -20,6 +20,7 @@ import { OrgAgentType } from '@credebl/enum/enum'; import { ICredDefWithPagination, ISchemaData, ISchemasWithPagination } from '@credebl/common/interfaces/schema.interface'; import { Cache } from 'cache-manager'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; +import { CommonConstants } from '@credebl/common/common.constant'; @Injectable() export class SchemaService extends BaseService { @@ -254,7 +255,6 @@ export class SchemaService extends BaseService { ); } const { agentEndPoint } = agentDetails; - const apiKey: string = await this.cacheService.get(CommonConstants.CACHE_APIKEY_KEY) || await this._getOrgAgentApiKey(orgId); const getAgentDetails = await this.schemaRepository.getAgentType(orgId); const orgAgentType = await this.schemaRepository.getOrgAgentType(getAgentDetails.org_agents[0].orgAgentTypeId); let url; @@ -266,7 +266,7 @@ export class SchemaService extends BaseService { } const W3cSchemaPayload = { url, - apiKey, + orgId, schemaRequestPayload: schemaRequestPayload.schemaPayload }; return this._createW3CSchema(W3cSchemaPayload); From 3212ad8655f3f1610e2c4c54be246f55043a8c13 Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Thu, 28 Mar 2024 13:41:49 +0530 Subject: [PATCH 08/18] fix: logger issue Signed-off-by: tipusinghaw --- apps/ledger/src/schema/schema.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index 0f65ac7f7..c3af49025 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -320,7 +320,7 @@ export class SchemaService extends BaseService { })) ).toPromise() .catch(error => { - this.logger.error(`Error in creating WC3 schema : ${JSON.stringify(error)}`); + this.logger.error(`Error in creating W3C schema : ${JSON.stringify(error)}`); throw new RpcException(error.error ? error.error.message : error.message); }); return W3CSchemaResponse; From d0d6c1ddcf6dc6f36d41c7c1e3741f155b1deaeb Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Thu, 4 Apr 2024 17:58:31 +0530 Subject: [PATCH 09/18] feat: W3C schema builder Signed-off-by: tipusinghaw --- .../src/agent-service.service.ts | 2 +- .../api-gateway/src/dtos/create-schema.dto.ts | 26 ++- .../src/interfaces/ISchemaSearch.interface.ts | 7 +- .../interfaces/schema-payload.interface.ts | 20 +- apps/ledger/src/schema/schema.controller.ts | 3 +- apps/ledger/src/schema/schema.service.ts | 215 ++++++++++++++++-- 6 files changed, 247 insertions(+), 26 deletions(-) diff --git a/apps/agent-service/src/agent-service.service.ts b/apps/agent-service/src/agent-service.service.ts index 5a595fbf1..24773534b 100644 --- a/apps/agent-service/src/agent-service.service.ts +++ b/apps/agent-service/src/agent-service.service.ts @@ -1570,7 +1570,7 @@ export class AgentServiceService { .then(async response => response); return schemaRequest; } catch (error) { - this.logger.error(`Error in schema endorsement request in agent service : ${JSON.stringify(error)}`); + this.logger.error(`Error in createW3CSchema request in agent service : ${JSON.stringify(error)}`); } } diff --git a/apps/api-gateway/src/dtos/create-schema.dto.ts b/apps/api-gateway/src/dtos/create-schema.dto.ts index 65b109a5c..09180c22c 100644 --- a/apps/api-gateway/src/dtos/create-schema.dto.ts +++ b/apps/api-gateway/src/dtos/create-schema.dto.ts @@ -73,19 +73,35 @@ export class CreateSchemaDto { export class CreateW3CSchemaDto { @ApiProperty() - @IsNotEmpty({ message: 'schemaObject is required' }) - schema: object; + @IsNotEmpty({ message: 'schemaAttribute is required' }) + schemaAttributes: SchemaAttributes []; @ApiProperty() @IsString({ message: 'schemaName must be a string' }) - @Transform(({ value }) => trim(value)) + @Transform(({ value }) => value.trim()) @IsNotEmpty({ message: 'schemaName is required' }) schemaName: string; @ApiProperty() @IsString({ message: 'did must be a string' }) - @Transform(({ value }) => trim(value)) + @Transform(({ value }) => value.trim()) @IsNotEmpty({ message: 'did is required' }) did: string; - + + @ApiProperty() + @IsString({ message: 'description must be a string' }) + @IsOptional() + description?: string; } + +export class SchemaAttributes { + @ApiProperty() + @IsNotEmpty({ message: 'type is required' }) + @IsString({ message: 'type must be a string' }) + type: string; + + @ApiProperty() + @IsNotEmpty({ message: 'title is required' }) + @IsString({ message: 'title must be a string' }) + title: string; +} \ No newline at end of file diff --git a/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts b/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts index 6266a4e37..51c10b237 100644 --- a/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts +++ b/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts @@ -12,7 +12,12 @@ export interface ISchemaSearchPayload { export interface W3CSchemaPayload { - schema: object; + schemaAttributes: W3CSchemaAttributes []; schemaName: string; did: string; } + + interface W3CSchemaAttributes { + type: string, + title: string + } diff --git a/apps/ledger/src/schema/interfaces/schema-payload.interface.ts b/apps/ledger/src/schema/interfaces/schema-payload.interface.ts index bd091074e..f56ffbfda 100644 --- a/apps/ledger/src/schema/interfaces/schema-payload.interface.ts +++ b/apps/ledger/src/schema/interfaces/schema-payload.interface.ts @@ -72,11 +72,17 @@ export interface ISchemaExist { version: string; } -interface SchemaPayload { - schema: object, +export interface SchemaPayload { + schemaAttributes: W3CSchemaAttributes [], schemaName: string, - did: string + did: string, + description: string } + + export interface W3CSchemaAttributes { + type: string, + title: string, + } export interface W3CSchemaPayload { schemaPayload: SchemaPayload, @@ -86,5 +92,11 @@ export interface W3CSchemaPayload { export interface W3CCreateSchema { url: string, orgId: string, - schemaRequestPayload: SchemaPayload + schemaRequestPayload: object } + +export interface IdAttribute extends W3CSchemaAttributes { + format: string; + order?: string +} + diff --git a/apps/ledger/src/schema/schema.controller.ts b/apps/ledger/src/schema/schema.controller.ts index dafc53a89..e428607a0 100644 --- a/apps/ledger/src/schema/schema.controller.ts +++ b/apps/ledger/src/schema/schema.controller.ts @@ -27,7 +27,8 @@ export class SchemaController { @MessagePattern({ cmd: 'create-w3c-schema' }) async createW3CSchema(payload: W3CSchemaPayload): Promise { - return this.schemaService.createW3CSchema(payload); + const {orgId, schemaPayload} = payload; + return this.schemaService.createW3CSchema(orgId, schemaPayload); } @MessagePattern({ cmd: 'get-schema-by-id' }) diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index c3af49025..69e5471ad 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -11,7 +11,7 @@ import { ClientProxy, RpcException } from '@nestjs/microservices'; import { BaseService } from 'libs/service/base.service'; import { SchemaRepository } from './repositories/schema.repository'; import { schema } from '@prisma/client'; -import { ISchema, ISchemaCredDeffSearchInterface, ISchemaExist, ISchemaPayload, ISchemaSearchCriteria, W3CCreateSchema, W3CSchemaPayload } from './interfaces/schema-payload.interface'; +import { ISchema, ISchemaCredDeffSearchInterface, ISchemaExist, ISchemaPayload, ISchemaSearchCriteria, SchemaPayload, W3CCreateSchema } from './interfaces/schema-payload.interface'; import { ResponseMessages } from '@credebl/common/response-messages'; import { IUserRequestInterface } from './interfaces/schema.interface'; import { CreateSchemaAgentRedirection, GetSchemaAgentRedirection } from './schema.interface'; @@ -242,17 +242,15 @@ export class SchemaService extends BaseService { } } - async createW3CSchema( - schemaRequestPayload: W3CSchemaPayload - ): Promise { + async createW3CSchema(orgId:string, schemaPayload: SchemaPayload): Promise { try { - const { orgId } = schemaRequestPayload; + const { description, did, schemaAttributes, schemaName} = schemaPayload; const agentDetails = await this.schemaRepository.getAgentDetailsByOrgId(orgId); if (!agentDetails) { - throw new NotFoundException( - ResponseMessages.schema.error.agentDetailsNotFound, - { cause: new Error(), description: ResponseMessages.errorMessages.notFound } - ); + throw new NotFoundException(ResponseMessages.schema.error.agentDetailsNotFound, { + cause: new Error(), + description: ResponseMessages.errorMessages.notFound + }); } const { agentEndPoint } = agentDetails; const getAgentDetails = await this.schemaRepository.getAgentType(orgId); @@ -264,21 +262,210 @@ export class SchemaService extends BaseService { const { tenantId } = await this.schemaRepository.getAgentDetailsByOrgId(orgId); url = `${agentEndPoint}${CommonConstants.SHARED_CREATE_POLYGON_W3C_SCHEMA}${tenantId}`; } + + const schemaObject = await this.w3cSchemaBuilder(schemaAttributes, schemaName, description); + const agentSchemaPayload = { + schema:schemaObject, + did, + schemaName + }; + const W3cSchemaPayload = { url, orgId, - schemaRequestPayload: schemaRequestPayload.schemaPayload + schemaRequestPayload: agentSchemaPayload }; return this._createW3CSchema(W3cSchemaPayload); } catch (error) { - this.logger.error( - `[createSchema] - outer Error: ${JSON.stringify(error)}` - ); + this.logger.error(`[createSchema] - outer Error: ${JSON.stringify(error)}`); throw new RpcException(error.error ? error.error.message : error.message); } } - + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + private async w3cSchemaBuilder(schemaAttributes, schemaName: string, description: string) { + const schemaAttributeJson = schemaAttributes.map((attribute, index) => ({ + [attribute.title]: { + type: attribute.type.toLowerCase(), + order: index, + title: attribute.title + } + })); + + // Add the format property to the id key + schemaAttributeJson.unshift({ + id: { + type: 'string', + format: 'uri' + } + }); + + const nestedObject = {}; + schemaAttributeJson.forEach((obj) => { + // eslint-disable-next-line prefer-destructuring + const key = Object.keys(obj)[0]; + nestedObject[key] = obj[key]; + }); + + const schemaNameObject = {}; + schemaNameObject[schemaName] = { + "const": schemaName + }; + const date = new Date().toISOString(); + + const W3CSchema = { + $schema: 'http://json-schema.org/draft-07/schema#', + $id: `${date}-${schemaName}`, + type: 'object', + required: ['@context', 'issuer', 'issuanceDate', 'type', 'credentialSubject'], + properties: { + '@context': { + $ref: '#/definitions/context' + }, + type: { + type: 'array', + items: { + anyOf: [ + { + $ref: '#/definitions/VerifiableCredential' + }, + { + const: '#/definitions/$AAdharCard' + } + ] + } + }, + credentialSubject: { + $ref: '#/definitions/credentialSubject' + }, + id: { + type: 'string', + format: 'uri' + }, + issuer: { + $ref: '#/definitions/uriOrId' + }, + issuanceDate: { + type: 'string', + format: 'date-time' + }, + expirationDate: { + type: 'string', + format: 'date-time' + }, + credentialStatus: { + $ref: '#/definitions/credentialStatus' + }, + credentialSchema: { + $ref: '#/definitions/credentialSchema' + } + }, + definitions: { + context: { + type: 'array', + items: [ + { + const: 'https://www.w3.org/2018/credentials/v1' + } + ], + additionalItems: { + oneOf: [ + { + type: 'string', + format: 'uri' + }, + { + type: 'object' + }, + { + type: 'array', + items: { + $ref: '#/definitions/context' + } + } + ] + }, + minItems: 1, + uniqueItems: true + }, + credentialSubject: { + type: 'object', + required: ['id'], + additionalProperties: false, + properties: nestedObject + }, + VerifiableCredential: { + const: 'VerifiableCredential' + }, + credentialSchema: { + oneOf: [ + { + $ref: '#/definitions/idAndType' + }, + { + type: 'array', + items: { + $ref: '#/definitions/idAndType' + }, + minItems: 1, + uniqueItems: true + } + ] + }, + credentialStatus: { + oneOf: [ + { + $ref: '#/definitions/idAndType' + }, + { + type: 'array', + items: { + $ref: '#/definitions/idAndType' + }, + minItems: 1, + uniqueItems: true + } + ] + }, + idAndType: { + type: 'object', + required: ['id', 'type'], + properties: { + id: { + type: 'string', + format: 'uri' + }, + type: { + type: 'string' + } + } + }, + uriOrId: { + oneOf: [ + { + type: 'string', + format: 'uri' + }, + { + type: 'object', + required: ['id'], + properties: { + id: { + type: 'string', + format: 'uri' + } + } + } + ] + }, + ...schemaNameObject + }, + title: schemaName, + description: `${description}` + }; + return W3CSchema; + } + async _createSchema(payload: CreateSchemaAgentRedirection): Promise<{ response: string; }> { From de7c2209cee24771462376eceb92eb532d426209 Mon Sep 17 00:00:00 2001 From: KulkarniShashank Date: Thu, 4 Apr 2024 19:29:16 +0530 Subject: [PATCH 10/18] fix: import common constants in schema service Signed-off-by: KulkarniShashank --- apps/ledger/src/schema/schema.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index 85052cd8c..c3af49025 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -20,6 +20,7 @@ import { OrgAgentType } from '@credebl/enum/enum'; import { ICredDefWithPagination, ISchemaData, ISchemasWithPagination } from '@credebl/common/interfaces/schema.interface'; import { Cache } from 'cache-manager'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; +import { CommonConstants } from '@credebl/common/common.constant'; @Injectable() export class SchemaService extends BaseService { From 8668a05c97fb3de9e87feee20ebc043eaca904f0 Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Fri, 5 Apr 2024 12:36:42 +0530 Subject: [PATCH 11/18] fix: required message Signed-off-by: tipusinghaw --- apps/api-gateway/src/dtos/create-schema.dto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api-gateway/src/dtos/create-schema.dto.ts b/apps/api-gateway/src/dtos/create-schema.dto.ts index 09180c22c..08175c362 100644 --- a/apps/api-gateway/src/dtos/create-schema.dto.ts +++ b/apps/api-gateway/src/dtos/create-schema.dto.ts @@ -73,7 +73,7 @@ export class CreateSchemaDto { export class CreateW3CSchemaDto { @ApiProperty() - @IsNotEmpty({ message: 'schemaAttribute is required' }) + @IsNotEmpty({ message: 'Schema attributes are required' }) schemaAttributes: SchemaAttributes []; @ApiProperty() From f075cf44242f0b676a2f1b852844296ba4efffa9 Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Fri, 5 Apr 2024 12:41:25 +0530 Subject: [PATCH 12/18] refactor: Added error handling for schema builder Signed-off-by: tipusinghaw --- apps/ledger/src/schema/schema.service.ts | 7 +++++++ libs/common/src/response-messages/index.ts | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index 69e5471ad..51d068c80 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -264,6 +264,13 @@ export class SchemaService extends BaseService { } const schemaObject = await this.w3cSchemaBuilder(schemaAttributes, schemaName, description); + + if (!schemaObject) { + throw new BadRequestException(ResponseMessages.schema.error.schemaBuilder, { + cause: new Error(), + description: ResponseMessages.errorMessages.badRequest + }); + } const agentSchemaPayload = { schema:schemaObject, did, diff --git a/libs/common/src/response-messages/index.ts b/libs/common/src/response-messages/index.ts index 5363cdd80..89d149584 100644 --- a/libs/common/src/response-messages/index.ts +++ b/libs/common/src/response-messages/index.ts @@ -161,7 +161,8 @@ export const ResponseMessages = { notStoredCredential: 'User credential not stored', agentDetailsNotFound: 'Agent details not found', failedFetchSchema: 'Failed to fetch schema data', - atLeastOneRequired: 'At least one of the attributes should have isReuired as `true`' + atLeastOneRequired: 'At least one of the attributes should have isReuired as `true`', + schemaBuilder: 'Error while creating schema JSON`' } }, credentialDefinition: { From 873e02a76b6098446dbe365808f92a72e49025df Mon Sep 17 00:00:00 2001 From: tipusinghaw <126460794+tipusinghaw@users.noreply.github.com> Date: Fri, 5 Apr 2024 12:46:58 +0530 Subject: [PATCH 13/18] feat: implemented W3C schema builder (#627) * feat: added w3c schema Signed-off-by: tipusinghaw * feat: added interface Signed-off-by: tipusinghaw * fix: schema dto Signed-off-by: tipusinghaw * fix: sonar cloud issue Signed-off-by: tipusinghaw * fix: changed the interface of create schema Signed-off-by: tipusinghaw * fix: multiple error messages Signed-off-by: tipusinghaw * refactor: changed API key fetching logic Signed-off-by: tipusinghaw * fix: logger issue Signed-off-by: tipusinghaw * feat: W3C schema builder Signed-off-by: tipusinghaw * fix: required message Signed-off-by: tipusinghaw * refactor: Added error handling for schema builder Signed-off-by: tipusinghaw --------- Signed-off-by: tipusinghaw --- .../src/agent-service.service.ts | 2 +- .../api-gateway/src/dtos/create-schema.dto.ts | 26 +- .../src/interfaces/ISchemaSearch.interface.ts | 7 +- .../interfaces/schema-payload.interface.ts | 20 +- apps/ledger/src/schema/schema.controller.ts | 3 +- apps/ledger/src/schema/schema.service.ts | 222 ++++++++++++++++-- libs/common/src/response-messages/index.ts | 3 +- 7 files changed, 256 insertions(+), 27 deletions(-) diff --git a/apps/agent-service/src/agent-service.service.ts b/apps/agent-service/src/agent-service.service.ts index 5a595fbf1..24773534b 100644 --- a/apps/agent-service/src/agent-service.service.ts +++ b/apps/agent-service/src/agent-service.service.ts @@ -1570,7 +1570,7 @@ export class AgentServiceService { .then(async response => response); return schemaRequest; } catch (error) { - this.logger.error(`Error in schema endorsement request in agent service : ${JSON.stringify(error)}`); + this.logger.error(`Error in createW3CSchema request in agent service : ${JSON.stringify(error)}`); } } diff --git a/apps/api-gateway/src/dtos/create-schema.dto.ts b/apps/api-gateway/src/dtos/create-schema.dto.ts index 65b109a5c..08175c362 100644 --- a/apps/api-gateway/src/dtos/create-schema.dto.ts +++ b/apps/api-gateway/src/dtos/create-schema.dto.ts @@ -73,19 +73,35 @@ export class CreateSchemaDto { export class CreateW3CSchemaDto { @ApiProperty() - @IsNotEmpty({ message: 'schemaObject is required' }) - schema: object; + @IsNotEmpty({ message: 'Schema attributes are required' }) + schemaAttributes: SchemaAttributes []; @ApiProperty() @IsString({ message: 'schemaName must be a string' }) - @Transform(({ value }) => trim(value)) + @Transform(({ value }) => value.trim()) @IsNotEmpty({ message: 'schemaName is required' }) schemaName: string; @ApiProperty() @IsString({ message: 'did must be a string' }) - @Transform(({ value }) => trim(value)) + @Transform(({ value }) => value.trim()) @IsNotEmpty({ message: 'did is required' }) did: string; - + + @ApiProperty() + @IsString({ message: 'description must be a string' }) + @IsOptional() + description?: string; } + +export class SchemaAttributes { + @ApiProperty() + @IsNotEmpty({ message: 'type is required' }) + @IsString({ message: 'type must be a string' }) + type: string; + + @ApiProperty() + @IsNotEmpty({ message: 'title is required' }) + @IsString({ message: 'title must be a string' }) + title: string; +} \ No newline at end of file diff --git a/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts b/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts index 6266a4e37..51c10b237 100644 --- a/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts +++ b/apps/api-gateway/src/interfaces/ISchemaSearch.interface.ts @@ -12,7 +12,12 @@ export interface ISchemaSearchPayload { export interface W3CSchemaPayload { - schema: object; + schemaAttributes: W3CSchemaAttributes []; schemaName: string; did: string; } + + interface W3CSchemaAttributes { + type: string, + title: string + } diff --git a/apps/ledger/src/schema/interfaces/schema-payload.interface.ts b/apps/ledger/src/schema/interfaces/schema-payload.interface.ts index bd091074e..f56ffbfda 100644 --- a/apps/ledger/src/schema/interfaces/schema-payload.interface.ts +++ b/apps/ledger/src/schema/interfaces/schema-payload.interface.ts @@ -72,11 +72,17 @@ export interface ISchemaExist { version: string; } -interface SchemaPayload { - schema: object, +export interface SchemaPayload { + schemaAttributes: W3CSchemaAttributes [], schemaName: string, - did: string + did: string, + description: string } + + export interface W3CSchemaAttributes { + type: string, + title: string, + } export interface W3CSchemaPayload { schemaPayload: SchemaPayload, @@ -86,5 +92,11 @@ export interface W3CSchemaPayload { export interface W3CCreateSchema { url: string, orgId: string, - schemaRequestPayload: SchemaPayload + schemaRequestPayload: object } + +export interface IdAttribute extends W3CSchemaAttributes { + format: string; + order?: string +} + diff --git a/apps/ledger/src/schema/schema.controller.ts b/apps/ledger/src/schema/schema.controller.ts index dafc53a89..e428607a0 100644 --- a/apps/ledger/src/schema/schema.controller.ts +++ b/apps/ledger/src/schema/schema.controller.ts @@ -27,7 +27,8 @@ export class SchemaController { @MessagePattern({ cmd: 'create-w3c-schema' }) async createW3CSchema(payload: W3CSchemaPayload): Promise { - return this.schemaService.createW3CSchema(payload); + const {orgId, schemaPayload} = payload; + return this.schemaService.createW3CSchema(orgId, schemaPayload); } @MessagePattern({ cmd: 'get-schema-by-id' }) diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index c3af49025..51d068c80 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -11,7 +11,7 @@ import { ClientProxy, RpcException } from '@nestjs/microservices'; import { BaseService } from 'libs/service/base.service'; import { SchemaRepository } from './repositories/schema.repository'; import { schema } from '@prisma/client'; -import { ISchema, ISchemaCredDeffSearchInterface, ISchemaExist, ISchemaPayload, ISchemaSearchCriteria, W3CCreateSchema, W3CSchemaPayload } from './interfaces/schema-payload.interface'; +import { ISchema, ISchemaCredDeffSearchInterface, ISchemaExist, ISchemaPayload, ISchemaSearchCriteria, SchemaPayload, W3CCreateSchema } from './interfaces/schema-payload.interface'; import { ResponseMessages } from '@credebl/common/response-messages'; import { IUserRequestInterface } from './interfaces/schema.interface'; import { CreateSchemaAgentRedirection, GetSchemaAgentRedirection } from './schema.interface'; @@ -242,17 +242,15 @@ export class SchemaService extends BaseService { } } - async createW3CSchema( - schemaRequestPayload: W3CSchemaPayload - ): Promise { + async createW3CSchema(orgId:string, schemaPayload: SchemaPayload): Promise { try { - const { orgId } = schemaRequestPayload; + const { description, did, schemaAttributes, schemaName} = schemaPayload; const agentDetails = await this.schemaRepository.getAgentDetailsByOrgId(orgId); if (!agentDetails) { - throw new NotFoundException( - ResponseMessages.schema.error.agentDetailsNotFound, - { cause: new Error(), description: ResponseMessages.errorMessages.notFound } - ); + throw new NotFoundException(ResponseMessages.schema.error.agentDetailsNotFound, { + cause: new Error(), + description: ResponseMessages.errorMessages.notFound + }); } const { agentEndPoint } = agentDetails; const getAgentDetails = await this.schemaRepository.getAgentType(orgId); @@ -264,21 +262,217 @@ export class SchemaService extends BaseService { const { tenantId } = await this.schemaRepository.getAgentDetailsByOrgId(orgId); url = `${agentEndPoint}${CommonConstants.SHARED_CREATE_POLYGON_W3C_SCHEMA}${tenantId}`; } + + const schemaObject = await this.w3cSchemaBuilder(schemaAttributes, schemaName, description); + + if (!schemaObject) { + throw new BadRequestException(ResponseMessages.schema.error.schemaBuilder, { + cause: new Error(), + description: ResponseMessages.errorMessages.badRequest + }); + } + const agentSchemaPayload = { + schema:schemaObject, + did, + schemaName + }; + const W3cSchemaPayload = { url, orgId, - schemaRequestPayload: schemaRequestPayload.schemaPayload + schemaRequestPayload: agentSchemaPayload }; return this._createW3CSchema(W3cSchemaPayload); } catch (error) { - this.logger.error( - `[createSchema] - outer Error: ${JSON.stringify(error)}` - ); + this.logger.error(`[createSchema] - outer Error: ${JSON.stringify(error)}`); throw new RpcException(error.error ? error.error.message : error.message); } } - + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + private async w3cSchemaBuilder(schemaAttributes, schemaName: string, description: string) { + const schemaAttributeJson = schemaAttributes.map((attribute, index) => ({ + [attribute.title]: { + type: attribute.type.toLowerCase(), + order: index, + title: attribute.title + } + })); + + // Add the format property to the id key + schemaAttributeJson.unshift({ + id: { + type: 'string', + format: 'uri' + } + }); + + const nestedObject = {}; + schemaAttributeJson.forEach((obj) => { + // eslint-disable-next-line prefer-destructuring + const key = Object.keys(obj)[0]; + nestedObject[key] = obj[key]; + }); + + const schemaNameObject = {}; + schemaNameObject[schemaName] = { + "const": schemaName + }; + const date = new Date().toISOString(); + + const W3CSchema = { + $schema: 'http://json-schema.org/draft-07/schema#', + $id: `${date}-${schemaName}`, + type: 'object', + required: ['@context', 'issuer', 'issuanceDate', 'type', 'credentialSubject'], + properties: { + '@context': { + $ref: '#/definitions/context' + }, + type: { + type: 'array', + items: { + anyOf: [ + { + $ref: '#/definitions/VerifiableCredential' + }, + { + const: '#/definitions/$AAdharCard' + } + ] + } + }, + credentialSubject: { + $ref: '#/definitions/credentialSubject' + }, + id: { + type: 'string', + format: 'uri' + }, + issuer: { + $ref: '#/definitions/uriOrId' + }, + issuanceDate: { + type: 'string', + format: 'date-time' + }, + expirationDate: { + type: 'string', + format: 'date-time' + }, + credentialStatus: { + $ref: '#/definitions/credentialStatus' + }, + credentialSchema: { + $ref: '#/definitions/credentialSchema' + } + }, + definitions: { + context: { + type: 'array', + items: [ + { + const: 'https://www.w3.org/2018/credentials/v1' + } + ], + additionalItems: { + oneOf: [ + { + type: 'string', + format: 'uri' + }, + { + type: 'object' + }, + { + type: 'array', + items: { + $ref: '#/definitions/context' + } + } + ] + }, + minItems: 1, + uniqueItems: true + }, + credentialSubject: { + type: 'object', + required: ['id'], + additionalProperties: false, + properties: nestedObject + }, + VerifiableCredential: { + const: 'VerifiableCredential' + }, + credentialSchema: { + oneOf: [ + { + $ref: '#/definitions/idAndType' + }, + { + type: 'array', + items: { + $ref: '#/definitions/idAndType' + }, + minItems: 1, + uniqueItems: true + } + ] + }, + credentialStatus: { + oneOf: [ + { + $ref: '#/definitions/idAndType' + }, + { + type: 'array', + items: { + $ref: '#/definitions/idAndType' + }, + minItems: 1, + uniqueItems: true + } + ] + }, + idAndType: { + type: 'object', + required: ['id', 'type'], + properties: { + id: { + type: 'string', + format: 'uri' + }, + type: { + type: 'string' + } + } + }, + uriOrId: { + oneOf: [ + { + type: 'string', + format: 'uri' + }, + { + type: 'object', + required: ['id'], + properties: { + id: { + type: 'string', + format: 'uri' + } + } + } + ] + }, + ...schemaNameObject + }, + title: schemaName, + description: `${description}` + }; + return W3CSchema; + } + async _createSchema(payload: CreateSchemaAgentRedirection): Promise<{ response: string; }> { diff --git a/libs/common/src/response-messages/index.ts b/libs/common/src/response-messages/index.ts index 5363cdd80..89d149584 100644 --- a/libs/common/src/response-messages/index.ts +++ b/libs/common/src/response-messages/index.ts @@ -161,7 +161,8 @@ export const ResponseMessages = { notStoredCredential: 'User credential not stored', agentDetailsNotFound: 'Agent details not found', failedFetchSchema: 'Failed to fetch schema data', - atLeastOneRequired: 'At least one of the attributes should have isReuired as `true`' + atLeastOneRequired: 'At least one of the attributes should have isReuired as `true`', + schemaBuilder: 'Error while creating schema JSON`' } }, credentialDefinition: { From b8f09d7e2ea278afea882f8ecfce0edb94b317f5 Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Fri, 5 Apr 2024 13:20:33 +0530 Subject: [PATCH 14/18] fix: schema name in schema builder Signed-off-by: tipusinghaw --- apps/ledger/src/schema/schema.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index 51d068c80..a5c71aa9c 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -337,7 +337,7 @@ export class SchemaService extends BaseService { $ref: '#/definitions/VerifiableCredential' }, { - const: '#/definitions/$AAdharCard' + const: `#/definitions/$${schemaName}` } ] } From 99f60a5d358d70691acb0835675c33e08affeaca Mon Sep 17 00:00:00 2001 From: tipusinghaw <126460794+tipusinghaw@users.noreply.github.com> Date: Fri, 5 Apr 2024 13:31:08 +0530 Subject: [PATCH 15/18] fix: change schema name in schema builder (#644) * feat: added w3c schema Signed-off-by: tipusinghaw * feat: added interface Signed-off-by: tipusinghaw * fix: schema dto Signed-off-by: tipusinghaw * fix: sonar cloud issue Signed-off-by: tipusinghaw * fix: changed the interface of create schema Signed-off-by: tipusinghaw * fix: multiple error messages Signed-off-by: tipusinghaw * refactor: changed API key fetching logic Signed-off-by: tipusinghaw * fix: logger issue Signed-off-by: tipusinghaw * feat: W3C schema builder Signed-off-by: tipusinghaw * fix: required message Signed-off-by: tipusinghaw * refactor: Added error handling for schema builder Signed-off-by: tipusinghaw * fix: schema name in schema builder Signed-off-by: tipusinghaw --------- Signed-off-by: tipusinghaw --- apps/ledger/src/schema/schema.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ledger/src/schema/schema.service.ts b/apps/ledger/src/schema/schema.service.ts index 51d068c80..a5c71aa9c 100644 --- a/apps/ledger/src/schema/schema.service.ts +++ b/apps/ledger/src/schema/schema.service.ts @@ -337,7 +337,7 @@ export class SchemaService extends BaseService { $ref: '#/definitions/VerifiableCredential' }, { - const: '#/definitions/$AAdharCard' + const: `#/definitions/$${schemaName}` } ] } From 247f503c746e603940edfc05df85779f2a2175a7 Mon Sep 17 00:00:00 2001 From: Krishna Date: Wed, 10 Apr 2024 15:18:14 +0530 Subject: [PATCH 16/18] fix: email template for oob verification Signed-off-by: Krishna --- apps/verification/src/verification.service.ts | 2 +- .../templates/out-of-band-verification.template.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/verification/src/verification.service.ts b/apps/verification/src/verification.service.ts index ed5972689..dabf7fbd0 100644 --- a/apps/verification/src/verification.service.ts +++ b/apps/verification/src/verification.service.ts @@ -489,7 +489,7 @@ export class VerificationService { this.emailData.emailFrom = platformConfigData.emailFrom; this.emailData.emailTo = email; this.emailData.emailSubject = `${process.env.PLATFORM_NAME} Platform: Verification of Your Credentials`; - this.emailData.emailHtml = await this.outOfBandVerification.outOfBandVerification(email, organizationDetails.name, outOfBandVerificationQrCode); + this.emailData.emailHtml = await this.outOfBandVerification.outOfBandVerification(email, organizationDetails.name, shortenedUrl); this.emailData.emailAttachments = [ { filename: 'qrcode.png', diff --git a/apps/verification/templates/out-of-band-verification.template.ts b/apps/verification/templates/out-of-band-verification.template.ts index ebb5e0693..cbe4d4af2 100644 --- a/apps/verification/templates/out-of-band-verification.template.ts +++ b/apps/verification/templates/out-of-band-verification.template.ts @@ -1,6 +1,6 @@ export class OutOfBandVerification { - public outOfBandVerification(email: string, orgName: string, verificationQrCode: string): string { + public outOfBandVerification(email: string, orgName: string, shortenedUrl: string): string { try { return ` @@ -33,7 +33,7 @@ export class OutOfBandVerification {
  • Tap the "Send Proof" button in ${process.env.MOBILE_APP} to share you credential data.
  • - Share Credential From e8d9d1fb0c1c267aa1600c9acfb6a8b951106bb4 Mon Sep 17 00:00:00 2001 From: Krishna Date: Thu, 11 Apr 2024 13:56:36 +0530 Subject: [PATCH 17/18] fix: incorrect error message Signed-off-by: Krishna --- apps/api-gateway/src/authz/guards/org-roles.guard.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api-gateway/src/authz/guards/org-roles.guard.ts b/apps/api-gateway/src/authz/guards/org-roles.guard.ts index c109525fb..f3c1178d1 100644 --- a/apps/api-gateway/src/authz/guards/org-roles.guard.ts +++ b/apps/api-gateway/src/authz/guards/org-roles.guard.ts @@ -84,7 +84,7 @@ export class OrgRolesGuard implements CanActivate { return false; } else { - throw new BadRequestException('organization is required'); + throw new BadRequestException('Please provide valid orgId'); } // Sending user friendly message if a user attempts to access an API that is inaccessible to their role From 5199c864c2b992c6bb7d0e386e95cf5bb6912b32 Mon Sep 17 00:00:00 2001 From: tipusinghaw Date: Thu, 11 Apr 2024 14:13:12 +0530 Subject: [PATCH 18/18] fix: added example in w3c schema DTO Signed-off-by: tipusinghaw --- apps/api-gateway/src/dtos/create-schema.dto.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/api-gateway/src/dtos/create-schema.dto.ts b/apps/api-gateway/src/dtos/create-schema.dto.ts index 08175c362..380b797a3 100644 --- a/apps/api-gateway/src/dtos/create-schema.dto.ts +++ b/apps/api-gateway/src/dtos/create-schema.dto.ts @@ -72,7 +72,15 @@ export class CreateSchemaDto { } export class CreateW3CSchemaDto { - @ApiProperty() + @ApiProperty({ + type: [], + 'example': [ + { + title: 'name', + type: 'string' + } + ] + }) @IsNotEmpty({ message: 'Schema attributes are required' }) schemaAttributes: SchemaAttributes []; @@ -90,8 +98,8 @@ export class CreateW3CSchemaDto { @ApiProperty() @IsString({ message: 'description must be a string' }) - @IsOptional() - description?: string; + @IsNotEmpty({ message: 'description is required' }) + description: string; } export class SchemaAttributes {