From 2c5d6c12af3e084a60937ad9722dafbd1648d2f4 Mon Sep 17 00:00:00 2001 From: ohager Date: Tue, 8 Aug 2023 15:12:14 -0300 Subject: [PATCH] Fix/type stuff (#64) * fix: types in HttpError and Attachment * feat: more expressive attahcment typing * test: fixed unit tests * fix: binary message verification - fixes #63 --- .../src/api/__tests__/transactionApi.spec.ts | 16 ++++++------ .../createParametersFromAttachment.spec.ts | 16 ++++++------ .../__tests__/verifyTransaction.spec.ts | 23 +++++++++++++++++ .../verifyTransaction/verifyTransaction.ts | 6 +++++ packages/core/src/typings/attachment.ts | 25 +++++++++++-------- packages/http/src/httpError.ts | 3 ++- 6 files changed, 64 insertions(+), 25 deletions(-) diff --git a/packages/core/src/api/__tests__/transactionApi.spec.ts b/packages/core/src/api/__tests__/transactionApi.spec.ts index 5052e5f0..c83ba9d2 100644 --- a/packages/core/src/api/__tests__/transactionApi.spec.ts +++ b/packages/core/src/api/__tests__/transactionApi.spec.ts @@ -426,10 +426,11 @@ describe('TransactionApi', () => { const service = createChainService(httpMock, 'relPath'); - const encryptedMessage = new AttachmentEncryptedMessage(); - encryptedMessage.data = 'data'; - encryptedMessage.isText = true; - encryptedMessage.nonce = 'nonce'; + const encryptedMessage = new AttachmentEncryptedMessage({ + data: 'data', + isText: true, + nonce: 'nonce', + }); const status = await sendAmountToSingleRecipient(service)( { @@ -459,9 +460,10 @@ describe('TransactionApi', () => { const service = createChainService(httpMock, 'relPath'); - const message = new AttachmentMessage(); - message.message = 'message'; - message.messageIsText = true; + const message = new AttachmentMessage({ + message: 'message', + messageIsText: true, + }); const status = await sendAmountToSingleRecipient(service)({ amountPlanck: '2000', diff --git a/packages/core/src/internal/__tests__/createParametersFromAttachment.spec.ts b/packages/core/src/internal/__tests__/createParametersFromAttachment.spec.ts index 175a4911..33e27cbb 100644 --- a/packages/core/src/internal/__tests__/createParametersFromAttachment.spec.ts +++ b/packages/core/src/internal/__tests__/createParametersFromAttachment.spec.ts @@ -6,9 +6,10 @@ describe('createParametersFromAttachment', () => { it('should construct message attachment', () => { - const messageAttachment = new AttachmentMessage(); - messageAttachment.message = 'message'; - messageAttachment.messageIsText = true; + const messageAttachment = new AttachmentMessage({ + message: 'message', + messageIsText: true, + }); const params = createParametersFromAttachment(messageAttachment, {foo: 'bar'}); expect(params).toEqual( @@ -19,10 +20,11 @@ describe('createParametersFromAttachment', () => { it('should construct encrypted message attachment', () => { - const encryptedMessageAttachment = new AttachmentEncryptedMessage(); - encryptedMessageAttachment.data = 'data'; - encryptedMessageAttachment.nonce = 'nonce'; - encryptedMessageAttachment.isText = true; + const encryptedMessageAttachment = new AttachmentEncryptedMessage({ + data: 'data', + isText: true, + nonce: 'nonce' + }); const params = createParametersFromAttachment(encryptedMessageAttachment, {foo: 'bar'}); expect(params).toEqual( diff --git a/packages/core/src/internal/verifyTransaction/__tests__/verifyTransaction.spec.ts b/packages/core/src/internal/verifyTransaction/__tests__/verifyTransaction.spec.ts index fbc5549c..a275b6dc 100644 --- a/packages/core/src/internal/verifyTransaction/__tests__/verifyTransaction.spec.ts +++ b/packages/core/src/internal/verifyTransaction/__tests__/verifyTransaction.spec.ts @@ -23,6 +23,28 @@ describe('verifyTransaction', function () { verifyTransaction(requestType, formData, testResponse); }).not.toThrow(); }); + it('should pass verification as expected - for non-text messages - case-insensitive', () => { + const requestType = 'sendMoney'; + const formData = { + feeNQT: '2000000', + amountNQT: '30000000', + recipient: '4388562308859987170', + publicKey: '497d559d18d989b8e2d729eb6f69b70c1ddc3e554f75bef3ed2716a4b2121902', + message: 'C8AEA1C25FE7BFFE', + messageIsText: false, + deadline: 1440 + }; + + const testResponse = { + 'broadcasted': false, + 'unsignedTransactionBytes': '0020195dea10a005497d559d18d989b8e2d729eb6f69b70c1ddc3e554f75bef3ed2716a4b2121902e28444162b4ee73c80c3c9010000000080841e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000eef21100d97ccce0e6e218e304cfe1531b543c7c0108000000c8aea1c25fe7bffe', + 'transactionJSON': {}, + 'requestProcessingTime': 8 + }; + expect(() => { + verifyTransaction(requestType, formData, testResponse); + }).not.toThrow(); + }); it('should throw error. Response is another transaction type', () => { const requestType = 'sendMoneyMultiSame'; const formData = { @@ -215,6 +237,7 @@ describe('verifyTransaction', function () { verifyTransaction(requestType, formData, testResponse); }).not.toThrow(); }); + it('should pass verification as expected - with non-zero quantity and non-mintable', () => { const requestType = 'issueAsset'; const formData = { diff --git a/packages/core/src/internal/verifyTransaction/verifyTransaction.ts b/packages/core/src/internal/verifyTransaction/verifyTransaction.ts index 910a17a9..87ad2ceb 100644 --- a/packages/core/src/internal/verifyTransaction/verifyTransaction.ts +++ b/packages/core/src/internal/verifyTransaction/verifyTransaction.ts @@ -46,6 +46,7 @@ export function verifyTransaction(method: string, parameters: any, response: any throw new Error('Verification failed - Node Response does not match transaction parameters (A)'); } + let nParameters = 0; // tslint:disable-next-line:forin for (const prop in parameters) { @@ -75,6 +76,11 @@ export function verifyTransaction(method: string, parameters: any, response: any throw new Error(`Verification failed - Node Response does not match transaction parameter '${prop}'.`); } break; + case 'message': + if (Boolean(parameters['messageIsText']) && String(parameters['message']).toLocaleLowerCase() !== String(rebuiltObject.rebuiltData['message']).toLocaleLowerCase()) { + throw new Error(`Verification failed - Node Response does not match transaction parameter 'message'.`); + } + break; default: // case sensitive properties if (String(parameters[prop]) !== String(rebuiltObject.rebuiltData[prop])) { diff --git a/packages/core/src/typings/attachment.ts b/packages/core/src/typings/attachment.ts index 8719d816..b428287c 100644 --- a/packages/core/src/typings/attachment.ts +++ b/packages/core/src/typings/attachment.ts @@ -16,8 +16,8 @@ export class Attachment { } interface AttachmentMessageArgs { - messageIsText?: boolean; - message?: string; + messageIsText: boolean; + message: string; } /** @@ -30,13 +30,19 @@ export class AttachmentMessage extends Attachment { public messageIsText: boolean; public message: string; - constructor(data: AttachmentMessageArgs = {}) { + constructor(data: AttachmentMessageArgs) { super('message'); - this.messageIsText = data.messageIsText || false; - this.message = data.message || undefined; + this.messageIsText = data.messageIsText; + this.message = data.message; } } +interface AttachmentEncryptedMessageArgs { + data: string; + nonce: string; + isText: boolean; +} + /** * EncryptedMessage class * @@ -48,11 +54,10 @@ export class AttachmentEncryptedMessage extends Attachment { public nonce: string; public isText: boolean; - // TODO: make constructor attrs as single args to be more expressive - constructor(data: any = {}) { + constructor(data: AttachmentEncryptedMessageArgs) { super('encrypted_message'); - this.data = data.data || undefined; - this.nonce = data.nonce || undefined; - this.isText = data.isText || false; + this.data = data.data; + this.nonce = data.nonce; + this.isText = data.isText; } } diff --git a/packages/http/src/httpError.ts b/packages/http/src/httpError.ts index 5bbb2ce4..ad8d16e5 100644 --- a/packages/http/src/httpError.ts +++ b/packages/http/src/httpError.ts @@ -8,12 +8,13 @@ * Thrown on HTTP errors * @module http */ -export class HttpError { +export class HttpError extends Error { public timestamp: number = Date.now(); constructor(public requestUrl: string, public status: number, public message: string, public data: any) { + super(message); } }