From 7461529ca4a0b54c10ba5f45ccad18fc4c763b1a Mon Sep 17 00:00:00 2001 From: varsha766 Date: Thu, 19 Sep 2024 15:08:00 +0530 Subject: [PATCH 1/8] fixed dto related issue --- .../services/credential.ssi.service.ts | 5 +- src/did/dto/sign-did.dto.ts | 53 ++++++++++--------- src/did/dto/verify-did.dto.ts | 28 +++++++++- src/did/services/did.service.ts | 22 ++++++-- 4 files changed, 77 insertions(+), 31 deletions(-) diff --git a/src/credential/services/credential.ssi.service.ts b/src/credential/services/credential.ssi.service.ts index 742043bb..d74c9ece 100644 --- a/src/credential/services/credential.ssi.service.ts +++ b/src/credential/services/credential.ssi.service.ts @@ -10,7 +10,10 @@ export class CredentialSSIService { private readonly config: ConfigService, private readonly hidWallet: HidWalletService, ) {} - async initateHypersignVC(mnemonic: string,namespace: string): Promise { + async initateHypersignVC( + mnemonic: string, + namespace: string, + ): Promise { Logger.log('InitateHypersignVC(): starts....', 'CredentialSSIService'); const nodeRpcEndpoint = this.config.get('HID_NETWORK_RPC'); const nodeRestEndpoint = this.config.get('HID_NETWORK_API'); diff --git a/src/did/dto/sign-did.dto.ts b/src/did/dto/sign-did.dto.ts index 01327f87..7be7f4ee 100644 --- a/src/did/dto/sign-did.dto.ts +++ b/src/did/dto/sign-did.dto.ts @@ -85,35 +85,19 @@ export class SignedDidDocument extends DidDoc { }) proof: Proof; } - -export class BaseDidDto { - @ApiProperty({ - name: 'didDocument', - description: 'didDocument', - type: DidDoc, - required: false, - }) - didDocument: any; - @ApiProperty({ - description: 'Verification Method id for did registration', - example: 'did:hid:testnet:........#key-${idx}', - required: true, - }) - @ValidateVerificationMethodId() - @IsString() - @Matches(/^[a-zA-Z0-9\:]*testnet[a-zA-Z0-9\-:#]*$/, { - message: "Did's namespace should be testnet", - }) // this is to validate if did is generated using empty namespace - verificationMethodId: string; +export class DidSignOption { @ApiProperty({ name: 'purpose', description: 'purpose for signing didDocument', example: 'authentication', - required: true, + required: false, + enum: SupportedPurpose, + default: SupportedPurpose.assertionMethod, }) + @IsOptional() @IsString() @IsEnum(SupportedPurpose) - purpose: SupportedPurpose; + purpose?: SupportedPurpose; @ApiProperty({ name: 'challenge', description: @@ -134,8 +118,7 @@ export class BaseDidDto { @IsString() domain: string; } - -export class SignDidDto extends BaseDidDto { +export class SignDidDto { @ApiProperty({ name: 'didDocument', description: 'didDocument', @@ -157,4 +140,26 @@ export class SignDidDto extends BaseDidDto { @IsDid() @IsString() did: string; + + @ApiProperty({ + description: 'Verification Method id for did registration', + example: 'did:hid:testnet:........#key-${idx}', + required: true, + }) + @ValidateVerificationMethodId() + @IsString() + @Matches(/^[a-zA-Z0-9\:]*testnet[a-zA-Z0-9\-:#]*$/, { + message: "Did's namespace should be testnet", + }) + verificationMethodId: string; + @ApiProperty({ + name: 'options', + description: 'optional parameter', + type: DidSignOption, + required: false, + }) + @IsOptional() + @Type(() => DidSignOption) + @ValidateNested({ each: true }) + options?: DidSignOption; } diff --git a/src/did/dto/verify-did.dto.ts b/src/did/dto/verify-did.dto.ts index 2c0a0633..2c0bb944 100644 --- a/src/did/dto/verify-did.dto.ts +++ b/src/did/dto/verify-did.dto.ts @@ -1,17 +1,19 @@ import { ApiProperty } from '@nestjs/swagger'; -import { BaseDidDto, Proof, SignedDidDocument } from './sign-did.dto'; +import { DidSignOption, Proof, SignedDidDocument } from './sign-did.dto'; import { IsBoolean, IsNotEmptyObject, IsOptional, IsString, + Matches, ValidateNested, } from 'class-validator'; import { Type } from 'class-transformer'; import { DidDoc } from './update-did.dto'; import { IKeyType } from 'hs-ssi-sdk'; +import { ValidateVerificationMethodId } from 'src/utils/customDecorator/vmId.decorator'; -export class VerifyDidDto extends BaseDidDto { +export class VerifyDidDto { @ApiProperty({ name: 'didDocument', description: 'didDocument', @@ -22,6 +24,28 @@ export class VerifyDidDto extends BaseDidDto { @Type(() => SignedDidDocument) @ValidateNested({ each: true }) didDocument: SignedDidDocument; + @ApiProperty({ + description: 'Verification Method id for did registration', + example: 'did:hid:testnet:........#key-${idx}', + required: true, + }) + @ValidateVerificationMethodId() + @IsString() + @Matches(/^[a-zA-Z0-9\:]*testnet[a-zA-Z0-9\-:#]*$/, { + message: "Did's namespace should be testnet", + }) // this is to validate if did is generated using empty namespace + verificationMethodId: string; + + @ApiProperty({ + name: 'options', + description: 'optional parameter', + type: DidSignOption, + required: false, + }) + @IsOptional() + @Type(() => DidSignOption) + @ValidateNested({ each: true }) + options?: DidSignOption; } export class Controller { diff --git a/src/did/services/did.service.ts b/src/did/services/did.service.ts index b96c5552..acb90af6 100644 --- a/src/did/services/did.service.ts +++ b/src/did/services/did.service.ts @@ -19,6 +19,7 @@ import { IKeyType, IClientSpec, Did, + SupportedPurpose, } from 'hs-ssi-sdk'; import { DidRepository, DidMetaDataRepo } from '../repository/did.repository'; import { Slip10RawIndex } from '@cosmjs/crypto'; @@ -780,8 +781,11 @@ export class DidService { namespace, ); let { didDocument } = signDidDto; - const { verificationMethodId, purpose, did, domain, challenge } = - signDidDto; + const { verificationMethodId, did } = signDidDto; + const purpose = + signDidDto?.options?.purpose || SupportedPurpose.assertionMethod; + const domain = signDidDto?.options?.domain; + const challenge = signDidDto?.options?.challenge; if (!didDocument) { const didDocToBeSigned = await hypersignDid.resolve({ did: signDidDto.did ?? did, @@ -802,7 +806,7 @@ export class DidService { verificationMethodId, domain, challenge, - purpose: purpose, + purpose, }); return signedDidDocument; } @@ -822,7 +826,17 @@ export class DidService { appMenemonic, namespace, ); - const params = { ...verifyDidDto }; + const purpose = + verifyDidDto?.options?.purpose || SupportedPurpose.assertionMethod; + const domain = verifyDidDto?.options?.domain; + const challenge = verifyDidDto?.options?.challenge; + const params = { + didDocument: verifyDidDto.didDocument, + verificationMethodId: verifyDidDto.verificationMethodId, + domain, + challenge, + purpose, + }; const verifiedDidDocument = await hypersignDid.verify(params); return verifiedDidDocument; } From 2f62188846563b342ddfffcc48516eae62464ab4 Mon Sep 17 00:00:00 2001 From: varsha766 Date: Thu, 19 Sep 2024 15:44:40 +0530 Subject: [PATCH 2/8] updated api path and updated dto --- src/did/controllers/did.controller.ts | 5 ++--- src/did/dto/verify-did.dto.ts | 30 ++++----------------------- src/did/services/did.service.ts | 13 ++++++------ 3 files changed, 13 insertions(+), 35 deletions(-) diff --git a/src/did/controllers/did.controller.ts b/src/did/controllers/did.controller.ts index a433cff3..e28d23b5 100644 --- a/src/did/controllers/did.controller.ts +++ b/src/did/controllers/did.controller.ts @@ -224,7 +224,7 @@ export class DidController { return this.didService.addVerificationMethod(addVm); } - @Post('/sign') + @Post('/auth/sign') @ApiOkResponse({ description: 'DidDocument is signed successfully', type: SignedDidDocument, @@ -254,7 +254,7 @@ export class DidController { Logger.log('SignDidDocument() method: starts', 'DidController'); return this.didService.SignDidDocument(signDidDocDto, req.user); } - @Post('/verify') + @Post('/auth/verify') @ApiOkResponse({ description: 'DidDocument is verified successfully', type: VerifyDidDocResponseDto, @@ -275,7 +275,6 @@ export class DidController { required: false, }) @UsePipes(ValidationPipe) - @UsePipes(new AtLeastOneParamPipe(['did', 'didDocument'])) VerifyDidDocument( @Headers('Authorization') authorization: string, @Req() req: any, diff --git a/src/did/dto/verify-did.dto.ts b/src/did/dto/verify-did.dto.ts index 2c0bb944..34a2881e 100644 --- a/src/did/dto/verify-did.dto.ts +++ b/src/did/dto/verify-did.dto.ts @@ -15,37 +15,15 @@ import { ValidateVerificationMethodId } from 'src/utils/customDecorator/vmId.dec export class VerifyDidDto { @ApiProperty({ - name: 'didDocument', - description: 'didDocument', - type: DidDoc, + name: 'signedDidDocument', + description: 'signedDidDocument', + type: SignedDidDocument, }) @IsOptional() @IsNotEmptyObject() @Type(() => SignedDidDocument) @ValidateNested({ each: true }) - didDocument: SignedDidDocument; - @ApiProperty({ - description: 'Verification Method id for did registration', - example: 'did:hid:testnet:........#key-${idx}', - required: true, - }) - @ValidateVerificationMethodId() - @IsString() - @Matches(/^[a-zA-Z0-9\:]*testnet[a-zA-Z0-9\-:#]*$/, { - message: "Did's namespace should be testnet", - }) // this is to validate if did is generated using empty namespace - verificationMethodId: string; - - @ApiProperty({ - name: 'options', - description: 'optional parameter', - type: DidSignOption, - required: false, - }) - @IsOptional() - @Type(() => DidSignOption) - @ValidateNested({ each: true }) - options?: DidSignOption; + signedDidDocument: SignedDidDocument; } export class Controller { diff --git a/src/did/services/did.service.ts b/src/did/services/did.service.ts index acb90af6..ca76cf76 100644 --- a/src/did/services/did.service.ts +++ b/src/did/services/did.service.ts @@ -826,13 +826,14 @@ export class DidService { appMenemonic, namespace, ); - const purpose = - verifyDidDto?.options?.purpose || SupportedPurpose.assertionMethod; - const domain = verifyDidDto?.options?.domain; - const challenge = verifyDidDto?.options?.challenge; + const purpose = verifyDidDto.signedDidDocument.proof + .proofPurpose as SupportedPurpose; + const domain = verifyDidDto?.signedDidDocument.proof?.domain; + const challenge = verifyDidDto?.signedDidDocument.proof?.challenge; const params = { - didDocument: verifyDidDto.didDocument, - verificationMethodId: verifyDidDto.verificationMethodId, + didDocument: verifyDidDto.signedDidDocument, + verificationMethodId: + verifyDidDto.signedDidDocument.proof.verificationMethod, domain, challenge, purpose, From f26a25a0c32891ddd0918de075b9d10847f75202 Mon Sep 17 00:00:00 2001 From: varsha766 Date: Sun, 13 Oct 2024 21:02:11 +0530 Subject: [PATCH 3/8] implemetned new keytype bjj --- src/did/controllers/did.controller.ts | 54 +- src/did/dto/create-did.dto.ts | 35 +- src/did/dto/register-did.dto.ts | 68 +++ src/did/services/did.service.ts | 462 ++++++++++++++++-- src/did/services/did.ssi.service.ts | 40 +- src/main.ts | 1 - .../services/presentation.service.ts | 102 +++- .../customDecorator/keyType.decorator.ts | 84 ++++ 8 files changed, 747 insertions(+), 99 deletions(-) create mode 100644 src/utils/customDecorator/keyType.decorator.ts diff --git a/src/did/controllers/did.controller.ts b/src/did/controllers/did.controller.ts index e28d23b5..96ece102 100644 --- a/src/did/controllers/did.controller.ts +++ b/src/did/controllers/did.controller.ts @@ -46,7 +46,7 @@ import { PaginationDto } from 'src/utils/pagination.dto'; import { Did } from '../schemas/did.schema'; import { DidResponseInterceptor } from '../interceptors/transformResponse.interseptor'; import { GetDidList } from '../dto/fetch-did.dto'; -import { RegisterDidDto } from '../dto/register-did.dto'; +import { RegisterDidDto, RegisterV2DidDto } from '../dto/register-did.dto'; import { IKeyType } from 'hs-ssi-sdk'; import { AtLeastOneParamPipe } from 'src/utils/Pipes/atleastOneParam.pipe'; import { AddVMResponse, AddVerificationMethodDto } from '../dto/addVm.dto'; @@ -169,7 +169,13 @@ export class DidController { Logger.log('create() method: starts', 'DidController'); const { options } = createDidDto; const appDetail = req.user; - switch (options?.keyType) { + const keyTypes = Array.isArray(options?.keyType) + ? options.keyType + : options?.keyType + ? [options.keyType] + : [IKeyType.Ed25519VerificationKey2020]; + const keyTypeAtZeroIndex = keyTypes[0]; + switch (keyTypeAtZeroIndex) { case IKeyType.EcdsaSecp256k1RecoveryMethod2020: { const response = this.didService.createByClientSpec( createDidDto, @@ -186,9 +192,21 @@ export class DidController { return classToPlain(response, { excludePrefixes: ['transactionHash'] }); } + case IKeyType.BabyJubJubKey2021: { + const response = this.didService.createBjjDid( + createDidDto, + appDetail, + keyTypes, + ); + return classToPlain(response, { excludePrefixes: ['transactionHash'] }); + } default: - const response = this.didService.create(createDidDto, appDetail); + const response = this.didService.create( + createDidDto, + appDetail, + keyTypes, + ); return classToPlain(response, { excludePrefixes: ['transactionHash'] }); } } @@ -352,4 +370,34 @@ export class DidController { const appDetail = req.user; return this.didService.updateDid(updateDidDto, appDetail); } + @ApiOkResponse({ + description: 'DID Registred', + type: RegisterDidResponse, + }) + @ApiBadRequestResponse({ + status: 400, + description: 'Error occured at the time of creating did', + type: DidError, + }) + @ApiHeader({ + name: 'Authorization', + description: 'Bearer ', + required: false, + }) + @ApiHeader({ + name: 'Origin', + description: 'Origin as you set in application cors', + required: false, + }) + @UsePipes(ValidationPipe) + @Post('register/v2') + registerV2( + @Headers('Authorization') authorization: string, + @Body() registerV2Dto: RegisterV2DidDto, + @Req() req: any, + ) { + Logger.log('registerV2() method: starts', 'DidController'); + const appDetail = req.user; + return this.didService.registerV2(registerV2Dto, appDetail); + } } diff --git a/src/did/dto/create-did.dto.ts b/src/did/dto/create-did.dto.ts index 3e17548b..b77b0b24 100644 --- a/src/did/dto/create-did.dto.ts +++ b/src/did/dto/create-did.dto.ts @@ -16,6 +16,7 @@ import { DidDoc } from '../dto/update-did.dto'; import { IsDid } from 'src/utils/customDecorator/did.decorator'; import { ValidatePublicKeyMultibase } from 'src/utils/customDecorator/pubKeyMultibase.decorator'; import { IVerificationRelationships, IKeyType } from 'hs-ssi-sdk'; +import { IsKeyTypeArrayOrSingle } from 'src/utils/customDecorator/keyType.decorator'; export enum Namespace { testnet = 'testnet', @@ -24,14 +25,14 @@ export enum Namespace { export class Options { @ApiProperty({ description: - 'Verification Method Keytype Ed25519VerificationKey2020 or EcdsaSecp256k1RecoveryMethod2020', + 'Verification Method Keytype Ed25519VerificationKey2020 or EcdsaSecp256k1RecoveryMethod2020 or BabyJubJubKey2021', example: 'keyType:EcdsaSecp256k1RecoveryMethod2020', name: 'keyType', required: false, }) @ValidateIf((o) => o.keyType !== undefined) - @IsEnum(IKeyType) - keyType: IKeyType; + @IsKeyTypeArrayOrSingle() + keyType: IKeyType | IKeyType[]; @ApiProperty({ name: 'chainId', @@ -67,18 +68,18 @@ export class Options { @IsBoolean() register?: boolean = false; // keeping it for time being will remove it later - @ApiProperty({ - description: - 'verificationRelationships defines verification methods to be used for which purposes', - example: 'authentication/ assertionMethod', - name: 'verificationRelationships', - required: false, - isArray: true, - }) - @IsOptional() - @IsArray() - @IsEnum(IVerificationRelationships, { each: true }) - verificationRelationships?: IVerificationRelationships[]; + // @ApiProperty({ + // description: + // 'verificationRelationships defines verification methods to be used for which purposes', + // example: 'authentication/ assertionMethod', + // name: 'verificationRelationships', + // required: false, + // isArray: true, + // }) + // @IsOptional() + // @IsArray() + // @IsEnum(IVerificationRelationships, { each: true }) + // verificationRelationships?: IVerificationRelationships[]; @ApiProperty({ name: 'name', @@ -115,11 +116,11 @@ export class CreateDidDto { description: ' keyType used for verification', required: false, example: { - keyType: 'Ed25519VerificationKey2020', + keyType: ['Ed25519VerificationKey2020'], chainId: '0x1', publicKey: 'z76tzt4XCb6FNqC3CPZvsxRfEDX5HHQc2VPux4DeZYndW', walletAddress: '0x01978e553Df0C54A63e2E063DFFe71c688d91C76', - verificationRelationships: ['assertionMethod', 'authentication'], + // verificationRelationships: ['assertionMethod', 'authentication'], }, }) @IsOptional() diff --git a/src/did/dto/register-did.dto.ts b/src/did/dto/register-did.dto.ts index d5cd98e5..054e74a9 100644 --- a/src/did/dto/register-did.dto.ts +++ b/src/did/dto/register-did.dto.ts @@ -152,3 +152,71 @@ export class RegisterDidDto { // @IsString() // address?: string; } + +export class RegisterV2SignInfo { + @ApiProperty({ + description: 'Verification Method id for did registration', + example: 'did:hid:testnet:........#key-${idx}', + required: true, + }) + @ValidateVerificationMethodId() + @IsString() + @Matches(/^[a-zA-Z0-9\:]*testnet[a-zA-Z0-9\-:#]*$/, { + message: "Did's namespace should be testnet", + }) + verification_method_id: string; + @ApiProperty({ + description: 'Signature for clientSpec', + example: 'afafljagahgp9agjagknaglkj/kagka=', + name: 'signature', + required: false, + }) + @ValidateIf((o, value) => o.clientSpec !== undefined) + @IsNotEmpty() + @IsString() + signature?: string; + @ApiProperty({ + description: 'ClientSpec ', + example: { + type: IClientSpec['cosmos-ADR036'], + adr036SignerAddress: 'bech32address', + }, + type: ClientSpec, + name: 'clientSpec', + required: false, + }) + @IsOptional() + @Type(() => ClientSpec) + @ValidateNested({ each: true }) + clientSpec?: ClientSpec; + @ApiProperty({ + description: 'created', + example: '2023-01-23T13:45:17Z', + required: false, + }) + @IsOptional() + @IsString() + @IsNotEmpty() + created?: string; +} +export class RegisterV2DidDto { + @ApiProperty({ + description: 'Did doc to be registered', + type: DidDoc, + required: true, + }) + @IsNotEmptyObject() + @Type(() => DidDoc) + @ValidateNested({ each: true }) + didDocument: Partial; + + @ApiProperty({ + description: 'Sign Info', + isArray: true, + required: true, + type: RegisterV2SignInfo, + }) + @ValidateNested({ each: false }) + @Type(() => RegisterV2SignInfo) + signInfos: Array; +} diff --git a/src/did/services/did.service.ts b/src/did/services/did.service.ts index ca76cf76..f03005f1 100644 --- a/src/did/services/did.service.ts +++ b/src/did/services/did.service.ts @@ -26,7 +26,7 @@ import { Slip10RawIndex } from '@cosmjs/crypto'; import { HidWalletService } from '../../hid-wallet/services/hid-wallet.service'; import { DidSSIService } from './did.ssi.service'; import { RegistrationStatus } from '../schemas/did.schema'; -import { RegisterDidDto } from '../dto/register-did.dto'; +import { RegisterDidDto, RegisterV2DidDto } from '../dto/register-did.dto'; import { Did as IDidDto } from '../schemas/did.schema'; import { AddVerificationMethodDto } from '../dto/addVm.dto'; import { getAppVault, getAppMenemonic } from '../../utils/app-vault-service'; @@ -70,30 +70,30 @@ export class DidService { let methodSpecificId = createDidDto.methodSpecificId; const publicKey = createDidDto.options?.publicKey; const chainId = createDidDto.options.chainId; - const keyType: IKeyType = createDidDto.options.keyType; + const keyType = createDidDto.options.keyType; const address = createDidDto.options.walletAddress; const register = createDidDto.options?.register; - let verificationRelationships: IVerificationRelationships[]; - if ( - createDidDto.options?.verificationRelationships && - createDidDto.options?.verificationRelationships.length > 0 - ) { - verificationRelationships = - createDidDto.options.verificationRelationships; - if ( - verificationRelationships.includes( - IVerificationRelationships.keyAgreement, - ) - ) { - Logger.error( - 'createByClientSpec() method: Invalid varifiactionRelationship method', - 'DidService', - ); - throw new BadRequestException([ - 'verificationRelationships.keyAgreement is not allowed at the time of creating a did', - ]); - } - } + // let verificationRelationships: IVerificationRelationships[]; + // if ( + // createDidDto.options?.verificationRelationships && + // createDidDto.options?.verificationRelationships.length > 0 + // ) { + // verificationRelationships = + // createDidDto.options.verificationRelationships; + // if ( + // verificationRelationships.includes( + // IVerificationRelationships.keyAgreement, + // ) + // ) { + // Logger.error( + // 'createByClientSpec() method: Invalid varifiactionRelationship method', + // 'DidService', + // ); + // throw new BadRequestException([ + // 'verificationRelationships.keyAgreement is not allowed at the time of creating a did', + // ]); + // } + // } if (!methodSpecificId) { methodSpecificId = address; } @@ -161,7 +161,7 @@ export class DidService { chainId, clientSpec, address, - verificationRelationships, + // verificationRelationships, }); return { @@ -177,28 +177,29 @@ export class DidService { async create( createDidDto: CreateDidDto, appDetail, + keyTypes?: IKeyType[], ): Promise { Logger.log('create() method: starts....', 'DidService'); try { const methodSpecificId = createDidDto.methodSpecificId; - let verificationRelationships: IVerificationRelationships[]; - if ( - createDidDto.options?.verificationRelationships && - createDidDto.options?.verificationRelationships.length > 0 - ) { - verificationRelationships = - createDidDto.options.verificationRelationships; - if ( - verificationRelationships.includes( - IVerificationRelationships.keyAgreement, - ) - ) { - throw new BadRequestException([ - 'verificationRelationships.keyAgreement is not allowed at the time of creating a did', - ]); - } - } + // let verificationRelationships: IVerificationRelationships[]; + // if ( + // createDidDto.options?.verificationRelationships && + // createDidDto.options?.verificationRelationships.length > 0 + // ) { + // verificationRelationships = + // createDidDto.options.verificationRelationships; + // if ( + // verificationRelationships.includes( + // IVerificationRelationships.keyAgreement, + // ) + // ) { + // throw new BadRequestException([ + // 'verificationRelationships.keyAgreement is not allowed at the time of creating a did', + // ]); + // } + // } const { edvId, kmsId } = appDetail; // Step 1: Generate a new menmonic Logger.log('Before calling hidWallet.generateWallet()', 'DidService'); @@ -236,10 +237,10 @@ export class DidService { Logger.log('After calling hypersignDid.generateKeys', 'DidService'); Logger.log('Before calling hypersignDid.generate()', 'DidService'); - const didDoc = await hypersignDid.generate({ + let didDoc: any = await hypersignDid.generate({ methodSpecificId, publicKeyMultibase, - verificationRelationships, + // verificationRelationships, }); Logger.log('After calling hypersignDid.generate()', 'DidService'); @@ -278,7 +279,6 @@ export class DidService { ); } const { id: userKMSId } = insertedDoc; - // Step 4: Store user's kmsId in DID db for that application. x Logger.log( 'Before calling didRepositiory.create() did ' + didDoc.id, @@ -298,7 +298,25 @@ export class DidService { 'After calling didRepositiory.create() did ' + didDoc.id, 'DidService', ); - + if (keyTypes.length > 1) { + for (const type of keyTypes.slice(1)) { + if (type === IKeyType.BabyJubJubKey2021) { + const hypersignBjjDid = + await this.didSSIService.initiateHyperSignBJJDid( + userWallet.mnemonic, + createDidDto.namespace, + ); + const { publicKeyMultibase } = await hypersignBjjDid.generateKeys({ + mnemonic: userWallet.mnemonic, + }); + didDoc = await this.addVerificationMethod({ + didDocument: didDoc, + type: type, + publicKeyMultibase, + }); + } + } + } return { did: didDoc.id, registrationStatus: RegistrationStatus.UNREGISTRED, @@ -315,6 +333,159 @@ export class DidService { throw new BadRequestException([e.message]); } } + async createBjjDid( + createDidDto: CreateDidDto, + appDetail, + keyTypes?: IKeyType[], + ): Promise { + Logger.log( + 'createBjjDid() method: starts to create a bjj did', + 'DidService', + ); + try { + const methodSpecificId = createDidDto.methodSpecificId; + // let verificationRelationships: IVerificationRelationships[]; + // if ( + // createDidDto.options?.verificationRelationships && + // createDidDto.options?.verificationRelationships.length > 0 + // ) { + // verificationRelationships = + // createDidDto.options.verificationRelationships; + // if ( + // verificationRelationships.includes( + // IVerificationRelationships.keyAgreement, + // ) + // ) { + // throw new BadRequestException([ + // 'verificationRelationships.keyAgreement is not allowed at the time of creating a did', + // ]); + // } + // } + const { edvId, kmsId } = appDetail; + Logger.log('Before calling hidWallet.generateWallet()', 'DidService'); + const userWallet = await this.hidWallet.generateWallet(); + Logger.log('After calling hidWallet.generateWallet()', 'DidService'); + Logger.log( + 'Before calling didSSIService.initiateHypersignDid()', + 'DidService', + ); + const hypersignBjjDid = await this.didSSIService.initiateHyperSignBJJDid( + userWallet.mnemonic, + createDidDto.namespace, + ); + Logger.log( + 'After calling didSSIService.initiateHyperSignBJJDid()', + 'DidService', + ); + + Logger.log( + 'Before calling .hidWallet.getSeedFromMnemonic()', + 'DidService', + ); + const seed = await this.hidWallet.getSeedFromMnemonic( + userWallet.mnemonic, + ); + + Logger.log( + 'After calling .hidWallet.getSeedFromMnemonic()', + 'DidService', + ); + Logger.log('Before calling hypersignBjjDid.generateKeys', 'DidService'); + const { publicKeyMultibase, privateKeyMultibase } = + await hypersignBjjDid.generateKeys({ + mnemonic: userWallet.mnemonic, + }); + Logger.log('After calling hypersignBjjDid.generateKeys', 'DidService'); + + Logger.log('Before calling hypersignBjjDid.generate()', 'DidService'); + let didDoc: any = await hypersignBjjDid.generate({ + methodSpecificId, + publicKeyMultibase, + // verificationRelationships, + }); + Logger.log('After calling hypersignDid.generate()', 'DidService'); + + if (!didDoc) { + throw new Error('Could not generate dIDDoc'); + } + Logger.log('Before calling getAppVault ', 'DidService'); + const appVault = await getAppVault(kmsId, edvId); + Logger.log('After calling getAppVault ', 'DidService'); + if (!appVault) { + throw new Error('KeyManager is not null or not initialized'); + } + const userCredential = { + mnemonic: userWallet.mnemonic, + walletAddress: userWallet.address, + }; + Logger.log('Before calling appVault.prepareEdvDocument() ', 'DidService'); + const userEdvDoc = appVault.prepareEdvDocument(userCredential, [ + { index: 'content.walletAddress', unique: false }, + ]); + Logger.log('After calling appVault.prepareEdvDocument() ', 'DidService'); + + Logger.log('Before calling appVault.insertDocument() ', 'DidService'); + const insertedDoc = await appVault.insertDocument(userEdvDoc); + Logger.log('After calling appVault.insertDocument() ', 'DidService'); + + Logger.log(JSON.stringify(insertedDoc), 'DidService'); + if (!insertedDoc) { + throw new Error( + 'Could not insert document for userCredential.walletAddress' + + userCredential.walletAddress, + ); + } + const { id: userKMSId } = insertedDoc; + Logger.log( + 'Before calling didRepositiory.create() did ' + didDoc.id, + 'DidService', + ); + await this.didRepositiory.create({ + did: didDoc.id, + appId: appDetail.appId, + kmsId: userKMSId, + slipPathKeys: null, + hdPathIndex: null, + transactionHash: '', + registrationStatus: RegistrationStatus.UNREGISTRED, + name: createDidDto.options?.name, + }); + Logger.log( + 'After calling didRepositiory.create() did ' + didDoc.id, + 'DidService', + ); + if (keyTypes.length > 1) { + for (const type of keyTypes.slice(1)) { + const hypersignDid = await this.didSSIService.initiateHypersignDid( + userWallet.mnemonic, + createDidDto.namespace, + ); + const { publicKeyMultibase } = await hypersignDid.generateKeys({ + seed, + }); + didDoc = await this.addVerificationMethod({ + didDocument: didDoc, + type: type, + publicKeyMultibase, + }); + } + } + return { + did: didDoc.id, + registrationStatus: RegistrationStatus.UNREGISTRED, + transactionHash: '', + metaData: { + didDocument: didDoc, + }, + }; + } catch (e) { + Logger.error(`createBjjDid() method: Error: ${e.message}`, 'DidService'); + if (e.code === 11000) { + throw new ConflictException(['Duplicate key error']); + } + throw new BadRequestException([e.message]); + } + } async register( registerDidDto: RegisterDidDto, @@ -450,6 +621,203 @@ export class DidService { }; } + async registerV2( + registerV2DidDto: RegisterV2DidDto, + appDetail, // : Promise + ) { + Logger.log('registerV2() method: starts....', 'DidService'); + const { edvId, kmsId } = appDetail; + Logger.log('registerV2() method: initialising edv service', 'DidService'); + + const appMenemonic = await getAppMenemonic(kmsId); + const namespace = this.config.get('NETWORK') + ? this.config.get('NETWORK') + : 'testnet'; + const didInfo = await this.didRepositiory.findOne({ + appId: appDetail.appId, + did: registerV2DidDto.didDocument['id'], + }); + if (didInfo !== null && didInfo.registrationStatus === 'COMPLETED') { + throw new BadRequestException([ + `${registerV2DidDto.didDocument['id']} already registered`, + ]); + } + Logger.log( + 'registerV2() method: initialising didSSIService service', + 'DidService', + ); + const hypersignDid = await this.didSSIService.initiateHypersignDid( + appMenemonic, + namespace, + ); + const hypersignBjjDid = await this.didSSIService.initiateHyperSignBJJDid( + appMenemonic, + namespace, + ); + const { didDocument, signInfos: providedSignInfos } = registerV2DidDto; + const finalSignInfos: any = []; + const didDocPreserved = { ...didDocument }; + + const checkIfBjjExist = didDocument.verificationMethod.some( + (vm) => vm.type === IKeyType.BabyJubJubKey2021, + ); + if (checkIfBjjExist) { + delete didDocument.alsoKnownAs; + delete didDocPreserved.alsoKnownAs; + } + for (let i = 0; i < didDocument.verificationMethod.length; i++) { + const vm = didDocument.verificationMethod[i]; + const keyType = vm.type; + + const selectedSignInfo = providedSignInfos.find( + (sign) => sign.verification_method_id === vm.id, + ); + if (!selectedSignInfo) { + throw new BadRequestException([ + `Missing sign info for verification method: ${vm.id}`, + ]); + } + if ( + keyType === IKeyType.EcdsaSecp256k1RecoveryMethod2020 || + keyType === IKeyType.EcdsaSecp256k1VerificationKey2019 + ) { + if (!selectedSignInfo.signature) { + throw new BadRequestException([ + `signature must be passed for keyType:${keyType}`, + ]); + } + if (!selectedSignInfo.clientSpec) { + throw new BadRequestException([ + `clientSpec must passed for keyType:${keyType}`, + ]); + } + if (!selectedSignInfo.created) { + throw new BadRequestException([ + `created must passed for keyType:${keyType}`, + ]); + } + finalSignInfos.push(selectedSignInfo); + } + // let didData; + // if ( + // (keyType === IKeyType.Ed25519VerificationKey2020 || + // keyType === IKeyType.BabyJubJubKey2021) && + // !selectedSignInfo.signature + // ) { + // didData = await this.didRepositiory.findOne({ + // did: didDocument['id'], + // }); + + // } + + if (keyType === IKeyType.Ed25519VerificationKey2020) { + //genrate signInfo + if (!didInfo) { + throw new NotFoundException([didDocument['id'] + ' not found']); + } + const appVault = await getAppVault(kmsId, edvId); + const { mnemonic: userMnemonic } = await appVault.getDecryptedDocument( + didInfo.kmsId, + ); + + const seed = await this.hidWallet.getSeedFromMnemonic(userMnemonic); + const { privateKeyMultibase } = await hypersignDid.generateKeys({ + seed: seed, + }); + const generatedSignInfo = await hypersignDid.createSignInfos({ + didDocument: JSON.parse(JSON.stringify(didDocPreserved)), + privateKeyMultibase, + verificationMethodId: selectedSignInfo.verification_method_id, + }); + finalSignInfos.push(generatedSignInfo[0]); + } + if (keyType === IKeyType.BabyJubJubKey2021) { + if (!didInfo) { + throw new NotFoundException([didDocument['id'] + ' not found']); + } + const appVault = await getAppVault(kmsId, edvId); + const { mnemonic: userMnemonic } = await appVault.getDecryptedDocument( + didInfo.kmsId, + ); + + const { privateKeyMultibase } = await hypersignBjjDid.generateKeys({ + mnemonic: userMnemonic, + }); + + const generatedSignInfo = await hypersignBjjDid.createSignInfos({ + didDocument: JSON.parse(JSON.stringify(didDocPreserved)), + privateKeyMultibase, + verificationMethodId: selectedSignInfo.verification_method_id, + }); + finalSignInfos.push(generatedSignInfo[0]); + } + } + const registerDidDoc = await hypersignDid.registerByClientSpec({ + didDocument, + signInfos: finalSignInfos, + }); + let registerDidData; + + if (!didInfo || didInfo == undefined) { + registerDidData = await this.didRepositiory.create({ + did: didDocument['id'], + appId: appDetail.appId, + slipPathKeys: null, + hdPathIndex: null, + kmsId: didInfo.kmsId, + transactionHash: + registerDidDoc && registerDidDoc?.transactionHash + ? registerDidDoc.transactionHash + : '', + registrationStatus: + registerDidDoc && registerDidDoc?.transactionHash + ? RegistrationStatus.COMPLETED + : RegistrationStatus.UNREGISTRED, + name: didInfo.name, + }); + } else { + // const { wallet, address } = await this.hidWallet.generateWallet( + // appMenemonic, + // ); + // if (await this.checkAllowence(address)) { + // await this.txnService.sendDIDTxn( + // didDocument, + // finalSignInfos, + // verificationMethodId, + // appMenemonic, + // ); + // } + // else { + // registerDidDoc = await hypersignDid.register(params); + // } + registerDidData = await this.didRepositiory.findOneAndUpdate( + { did: didDocument['id'] }, + { + did: didDocument['id'], + appId: appDetail.appId, + slipPathKeys: null, + hdPathIndex: null, + transactionHash: + registerDidDoc && registerDidDoc?.transactionHash + ? registerDidDoc.transactionHash + : '', + registrationStatus: + registerDidDoc && registerDidDoc?.transactionHash + ? RegistrationStatus.COMPLETED + : RegistrationStatus.UNREGISTRED, + }, + ); + } + return { + did: registerDidData.did, + registrationStatus: registerDidData.registrationStatus, + transactionHash: registerDidData.transactionHash, + metaData: { + didDocument: didDocument, + }, + }; + } + async getDidList(appDetail, option): Promise { Logger.log('getDidList() method: starts....', 'DidService'); @@ -559,10 +927,6 @@ export class DidService { did, }); const { signInfos } = updateDidDto; - console.log({ - signInfos, - didInfo, - }); // If signature is passed then no need to check if it is present in db or not if (!signInfos && (!didInfo || didInfo == null || didInfo == undefined)) { diff --git a/src/did/services/did.ssi.service.ts b/src/did/services/did.ssi.service.ts index 98a47d7c..ac82eeb8 100644 --- a/src/did/services/did.ssi.service.ts +++ b/src/did/services/did.ssi.service.ts @@ -1,7 +1,5 @@ import { Injectable, Logger, Scope } from '@nestjs/common'; - -import { HypersignDID } from 'hs-ssi-sdk'; - +import { HypersignDID, HypersignSSISdk } from 'hs-ssi-sdk'; import { ConfigService } from '@nestjs/config'; import { HidWalletService } from '../../hid-wallet/services/hid-wallet.service'; @@ -45,4 +43,40 @@ export class DidSSIService { }); return hypersignDid; } + async initiateHyperSignBJJDid(mnemonic: string, namespace: string) { + Logger.log('InitateHypersignDid(): starts....', 'DidSSIService'); + const nodeRpcEndpoint = this.config.get('HID_NETWORK_RPC'); + const nodeRestEndpoint = this.config.get('HID_NETWORK_API'); + await this.hidWallet.generateWallet(mnemonic); + Logger.log( + 'initiateHypersignBJJDid() method: before getting offlinesigner', + 'DidSSIService', + ); + const offlineSigner = this.hidWallet.getOfflineSigner(); + const hsSdk = new HypersignSSISdk({ + offlineSigner, + nodeRpcEndpoint, + nodeRestEndpoint, + namespace: namespace, + }); + await hsSdk.init(); + const hypersignBjjDid = hsSdk.did.bjjDID; + return hypersignBjjDid; + } + async initiateHyperSignBJJDidOffline(namespace: string) { + Logger.log('InitateHypersignDid(): starts....', 'DidSSIService'); + const nodeRpcEndpoint = this.config.get('HID_NETWORK_RPC'); + const nodeRestEndpoint = this.config.get('HID_NETWORK_API'); + Logger.log( + 'initiateHypersignBJJDid() method: before getting offlinesigner', + 'DidSSIService', + ); + const hypersignDid = new HypersignDID({ + nodeRpcEndpoint, + nodeRestEndpoint, + namespace: namespace, + }); + const hypersignBjjDid = hypersignDid.bjjDID; + return hypersignBjjDid; + } } diff --git a/src/main.ts b/src/main.ts index a935974f..6384617d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -96,7 +96,6 @@ async function bootstrap() { : 'hs:developer-dashboard:'; const edvId = vaultPrefix + 'kms:' + kmsVaultWallet.didDocument.id; const kmsVault = await kmsVaultManager.createVault(kmsVaultWallet, edvId); - // TODO rename this to kmsVault for bnetter cla globalThis.kmsVault = kmsVault; diff --git a/src/presentation/services/presentation.service.ts b/src/presentation/services/presentation.service.ts index eb785a9a..68258b2e 100644 --- a/src/presentation/services/presentation.service.ts +++ b/src/presentation/services/presentation.service.ts @@ -17,6 +17,7 @@ import { HypersignDID, IVerifiableCredential, IVerifiablePresentation, + IKeyType, } from 'hs-ssi-sdk'; import { ConfigService } from '@nestjs/config'; import { HidWalletService } from 'src/hid-wallet/services/hid-wallet.service'; @@ -24,6 +25,8 @@ import { DidRepository } from 'src/did/repository/did.repository'; import { VerifyPresentationDto } from '../dto/verify-presentation.dto'; import { getAppVault } from '../../utils/app-vault-service'; import { generateAppId } from 'src/utils/utils'; +import { VerificationMethodRelationships } from 'hs-ssi-sdk/build/libs/generated/ssi/client/enums'; +import { DidSSIService } from 'src/did/services/did.ssi.service'; @Injectable() export class PresentationService { constructor( @@ -199,6 +202,7 @@ export class PresentationRequestService { private readonly didRepositiory: DidRepository, private readonly config: ConfigService, private readonly hidWallet: HidWalletService, + private readonly didSSIService: DidSSIService, ) {} async createPresentationRequest( @@ -285,7 +289,6 @@ export class PresentationRequestService { const { didDocument } = await hypersignDID.resolve({ did: holderDid, }); - // TODO: Remove hardcoing const verificationMethodIdforAssert = didDocument.assertionMethod[0]; Logger.log( @@ -306,29 +309,60 @@ export class PresentationRequestService { // Holder Identity: - used for authenticating presentation const { edvId, kmsId } = appDetail; const appVault = await getAppVault(kmsId, edvId); + const vmWithAssertion = didDocument.verificationMethod.find( + (vm) => vm.id === verificationMethodIdforAssert, + ); + console.log(vmWithAssertion); const { mnemonic: holderMnemonic } = await appVault.getDecryptedDocument( didInfo.kmsId, ); const seed = await this.hidWallet.getSeedFromMnemonic(holderMnemonic); - const hypersignDid = new HypersignDID(); - const { privateKeyMultibase } = await hypersignDid.generateKeys({ seed }); + let hypersignDid; + let privateKeyMultibase; + let signedVerifiablePresentation; + if ( + vmWithAssertion && + vmWithAssertion.type === IKeyType.BabyJubJubKey2021 + ) { + hypersignDid = await this.didSSIService.initiateHyperSignBJJDidOffline( + 'testnet', + ); + const keys = await hypersignDid.generateKeys(holderMnemonic); + privateKeyMultibase = keys.privateKeyMultibase; + console.log(privateKeyMultibase); - Logger.log( - 'createPresentation() method: before calling hypersignVP.sign', - 'PresentationRequestService', - ); - const signedVerifiablePresentation = await hypersignVP.sign({ - presentation: unsignedverifiablePresentation as IVerifiablePresentation, - holderDid, - verificationMethodId: verificationMethodIdforAssert, - challenge, - privateKeyMultibase, - }); - Logger.log( - 'createPresentation() method: ends....', - 'PresentationRequestService', - ); + Logger.log( + 'createPresentation() method: before calling hypersignVP.sign for bjj', + 'PresentationRequestService', + ); + signedVerifiablePresentation = await hypersignVP.bjjVp.sign({ + presentation: unsignedverifiablePresentation as IVerifiablePresentation, + holderDid, + verificationMethodId: verificationMethodIdforAssert, + challenge, + privateKeyMultibase, + }); + } else { + hypersignDid = new HypersignDID(); + const keys = await hypersignDid.generateKeys({ seed }); + privateKeyMultibase = keys.privateKeyMultibase; + Logger.log( + 'createPresentation() method: before calling hypersignVP.sign', + 'PresentationRequestService', + ); + signedVerifiablePresentation = await hypersignVP.sign({ + presentation: unsignedverifiablePresentation as IVerifiablePresentation, + holderDid, + verificationMethodId: verificationMethodIdforAssert, + challenge, + privateKeyMultibase, + }); + Logger.log( + 'createPresentation() method: ends....', + 'PresentationRequestService', + ); + } return { presentation: signedVerifiablePresentation }; } @@ -355,18 +389,34 @@ export class PresentationRequestService { // const domain = presentation['proof']['domain']; const challenge = presentation['proof']['challenge']; + const type = presentation['proof']['type']; + Logger.log( 'verifyPresentation() method:before calling hypersignVP.verify', 'PresentationRequestService', ); - const verifiedPresentationDetail = await hypersignVP.verify({ - signedPresentation: presentation as any, - issuerDid, - holderDid, - holderVerificationMethodId: holderDid + '#key-1', - issuerVerificationMethodId: issuerDid + '#key-1', - challenge, - }); + let verifiedPresentationDetail; + if (type === 'BJJSignature2021') { + console.log('in if'); + verifiedPresentationDetail = await hypersignVP.bjjVp.verify({ + signedPresentation: presentation as any, + issuerDid, + holderDid, + holderVerificationMethodId: holderDid + '#key-1', + issuerVerificationMethodId: issuerDid + '#key-1', + challenge, + }); + } else { + verifiedPresentationDetail = await hypersignVP.verify({ + signedPresentation: presentation as any, + issuerDid, + holderDid, + holderVerificationMethodId: holderDid + '#key-1', + issuerVerificationMethodId: issuerDid + '#key-1', + challenge, + }); + } + Logger.log( 'verifyPresentation() method: ends....', 'PresentationRequestService', diff --git a/src/utils/customDecorator/keyType.decorator.ts b/src/utils/customDecorator/keyType.decorator.ts new file mode 100644 index 00000000..8aed907c --- /dev/null +++ b/src/utils/customDecorator/keyType.decorator.ts @@ -0,0 +1,84 @@ +import { + registerDecorator, + ValidationOptions, + ValidationArguments, +} from 'class-validator'; +import { IKeyType } from 'hs-ssi-sdk'; + +export function IsKeyTypeArrayOrSingle(validationOptions?: ValidationOptions) { + return function (object: object, propertyName: string) { + registerDecorator({ + name: 'isValidKeyType', + target: object.constructor, + propertyName: propertyName, + options: validationOptions, + validator: { + validate(value: any, args: ValidationArguments) { + const ecdsaTypes = [ + IKeyType.EcdsaSecp256k1RecoveryMethod2020, + IKeyType.EcdsaSecp256k1VerificationKey2019, + ]; + + // Ensure value is either a single string or an array + const values = Array.isArray(value) ? value : [value]; + console.log(values); + const invalidKeyTypes = values.filter( + (val) => !Object.values(IKeyType).includes(val), + ); + console.log(invalidKeyTypes, 'invalidKeyTypes'); + // Ensure each value is part of the IKeyType enum + if (invalidKeyTypes.length > 0) { + (args as any).invalidKeyTypes = invalidKeyTypes; // Pass invalid key types for custom message + console.log('if1'); + + return false; + } + + // Check for ECDSA-specific validation rules + const containsEcdsa = values.some((type) => + ecdsaTypes.includes(type), + ); + const containsOthers = values.some( + (type) => !ecdsaTypes.includes(type), + ); + + // ECDSA types must not be mixed with other types + if (containsEcdsa && containsOthers) { + return false; + } + + // There must be no more than one ECDSA type + if ( + containsEcdsa && + values.filter((type) => ecdsaTypes.includes(type)).length > 1 + ) { + (args as any).multipleEcdsa = true; // Flag for multiple ECDSA error message + return false; + } + + return true; + }, + defaultMessage(args: ValidationArguments) { + // Check for the error flags set during validation and customize the message accordingly + console.log(args); + if ((args as any).invalidKeyTypes) { + console.log('if'); + return `The provided key types ${JSON.stringify( + (args as any).invalidKeyTypes, + )} are invalid.`; + } + + if ((args as any).mixingEcdsa) { + return 'ECDSA key types must not be mixed with other key types.'; + } + + if ((args as any).multipleEcdsa) { + return 'Only one ECDSA key type is allowed.'; + } + + return 'The provided key types are invalid. They must be one of the supported types, and ECDSA types must be used exclusively without mixing with other types.'; + }, + }, + }); + }; +} From beabfa5898e95a07171118f4aaa6930f6dfbb908 Mon Sep 17 00:00:00 2001 From: varsha766 Date: Thu, 17 Oct 2024 15:53:42 +0530 Subject: [PATCH 4/8] added some validation --- src/did/controllers/did.controller.ts | 2 +- src/did/dto/register-did.dto.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/did/controllers/did.controller.ts b/src/did/controllers/did.controller.ts index 96ece102..823a3bbb 100644 --- a/src/did/controllers/did.controller.ts +++ b/src/did/controllers/did.controller.ts @@ -131,7 +131,7 @@ export class DidController { } @UsePipes( new ValidationPipe({ - whitelist: true, + // whitelist: true, transform: true, forbidNonWhitelisted: true, }), diff --git a/src/did/dto/register-did.dto.ts b/src/did/dto/register-did.dto.ts index 054e74a9..84353e60 100644 --- a/src/did/dto/register-did.dto.ts +++ b/src/did/dto/register-did.dto.ts @@ -1,6 +1,8 @@ import { ApiProperty } from '@nestjs/swagger'; import { DidDoc } from './update-did.dto'; import { + ArrayNotEmpty, + IsArray, IsEnum, IsNotEmpty, IsNotEmptyObject, @@ -216,6 +218,8 @@ export class RegisterV2DidDto { required: true, type: RegisterV2SignInfo, }) + @IsArray() + @ArrayNotEmpty() @ValidateNested({ each: false }) @Type(() => RegisterV2SignInfo) signInfos: Array; From 8705921af1d04db9c613e99128f5165fd5265b74 Mon Sep 17 00:00:00 2001 From: varsha766 Date: Fri, 18 Oct 2024 14:05:29 +0530 Subject: [PATCH 5/8] issue bjj credential --- src/credential/dto/register-credential.dto.ts | 5 +- src/credential/services/credential.service.ts | 82 +++++++++++++++---- .../services/credential.ssi.service.ts | 21 ++++- 3 files changed, 92 insertions(+), 16 deletions(-) diff --git a/src/credential/dto/register-credential.dto.ts b/src/credential/dto/register-credential.dto.ts index 71b8cf51..93918ca2 100644 --- a/src/credential/dto/register-credential.dto.ts +++ b/src/credential/dto/register-credential.dto.ts @@ -2,7 +2,10 @@ import { ApiProperty } from '@nestjs/swagger'; import { CredStatus, Namespace } from './create-credential.dto'; import { Type } from 'class-transformer'; import { IsEnum, ValidateNested } from 'class-validator'; - +export enum SupportedSignatureType { + BJJSignature2021 = 'BJJSignature2021', + Ed25519Signature2020 = 'Ed25519Signature2020', +} export class RegisterCredentialStatusDto { @ApiProperty({ name: 'credentialStatus', diff --git a/src/credential/services/credential.service.ts b/src/credential/services/credential.service.ts index aa351241..b7df29f7 100644 --- a/src/credential/services/credential.service.ts +++ b/src/credential/services/credential.service.ts @@ -11,9 +11,16 @@ import { CredentialSSIService } from './credential.ssi.service'; import { HidWalletService } from 'src/hid-wallet/services/hid-wallet.service'; import { CredentialRepository } from '../repository/credential.repository'; import { DidRepository } from 'src/did/repository/did.repository'; -import { HypersignDID, HypersignVerifiableCredential } from 'hs-ssi-sdk'; +import { + HypersignDID, + HypersignVerifiableCredential, + IKeyType, +} from 'hs-ssi-sdk'; import { VerifyCredentialDto } from '../dto/verify-credential.dto'; -import { RegisterCredentialStatusDto } from '../dto/register-credential.dto'; +import { + RegisterCredentialStatusDto, + SupportedSignatureType, +} from '../dto/register-credential.dto'; import { getAppVault, getAppMenemonic } from '../../utils/app-vault-service'; import { TxSendModuleService } from 'src/tx-send-module/tx-send-module.service'; @@ -105,14 +112,42 @@ export class CredentialService { ); const seed = await this.hidWallet.getSeedFromMnemonic(issuerMnemonic); const hypersignDid = new HypersignDID(); - const { privateKeyMultibase } = await hypersignDid.generateKeys({ seed }); - + const { didDocument } = await hypersignDid.resolve({ did: issuerDid }); + const verificationMethod = didDocument.verificationMethod.find( + (vm) => vm.id === verificationMethodId, + ); // Apps Identity: - used for gas fee const appMenemonic = await getAppMenemonic(kmsId); - const hypersignVC = await this.credentialSSIService.initateHypersignVC( + // let privateKeyMultibase; + // let hypersignVC; + if (!verificationMethod) { + throw new Error( + `VerificationMethod does not exists for vmId ${verificationMethodId}`, + ); + } + // if ( + // verificationMethod && + // verificationMethod.type === IKeyType.Ed25519VerificationKey2020 + // ) { + // const key = await hypersignDid.generateKeys({ seed }); + // privateKeyMultibase = key.privateKeyMultibase; + // hypersignVC = await this.credentialSSIService.initateHypersignVC( + // appMenemonic, + // nameSpace, + // ); + // } else if ( + // verificationMethod && + // verificationMethod.type === IKeyType.BabyJubJubKey2021 + // ) { + const key = await hypersignDid.bjjDID.generateKeys(issuerMnemonic); + const privateKeyMultibase = key.privateKeyMultibase; + // console.log(privateKeyMultibase); + const hypersignVC = await this.credentialSSIService.initateHypersignBjjVC( appMenemonic, nameSpace, ); + // } + let credential; if (schemaId) { @@ -142,6 +177,7 @@ export class CredentialService { expirationDate, }); } + console.log(credential, null, 2); Logger.log( 'create() method: before calling hypersignVC.issue', 'CredentialService', @@ -158,9 +194,9 @@ export class CredentialService { issuerDid, verificationMethodId, privateKeyMultibase, - registerCredential: false, + registerCredential: true, }); - + console.log(JSON.stringify(signedCredential, null, 2)); const credStatusTemp = {}; Object.assign(credStatusTemp, credentialStatus); @@ -168,9 +204,9 @@ export class CredentialService { credentialStatus, namespace: nameSpace, } as RegisterCredentialStatusDto; - if (registerCredentialStatus) { - await this.registerCredentialStatus(credStatus, appDetail); - } + // if (registerCredentialStatus) { + // // await this.registerCredentialStatus(credStatus, appDetail); + // } let edvData = undefined; if (persist) { @@ -502,15 +538,33 @@ export class CredentialService { const { wallet, address } = await this.hidWallet.generateWallet( appMenemonic, ); + let hypersignVC; + if ( + proof && + proof.type && + proof.type === SupportedSignatureType.BJJSignature2021 + ) { + hypersignVC = await this.credentialSSIService.initateHypersignVC( + appMenemonic, + namespace, + ); + hypersignVC.bjjVC; + } else { + hypersignVC = await this.credentialSSIService.initateHypersignVC( + appMenemonic, + namespace, + ); + } - const hypersignVC = await this.credentialSSIService.initateHypersignVC( - appMenemonic, - namespace, - ); + console.log(JSON.stringify(credentialStatus, null, 2)); + console.log(JSON.stringify(proof, null, 2)); if (await this.checkAllowence(address)) { + console.log('if'); await this.txnService.sendVCTxn(credentialStatus, proof, appMenemonic); } else { + console.log('else'); + registeredVC = await hypersignVC.registerCredentialStatus({ credentialStatus, credentialStatusProof: proof, diff --git a/src/credential/services/credential.ssi.service.ts b/src/credential/services/credential.ssi.service.ts index d74c9ece..cd793ed8 100644 --- a/src/credential/services/credential.ssi.service.ts +++ b/src/credential/services/credential.ssi.service.ts @@ -1,7 +1,7 @@ import { Injectable, Scope, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; -import { HypersignVerifiableCredential } from 'hs-ssi-sdk'; +import { HypersignVerifiableCredential, HypersignSSISdk } from 'hs-ssi-sdk'; import { HidWalletService } from 'src/hid-wallet/services/hid-wallet.service'; @Injectable({ scope: Scope.REQUEST }) @@ -33,4 +33,23 @@ export class CredentialSSIService { await hypersignVC.init(); return hypersignVC; } + async initateHypersignBjjVC(mnemonic: string, namespace: string) { + Logger.log('InitateHypersignVC(): starts....', 'CredentialSSIService'); + const nodeRpcEndpoint = this.config.get('HID_NETWORK_RPC'); + const nodeRestEndpoint = this.config.get('HID_NETWORK_API'); + Logger.log( + 'InitateHypersignVC() method: before getting offlinesigner', + 'CredentialSSIService', + ); + await this.hidWallet.generateWallet(mnemonic); + const offlineSigner = this.hidWallet.getOfflineSigner(); + const hsSSiSdk = new HypersignSSISdk({ + offlineSigner, + nodeRpcEndpoint, + nodeRestEndpoint, + namespace: namespace, + }); + await hsSSiSdk.init(); + return hsSSiSdk.vc.bjjVC; + } } From aa80e1490297dda1b15a55cafef8a765d8f49e0a Mon Sep 17 00:00:00 2001 From: varsha766 Date: Fri, 18 Oct 2024 15:22:39 +0530 Subject: [PATCH 6/8] fixed signature issue --- src/credential/services/credential.service.ts | 69 ++++++++----------- .../services/presentation.service.ts | 4 -- 2 files changed, 30 insertions(+), 43 deletions(-) diff --git a/src/credential/services/credential.service.ts b/src/credential/services/credential.service.ts index b7df29f7..af5f6f28 100644 --- a/src/credential/services/credential.service.ts +++ b/src/credential/services/credential.service.ts @@ -118,35 +118,36 @@ export class CredentialService { ); // Apps Identity: - used for gas fee const appMenemonic = await getAppMenemonic(kmsId); - // let privateKeyMultibase; - // let hypersignVC; + let privateKeyMultibase; + let hypersignVC; if (!verificationMethod) { throw new Error( `VerificationMethod does not exists for vmId ${verificationMethodId}`, ); } - // if ( - // verificationMethod && - // verificationMethod.type === IKeyType.Ed25519VerificationKey2020 - // ) { - // const key = await hypersignDid.generateKeys({ seed }); - // privateKeyMultibase = key.privateKeyMultibase; - // hypersignVC = await this.credentialSSIService.initateHypersignVC( - // appMenemonic, - // nameSpace, - // ); - // } else if ( - // verificationMethod && - // verificationMethod.type === IKeyType.BabyJubJubKey2021 - // ) { - const key = await hypersignDid.bjjDID.generateKeys(issuerMnemonic); - const privateKeyMultibase = key.privateKeyMultibase; - // console.log(privateKeyMultibase); - const hypersignVC = await this.credentialSSIService.initateHypersignBjjVC( - appMenemonic, - nameSpace, - ); - // } + if ( + verificationMethod && + verificationMethod.type === IKeyType.Ed25519VerificationKey2020 + ) { + const key = await hypersignDid.generateKeys({ seed }); + privateKeyMultibase = key.privateKeyMultibase; + hypersignVC = await this.credentialSSIService.initateHypersignVC( + appMenemonic, + nameSpace, + ); + } else if ( + verificationMethod && + verificationMethod.type === IKeyType.BabyJubJubKey2021 + ) { + const key = await hypersignDid.bjjDID.generateKeys({ + mnemonic: issuerMnemonic, + }); + privateKeyMultibase = key.privateKeyMultibase; + hypersignVC = await this.credentialSSIService.initateHypersignBjjVC( + appMenemonic, + nameSpace, + ); + } let credential; @@ -177,7 +178,6 @@ export class CredentialService { expirationDate, }); } - console.log(credential, null, 2); Logger.log( 'create() method: before calling hypersignVC.issue', 'CredentialService', @@ -194,9 +194,8 @@ export class CredentialService { issuerDid, verificationMethodId, privateKeyMultibase, - registerCredential: true, + registerCredential: false, }); - console.log(JSON.stringify(signedCredential, null, 2)); const credStatusTemp = {}; Object.assign(credStatusTemp, credentialStatus); @@ -204,9 +203,9 @@ export class CredentialService { credentialStatus, namespace: nameSpace, } as RegisterCredentialStatusDto; - // if (registerCredentialStatus) { - // // await this.registerCredentialStatus(credStatus, appDetail); - // } + if (registerCredentialStatus) { + await this.registerCredentialStatus(credStatus, appDetail); + } let edvData = undefined; if (persist) { @@ -544,27 +543,19 @@ export class CredentialService { proof.type && proof.type === SupportedSignatureType.BJJSignature2021 ) { - hypersignVC = await this.credentialSSIService.initateHypersignVC( + hypersignVC = await this.credentialSSIService.initateHypersignBjjVC( appMenemonic, namespace, ); - hypersignVC.bjjVC; } else { hypersignVC = await this.credentialSSIService.initateHypersignVC( appMenemonic, namespace, ); } - - console.log(JSON.stringify(credentialStatus, null, 2)); - console.log(JSON.stringify(proof, null, 2)); - if (await this.checkAllowence(address)) { - console.log('if'); await this.txnService.sendVCTxn(credentialStatus, proof, appMenemonic); } else { - console.log('else'); - registeredVC = await hypersignVC.registerCredentialStatus({ credentialStatus, credentialStatusProof: proof, diff --git a/src/presentation/services/presentation.service.ts b/src/presentation/services/presentation.service.ts index 68258b2e..a69d9e5c 100644 --- a/src/presentation/services/presentation.service.ts +++ b/src/presentation/services/presentation.service.ts @@ -312,7 +312,6 @@ export class PresentationRequestService { const vmWithAssertion = didDocument.verificationMethod.find( (vm) => vm.id === verificationMethodIdforAssert, ); - console.log(vmWithAssertion); const { mnemonic: holderMnemonic } = await appVault.getDecryptedDocument( didInfo.kmsId, ); @@ -329,8 +328,6 @@ export class PresentationRequestService { ); const keys = await hypersignDid.generateKeys(holderMnemonic); privateKeyMultibase = keys.privateKeyMultibase; - console.log(privateKeyMultibase); - Logger.log( 'createPresentation() method: before calling hypersignVP.sign for bjj', 'PresentationRequestService', @@ -397,7 +394,6 @@ export class PresentationRequestService { ); let verifiedPresentationDetail; if (type === 'BJJSignature2021') { - console.log('in if'); verifiedPresentationDetail = await hypersignVP.bjjVp.verify({ signedPresentation: presentation as any, issuerDid, From f9867d7503303a41d3bda2669912ff92f5cd30e5 Mon Sep 17 00:00:00 2001 From: varsha766 Date: Mon, 21 Oct 2024 10:33:46 +0530 Subject: [PATCH 7/8] Added bjj credential --- src/credential/services/credential.service.ts | 60 ++++++++++++---- src/did/services/did.service.ts | 35 +++++----- src/tx-send-module/tx-send-module.service.ts | 69 +++++++++++-------- .../customDecorator/keyType.decorator.ts | 6 -- 4 files changed, 106 insertions(+), 64 deletions(-) diff --git a/src/credential/services/credential.service.ts b/src/credential/services/credential.service.ts index af5f6f28..61108feb 100644 --- a/src/credential/services/credential.service.ts +++ b/src/credential/services/credential.service.ts @@ -370,20 +370,41 @@ export class CredentialService { didInfo.kmsId, ); const seed = await this.hidWallet.getSeedFromMnemonic(issuerMnemonic); + let hypersignVC; const hypersignDid = new HypersignDID(); - const { privateKeyMultibase } = await hypersignDid.generateKeys({ seed }); - - // Apps Identity: - used for gas fee + const { didDocument } = await hypersignDid.resolve({ did: issuerDid }); + const verificationMethod = didDocument.verificationMethod.find( + (vm) => vm.id === verificationMethodId, + ); + let privateKeyMultibase; const appMenemonic = await getAppMenemonic(kmsId); const nameSpace = namespace ? namespace : this.config.get('NETWORK') ? this.config.get('NETWORK') : namespace; - const hypersignVC = await this.credentialSSIService.initateHypersignVC( - appMenemonic, - nameSpace, - ); + if ( + verificationMethod && + verificationMethod.type === IKeyType.BabyJubJubKey2021 + ) { + const key = await hypersignDid.bjjDID.generateKeys({ + mnemonic: issuerMnemonic, + }); + privateKeyMultibase = key.privateKeyMultibase; + hypersignVC = await this.credentialSSIService.initateHypersignBjjVC( + appMenemonic, + nameSpace, + ); + } else { + const key = await hypersignDid.generateKeys({ seed }); + privateKeyMultibase = key.privateKeyMultibase; + hypersignVC = await this.credentialSSIService.initateHypersignVC( + appMenemonic, + nameSpace, + ); + } + // Apps Identity: - used for gas fee + Logger.log( 'update() method: before calling hypersignVC.resolveCredentialStatus to resolve cred status', 'CredentialService', @@ -487,12 +508,25 @@ export class CredentialService { 'verfiyCredential() method: before calling hypersignVC.verify to verify credential', 'CredentialService', ); - verificationResult = await hypersignCredential.verify({ - credential: verifyCredentialDto.credentialDocument as any, // will fix it latter - issuerDid: issuer, - verificationMethodId: - verifyCredentialDto.credentialDocument.proof.verificationMethod, - }); + if ( + verifyCredentialDto.credentialDocument && + verifyCredentialDto.credentialDocument.proof.type === + SupportedSignatureType.BJJSignature2021 + ) { + verificationResult = await hypersignCredential.bjjVC.verify({ + credential: verifyCredentialDto.credentialDocument as any, // will fix it latter + issuerDid: issuer, + verificationMethodId: + verifyCredentialDto.credentialDocument.proof.verificationMethod, + }); + } else { + verificationResult = await hypersignCredential.verify({ + credential: verifyCredentialDto.credentialDocument as any, // will fix it latter + issuerDid: issuer, + verificationMethodId: + verifyCredentialDto.credentialDocument.proof.verificationMethod, + }); + } } catch (e) { Logger.error( `verfiyCredential() method: Error:${e.message}`, diff --git a/src/did/services/did.service.ts b/src/did/services/did.service.ts index f03005f1..b620cba3 100644 --- a/src/did/services/did.service.ts +++ b/src/did/services/did.service.ts @@ -752,10 +752,23 @@ export class DidService { finalSignInfos.push(generatedSignInfo[0]); } } - const registerDidDoc = await hypersignDid.registerByClientSpec({ - didDocument, - signInfos: finalSignInfos, - }); + let registerDidDoc; + const { wallet, address } = await this.hidWallet.generateWallet( + appMenemonic, + ); + if (await this.checkAllowence(address)) { + await this.txnService.sendDIDTxn( + didDocument, + finalSignInfos, + registerV2DidDto.signInfos, + appMenemonic, + ); + } else { + registerDidDoc = await hypersignDid.registerByClientSpec({ + didDocument, + signInfos: finalSignInfos, + }); + } let registerDidData; if (!didInfo || didInfo == undefined) { @@ -776,20 +789,6 @@ export class DidService { name: didInfo.name, }); } else { - // const { wallet, address } = await this.hidWallet.generateWallet( - // appMenemonic, - // ); - // if (await this.checkAllowence(address)) { - // await this.txnService.sendDIDTxn( - // didDocument, - // finalSignInfos, - // verificationMethodId, - // appMenemonic, - // ); - // } - // else { - // registerDidDoc = await hypersignDid.register(params); - // } registerDidData = await this.didRepositiory.findOneAndUpdate( { did: didDocument['id'] }, { diff --git a/src/tx-send-module/tx-send-module.service.ts b/src/tx-send-module/tx-send-module.service.ts index 308bd773..3bb40781 100644 --- a/src/tx-send-module/tx-send-module.service.ts +++ b/src/tx-send-module/tx-send-module.service.ts @@ -57,41 +57,57 @@ export class TxSendModuleService { async prepareMsgCreateDID( didDocument, didDocumentSigned, - verificationMethodId, + verificationMethodIdOrArray, txAuthor, ): Promise { - const proof = didDocumentSigned?.find((e) => { - return e.verification_method_id === verificationMethodId; - }); - - const vm = didDocument.verificationMethod?.find((e) => { - return e.id == verificationMethodId; - }); - let signatureType = ''; - let proofPurpose = ''; - switch (vm.type) { - case 'Ed25519VerificationKey2020': { - signatureType = 'Ed25519Signature2020'; - proofPurpose = 'assertionMethod'; - - break; + const verificationMethods = Array.isArray(verificationMethodIdOrArray) + ? verificationMethodIdOrArray + : [{ verification_method_id: verificationMethodIdOrArray }]; + const didDocumentProofs = []; + for (const { verification_method_id } of verificationMethods) { + const proof = didDocumentSigned?.find((e) => { + return e.verification_method_id === verification_method_id; + }); + const vm = didDocument.verificationMethod?.find((e) => { + return e.id == verification_method_id; + }); + if (!vm) { + throw new Error( + `Verification method ${verification_method_id} not found in DID document`, + ); } - default: { - throw Error('Type is not matched'); + + let signatureType = ''; + let proofPurpose = ''; + switch (vm.type) { + case 'Ed25519VerificationKey2020': { + signatureType = 'Ed25519Signature2020'; + proofPurpose = 'assertionMethod'; + break; + } + default: { + throw Error('Type is not matched'); + } } - } - return MsgRegisterDID.fromPartial({ - didDocument: didDocument, - didDocumentProofs: [ - { - verificationMethod: verificationMethodId, + if (proof) { + didDocumentProofs.push({ + verificationMethod: verification_method_id, type: signatureType, proofPurpose: proofPurpose, created: proof.created, proofValue: proof.signature, - }, - ], + }); + } else { + throw new Error( + `Proof for verification method ${verification_method_id} not found`, + ); + } + } + + return MsgRegisterDID.fromPartial({ + didDocument: didDocument, + didDocumentProofs, txAuthor: txAuthor, }); } @@ -406,7 +422,6 @@ export class TxSendModuleService { verificationMethodId, address, ); - const authExecMsg: MsgExec = { grantee: address, msgs: [ diff --git a/src/utils/customDecorator/keyType.decorator.ts b/src/utils/customDecorator/keyType.decorator.ts index 8aed907c..994ad3db 100644 --- a/src/utils/customDecorator/keyType.decorator.ts +++ b/src/utils/customDecorator/keyType.decorator.ts @@ -21,16 +21,12 @@ export function IsKeyTypeArrayOrSingle(validationOptions?: ValidationOptions) { // Ensure value is either a single string or an array const values = Array.isArray(value) ? value : [value]; - console.log(values); const invalidKeyTypes = values.filter( (val) => !Object.values(IKeyType).includes(val), ); - console.log(invalidKeyTypes, 'invalidKeyTypes'); // Ensure each value is part of the IKeyType enum if (invalidKeyTypes.length > 0) { (args as any).invalidKeyTypes = invalidKeyTypes; // Pass invalid key types for custom message - console.log('if1'); - return false; } @@ -60,9 +56,7 @@ export function IsKeyTypeArrayOrSingle(validationOptions?: ValidationOptions) { }, defaultMessage(args: ValidationArguments) { // Check for the error flags set during validation and customize the message accordingly - console.log(args); if ((args as any).invalidKeyTypes) { - console.log('if'); return `The provided key types ${JSON.stringify( (args as any).invalidKeyTypes, )} are invalid.`; From e453ebab3c2743b3a5a94dd02e803ff77c7d5a49 Mon Sep 17 00:00:00 2001 From: varsha766 Date: Mon, 21 Oct 2024 17:48:52 +0530 Subject: [PATCH 8/8] fixed presentation issue --- .../dto/create-presentation-request.dto.ts | 12 ++++++ .../dto/verify-presentation.dto.ts | 23 +++++++++++ .../services/presentation.service.ts | 38 ++++++++++++------- 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/src/presentation/dto/create-presentation-request.dto.ts b/src/presentation/dto/create-presentation-request.dto.ts index 250be858..e203aae2 100644 --- a/src/presentation/dto/create-presentation-request.dto.ts +++ b/src/presentation/dto/create-presentation-request.dto.ts @@ -10,6 +10,7 @@ import { ValidateNested, IsArray, ArrayNotEmpty, + IsOptional, } from 'class-validator'; import { CredDoc } from 'src/credential/dto/create-credential.dto'; import { IsDid } from 'src/utils/customDecorator/did.decorator'; @@ -167,6 +168,17 @@ export class CreatePresentationDto { @IsNotEmpty() @IsUrl() domain: string; + @ApiProperty({ + name: 'verificationMethodId', + description: + 'verificationMethodId of the holder that will be used to sign the presentation.', + example: 'did:hid:testnet:........#key-${idx}', + required: false, + }) + @IsOptional() + @ValidateVerificationMethodId() + @IsString() + verificationMethodId: string; } class PresentationProof { diff --git a/src/presentation/dto/verify-presentation.dto.ts b/src/presentation/dto/verify-presentation.dto.ts index ade6834a..fba443c9 100644 --- a/src/presentation/dto/verify-presentation.dto.ts +++ b/src/presentation/dto/verify-presentation.dto.ts @@ -6,6 +6,7 @@ import { IsNotEmpty, IsNotEmptyObject, IsObject, + IsOptional, IsString, ValidateNested, } from 'class-validator'; @@ -24,6 +25,28 @@ export class VerifyPresentationDto { @Type(() => Presentation) @ValidateNested({ each: true }) presentation: Presentation; + @ApiProperty({ + name: 'holderVerificationMethodId', + description: + 'The verificationMethodId used by the holder for signing the presentation.', + example: 'did:hid:testnet:........#key-${idx}', + required: false, + }) + @IsOptional() + @ValidateVerificationMethodId() + @IsString() + holderVerificationMethodId?: string; + @ApiProperty({ + name: 'issuerVerificationMethodId', + description: + 'The verificationMethodId used by the issuer for signing the credential.', + example: 'did:hid:testnet:........#key-${idx}', + required: false, + }) + @IsOptional() + @ValidateVerificationMethodId() + @IsString() + issuerVerificationMethodId?: string; } class PResultProof { diff --git a/src/presentation/services/presentation.service.ts b/src/presentation/services/presentation.service.ts index a69d9e5c..302d9b37 100644 --- a/src/presentation/services/presentation.service.ts +++ b/src/presentation/services/presentation.service.ts @@ -204,7 +204,6 @@ export class PresentationRequestService { private readonly hidWallet: HidWalletService, private readonly didSSIService: DidSSIService, ) {} - async createPresentationRequest( createPresentationRequestDto: CreatePresentationRequestDto, appDetail, @@ -250,8 +249,10 @@ export class PresentationRequestService { return response; } - - async createPresentation(credentialsDto: CreatePresentationDto, appDetail) { + async createPresentation( + CreatePresentationDto: CreatePresentationDto, + appDetail, + ) { Logger.log( 'createPresentation() method: starts....', 'PresentationRequestService', @@ -274,8 +275,13 @@ export class PresentationRequestService { namespace: 'testnet', }); - const { credentialDocuments, holderDid, challenge, domain } = - credentialsDto; + const { + credentialDocuments, + holderDid, + challenge, + verificationMethodId, + domain, + } = CreatePresentationDto; Logger.log( 'createPresentation() method: before calling hypersignVP.generate', 'PresentationRequestService', @@ -289,8 +295,8 @@ export class PresentationRequestService { const { didDocument } = await hypersignDID.resolve({ did: holderDid, }); - // TODO: Remove hardcoing - const verificationMethodIdforAssert = didDocument.assertionMethod[0]; + const verificationMethodIdforAssert = + verificationMethodId || didDocument.assertionMethod[0]; Logger.log( 'createPresentation() method: initialising edv service', 'PresentationRequestService', @@ -326,7 +332,9 @@ export class PresentationRequestService { hypersignDid = await this.didSSIService.initiateHyperSignBJJDidOffline( 'testnet', ); - const keys = await hypersignDid.generateKeys(holderMnemonic); + const keys = await hypersignDid.generateKeys({ + mnemonic: holderMnemonic, + }); privateKeyMultibase = keys.privateKeyMultibase; Logger.log( 'createPresentation() method: before calling hypersignVP.sign for bjj', @@ -383,8 +391,6 @@ export class PresentationRequestService { const holderDid = presentation['holder']; const issuerDid = presentation['verifiableCredential'][0]['issuer']; - - // const domain = presentation['proof']['domain']; const challenge = presentation['proof']['challenge']; const type = presentation['proof']['type']; @@ -393,13 +399,17 @@ export class PresentationRequestService { 'PresentationRequestService', ); let verifiedPresentationDetail; + const holderVerificationMethodId = + presentations.holderVerificationMethodId || holderDid + '#key-1'; + const issuerVerificationMethodId = + presentations.issuerVerificationMethodId || issuerDid + '#key-1'; if (type === 'BJJSignature2021') { verifiedPresentationDetail = await hypersignVP.bjjVp.verify({ signedPresentation: presentation as any, issuerDid, holderDid, - holderVerificationMethodId: holderDid + '#key-1', - issuerVerificationMethodId: issuerDid + '#key-1', + holderVerificationMethodId: holderVerificationMethodId, + issuerVerificationMethodId: issuerVerificationMethodId, challenge, }); } else { @@ -407,8 +417,8 @@ export class PresentationRequestService { signedPresentation: presentation as any, issuerDid, holderDid, - holderVerificationMethodId: holderDid + '#key-1', - issuerVerificationMethodId: issuerDid + '#key-1', + holderVerificationMethodId: holderVerificationMethodId, + issuerVerificationMethodId: issuerVerificationMethodId, challenge, }); }