diff --git a/src/communication/communication.gateway.ts b/src/communication/communication.gateway.ts index 87e5143..70e0c95 100644 --- a/src/communication/communication.gateway.ts +++ b/src/communication/communication.gateway.ts @@ -16,11 +16,11 @@ import { UsePipes, } from '@nestjs/common'; import { TransformVcPipe } from './transform-vc/transform-vc.pipe'; -import { MessageDto } from './dto/message.dto'; import { Client } from './dto/client.dto'; import { WsExceptionFilter } from './ws-exception/ws-exception.filter'; import { AuthenticationMessage } from '@tonomy/tonomy-id-sdk'; import { CommunicationGuard } from './communication.guard'; +import { BodyDto } from './dto/body.dto'; export type WebsocketReturnType = { status: HttpStatus; @@ -45,16 +45,19 @@ export class CommunicationGateway implements OnGatewayDisconnect { /** * Logs in the user and added it to the loggedIn map * - * @param {MessageDto} message - the VC the user sent + * @param {BodyDto} body - The message VC or an error from the transformer * @param {Client} client - user socket - * @returns void */ @SubscribeMessage('login') async connectUser( - @MessageBody() message: MessageDto, + @MessageBody() body: BodyDto, @ConnectedSocket() client: Client, ) { try { + if (body.error) throw body.error; + if (!body.value) throw new Error('Body not found'); + const message = body.value; + if (message.getType() !== AuthenticationMessage.getType()) { throw new HttpException( "Message type must be 'AuthenticationMessage'", @@ -73,17 +76,20 @@ export class CommunicationGateway implements OnGatewayDisconnect { /** * sends the message to the VC recipient if is connected and loggedIn - * @param message the VC the user sent + * @param {BodyDto} body - The message VC or an error from the transformer * @param client user socket - * @returns void */ @SubscribeMessage('message') @UseGuards(CommunicationGuard) async relayMessage( - @MessageBody() message: MessageDto, + @MessageBody() body: BodyDto, @ConnectedSocket() client: Client, ) { try { + if (body.error) throw body.error; + if (!body.value) throw new Error('Body not found'); + const message = body.value; + return { status: HttpStatus.OK, details: await this.usersService.sendMessage(client, message), diff --git a/src/communication/communication.service.ts b/src/communication/communication.service.ts index 2951c9a..f466e58 100644 --- a/src/communication/communication.service.ts +++ b/src/communication/communication.service.ts @@ -70,7 +70,8 @@ export class CommunicationService { } handleError(e): WebsocketReturnType { - this.logger.error(e); + console.error(e); + // this.logger.error(e); // This does not print stack trace if (e instanceof HttpException) { return { diff --git a/src/communication/dto/body.dto.ts b/src/communication/dto/body.dto.ts new file mode 100644 index 0000000..8eefb2f --- /dev/null +++ b/src/communication/dto/body.dto.ts @@ -0,0 +1,6 @@ +import { MessageDto } from './message.dto'; + +export type BodyDto = { + value?: MessageDto; + error?: any; +}; diff --git a/src/communication/transform-vc/transform-vc.pipe.ts b/src/communication/transform-vc/transform-vc.pipe.ts index ff2307f..132d7f7 100644 --- a/src/communication/transform-vc/transform-vc.pipe.ts +++ b/src/communication/transform-vc/transform-vc.pipe.ts @@ -6,42 +6,52 @@ import { PipeTransform, } from '@nestjs/common'; import { MessageDto, MessageRto } from '../dto/message.dto'; +import { BodyDto } from '../dto/body.dto'; @Injectable() export class TransformVcPipe implements PipeTransform { - async transform(value: MessageRto, metadata: ArgumentMetadata) { - if (metadata.type === 'body') { - const message = new MessageDto(value.message); + async transform( + value: MessageRto, + metadata: ArgumentMetadata, + ): Promise { + try { + if (metadata.type === 'body') { + const message = new MessageDto(value.message); - try { - const result = await message.verify(); + try { + const result = await message.verify(); - if (!result) - throw new HttpException( - `VC not could not verify signer from ${message.getSender()}`, - HttpStatus.UNAUTHORIZED, - ); - return message; - } catch (e) { - if ( - e.message?.startsWith( - 'resolver_error: Unable to resolve DID document for', - ) - ) { - throw new HttpException( - `DID could not be resolved from ${message.getSender()}`, - HttpStatus.NOT_FOUND, - ); - } + if (!result) + throw new HttpException( + `VC not could not verify signer from ${message.getSender()}`, + HttpStatus.UNAUTHORIZED, + ); + return { value: message }; + } catch (e) { + if ( + e.message?.startsWith( + 'resolver_error: Unable to resolve DID document for', + ) + ) { + throw new HttpException( + `DID could not be resolved from ${message.getSender()}`, + HttpStatus.NOT_FOUND, + ); + } - if (e instanceof HttpException) { - throw e; - } + if (e instanceof HttpException) { + throw e; + } - throw new HttpException(e, HttpStatus.INTERNAL_SERVER_ERROR); + throw new HttpException(e, HttpStatus.INTERNAL_SERVER_ERROR); + } + } else { + // Do nothing. transform() is not needed } + } catch (e) { + return { + error: e, + }; } - - return value; } } diff --git a/test/communication.e2e-spec.ts b/test/communication.e2e-spec.ts index 5a21ff3..77e7b97 100644 --- a/test/communication.e2e-spec.ts +++ b/test/communication.e2e-spec.ts @@ -38,6 +38,12 @@ describe('CommunicationGateway (e2e)', () => { }); describe('login event', () => { + // it('fails when provide an empty body', async () => { + // await expect(() => emitMessage(socket, 'login', {})).rejects.toThrow( + // "Cannot read properties of undefined (reading 'getCredentialSubject')", + // ); + // }); + it('succeeds for did:jwk message', async () => { const { privateKey, publicKey } = generateRandomKeyPair(); const signer = ES256KSigner(privateKey.data.array, true); diff --git a/test/ws-client.helper.ts b/test/ws-client.helper.ts index 98cde7f..bb1fa55 100644 --- a/test/ws-client.helper.ts +++ b/test/ws-client.helper.ts @@ -55,33 +55,3 @@ export async function emitMessage( return res.details; } } - -// export async function emitMessage( -// socket: Socket, -// event: string, -// body: any, -// ): Promise { -// return await new Promise((resolve, reject) => { -// let resolved = false; - -// const res = socket.emit(event, body, (response: any) => { -// console.log('response', response); - -// if (response.error) { -// reject(response.error); -// return; -// } - -// resolved = true; -// resolve(response); -// return; -// }); - -// // console.log('res', res); - -// setTimeout(() => { -// if (resolved) return; -// reject(new Error('Websocket event timed out')); -// }, 1000); -// }); -// }