diff --git a/src/app-auth/app-auth.module.ts b/src/app-auth/app-auth.module.ts index 9a6dfc0c..f6b97a95 100644 --- a/src/app-auth/app-auth.module.ts +++ b/src/app-auth/app-auth.module.ts @@ -22,14 +22,14 @@ import { AppAuthSecretService } from './services/app-auth-passord.service'; import { JwtModule } from '@nestjs/jwt'; import { JwtStrategy, JwtStrategyApp } from './strategy/jwt.strategy'; import { AppAuthApiKeyService } from './services/app-auth-apikey.service'; -import { WhitelistCorsMiddleware } from './middlewares/cors.middleware'; +import { WhitelistAppCorsMiddleware } from './middlewares/cors.middleware'; import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; @Module({ imports: [ MongooseModule.forFeature([{ name: App.name, schema: AppSchema }]), HidWalletModule, EdvModule, - + JwtModule.register({}), ], providers: [ @@ -41,16 +41,15 @@ import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; JwtStrategy, JwtStrategyApp, AppAuthApiKeyService, - ], controllers: [AppAuthController, AppOAuthController], - exports: [AppAuthService, AppRepository,AppAuthApiKeyService], + exports: [AppAuthService, AppRepository, AppAuthApiKeyService], }) export class AppAuthModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer - .apply(WhitelistCorsMiddleware) + .apply(WhitelistAppCorsMiddleware) .forRoutes(AppAuthController, AppOAuthController); consumer .apply(TrimMiddleware) diff --git a/src/app-auth/controllers/app-auth.controller.ts b/src/app-auth/controllers/app-auth.controller.ts index 67ca3bc8..dcd12e35 100644 --- a/src/app-auth/controllers/app-auth.controller.ts +++ b/src/app-auth/controllers/app-auth.controller.ts @@ -45,6 +45,7 @@ import { PaginationDto } from 'src/utils/pagination.dto'; import { AppSecretHeader } from '../decorator/app-sercret.decorator'; import { TransformResponseInterceptor } from '../interceptors/transformResponse.interseptor'; import { JwtGuard } from '../guard/jwt.guard'; +import { SanitizeUrl } from 'src/utils/customDecorator/urlSanitiser.decorator'; @UseFilters(AllExceptionsFilter) @Controller('app') @@ -124,6 +125,7 @@ export class AppAuthController { } @Post() + @SanitizeUrl() @UseInterceptors( MongooseClassSerializerInterceptor(createAppResponse, { excludePrefixes: ['apiKeyPrefix', '_', '__'], @@ -153,6 +155,7 @@ export class AppAuthController { }), ) @Put(':appId') + @SanitizeUrl() @ApiResponse({ status: 200, description: 'App updated', diff --git a/src/app-auth/middlewares/cors.middleware.ts b/src/app-auth/middlewares/cors.middleware.ts index 091086ec..ca0b5925 100644 --- a/src/app-auth/middlewares/cors.middleware.ts +++ b/src/app-auth/middlewares/cors.middleware.ts @@ -3,20 +3,36 @@ import { NestMiddleware, UnauthorizedException, } from '@nestjs/common'; - import { NextFunction, Request, Response } from 'express'; import { AppRepository } from 'src/app-auth/repositories/app.repository'; @Injectable() -export class WhitelistCorsMiddleware implements NestMiddleware { +export class WhitelistAppCorsMiddleware implements NestMiddleware { constructor(private readonly appRepositiory: AppRepository) {} async use(req: Request, res: Response, next: NextFunction) { const whitelistedOrigins = process.env.WHITELISTED_CORS; + const apiSecretKey = req.headers['x-api-secret-key'] as string; const origin = req.header('Origin'); - if (!whitelistedOrigins.includes(origin)) { + if (whitelistedOrigins.includes(origin)) { + return next(); + } else if (apiSecretKey !== '' && apiSecretKey != undefined) { + const apikeyIndex = apiSecretKey?.split('.')[0]; + const appDetail = await this.appRepositiory.findOne({ + apiKeyPrefix: apikeyIndex, + }); + if (!appDetail) { + throw new UnauthorizedException(['access_denied']); + } + if (appDetail.whitelistedCors.includes('*')) { + return next(); + } + if (!appDetail.whitelistedCors.includes(origin)) { + throw new UnauthorizedException(['Origin mismatch']); + } + return next(); + } else { throw new UnauthorizedException([ 'This is CORS-enabled for a whitelisted domain.', ]); } - next(); } } diff --git a/src/app-auth/services/app-auth.service.ts b/src/app-auth/services/app-auth.service.ts index 36f90ee9..0008a06b 100644 --- a/src/app-auth/services/app-auth.service.ts +++ b/src/app-auth/services/app-auth.service.ts @@ -34,7 +34,7 @@ export class AppAuthService { userId: string, ): Promise { const { mnemonic, address } = await this.hidWalletService.generateWallet(); - const appId=await this.appAuthApiKeyService.generateAppId() + const appId = await this.appAuthApiKeyService.generateAppId(); const edvId = 'hs:apiservice:edv:' + appId; await this.edvService.init(edvId); const document: EdvDocsDto = { diff --git a/src/credential/credential.module.ts b/src/credential/credential.module.ts index 9b605e44..1a152b0f 100644 --- a/src/credential/credential.module.ts +++ b/src/credential/credential.module.ts @@ -16,7 +16,7 @@ import { HidWalletService } from 'src/hid-wallet/services/hid-wallet.service'; import { CredentialRepository } from './repository/credential.repository'; import { DidModule } from 'src/did/did.module'; import { AppAuthModule } from 'src/app-auth/app-auth.module'; -import { WhitelistMiddleware } from 'src/utils/middleware/cors.middleware'; +import { WhitelistSSICorsMiddleware } from 'src/utils/middleware/cors.middleware'; import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; @Module({ imports: [ @@ -42,7 +42,7 @@ import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; }) export class CredentialModule implements NestModule { configure(consumer: MiddlewareConsumer) { - consumer.apply(WhitelistMiddleware).forRoutes(CredentialController); + consumer.apply(WhitelistSSICorsMiddleware).forRoutes(CredentialController); consumer .apply(TrimMiddleware) .exclude( diff --git a/src/did/controllers/did.controller.ts b/src/did/controllers/did.controller.ts index 2e0dc64c..d12e4b08 100644 --- a/src/did/controllers/did.controller.ts +++ b/src/did/controllers/did.controller.ts @@ -134,31 +134,29 @@ export class DidController { required: false, }) create(@Body() createDidDto: CreateDidDto, @Req() req: any) { - const { options } = createDidDto; + const { options } = createDidDto; const appDetail = req.user; switch (options?.keyType) { - case IKeyType.EcdsaSecp256k1RecoveryMethod2020:{ - + case IKeyType.EcdsaSecp256k1RecoveryMethod2020: { return this.didService.createByClientSpec(createDidDto, appDetail); break; } - - case IKeyType.EcdsaSecp256k1VerificationKey2019: - { - throw new NotFoundException({ - message: [`${options.keyType} is not supported`, `Feature coming soon`], - error: 'Not Supported', - status: 404, - }); - } - + case IKeyType.EcdsaSecp256k1VerificationKey2019: { + throw new NotFoundException({ + message: [ + `${options.keyType} is not supported`, + `Feature coming soon`, + ], + error: 'Not Supported', + status: 404, + }); + } + default: return this.didService.create(createDidDto, appDetail); - } - } @ApiCreatedResponse({ @@ -170,11 +168,16 @@ export class DidController { description: 'Error occured at the time of creating did', type: DidError, }) + @ApiHeader({ + name: 'Authorization', + description: 'Bearer ', + required: false, + }) @Post('/register') @UsePipes(ValidationPipe) - register(@Body() registerDidDto: RegisterDidDto,@Req() req:any){ + register(@Body() registerDidDto: RegisterDidDto, @Req() req: any) { const appDetail = req.user; - return this.didService.register(registerDidDto,appDetail) + return this.didService.register(registerDidDto, appDetail); } @UsePipes(ValidationPipe) diff --git a/src/did/did.module.ts b/src/did/did.module.ts index 4ef3b310..a7532939 100644 --- a/src/did/did.module.ts +++ b/src/did/did.module.ts @@ -20,7 +20,7 @@ import { import { HidWalletModule } from 'src/hid-wallet/hid-wallet.module'; import { HidWalletService } from 'src/hid-wallet/services/hid-wallet.service'; import { AppAuthModule } from 'src/app-auth/app-auth.module'; -import { WhitelistMiddleware } from 'src/utils/middleware/cors.middleware'; +import { WhitelistSSICorsMiddleware } from 'src/utils/middleware/cors.middleware'; import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; @Module({ imports: [ @@ -52,7 +52,7 @@ import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; }) export class DidModule implements NestModule { configure(consumer: MiddlewareConsumer) { - consumer.apply(WhitelistMiddleware).forRoutes(DidController); + consumer.apply(WhitelistSSICorsMiddleware).forRoutes(DidController); consumer .apply(TrimMiddleware) .exclude( diff --git a/src/did/dto/create-did.dto.ts b/src/did/dto/create-did.dto.ts index 0992d972..34e7875c 100644 --- a/src/did/dto/create-did.dto.ts +++ b/src/did/dto/create-did.dto.ts @@ -15,7 +15,6 @@ import { import { RegistrationStatus } from '../schemas/did.schema'; import { DidDoc } from '../dto/update-did.dto'; import { IsDid } from 'src/utils/customDecorator/did.decorator'; -import { Optional } from '@nestjs/common'; export enum IKeyType { Ed25519VerificationKey2020 = 'Ed25519VerificationKey2020', @@ -23,50 +22,56 @@ export enum IKeyType { EcdsaSecp256k1RecoveryMethod2020 = 'EcdsaSecp256k1RecoveryMethod2020', } - export class Options { @ApiProperty({ description: 'Verification Method Keytype Ed25519VerificationKey2020 or EcdsaSecp256k1RecoveryMethod2020', example: 'keyType:EcdsaSecp256k1RecoveryMethod2020', name: 'keyType', + required: false, }) @ValidateIf((o) => o.keyType !== undefined) @IsEnum(IKeyType) keyType: IKeyType; - @ApiProperty({ - name:'chainId', - example:'0x1', - description:"Chain Id" + name: 'chainId', + example: '0x1', + description: 'Chain Id', + required: false, }) @IsOptional() @IsString() - chainId:string; + chainId?: string; @ApiProperty({ - name:'publicKey', - example:`z76tzt4XCb6FNqC3CPZvsxRfEDX5HHQc2VPux4DeZYndW`, - description:"Public Key extracted from keplr" + name: 'publicKey', + example: `z76tzt4XCb6FNqC3CPZvsxRfEDX5HHQc2VPux4DeZYndW`, + description: 'Public Key extracted from keplr', + required: false, }) - @IsOptional() - @Type(()=>Uint8Array || String) - publicKey?:Uint8Array | string; + @Type(() => Uint8Array || String) + publicKey?: Uint8Array | string; @ApiProperty({ - name:'address', - example:`0x01978e553Df0C54A63e2E063DFFe71c688d91C76`, - description:"Checksum address from web3 wallet" + name: 'walletAddress', + example: `0x01978e553Df0C54A63e2E063DFFe71c688d91C76`, + description: 'Checksum address from web3 wallet', + required: false, }) @IsOptional() @IsString() - address:string - + walletAddress?: string; + @ApiProperty({ + name: 'register', + example: true, + description: 'If set to true did will be registerd on blockchain', + required: false, + }) @IsOptional() @IsBoolean() - register:boolean + register?: boolean; } export class CreateDidDto { @ApiProperty({ @@ -91,13 +96,13 @@ export class CreateDidDto { @ApiProperty({ name: 'options', description: ' keyType used for verification', + required: false, example: { keyType: 'Ed25519VerificationKey2020', - chainId:'0x1', - publicKey:'z76tzt4XCb6FNqC3CPZvsxRfEDX5HHQc2VPux4DeZYndW', - address:'0x01978e553Df0C54A63e2E063DFFe71c688d91C76', - register:false - + chainId: '0x1', + publicKey: 'z76tzt4XCb6FNqC3CPZvsxRfEDX5HHQc2VPux4DeZYndW', + walletAddress: '0x01978e553Df0C54A63e2E063DFFe71c688d91C76', + register: false, }, }) @IsOptional() @@ -106,7 +111,7 @@ export class CreateDidDto { @ValidateNested({ each: true, }) - options: Options; + options?: Options; } export class TxnHash { @@ -140,7 +145,7 @@ export class CreateDidResponse { description: 'Transaction Has', example: 'XYAIFLKFLKHSLFHKLAOHFOAIHG..........', }) - @IsString() + @IsString() transactionHash: string; @ApiProperty({ diff --git a/src/did/dto/register-did.dto.ts b/src/did/dto/register-did.dto.ts index 482d8820..ad234149 100644 --- a/src/did/dto/register-did.dto.ts +++ b/src/did/dto/register-did.dto.ts @@ -1,64 +1,57 @@ -import { ApiHideProperty, ApiProperty } from "@nestjs/swagger"; -import { DidDoc, UpdateDidDto } from "./update-did.dto"; -import { IsArray, IsEnum, IsNotEmpty, IsOptional, IsString, ValidateNested } from "class-validator"; -import { Type } from "class-transformer"; -import { ValidateVerificationMethodId } from "src/utils/customDecorator/vmId.decorator"; -import { type } from "os"; +import { ApiProperty } from '@nestjs/swagger'; +import { DidDoc } from './update-did.dto'; +import { IsEnum, IsOptional, IsString, ValidateNested } from 'class-validator'; +import { Type } from 'class-transformer'; +import { ValidateVerificationMethodId } from 'src/utils/customDecorator/vmId.decorator'; export enum IClientSpec { - 'eth-personalSign' = 'eth-personalSign', - 'cosmos-ADR036' = 'cosmos-ADR036', + 'eth-personalSign' = 'eth-personalSign', + 'cosmos-ADR036' = 'cosmos-ADR036', } export class RegisterDidDto { - @ApiProperty({ - description: 'Did doc to be updated', - type: DidDoc, - }) - @Type(() => DidDoc) - @ValidateNested({each:true}) - didDocument: DidDoc; - - @ApiProperty({ - description: 'Verification Method id for did updation', - example: 'did:hid:testnet:........#key-${idx}', - required:true - }) - @ValidateVerificationMethodId() - @IsString() - verificationMethodId: string; - - - @ApiProperty({ - description: - "IClientSpec 'eth-personalSign' or 'cosmos-ADR036'", - example: 'eth-personalSign', - name: 'clientSpec', - }) - @IsOptional() - @IsEnum(IClientSpec) - clientSpec: IClientSpec; - - - @ApiProperty({ - description: - "Signature for clientSpec", - example: 'afafljagahgp9agjagknaglkj/kagka=', - name: 'signature', - }) - @IsOptional() - @IsString() - signature: string; - @ApiProperty({ - description: - "Signature for clientSpec cosmos-ADR036", - example: "hid148273582", - name: 'address', - }) - @IsOptional() - @IsString() - address: string - - + @ApiProperty({ + description: 'Did doc to be updated', + type: DidDoc, + }) + @Type(() => DidDoc) + @ValidateNested({ each: true }) + didDocument: DidDoc; + + @ApiProperty({ + description: 'Verification Method id for did updation', + example: 'did:hid:testnet:........#key-${idx}', + required: true, + }) + @ValidateVerificationMethodId() + @IsString() + verificationMethodId: string; + + @ApiProperty({ + description: "IClientSpec 'eth-personalSign' or 'cosmos-ADR036'", + example: 'eth-personalSign', + name: 'clientSpec', + required: false, + }) + @IsOptional() + @IsEnum(IClientSpec) + clientSpec?: IClientSpec; + + @ApiProperty({ + description: 'Signature for clientSpec', + example: 'afafljagahgp9agjagknaglkj/kagka=', + name: 'signature', + required: false, + }) + @IsOptional() + @IsString() + signature?: string; + @ApiProperty({ + description: 'Checksum address from web3 wallet', + example: 'hid148273582', + name: 'address', + required: false, + }) + @IsOptional() + @IsString() + address?: string; } - - diff --git a/src/did/dto/update-did.dto.ts b/src/did/dto/update-did.dto.ts index 72c37c0a..9d522059 100644 --- a/src/did/dto/update-did.dto.ts +++ b/src/did/dto/update-did.dto.ts @@ -1,6 +1,12 @@ import { ApiProperty } from '@nestjs/swagger'; import { Type } from 'class-transformer'; -import { IsArray, IsEnum, IsOptional, IsString, ValidateNested } from 'class-validator'; +import { + IsArray, + IsEnum, + IsOptional, + IsString, + ValidateNested, +} from 'class-validator'; import { IsDid } from 'src/utils/customDecorator/did.decorator'; import { ValidateVerificationMethodId } from 'src/utils/customDecorator/vmId.decorator'; export enum IClientSpec { @@ -13,7 +19,6 @@ class verificationMethod { example: 'did:hid:testnet:z28ScfSszr2zi2Bd7qmNE4mfHX5j8nCwx4DBF6nAUHu4p#key-1', }) - @IsString() @ValidateVerificationMethodId() id: string; @@ -33,17 +38,19 @@ class verificationMethod { @ApiProperty({ description: 'publicKeyMultibase', example: 'z28ScfSszr2zi2Bd7qmNE4mfHX5j8nCwx4DBF6nAUHu4p', + required: false, }) @IsOptional() @IsString() - publicKeyMultibase: string; + publicKeyMultibase?: string; @ApiProperty({ description: 'blockchainAccountId', example: 'eip155:1:0x19d73aeeBcc6FEf2d0342375090401301Fe9663F', + required: false, }) @IsOptional() @IsString() - blockchainAccountId: string; + blockchainAccountId?: string; } class Service { @ApiProperty({ @@ -105,7 +112,7 @@ export class DidDoc { isArray: true, }) @Type(() => verificationMethod) - @ValidateNested({each:true}) + @ValidateNested({ each: true }) verificationMethod: Array; @ApiProperty({ description: 'authentication', @@ -142,6 +149,7 @@ export class DidDoc { description: 'service', type: Service, isArray: true, + required: false, }) @IsOptional() @Type(() => Array) @@ -210,25 +218,22 @@ export class UpdateDidDto { @IsString() verificationMethodId: string; @ApiProperty({ - description: - "IClientSpec 'eth-personalSign' or 'cosmos-ADR036'", + description: "IClientSpec 'eth-personalSign' or 'cosmos-ADR036'", example: 'eth-personalSign', name: 'clientSpec', -}) -@IsOptional() -@IsEnum(IClientSpec) -clientSpec: IClientSpec; - - -@ApiProperty({ - description: - "Signature for clientSpec", - example: 'afafljagahgp9agjagknaglkj/kagka=', - name: 'signature', -}) -@IsOptional() -@IsString() -signature: string; - + required: false, + }) + @IsOptional() + @IsEnum(IClientSpec) + clientSpec?: IClientSpec; + @ApiProperty({ + description: 'Signature for clientSpec', + example: 'afafljagahgp9agjagknaglkj/kagka=', + name: 'signature', + required: false, + }) + @IsOptional() + @IsString() + signature?: string; } diff --git a/src/did/schemas/did.schema.ts b/src/did/schemas/did.schema.ts index 55d41d9f..cc842049 100644 --- a/src/did/schemas/did.schema.ts +++ b/src/did/schemas/did.schema.ts @@ -11,7 +11,7 @@ export type DidDocumentMetaData = DidMetaData & Document; export enum RegistrationStatus { PROCESSING = 'PROCESSING', COMPLETED = 'COMPLETED', - UNREGISTRED='UNREGISTRED' + UNREGISTRED = 'UNREGISTRED', } @Schema() export class Did { diff --git a/src/did/services/did.service.ts b/src/did/services/did.service.ts index 12d80cf0..7241f1d8 100644 --- a/src/did/services/did.service.ts +++ b/src/did/services/did.service.ts @@ -28,33 +28,40 @@ export class DidService { private readonly edvService: EdvService, private readonly hidWallet: HidWalletService, private readonly didSSIService: DidSSIService, - ) { } - + ) {} async createByClientSpec(createDidDto: CreateDidDto, appDetail) { - let methodSpecificId = createDidDto.methodSpecificId; - - const publicKey = createDidDto.options?.publicKey - const chainId = createDidDto.options.chainId - const keyType = createDidDto.options.keyType - const address=createDidDto.options.address - const register=createDidDto.options?.register - if(!methodSpecificId){ - methodSpecificId=address - } - if(!address){ - throw new BadRequestException(["options.address is not passed , required for keyType "+IKeyType.EcdsaSecp256k1RecoveryMethod2020]) + const publicKey = createDidDto.options?.publicKey; + const chainId = createDidDto.options.chainId; + const keyType = createDidDto.options.keyType; + const address = createDidDto.options.walletAddress; + const register = createDidDto.options?.register; + if (!methodSpecificId) { + methodSpecificId = address; } - if(!chainId){ - throw new BadRequestException(["options.chainId is not passed , required for keyType "+IKeyType.EcdsaSecp256k1RecoveryMethod2020]) - + if (!address) { + throw new BadRequestException([ + 'options.walletAddress is not passed , required for keyType ' + + IKeyType.EcdsaSecp256k1RecoveryMethod2020, + ]); + } + if (!chainId) { + throw new BadRequestException([ + 'options.chainId is not passed , required for keyType ' + + IKeyType.EcdsaSecp256k1RecoveryMethod2020, + ]); } - if(register===true){ - throw new BadRequestException(["options.register is true for keyType "+ IKeyType.EcdsaSecp256k1RecoveryMethod2020,IKeyType.EcdsaSecp256k1RecoveryMethod2020 +" doesnot support register without signature being passed","options.register:false is strongly recomended"]) - + if (register === true) { + throw new BadRequestException([ + 'options.register is true for keyType ' + + IKeyType.EcdsaSecp256k1RecoveryMethod2020, + IKeyType.EcdsaSecp256k1RecoveryMethod2020 + + ' doesnot support register without signature being passed', + 'options.register:false is strongly recomended', + ]); } const { edvId, edvDocId } = appDetail; @@ -70,8 +77,8 @@ export class DidService { publicKey, chainId, keyType, - address - }) + address, + }); return { did: didDoc.id, @@ -79,9 +86,8 @@ export class DidService { transactionHash: '', metaData: { didDocument: didDoc, - } - - } + }, + }; } async create( @@ -122,7 +128,6 @@ export class DidService { publicKeyMultibase, }); - const params = { didDocument: didDoc, privateKeyMultibase, @@ -175,29 +180,33 @@ export class DidService { } } - - async register(registerDidDto: RegisterDidDto, - appDetail): Promise { + async register( + registerDidDto: RegisterDidDto, + appDetail, + ): Promise { let registerDidDoc; const { edvId, edvDocId } = appDetail; await this.edvService.init(edvId); const docs = await this.edvService.getDecryptedDocument(edvDocId); const mnemonic: string = docs.mnemonic; - const namespace = registerDidDto.didDocument['id'].split(":")[2] // Todo Remove this worst way of doing it + const namespace = registerDidDto.didDocument['id'].split(':')[2]; // Todo Remove this worst way of doing it const hypersignDid = await this.didSSIService.initiateHypersignDid( mnemonic, namespace, ); - + let data; switch (registerDidDto.clientSpec) { case IClientSpec['eth-personalSign']: { - const { didDocument, verificationMethodId, clientSpec, signature } = registerDidDto - + const { didDocument, verificationMethodId, clientSpec, signature } = + registerDidDto; registerDidDoc = await hypersignDid.registerByClientSpec({ - didDocument, clientSpec, verificationMethodId, signature - }) - const data=await this.didRepositiory.create({ + didDocument, + clientSpec, + verificationMethodId, + signature, + }); + data = await this.didRepositiory.create({ did: didDocument['id'], appId: appDetail.appId, slipPathKeys: null, @@ -211,36 +220,31 @@ export class DidService { ? RegistrationStatus.COMPLETED : RegistrationStatus.UNREGISTRED, }); - break; - } case IClientSpec['cosmos-ADR036']: { - throw new BadRequestException([ - 'Not Supported' - ]) - + throw new BadRequestException(['Not Supported']); } default: - const { didDocument, verificationMethodId } = registerDidDto + const { didDocument, verificationMethodId } = registerDidDto; const didData = await this.didRepositiory.findOne({ - did: didDocument['id'] - }) + did: didDocument['id'], + }); if (!didData) { - throw new NotFoundException([didDocument['id'] + " not found"]) - + throw new NotFoundException([didDocument['id'] + ' not found']); } - const hdPathIndex = didData.hdPathIndex + const hdPathIndex = didData.hdPathIndex; const slipPathKeys: Array = this.hidWallet.makeSSIWalletPath(hdPathIndex); - const seed = await this.hidWallet.generateMemonicToSeedFromSlip10RawIndex( - slipPathKeys, - ); + const seed = + await this.hidWallet.generateMemonicToSeedFromSlip10RawIndex( + slipPathKeys, + ); const { publicKeyMultibase, privateKeyMultibase } = await hypersignDid.generateKeys({ seed }); const params = { @@ -250,31 +254,33 @@ export class DidService { }; registerDidDoc = await hypersignDid.register(params); - this.didRepositiory.findOneAndUpdate({ did: didDocument['id'] }, { - did: didDocument['id'], - appId: appDetail.appId, - slipPathKeys, - hdPathIndex, - transactionHash: - registerDidDoc && registerDidDoc?.transactionHash - ? registerDidDoc.transactionHash - : '', - registrationStatus: - registerDidDoc && registerDidDoc?.transactionHash - ? RegistrationStatus.COMPLETED - : RegistrationStatus.UNREGISTRED, - }); + data = await this.didRepositiory.findOneAndUpdate( + { did: didDocument['id'] }, + { + did: didDocument['id'], + appId: appDetail.appId, + slipPathKeys, + hdPathIndex, + transactionHash: + registerDidDoc && registerDidDoc?.transactionHash + ? registerDidDoc.transactionHash + : '', + registrationStatus: + registerDidDoc && registerDidDoc?.transactionHash + ? RegistrationStatus.COMPLETED + : RegistrationStatus.UNREGISTRED, + }, + ); break; } - const data=await this.didRepositiory.findOne({did:registerDidDto.didDocument.id}) - return { + return { did: data.did, - registrationStatus:data.registrationStatus, - transactionHash:data.transactionHash, + registrationStatus: data.registrationStatus, + transactionHash: data.transactionHash, metaData: { didDocument: registerDidDto.didDocument, }, - } + }; } async getDidList(appDetail, option): Promise { @@ -365,7 +371,7 @@ export class DidService { switch (updateDidDto.clientSpec) { case IClientSpec['eth-personalSign']: - const { clientSpec, signature } = updateDidDto + const { clientSpec, signature } = updateDidDto; try { if (!updateDidDto.deactivate) { updatedDid = await hypersignDid.updateByClientSpec({ @@ -390,20 +396,23 @@ export class DidService { break; case IClientSpec['cosmos-ADR036']: { - throw new BadRequestException(["Not Supported"]) - break + throw new BadRequestException(['Not Supported']); + break; } default: { - - - const slipPathKeys = this.hidWallet.makeSSIWalletPath(didInfo.hdPathIndex); - - const seed = await this.hidWallet.generateMemonicToSeedFromSlip10RawIndex( - slipPathKeys, + const slipPathKeys = this.hidWallet.makeSSIWalletPath( + didInfo.hdPathIndex, ); - const { privateKeyMultibase } = await hypersignDid.generateKeys({ seed }); + const seed = + await this.hidWallet.generateMemonicToSeedFromSlip10RawIndex( + slipPathKeys, + ); + + const { privateKeyMultibase } = await hypersignDid.generateKeys({ + seed, + }); try { if (!updateDidDto.deactivate) { updatedDid = await hypersignDid.update({ diff --git a/src/presentation/presentation.module.ts b/src/presentation/presentation.module.ts index ef38bfe0..56af3eb8 100644 --- a/src/presentation/presentation.module.ts +++ b/src/presentation/presentation.module.ts @@ -22,14 +22,14 @@ import { HidWalletService } from 'src/hid-wallet/services/hid-wallet.service'; import { EdvService } from 'src/edv/services/edv.service'; import { DidModule } from 'src/did/did.module'; import { AppAuthModule } from 'src/app-auth/app-auth.module'; -import { WhitelistMiddleware } from 'src/utils/middleware/cors.middleware'; +import { WhitelistSSICorsMiddleware } from 'src/utils/middleware/cors.middleware'; import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; import { AppAuthApiKeyService } from 'src/app-auth/services/app-auth-apikey.service'; @Module({ imports: [ DidModule, AppAuthModule, - + MongooseModule.forFeature([ { name: PresentationTemplate.name, @@ -44,13 +44,12 @@ import { AppAuthApiKeyService } from 'src/app-auth/services/app-auth-apikey.serv PresentationRequestService, HidWalletService, EdvService, - ], }) export class PresentationModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer - .apply(WhitelistMiddleware) + .apply(WhitelistSSICorsMiddleware) .forRoutes(PresentationTempleteController, PresentationController); consumer .apply(TrimMiddleware) diff --git a/src/presentation/services/presentation.service.ts b/src/presentation/services/presentation.service.ts index c4545e56..74063f63 100644 --- a/src/presentation/services/presentation.service.ts +++ b/src/presentation/services/presentation.service.ts @@ -143,8 +143,7 @@ export class PresentationRequestService { private readonly config: ConfigService, private readonly edvService: EdvService, private readonly hidWallet: HidWalletService, - private readonly keyService:AppAuthApiKeyService - + private readonly keyService: AppAuthApiKeyService, ) {} async createPresentationRequest( diff --git a/src/schema/schema.module.ts b/src/schema/schema.module.ts index 77cf10cd..d88a4caa 100644 --- a/src/schema/schema.module.ts +++ b/src/schema/schema.module.ts @@ -14,7 +14,7 @@ import { DidModule } from 'src/did/did.module'; import { SchemaRepository } from './repository/schema.repository'; import { MongooseModule } from '@nestjs/mongoose'; import { Schemas, SchemasSchema } from './schemas/schemas.schema'; -import { WhitelistMiddleware } from 'src/utils/middleware/cors.middleware'; +import { WhitelistSSICorsMiddleware } from 'src/utils/middleware/cors.middleware'; import { AppAuthModule } from 'src/app-auth/app-auth.module'; import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; @Module({ @@ -37,7 +37,7 @@ import { TrimMiddleware } from 'src/utils/middleware/trim.middleware'; export class SchemaModule implements NestModule { configure(consumer: MiddlewareConsumer) { //// Appy middleware on all routes - consumer.apply(WhitelistMiddleware).forRoutes(SchemaController); + consumer.apply(WhitelistSSICorsMiddleware).forRoutes(SchemaController); //apply middleware on all routes except mentioned in exclude() consumer .apply(TrimMiddleware) diff --git a/src/utils/customDecorator/urlSanitiser.decorator.ts b/src/utils/customDecorator/urlSanitiser.decorator.ts new file mode 100644 index 00000000..bf6e16ee --- /dev/null +++ b/src/utils/customDecorator/urlSanitiser.decorator.ts @@ -0,0 +1,11 @@ +export const SanitizeUrl = () => (target, key, descriptor) => { + const originalMethod = descriptor.value; + descriptor.value = function (...args) { + const urls = args[0].body.whitelistedCors; + const cleanedUrls = urls.map((url) => url.replace(/\/$/, '')); + const uniqueUrls = Array.from(new Set(cleanedUrls)); + args[0].body.whitelistedCors = uniqueUrls; + return originalMethod.apply(this, args); + }; + return descriptor; +}; diff --git a/src/utils/middleware/cors.middleware.ts b/src/utils/middleware/cors.middleware.ts index aa011914..b231d5bc 100644 --- a/src/utils/middleware/cors.middleware.ts +++ b/src/utils/middleware/cors.middleware.ts @@ -8,11 +8,20 @@ import * as jwt from 'jsonwebtoken'; import { NextFunction, Request, Response } from 'express'; import { AppRepository } from 'src/app-auth/repositories/app.repository'; @Injectable() -export class WhitelistMiddleware implements NestMiddleware { +export class WhitelistSSICorsMiddleware implements NestMiddleware { constructor(private readonly appRepositiory: AppRepository) {} async use(req: Request, res: Response, next: NextFunction) { - const origin = req.header('Origin'); - if (req.header('authorization') == undefined) { + const origin = req.header('Origin') || req.header('Referer'); + let matchOrigin; + if (origin) { + // regex to check if url consists of some path or not + const originRegx = /^https?:\/\/[^\/]+/i; + matchOrigin = origin.match(originRegx); + } + if ( + req.header('authorization') == undefined || + req.header('authorization') == '' + ) { throw new UnauthorizedException([ 'Unauthorized', 'Please pass access token', @@ -25,6 +34,10 @@ export class WhitelistMiddleware implements NestMiddleware { } catch (e) { throw new UnauthorizedException([e]); } + const whitelistedOrigins = process.env.WHITELISTED_CORS; + if (matchOrigin && whitelistedOrigins.includes(matchOrigin[0])) { + return next(); + } const appInfo = await this.appRepositiory.findOne({ appId: decoded['appId'], userId: decoded['userId'], diff --git a/src/utils/utils.ts b/src/utils/utils.ts index f45a3896..b14723c5 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -85,7 +85,7 @@ export class AllExceptionsFilter implements ExceptionFilter { if (exception instanceof HttpException) { status = exception.getStatus(); message = exception.getResponse(); - } else { + } else { const msg = []; const error: Error = exception as Error; if (error.name) {