From 5418b679e52e3c19bec9589177119f31b14a562a Mon Sep 17 00:00:00 2001 From: Vassilis Barzokas Date: Mon, 16 Mar 2020 16:56:01 +0200 Subject: [PATCH] Feature/check for 404 (#262) * Added additional check of the returned status code being 404 in case there is a communication error with the target oracle endpoint. * Bump to 9.3.2 * Added comments to clarify the reason of this change. * Fixed vulnerabilities with `npm audit fix` * Fixed the remaining vulnerabilities with `npm audit fix` * Changed the returned error code on the edge case of `DESTINATION_COMMUNICATION_ERROR` && `NOTFOUND.CODE` to be `DESTINATION_FSP_ERROR` instead of `PARTY_NOT_FOUND` * Removed accidentally committed file. * Bumped to 9.4.1 --- package-lock.json | 49 ++++++++++++++++++- package.json | 2 +- src/models/oracle/facade.js | 14 ++++-- .../handlers/participants/{Type}/{ID}.test.js | 6 +-- .../participants/{Type}/{ID}/{SubId}.test.js | 6 +-- .../unit/handlers/parties/{Type}/{ID}.test.js | 6 +-- .../parties/{Type}/{ID}/{SubId}.test.js | 6 +-- 7 files changed, 69 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8528a49d..ad681765 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "account-lookup-service", - "version": "9.4.0", + "version": "9.4.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2155,12 +2155,58 @@ "protobufjs": "6.8.8", "rc": "1.2.8", "serialize-error": "4.1.0", + "sinon": "9.0.0", "traceparent": "1.0.0", "tslib": "1.11.1", "uuid4": "1.1.4", "winston": "3.2.1" }, "dependencies": { + "@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "@sinonjs/samsam": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz", + "integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==", + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "nise": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.3.tgz", + "integrity": "sha512-EGlhjm7/4KvmmE6B/UFsKh7eHykRl9VH+au8dduHLCyWUO/hr7+N+WtTvDUwc9zHuM1IaIJs/0lQ6Ag1jDkQSg==", + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "sinon": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.0.tgz", + "integrity": "sha512-c4bREcvuK5VuEGyMW/Oim9I3Rq49Vzb0aMdxouFaA44QCFpilc5LJOugrX+mkrvikbqCimxuK+4cnHVNnLR41g==", + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/formatio": "^5.0.0", + "@sinonjs/samsam": "^5.0.1", + "diff": "^4.0.2", + "nise": "^4.0.1", + "supports-color": "^7.1.0" + } + }, "tslib": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", @@ -2339,7 +2385,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.0.tgz", "integrity": "sha512-atR1J/jRXvQAb47gfzSK8zavXy7BcpnYq21ALon0U99etu99vsir0trzIO3wpeLtW+LLVY6X7EkfVTbjGSH8Ww==", - "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" } diff --git a/package.json b/package.json index 57e61968..e9f49142 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "account-lookup-service", "description": "Account Lookup Service is used to validate Party and Participant lookups", - "version": "9.4.0", + "version": "9.4.1", "license": "Apache-2.0", "author": "ModusBox", "contributors": [ diff --git a/src/models/oracle/facade.js b/src/models/oracle/facade.js index 49d1b9a1..970cdbfe 100644 --- a/src/models/oracle/facade.js +++ b/src/models/oracle/facade.js @@ -73,14 +73,18 @@ exports.oracleRequest = async (headers, method, params = {}, query = {}, payload Logger.error(err) // If the error was a 400 from the Oracle, we'll modify the error to generate a response to the // initiator of the request. - // Added error 404 to cover a special case of the Mowali implementation - // which uses mojaloop/als-oracle-pathfinder and currently returns 404. if ( err.name === 'FSPIOPError' && - err.apiErrorCode.code === ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code && - err.extensions.some(ext => (ext.key === 'status' && (ext.value === Enums.Http.ReturnCodes.BADREQUEST.CODE || ext.value === Enums.Http.ReturnCodes.NOTFOUND.CODE))) + err.apiErrorCode.code === ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_COMMUNICATION_ERROR.code ) { - throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND) + if (err.extensions.some(ext => (ext.key === 'status' && ext.value === Enums.Http.ReturnCodes.BADREQUEST.CODE))) { + throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND) + // Added error 404 to cover a special case of the Mowali implementation + // which uses mojaloop/als-oracle-pathfinder and currently returns 404 + // and in which case the Mowali implementation expects back `DESTINATION_FSP_ERROR`. + } else if (err.extensions.some(ext => (ext.key === 'status' && ext.value === Enums.Http.ReturnCodes.NOTFOUND.CODE))) { + throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR) + } } throw ErrorHandler.Factory.reformatFSPIOPError(err) } diff --git a/test/unit/handlers/participants/{Type}/{ID}.test.js b/test/unit/handlers/participants/{Type}/{ID}.test.js index 3f4e3ff8..c0b18613 100644 --- a/test/unit/handlers/participants/{Type}/{ID}.test.js +++ b/test/unit/handlers/participants/{Type}/{ID}.test.js @@ -79,7 +79,7 @@ describe('/participants/{Type}/{ID}', () => { participants.getParticipantsByTypeAndID.restore() }) - it('getParticipantsByTypeAndID sends an async 3200 for invalid party id on response with status 400', async () => { + it('getParticipantsByTypeAndID sends an async 3204 for invalid party id on response with status 400', async () => { // Arrange const mock = await Helper.generateMockRequest('/participants/{Type}/{ID}', 'get') const options = { @@ -113,7 +113,7 @@ describe('/participants/{Type}/{ID}', () => { // Added error 404 to cover a special case of the Mowali implementation // which uses mojaloop/als-oracle-pathfinder and currently returns 404. - it('getParticipantsByTypeAndID sends an async 3200 for invalid party id on response with status 404', async () => { + it('getParticipantsByTypeAndID sends an async 3201 for invalid party id on response with status 404', async () => { // Arrange const mock = await Helper.generateMockRequest('/participants/{Type}/{ID}', 'get') const options = { @@ -139,7 +139,7 @@ describe('/participants/{Type}/{ID}', () => { const errorCallStub = stubs[0] // Assert - expect(errorCallStub.args[0][2].errorInformation.errorCode).toBe('3204') + expect(errorCallStub.args[0][2].errorInformation.errorCode).toBe('3201') expect(errorCallStub.args[0][1]).toBe(Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_PUT_ERROR) expect(response.statusCode).toBe(202) stubs.forEach(s => s.restore()) diff --git a/test/unit/handlers/participants/{Type}/{ID}/{SubId}.test.js b/test/unit/handlers/participants/{Type}/{ID}/{SubId}.test.js index 35c993cf..dc4e6833 100644 --- a/test/unit/handlers/participants/{Type}/{ID}/{SubId}.test.js +++ b/test/unit/handlers/participants/{Type}/{ID}/{SubId}.test.js @@ -75,7 +75,7 @@ describe('/participants/{Type}/{ID}/{SubId}', () => { participants.getParticipantsByTypeAndID.restore() }) - it('getParticipantsByTypeAndID sends an async 3200 for invalid party id on response with status 400', async () => { + it('getParticipantsByTypeAndID sends an async 3204 for invalid party id on response with status 400', async () => { // Arrange const mock = await Helper.generateMockRequest('/participants/{Type}/{ID}/{SubId}', 'get') const options = { @@ -109,7 +109,7 @@ describe('/participants/{Type}/{ID}/{SubId}', () => { // Added error 404 to cover a special case of the Mowali implementation // which uses mojaloop/als-oracle-pathfinder and currently returns 404. - it('getParticipantsByTypeAndID sends an async 3200 for invalid party id on response with status 404', async () => { + it('getParticipantsByTypeAndID sends an async 3201 for invalid party id on response with status 404', async () => { // Arrange const mock = await Helper.generateMockRequest('/participants/{Type}/{ID}/{SubId}', 'get') const options = { @@ -135,7 +135,7 @@ describe('/participants/{Type}/{ID}/{SubId}', () => { const errorCallStub = stubs[0] // Assert - expect(errorCallStub.args[0][2].errorInformation.errorCode).toBe('3204') + expect(errorCallStub.args[0][2].errorInformation.errorCode).toBe('3201') expect(errorCallStub.args[0][1]).toBe(Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTICIPANT_SUB_ID_PUT_ERROR) expect(response.statusCode).toBe(202) stubs.forEach(s => s.restore()) diff --git a/test/unit/handlers/parties/{Type}/{ID}.test.js b/test/unit/handlers/parties/{Type}/{ID}.test.js index eb4a6a25..ca14614e 100644 --- a/test/unit/handlers/parties/{Type}/{ID}.test.js +++ b/test/unit/handlers/parties/{Type}/{ID}.test.js @@ -74,7 +74,7 @@ describe('/parties', () => { parties.getPartiesByTypeAndID.restore() }) - it('getPartiesByTypeAndID endpoint sends async 3200 to /error for invalid party ID on response with status 400', async () => { + it('getPartiesByTypeAndID endpoint sends async 3204 to /error for invalid party ID on response with status 400', async () => { // Arrange const mock = await Helper.generateMockRequest('/parties/{Type}/{ID}', 'get') const options = { @@ -110,7 +110,7 @@ describe('/parties', () => { // Added error 404 to cover a special case of the Mowali implementation // which uses mojaloop/als-oracle-pathfinder and currently returns 404. - it('getPartiesByTypeAndID endpoint sends async 3200 to /error for invalid party ID on response with status 404', async () => { + it('getPartiesByTypeAndID endpoint sends async 3201 to /error for invalid party ID on response with status 404', async () => { // Arrange const mock = await Helper.generateMockRequest('/parties/{Type}/{ID}', 'get') const options = { @@ -138,7 +138,7 @@ describe('/parties', () => { // Assert const errorCallStub = stubs[0] - expect(errorCallStub.args[0][2].errorInformation.errorCode).toBe('3204') + expect(errorCallStub.args[0][2].errorInformation.errorCode).toBe('3201') expect(errorCallStub.args[0][1]).toBe(Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR) expect(response.statusCode).toBe(202) stubs.forEach(s => s.restore()) diff --git a/test/unit/handlers/parties/{Type}/{ID}/{SubId}.test.js b/test/unit/handlers/parties/{Type}/{ID}/{SubId}.test.js index 54ccb888..dab92f34 100644 --- a/test/unit/handlers/parties/{Type}/{ID}/{SubId}.test.js +++ b/test/unit/handlers/parties/{Type}/{ID}/{SubId}.test.js @@ -71,7 +71,7 @@ describe('/parties/{Type}/{ID}/{SubId}', () => { parties.getPartiesByTypeAndID.restore() }) - it('getPartiesByTypeAndID endpoint sends async 3200 to /error for invalid party ID on response with status 400', async () => { + it('getPartiesByTypeAndID endpoint sends async 3204 to /error for invalid party ID on response with status 400', async () => { // Arrange const mock = await Helper.generateMockRequest('/parties/{Type}/{ID}/{SubId}', 'get') const options = { @@ -107,7 +107,7 @@ describe('/parties/{Type}/{ID}/{SubId}', () => { // Added error 404 to cover a special case of the Mowali implementation // which uses mojaloop/als-oracle-pathfinder and currently returns 404. - it('getPartiesByTypeAndID endpoint sends async 3200 to /error for invalid party ID with status 404', async () => { + it('getPartiesByTypeAndID endpoint sends async 3201 to /error for invalid party ID with status 404', async () => { // Arrange const mock = await Helper.generateMockRequest('/parties/{Type}/{ID}/{SubId}', 'get') const options = { @@ -135,7 +135,7 @@ describe('/parties/{Type}/{ID}/{SubId}', () => { // Assert const errorCallStub = stubs[0] - expect(errorCallStub.args[0][2].errorInformation.errorCode).toBe('3204') + expect(errorCallStub.args[0][2].errorInformation.errorCode).toBe('3201') expect(errorCallStub.args[0][1]).toBe(Enums.EndPoints.FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_PUT_ERROR) expect(response.statusCode).toBe(202) stubs.forEach(s => s.restore())