Skip to content
Snippets Groups Projects
Commit 29bb32bb authored by Steffen Schulze's avatar Steffen Schulze
Browse files

Merge branch 'chore/refactor-proof-manager' into 'main'

Refactor proof manager

See merge request !24
parents 8287e885 fdfc1641
No related branches found
No related tags found
No related merge requests found
Showing
with 0 additions and 3397 deletions
This diff is collapsed.
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
export default class AcceptPresentationDto {
@IsString()
@ApiProperty()
public proofRecordId: string;
}
import { IsString } from 'class-validator';
export default class AcceptProofRequestDto {
@IsString()
public proofRecordId: string;
}
import { IsDateString, IsNumber, IsString } from 'class-validator';
export default class FindProofPresentationDto {
@IsNumber()
public page: string;
@IsNumber()
public pageSize: string;
@IsString()
public proofRecordId: string;
@IsString()
public connectionId: string;
@IsString()
public credentialDefId: string;
@IsString()
public schemaId: string;
@IsString()
public theirDid: string;
@IsString()
public status: string;
@IsDateString()
public createdDateStart: string;
@IsDateString()
public createdDateEnd: string;
@IsDateString()
public updatedDateStart: string;
@IsDateString()
public updatedDateEnd: string;
}
import { IsString } from 'class-validator';
export default class GetPresentProofsDto {
@IsString()
public connectionId: string;
}
import { IsString } from 'class-validator';
export default class GetProofRequest {
@IsString()
public state: string;
@IsString()
public id: string;
@IsString()
public connectionId: string;
public isVerified?: boolean;
}
import { IsString } from 'class-validator';
export default class MembershipCredentialDto {
@IsString()
public connectionId: string;
public attributes: {
attributeName: string;
schemaId?: string;
credentialDefId?: string;
}[];
}
import { IsString, IsNotEmpty } from 'class-validator';
export default class PresentationSubscriptionEndpointDto {
@IsString()
@IsNotEmpty()
public proofRecordId: string;
@IsString()
@IsNotEmpty()
public status: string;
}
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
import GetProofRequest from './get-proof-request.dto.js';
export default class SendProofRequestBody {
@ApiProperty({ example: 'comments' })
public comment?: string;
@IsString()
public status?: string;
@ApiProperty({ example: 'WgWxqztrNooG92RXvxSTWv:3:CL:20:tag' })
@IsString()
public schemaId: string;
@IsString()
public theirDID?: string;
@IsString()
public presentationMessage?: string;
@ApiProperty({
example: {
type: 'Aries1.0',
credentialDefinitionId: 'credentialDefinitionId',
},
})
public options?: {
type: string;
credentialDefinitionId: string;
};
@IsString()
public invitation?: GetProofRequest;
@ApiProperty({ example: ['attributeName'] })
public attributes: [
{
attributeName: string;
schemaId: string;
credentialDefId: string;
value: string;
condition: string;
},
];
}
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
import GetProofRequest from './get-proof-request.dto.js';
export default class SendProofRequest {
@ApiProperty({ example: 'comments' })
public comment?: string;
@ApiProperty({ example: '3fa85f64-5717-4562-b3fc-2c963f66afa6' })
public connectionId?: string;
@IsString()
public proofRecordId?: string;
@IsString()
public status?: string;
@IsString()
public theirDID?: string;
@IsString()
public presentationMessage?: string;
@IsString()
public invitation?: GetProofRequest;
@ApiProperty({
example: [
{
attributeName: 'attributeName',
schemaId: 'schemaId',
credentialDefId: 'credentialDefId',
},
],
})
public attributes: {
attributeName: string;
schemaId?: string;
credentialDefId?: string;
value: string;
condition: string;
}[];
}
import PresentationProofsModule from './module';
describe('Check if the module is working', () => {
it('should be defined', () => {
expect(PresentationProofsModule).toBeDefined();
});
});
import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import NatsClientService from '../client/nats.client.js';
import RestClientService from '../client/rest.client.js';
import { NATSServices } from '../common/constants.js';
import config from '../config/config.js';
import PrismaService from '../prisma/prisma.service.js';
import PresentationProofsController from './controller/controller.js';
import PresentationProofsService from './services/service.js';
@Module({
imports: [
HttpModule,
ClientsModule.register([
{
name: NATSServices.SERVICE_NAME,
transport: Transport.NATS,
options: {
servers: [config().nats.url as string],
},
},
]),
],
controllers: [PresentationProofsController],
providers: [
PresentationProofsService,
PrismaService,
NatsClientService,
RestClientService,
],
})
export default class PresentationProofsModule {}
import type { Prisma } from '@prisma/client';
import { Injectable } from '@nestjs/common';
import PrismaService from '../../prisma/prisma.service.js';
@Injectable()
export default class PresentationProofRepository {
public constructor(private readonly prismaService: PrismaService) {}
public async createPresentationProof(data: Prisma.ProofCreateInput) {
return this.prismaService.proof.create({
data,
});
}
public async updatePresentationStatus(params: {
where: Prisma.ProofWhereUniqueInput;
data: Prisma.ProofUpdateInput;
}) {
const { where, data } = params;
return this.prismaService.proof.update({
data,
where,
});
}
public async findProofPresentation(params: {
skip?: number;
take?: number;
cursor?: Prisma.ProofWhereUniqueInput;
where?: Prisma.ProofWhereInput;
orderBy?: Prisma.ProofOrderByWithRelationInput;
}) {
const { skip, take, cursor, where, orderBy } = params;
return this.prismaService.$transaction([
this.prismaService.proof.count({
where,
}),
this.prismaService.proof.findMany({
skip,
take,
cursor,
where,
orderBy,
}),
]);
}
public async deleteProofRequest(proofRecordId: string) {
return this.prismaService.proof.delete({
where: { proofRecordId },
});
}
public async createShortUrl(originalUrl: string) {
return this.prismaService.shortUrl.create({
data: {
originalUrl,
},
});
}
public async getShortUrl(id: string) {
return this.prismaService.shortUrl.findUnique({
where: {
id,
},
});
}
}
/* eslint-disable @typescript-eslint/no-explicit-any */
import type MembershipCredentialDto from '../entities/membership-credential.dto.js';
import type SendProofRequest from '../entities/send-proof-request.dto.js';
import type { TestingModule } from '@nestjs/testing';
import { HttpModule } from '@nestjs/axios';
import { ConfigModule } from '@nestjs/config';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { Test } from '@nestjs/testing';
import NatsClientService from '../../client/nats.client.js';
import RestClientService from '../../client/rest.client.js';
import { NATSServices } from '../../common/constants.js';
import PrismaService from '../../prisma/prisma.service.js';
import PresentationProofsService from './service.js';
describe.skip('ConnectionsService', () => {
let service: PresentationProofsService;
let prismaService: PrismaService;
let natsClient: NatsClientService;
let restClient: RestClientService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
ConfigModule,
HttpModule,
ClientsModule.register([
{
name: NATSServices.SERVICE_NAME,
transport: Transport.NATS,
},
]),
],
providers: [
PresentationProofsService,
PrismaService,
NatsClientService,
RestClientService,
],
exports: [PrismaService],
}).compile();
prismaService = module.get<PrismaService>(PrismaService);
service = module.get<PresentationProofsService>(PresentationProofsService);
natsClient = module.get<NatsClientService>(NatsClientService);
restClient = module.get<RestClientService>(RestClientService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('find proof presentation function', () => {
it('find proof presentation by ID', async () => {
const getAgentDetails: any = {
statusCode: 200,
message: 'Agent',
data: {
id: '15b9c7d6-8bc9-47cb-b78e-314e6c12bf16',
participant_id: '662dc769-a4de-4c95-934c-f6dab8cf432c',
agent_url: 'http://3.111.77.38:4001',
invitation_url:
'http://3.111.77.38:4001?c_i=eyJAdHlwZSI6ImRpZDpzb3Y6QnpDYnNOWWhNcmpIaXFaRFRVQVNIZztzcGVjL2Nvbm5lY3Rpb25zLzEuMC9pbnZpdGF0aW9uIiwiQGlkIjoiZGVhMGY1NTYtOWM4MS00OTcyLTkxZjktODhmNWQ3MDNlNDRiIiwibGFiZWwiOiJPcmdfT25lIiwicmVjaXBpZW50S2V5cyI6WyI0eFFSMVVCUXV0TGg5S2tFc1lLZ2FZNDg5VEFtMUtRTVREcnR4WEdQNnNQUiJdLCJzZXJ2aWNlRW5kcG9pbnQiOiJodHRwOi8vMy4xMTEuNzcuMzg6NDAwMSIsInJvdXRpbmdLZXlzIjpbXX0',
public_did: 'Knwz4KG97ta6EnC5BT7uH3',
wallet_name: 'Org_One',
service_endpoint: 'http://3.111.77.38:4000',
status: true,
created_by: '662dc769-a4de-4c95-934c-f6dab8cf432c',
created_date: '2022-04-14T16:33:14.152Z',
updated_by: '662dc769-a4de-4c95-934c-f6dab8cf432c',
updated_date: '2022-04-26T06:03:32.178Z',
},
};
const result: any = {
_tags: {
connectionId: 'b6724f85-a633-43ee-9c1c-736eaccbb6f9',
state: 'request-sent',
threadId: '34881067-b9fc-49a4-814d-dee4668b4f90',
},
metadata: {},
id: '117631fe-06c8-4b2c-9132-9e9f775709d8',
createdAt: '2022-04-26T08:18:19.206Z',
requestMessage: {
'@type': 'https://didcomm.org/present-proof/1.0/request-presentation',
'@id': '34881067-b9fc-49a4-814d-dee4668b4f90',
comment: 'Gaia-x Test',
'request_presentations~attach': [
{
'@id': 'libindy-request-presentation-0',
'mime-type': 'application/json',
data: {
base64:
'eyJuYW1lIjoiUHJvb2YgUmVxdWVzdCIsInZlcnNpb24iOiJQcm9vZiBSZXF1ZXN0Iiwibm9uY2UiOiIxMjM4NzU3NTMwMTU2IiwicmVxdWVzdGVkX2F0dHJpYnV0ZXMiOnsiYWRkaXRpb25hbFByb3AxIjp7Im5hbWVzIjpbImVtYWlsIiwiaXNzdWVyRElEIl0sInJlc3RyaWN0aW9ucyI6W3siY3JlZF9kZWZfaWQiOiJLbnd6NEtHOTd0YTZFbkM1QlQ3dUgzOjM6Q0w6MjQxOTAxOmdhaWEteCBwcmluY2lwYWwgbWVtYmVyIGNyZWRlbnRpYWwgMC4yIn1dfX0sInJlcXVlc3RlZF9wcmVkaWNhdGVzIjp7fX0=',
},
},
],
},
state: 'request-sent',
connectionId: 'b6724f85-a633-43ee-9c1c-736eaccbb6f9',
threadId: '34881067-b9fc-49a4-814d-dee4668b4f90',
};
jest
.spyOn(natsClient, 'getConnectionById')
.mockResolvedValueOnce(getAgentDetails);
jest.spyOn(restClient, 'get').mockResolvedValueOnce(result);
const res: any = await service.findProofByProofRecordId(
'117631fe-06c8-4b2c-9132-9e9f775709d8',
);
expect(res).toStrictEqual(result);
});
it('find connections by participant Id and status', async () => {
const repositoryResult: any = [
2,
[
{
id: '77e98b6d-cbd0-41e4-b878-8161888ff489',
proof_record_id: '698fa724-675b-437d-bee9-b9e86a520572',
participant_id: '66398cf4-e14d-4d92-9dc4-b40a48ae97dd',
connectionId: '',
credential_def_id:
'S2YLfsoaWyePckkhLDqn4j:3:CL:183415:gaia-x test new test',
schemaId: '',
their_did: '',
status: 'request-sent',
created_date: '2022-04-13T13:14:10.057Z',
updated_date: '2022-04-13T13:14:10.057Z',
},
{
id: 'c02f4723-510a-4966-b3fa-de7ef6d8f1aa',
proof_record_id: 'ab0b3681-eccb-4c5d-9c2f-4dabc1828255',
participant_id: '66398cf4-e14d-4d92-9dc4-b40a48ae97dd',
connectionId: 'b213f9bd-3774-40dd-8f1f-085950c10c30',
credential_def_id:
'TP6CJhQ9xuPnTPpVu1kinR:3:CL:221970:gaia-x test sprint 4',
schemaId: '',
their_did: '',
status: 'request-sent',
created_date: '2022-04-08T12:53:46.193Z',
updated_date: '2022-04-08T12:53:46.196Z',
},
],
];
const result: any = [
2,
[
{
id: '77e98b6d-cbd0-41e4-b878-8161888ff489',
proof_record_id: '698fa724-675b-437d-bee9-b9e86a520572',
participant_id: '66398cf4-e14d-4d92-9dc4-b40a48ae97dd',
connectionId: '',
credential_def_id:
'S2YLfsoaWyePckkhLDqn4j:3:CL:183415:gaia-x test new test',
schemaId: '',
their_did: '',
status: 'request-sent',
created_date: '2022-04-13T13:14:10.057Z',
updated_date: '2022-04-13T13:14:10.057Z',
},
{
id: 'c02f4723-510a-4966-b3fa-de7ef6d8f1aa',
proof_record_id: 'ab0b3681-eccb-4c5d-9c2f-4dabc1828255',
participant_id: '66398cf4-e14d-4d92-9dc4-b40a48ae97dd',
connectionId: 'b213f9bd-3774-40dd-8f1f-085950c10c30',
credential_def_id:
'TP6CJhQ9xuPnTPpVu1kinR:3:CL:221970:gaia-x test sprint 4',
schemaId: '',
their_did: '',
status: 'request-sent',
created_date: '2022-04-08T12:53:46.193Z',
updated_date: '2022-04-08T12:53:46.196Z',
},
],
];
jest
.spyOn(prismaService, '$transaction')
.mockResolvedValueOnce(repositoryResult);
const res: any = await service.findProofPresentation(0, 0);
expect(res).toStrictEqual(result);
});
});
describe('create presentation request function', () => {
it('create presentation request', async () => {
const serviceDto: any = [
{
proof_record_id: '698fa724-675b-437d-bee9-b9e86a520572',
participant_id: '66398cf4-e14d-4d92-9dc4-b40a48ae97dd',
connectionId: '',
credential_def_id:
'S2YLfsoaWyePckkhLDqn4j:3:CL:183415:gaia-x test new test',
schemaId: '',
status: 'request-sent',
created_date: '2022-04-13T13:14:10.057Z',
updated_date: '2022-04-13T13:14:10.057Z',
},
];
const repositoryResult: any = {
id: 'c7e06b9e-d796-4a54-b8f2-9746d3188c97',
proof_record_id: '117631fe-06c8-4b2c-9132-9e9f775709d8',
participant_id: '662dc769-a4de-4c95-934c-f6dab8cf432c',
connectionId: 'b6724f85-a633-43ee-9c1c-736eaccbb6f9',
credential_def_id:
'Knwz4KG97ta6EnC5BT7uH3:3:CL:241901:gaia-x principal member credential 0.2',
schemaId: '',
their_did: '',
status: 'request-sent',
created_date: '2022-04-26T08:18:18.644Z',
updated_date: '2022-04-26T08:18:18.646Z',
};
const result: any = {
id: 'c7e06b9e-d796-4a54-b8f2-9746d3188c97',
proof_record_id: '117631fe-06c8-4b2c-9132-9e9f775709d8',
participant_id: '662dc769-a4de-4c95-934c-f6dab8cf432c',
connectionId: 'b6724f85-a633-43ee-9c1c-736eaccbb6f9',
credential_def_id:
'Knwz4KG97ta6EnC5BT7uH3:3:CL:241901:gaia-x principal member credential 0.2',
schemaId: '',
their_did: '',
status: 'request-sent',
created_date: '2022-04-26T08:18:18.644Z',
updated_date: '2022-04-26T08:18:18.646Z',
};
jest
.spyOn(prismaService.proof, 'create')
.mockResolvedValueOnce(repositoryResult);
const res: any = await service.createPresentationRequest(serviceDto);
expect(res).toStrictEqual(result);
});
});
describe('send presentation request function', () => {
it('send presentation request', async () => {
const serviceDto: SendProofRequest = {
comment: 'Gaia-x Test',
attributes: [
{
attributeName: 'email',
value: '',
condition: '',
},
{
attributeName: 'issuerDID',
value: '',
condition: '',
},
],
credentialDefId:
'Knwz4KG97ta6EnC5BT7uH3:3:CL:241901:gaia-x principal member credential 0.2',
connectionId: 'b6724f85-a633-43ee-9c1c-736eaccbb6f9',
participantId: '',
proofRecordId: '',
};
const getAgentDetails: any = {
statusCode: 200,
message: 'Agent',
data: {
id: '15b9c7d6-8bc9-47cb-b78e-314e6c12bf16',
participant_id: '662dc769-a4de-4c95-934c-f6dab8cf432c',
agent_url: 'http://3.111.77.38:4001',
invitation_url:
'http://3.111.77.38:4001?c_i=eyJAdHlwZSI6ImRpZDpzb3Y6QnpDYnNOWWhNcmpIaXFaRFRVQVNIZztzcGVjL2Nvbm5lY3Rpb25zLzEuMC9pbnZpdGF0aW9uIiwiQGlkIjoiZGVhMGY1NTYtOWM4MS00OTcyLTkxZjktODhmNWQ3MDNlNDRiIiwibGFiZWwiOiJPcmdfT25lIiwicmVjaXBpZW50S2V5cyI6WyI0eFFSMVVCUXV0TGg5S2tFc1lLZ2FZNDg5VEFtMUtRTVREcnR4WEdQNnNQUiJdLCJzZXJ2aWNlRW5kcG9pbnQiOiJodHRwOi8vMy4xMTEuNzcuMzg6NDAwMSIsInJvdXRpbmdLZXlzIjpbXX0',
public_did: 'Knwz4KG97ta6EnC5BT7uH3',
wallet_name: 'Org_One',
service_endpoint: 'http://3.111.77.38:4000',
status: true,
created_by: '662dc769-a4de-4c95-934c-f6dab8cf432c',
created_date: '2022-04-14T16:33:14.152Z',
updated_by: '662dc769-a4de-4c95-934c-f6dab8cf432c',
updated_date: '2022-04-26T06:03:32.178Z',
},
};
const natsConnectionIdResponce: any = {
id: '480f4738-3d34-4b80-8160-d59e7ad91b52',
connectionId: 'b6724f85-a633-43ee-9c1c-736eaccbb6f9',
participantId: '662dc769-a4de-4c95-934c-f6dab8cf432c',
status: 'complete',
participantDid: 'SQVgKy9CHSYN2TLRsg999E',
theirDid: '4D9hPSoWZLCkrCr57pqMqs',
theirLabel: 'Org_Two',
createdDate: '2022-04-26T08:17:45.295Z',
updatedDate: '2022-04-26T08:18:02.218Z',
isActive: false,
};
const result: any = {
_tags: {},
metadata: {},
id: '10ff9df7-c98b-48d4-b540-d5df0d91f7cd',
createdAt: '2022-04-26T10:02:59.310Z',
requestMessage: {
'@type': 'https://didcomm.org/present-proof/1.0/request-presentation',
'@id': 'cb5df550-36a4-4cba-8afc-3b89cedbc6bb',
comment: 'Gaia-x Test',
'request_presentations~attach': [[Object]],
},
state: 'request-sent',
connectionId: 'b6724f85-a633-43ee-9c1c-736eaccbb6f9',
threadId: 'cb5df550-36a4-4cba-8afc-3b89cedbc6bb',
participantId: '662dc769-a4de-4c95-934c-f6dab8cf432c',
theirDid: '4D9hPSoWZLCkrCr57pqMqs',
};
jest
.spyOn(natsClient, 'getConnectionById')
.mockResolvedValueOnce(natsConnectionIdResponce);
jest
.spyOn(natsClient, 'getConnectionById')
.mockResolvedValueOnce(getAgentDetails);
jest.spyOn(restClient, 'post').mockResolvedValueOnce(result);
const res: any = await service.sendPresentationRequest(serviceDto);
expect(res).toStrictEqual(result);
});
});
describe('send out of band presentation request function', () => {
it('send out of band presentation request', async () => {
const serviceDto: SendProofRequest = {
comment: 'Gaia-x Test',
attributes: [
{
attributeName: 'email',
value: '',
condition: '',
},
{
attributeName: 'issuerDID',
value: '',
condition: '',
},
],
credentialDefId:
'Knwz4KG97ta6EnC5BT7uH3:3:CL:241901:gaia-x principal member credential 0.2',
connectionId: '',
participantId: '662dc769-a4de-4c95-934c-f6dab8cf432c',
proofRecordId: '',
};
const getAgentDetails: any = {
statusCode: 200,
message: 'Agent',
data: {
id: '15b9c7d6-8bc9-47cb-b78e-314e6c12bf16',
participant_id: '662dc769-a4de-4c95-934c-f6dab8cf432c',
agent_url: 'http://3.111.77.38:4001',
invitation_url:
'http://3.111.77.38:4001?c_i=eyJAdHlwZSI6ImRpZDpzb3Y6QnpDYnNOWWhNcmpIaXFaRFRVQVNIZztzcGVjL2Nvbm5lY3Rpb25zLzEuMC9pbnZpdGF0aW9uIiwiQGlkIjoiZGVhMGY1NTYtOWM4MS00OTcyLTkxZjktODhmNWQ3MDNlNDRiIiwibGFiZWwiOiJPcmdfT25lIiwicmVjaXBpZW50S2V5cyI6WyI0eFFSMVVCUXV0TGg5S2tFc1lLZ2FZNDg5VEFtMUtRTVREcnR4WEdQNnNQUiJdLCJzZXJ2aWNlRW5kcG9pbnQiOiJodHRwOi8vMy4xMTEuNzcuMzg6NDAwMSIsInJvdXRpbmdLZXlzIjpbXX0',
public_did: 'Knwz4KG97ta6EnC5BT7uH3',
wallet_name: 'Org_One',
service_endpoint: 'http://3.111.77.38:4000',
status: true,
created_by: '662dc769-a4de-4c95-934c-f6dab8cf432c',
created_date: '2022-04-14T16:33:14.152Z',
updated_by: '662dc769-a4de-4c95-934c-f6dab8cf432c',
updated_date: '2022-04-26T06:03:32.178Z',
},
};
const result: any = {
_tags: {},
metadata: {},
id: '10ff9df7-c98b-48d4-b540-d5df0d91f7cd',
createdAt: '2022-04-26T10:02:59.310Z',
requestMessage: {
'@type': 'https://didcomm.org/present-proof/1.0/request-presentation',
'@id': 'cb5df550-36a4-4cba-8afc-3b89cedbc6bb',
comment: 'Gaia-x Test',
'request_presentations~attach': [[Object]],
},
state: 'request-sent',
connectionId: 'b6724f85-a633-43ee-9c1c-736eaccbb6f9',
threadId: 'cb5df550-36a4-4cba-8afc-3b89cedbc6bb',
participantId: '662dc769-a4de-4c95-934c-f6dab8cf432c',
theirDid: '4D9hPSoWZLCkrCr57pqMqs',
};
jest
.spyOn(natsClient, 'getConnectionById')
.mockResolvedValueOnce(getAgentDetails);
jest.spyOn(restClient, 'post').mockResolvedValueOnce(result);
const res: any =
await service.sendOutOfBandPresentationRequest(serviceDto);
expect(res).toStrictEqual(result);
});
});
describe('send membership credential presentation request function', () => {
it('send membership credential presentation request', async () => {
const serviceDto: MembershipCredentialDto = {
attributes: [
{
attributeName: 'email',
},
{
attributeName: 'issuerDID',
},
],
connectionId: '',
participant_id: '662dc769-a4de-4c95-934c-f6dab8cf432c',
schemaId: '',
};
const getAgentDetails: any = {
statusCode: 200,
message: 'Agent',
data: {
id: '15b9c7d6-8bc9-47cb-b78e-314e6c12bf16',
participant_id: '662dc769-a4de-4c95-934c-f6dab8cf432c',
agent_url: 'http://3.111.77.38:4001',
invitation_url:
'http://3.111.77.38:4001?c_i=eyJAdHlwZSI6ImRpZDpzb3Y6QnpDYnNOWWhNcmpIaXFaRFRVQVNIZztzcGVjL2Nvbm5lY3Rpb25zLzEuMC9pbnZpdGF0aW9uIiwiQGlkIjoiZGVhMGY1NTYtOWM4MS00OTcyLTkxZjktODhmNWQ3MDNlNDRiIiwibGFiZWwiOiJPcmdfT25lIiwicmVjaXBpZW50S2V5cyI6WyI0eFFSMVVCUXV0TGg5S2tFc1lLZ2FZNDg5VEFtMUtRTVREcnR4WEdQNnNQUiJdLCJzZXJ2aWNlRW5kcG9pbnQiOiJodHRwOi8vMy4xMTEuNzcuMzg6NDAwMSIsInJvdXRpbmdLZXlzIjpbXX0',
public_did: 'Knwz4KG97ta6EnC5BT7uH3',
wallet_name: 'Org_One',
service_endpoint: 'http://3.111.77.38:4000',
status: true,
created_by: '662dc769-a4de-4c95-934c-f6dab8cf432c',
created_date: '2022-04-14T16:33:14.152Z',
updated_by: '662dc769-a4de-4c95-934c-f6dab8cf432c',
updated_date: '2022-04-26T06:03:32.178Z',
},
};
const result: any = {
_tags: {},
metadata: {},
id: '10ff9df7-c98b-48d4-b540-d5df0d91f7cd',
createdAt: '2022-04-26T10:02:59.310Z',
requestMessage: {
'@type': 'https://didcomm.org/present-proof/1.0/request-presentation',
'@id': 'cb5df550-36a4-4cba-8afc-3b89cedbc6bb',
comment: 'Gaia-x Test',
'request_presentations~attach': [[Object]],
},
state: 'request-sent',
connectionId: 'b6724f85-a633-43ee-9c1c-736eaccbb6f9',
threadId: 'cb5df550-36a4-4cba-8afc-3b89cedbc6bb',
participantId: '662dc769-a4de-4c95-934c-f6dab8cf432c',
theirDid: '4D9hPSoWZLCkrCr57pqMqs',
};
jest
.spyOn(natsClient, 'getConnectionById')
.mockResolvedValueOnce(getAgentDetails);
jest.spyOn(restClient, 'post').mockResolvedValueOnce(result);
const res: any =
await service.sendPrincipalCredentialPresentationRequest(serviceDto);
expect(res).toStrictEqual(result);
});
});
});
import type GetPresentProofsDto from '../entities/get-present-proofs.dto.js';
import type GetProofRequest from '../entities/get-proof-request.dto.js';
import type MembershipCredentialDto from '../entities/membership-credential.dto.js';
import type PresentationSubscriptionEndpointDto from '../entities/presentationSubscribeEndPoint.entity.js';
import type SendProofRequest from '../entities/send-proof-request.dto.js';
import type { Prisma } from '@prisma/client';
import { HttpService } from '@nestjs/axios';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { lastValueFrom, map } from 'rxjs';
import NatsClientService from '../../client/nats.client.js';
import RestClientService from '../../client/rest.client.js';
import PrismaService from '../../prisma/prisma.service.js';
import logger from '../../utils/logger.js';
import pagination from '../../utils/pagination.js';
import PresentationProofRepository from '../repository/presentationProof.respository.js';
@Injectable()
export default class PresentationProofsService {
private presentationProofRepository;
private agentURL;
private didcommUrl;
public constructor(
private readonly natsClient: NatsClientService,
private readonly prismaService: PrismaService,
private readonly httpService: HttpService,
private readonly restClient: RestClientService,
private readonly configService: ConfigService,
) {
this.presentationProofRepository = new PresentationProofRepository(
this.prismaService,
);
this.agentURL = this.configService.get('agent').agentUrl;
this.didcommUrl = this.configService.get('agent').didcommUrl;
}
public getAppUrl() {
return this.configService.get('APP_URL');
}
public static readonly connectionStatus = {
TRUSTED: 'trusted',
};
public async findProofByProofRecordId(proof_record_id: string) {
return this.restClient.get(`${this.agentURL}/proofs/${proof_record_id}`);
}
public async findProofPresentation(
pageSize: number,
page: number,
proofRecordId?: string | false,
connectionId?: string | false,
credentialDefId?: string | false,
schemaId?: string | false,
theirDid?: string | false,
status?: string | false,
createdDateStart?: string | false,
createdDateEnd?: string | false,
updatedDateStart?: string | false,
updatedDateEnd?: string | false,
) {
let query: {
skip?: number;
take?: number;
cursor?: Prisma.ProofWhereUniqueInput;
where: Prisma.ProofWhereInput;
orderBy?: Prisma.ProofOrderByWithRelationInput;
} = {
where: {},
};
if (status) {
const states: string[] = status.split(',');
query.where.status = { in: states };
}
if (proofRecordId) {
query.where.proofRecordId = proofRecordId;
}
if (connectionId) {
query.where.connectionId = connectionId;
}
if (credentialDefId) {
query.where.credentialDefId = credentialDefId;
}
if (schemaId) {
query.where.schemaId = schemaId;
}
if (theirDid) {
query.where.theirDid = theirDid;
}
if (createdDateStart) {
query.where.createdDate = { gte: createdDateStart };
}
if (createdDateEnd) {
// eslint-disable-next-line prefer-object-spread
query.where.createdDate = Object.assign({}, query.where.createdDate, {
lte: createdDateEnd,
});
}
if (updatedDateStart) {
query.where.updatedDate = { gte: updatedDateStart };
}
if (updatedDateEnd) {
// eslint-disable-next-line prefer-object-spread
query.where.updatedDate = Object.assign({}, query.where.updatedDate, {
lte: updatedDateEnd,
});
}
query = { ...query, ...pagination(pageSize, page) };
return this.presentationProofRepository.findProofPresentation(query);
}
public async createPresentationRequest(sendProofRequest: SendProofRequest) {
const query: Prisma.ProofCreateInput = {
proofRecordId: sendProofRequest.proofRecordId || '',
connectionId: sendProofRequest.connectionId,
status: sendProofRequest.status,
};
return this.presentationProofRepository.createPresentationProof(query);
}
public async getConnectionByID(connectionID: string) {
const connection = await this.natsClient.getConnectionById(connectionID);
return connection;
}
public async sendPresentationRequest(sendProofRequest: SendProofRequest) {
const getPayloadRes =
PresentationProofsService.createCommonPresentationRequestPaylod(
sendProofRequest,
);
const proofRequestPayload = {
comment: getPayloadRes.comment,
connectionId: sendProofRequest.connectionId,
// trace: true,
autoAcceptProof: 'always',
proofRequest: {
name: 'Proof Request',
version: '1.0',
// nonce: getPayloadRes.nonce.toString(),
requested_attributes: getPayloadRes.requested_attributes,
requested_predicates: getPayloadRes.requested_predicates,
ver: '1.0',
},
};
logger.info(
`proofRequestPayload for proof request ${JSON.stringify(
proofRequestPayload,
)}`,
);
let responseData = null;
const getConnection = await this.getConnectionByID(
sendProofRequest.connectionId || '',
);
if (
getConnection?.status !==
PresentationProofsService.connectionStatus.TRUSTED
) {
responseData = {
message: 'Connection is not trusted',
};
return responseData;
}
responseData = await this.restClient.post(
`${this.agentURL}/proofs/request-proof`,
proofRequestPayload,
);
responseData.theirDid = getConnection.theirDid;
return responseData;
}
public static createCommonPresentationRequestPaylod(
sendProofRequest: SendProofRequest,
) {
const requestedAttributes: {
[key: string]: {
names: string[];
restrictions: {
schema_id?: string;
cred_def_id?: string;
}[];
};
} = {};
const requestedPredicates: {
[key: string]: Record<string, Array<object> | number>;
} = {};
const generateNonce: number = Math.floor(Math.random() * 10000000000000);
const comment = sendProofRequest.comment ? sendProofRequest.comment : '';
for (let i = 0; i < sendProofRequest.attributes.length; i += 1) {
const attribute = sendProofRequest.attributes[i];
const key = `${attribute.schemaId}_${attribute.credentialDefId}`;
requestedAttributes[key] = requestedAttributes[key] || {
names: [],
restrictions: [],
};
if (attribute.schemaId) {
requestedAttributes[key].restrictions[0] =
requestedAttributes[key].restrictions[0] || {};
requestedAttributes[key].restrictions[0].schema_id = attribute.schemaId;
}
if (attribute.credentialDefId) {
requestedAttributes[key].restrictions[0] =
requestedAttributes[key].restrictions[0] || {};
requestedAttributes[key].restrictions[0].cred_def_id =
attribute.credentialDefId;
}
if (attribute.attributeName) {
requestedAttributes[key].names.push(attribute.attributeName);
}
}
const payload = {
comment,
nonce: generateNonce.toString(),
requested_attributes: Object.fromEntries(
Object.entries(requestedAttributes).map(([, value], index) => [
`additionalProp${index + 1}`,
value,
]),
),
requested_predicates: requestedPredicates,
};
return payload;
}
public async sendOutOfBandPresentationRequest(
sendProofRequest: SendProofRequest,
) {
const getPayloadRes =
PresentationProofsService.createCommonPresentationRequestPaylod(
sendProofRequest,
);
const proofRequestPayload = {
comment: getPayloadRes.comment,
autoAcceptProof: 'always',
proofRequest: {
name: 'Out Of Band Proof Request',
version: '1.0',
nonce: getPayloadRes.nonce.toString(),
requested_attributes: getPayloadRes.requested_attributes,
requested_predicates: getPayloadRes.requested_predicates,
ver: '1.0',
},
};
let responseData = null;
responseData = await this.restClient.post(
`${this.agentURL}/proofs/request-outofband-proof`,
proofRequestPayload,
);
const shortRow = await this.presentationProofRepository.createShortUrl(
responseData.message,
);
const appUrl = this.getAppUrl();
responseData.messageShort = `${appUrl}/v1/url/${shortRow.id}`;
return responseData;
}
public async sendPrincipalCredentialPresentationRequest(
sendProofRequest: MembershipCredentialDto,
) {
const requestedAttributes: {
[key: string]: Record<string, Array<{ schema_id: string }>>;
} = {};
const requestedPredicates: {
[key: string]: Record<string, Array<object> | number>;
} = {};
const generateNonce: number = Math.floor(Math.random() * 10000000000000);
const comment = '';
for (
let index = 0;
index < sendProofRequest.attributes.length;
index += 1
) {
const attributeElement = sendProofRequest.attributes[index];
const attributeReferent = `additionalProp${index + 1}`;
const keys = Object.keys(requestedAttributes);
if (keys.length > 0) {
keys.forEach((attr, i) => {
if (
attributeElement.schemaId &&
requestedAttributes[attr].restrictions[i].schema_id ===
attributeElement.schemaId
) {
requestedAttributes[attr].names.push({
schema_id: attributeElement.schemaId,
});
} else if (keys.length === i + 1) {
requestedAttributes[attributeReferent] = {
names: [attributeElement.attributeName],
restrictions: [
{
schema_id: attributeElement.schemaId || '',
},
],
} as any; // eslint-disable-line @typescript-eslint/no-explicit-any
}
});
} else {
requestedAttributes[attributeReferent] = {
names: [attributeElement.attributeName],
restrictions: [
{
schema_id: attributeElement.schemaId || '',
},
],
} as any; // eslint-disable-line @typescript-eslint/no-explicit-any
}
}
const proofRequestPayload = {
comment,
connectionId: sendProofRequest.connectionId,
trace: true,
proofRequest: {
name: 'Membership Credential Proof Request',
version: '1.0',
nonce: generateNonce.toString(),
requested_attributes: requestedAttributes,
requested_predicates: requestedPredicates,
},
};
let responseData = null;
responseData = await this.restClient.post(
`${this.agentURL}/proofs/request-proof`,
proofRequestPayload,
);
return responseData;
}
public async updatePresentationStatus(getProofRequest: GetProofRequest) {
const getRes =
await this.presentationProofRepository.updatePresentationStatus({
where: { proofRecordId: getProofRequest.id },
data: {
status: getProofRequest.state,
updatedDate: new Date(),
},
});
return getRes;
}
public async acceptPresentation(proof_record_id: string) {
return lastValueFrom(
this.httpService
.post(`${this.agentURL}/proofs/${proof_record_id}/accept-presentation`)
.pipe(map((response) => response.data)),
);
}
public async acceptProofRequest(proofRecordId: string) {
return lastValueFrom(
this.httpService
.post(`${this.agentURL}/proofs/${proofRecordId}/accept-request`)
.pipe(map((response) => response.data)),
);
}
public async deleteProofRequest(proofRecordId: string) {
const response = lastValueFrom(
this.httpService
.delete(`${this.agentURL}/proofs/${proofRecordId}`)
.pipe(map((response) => response.data)),
);
await this.presentationProofRepository.deleteProofRequest(proofRecordId);
return response;
}
public async declineProofRequest(proofRecordId: string) {
return lastValueFrom(
this.httpService
.post(`${this.didcommUrl}/v1/agent/proofs/declineRequest`, {
data: [proofRecordId],
})
.pipe(map((response) => response.data)),
);
}
public async getAllProofRequest(threadId: string) {
const url = threadId
? `${this.agentURL}/proofs/?threadId=${threadId}`
: `${this.agentURL}/proofs/`;
return lastValueFrom(
this.httpService.get(url).pipe(map((response) => response.data)),
);
}
public async getSchemaById(schemaId: string) {
const url = `${this.agentURL}/schemas/${schemaId}`;
return lastValueFrom(
this.httpService.get(url).pipe(map((response) => response.data)),
);
}
public async getCredentialDefinitionsById(credentialDefinitionsId: string) {
const url = `${this.agentURL}/credential-definitions/${credentialDefinitionsId}`;
return lastValueFrom(
this.httpService.get(url).pipe(map((response) => response.data)),
);
}
public publishPresentationSubscriberEndpoint(
data: PresentationSubscriptionEndpointDto,
) {
this.natsClient.publishPresentation(data);
}
public getCredentialsTypeDetails(type: string) {
return this.natsClient.getCredentialsTypeDetails(type);
}
public makeConnectionTrusted(connectionId: string) {
return this.natsClient.makeConnectionTrusted(connectionId);
}
public async getPresentProofs(data: GetPresentProofsDto) {
return this.presentationProofRepository.findProofPresentation({
where: {
connectionId: data.connectionId,
},
});
}
public async findUrlByShortUrlId(id: string) {
return this.presentationProofRepository.getShortUrl(id);
}
}
import PrismaModule from './prisma.module';
describe('Check if the module is working', () => {
it('should be defined', () => {
expect(PrismaModule).toBeDefined();
});
});
import { Module } from '@nestjs/common';
import PrismaService from './prisma.service.js';
@Module({
providers: [PrismaService],
exports: [PrismaService],
})
export default class PrismaModule {}
import type { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaClient } from '@prisma/client';
@Injectable()
export default class PrismaService
extends PrismaClient
implements OnModuleInit, OnModuleDestroy
{
public constructor(configService: ConfigService) {
super({
datasources: {
db: {
url: configService.get('DATABASE_URL'),
},
},
});
}
public async onModuleInit() {
await this.$connect();
}
public async onModuleDestroy() {
await this.$disconnect();
}
}
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Proof {
id String @id @default(uuid())
proofRecordId String @unique @map("proof_record_id")
connectionId String @default("") @map("connection_id")
credentialDefId String @default("") @map("credential_def_id")
schemaId String @default("") @map("schema_id")
theirDid String @default("") @map("their_did")
status String @default("")
createdDate DateTime @default(now()) @map("created_date")
updatedDate DateTime @default(now()) @map("updated_date")
}
model ShortUrl {
id String @id @default(uuid())
originalUrl String
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment