account-lookup-service 17.13.0-snapshot.3 → 17.13.0-snapshot.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "account-lookup-service",
3
3
  "description": "Account Lookup Service is used to validate Party and Participant lookups.",
4
- "version": "17.13.0-snapshot.3",
4
+ "version": "17.13.0-snapshot.5",
5
5
  "license": "Apache-2.0",
6
6
  "author": "ModusBox",
7
7
  "contributors": [
@@ -95,13 +95,13 @@
95
95
  "@mojaloop/central-services-health": "15.1.0",
96
96
  "@mojaloop/central-services-logger": "11.9.3",
97
97
  "@mojaloop/central-services-metrics": "12.7.1",
98
- "@mojaloop/central-services-shared": "18.32.1",
98
+ "@mojaloop/central-services-shared": "18.33.0",
99
99
  "@mojaloop/central-services-stream": "11.8.7",
100
100
  "@mojaloop/database-lib": "^11.3.2",
101
101
  "@mojaloop/event-sdk": "14.7.0",
102
102
  "@mojaloop/inter-scheme-proxy-cache-lib": "2.6.0",
103
103
  "@mojaloop/ml-schema-transformer-lib": "2.7.8",
104
- "@mojaloop/sdk-standard-components": "19.16.8",
104
+ "@mojaloop/sdk-standard-components": "19.16.9",
105
105
  "@now-ims/hapi-now-auth": "2.1.0",
106
106
  "ajv": "8.17.1",
107
107
  "ajv-keywords": "5.1.0",
package/src/constants.js CHANGED
@@ -29,7 +29,7 @@ const { API_TYPES } = require('@mojaloop/central-services-shared').Util.Hapi
29
29
 
30
30
  const ERROR_MESSAGES = Object.freeze({
31
31
  emptyFilteredPartyList: 'Empty oracle partyList, filtered based on callbackEndpointType',
32
- externalPartyError: 'External party error', // todo: think better message
32
+ externalPartyError: 'External party resolution error',
33
33
  failedToCacheSendToProxiesList: 'Failed to cache sendToProxiesList',
34
34
  noDiscoveryRequestsForwarded: 'No discovery requests forwarded to participants',
35
35
  sourceFspNotFound: 'Requester FSP not found',
@@ -170,6 +170,26 @@ class BasePartiesService {
170
170
  this.log.info('sendErrorCallback is done', { sendTo, errorInfo })
171
171
  }
172
172
 
173
+ /**
174
+ * @returns {Promise<{ fspId: string, partySubIdOrType?: string }[]>} List of parties from oracle response
175
+ */
176
+ async sendOracleDiscoveryRequest () {
177
+ this.stepInProgress('#sendOracleDiscoveryRequest')
178
+ const { headers, params, query } = this.inputs
179
+
180
+ const response = await this.deps.oracle.oracleRequest(headers, RestMethods.GET, params, query, undefined, this.deps.cache)
181
+ this.log.verbose('oracle discovery raw response:', { response })
182
+
183
+ let { partyList } = response?.data || {}
184
+ if (!Array.isArray(partyList)) {
185
+ this.log.warn('invalid oracle discovery response:', { response })
186
+ // todo: maybe, it's better to throw an error
187
+ partyList = []
188
+ }
189
+
190
+ return partyList
191
+ }
192
+
173
193
  async sendDeleteOracleRequest (headers, params) {
174
194
  this.stepInProgress('sendDeleteOracleRequest')
175
195
  const result = await this.deps.oracle.oracleRequest(headers, RestMethods.DELETE, params, null, null, this.deps.cache)
@@ -28,7 +28,7 @@
28
28
  const { ERROR_MESSAGES } = require('../../../constants')
29
29
  const BasePartiesService = require('./BasePartiesService')
30
30
 
31
- const { FspEndpointTypes, RestMethods } = BasePartiesService.enums()
31
+ const { RestMethods } = BasePartiesService.enums()
32
32
  const proxyCacheTtlSec = 40 // todo: make configurable
33
33
 
34
34
  class GetPartiesService extends BasePartiesService {
@@ -45,8 +45,8 @@ class GetPartiesService extends BasePartiesService {
45
45
  return
46
46
  }
47
47
 
48
- const response = await this.sendOracleDiscoveryRequest()
49
- const isSent = await this.processOraclePartyListResponse(response)
48
+ const partyList = await this.sendOracleDiscoveryRequest()
49
+ const isSent = await this.processOraclePartyListResponse(partyList)
50
50
  this.log.info(`getParties request is ${isSent ? '' : 'NOT '}forwarded to oracle lookup DFSP`)
51
51
  if (isSent) return
52
52
 
@@ -117,20 +117,14 @@ class GetPartiesService extends BasePartiesService {
117
117
  log.info('discovery getPartiesByTypeAndID request was sent', { sendTo })
118
118
  }
119
119
 
120
- async sendOracleDiscoveryRequest () {
121
- this.stepInProgress('#sendOracleDiscoveryRequest')
122
- const { headers, params, query } = this.inputs
123
- return this.deps.oracle.oracleRequest(headers, RestMethods.GET, params, query, undefined, this.deps.cache)
124
- }
125
-
126
- async processOraclePartyListResponse (response) {
127
- if (!Array.isArray(response?.data?.partyList) || response.data.partyList.length === 0) {
120
+ async processOraclePartyListResponse (rawPartyList) {
121
+ if (rawPartyList.length === 0) {
128
122
  this.log.verbose('oracle partyList is empty')
129
123
  return false
130
124
  }
131
125
 
132
126
  this.stepInProgress('processOraclePartyList')
133
- const partyList = this.#filterOraclePartyList(response)
127
+ const partyList = this.#filterOraclePartyList(rawPartyList)
134
128
 
135
129
  let sentCount = 0
136
130
  await Promise.all(partyList.map(async party => {
@@ -174,28 +168,20 @@ class GetPartiesService extends BasePartiesService {
174
168
  return isLocal
175
169
  }
176
170
 
177
- #filterOraclePartyList (response) {
171
+ #filterOraclePartyList (partyList) {
178
172
  // Oracle's API is a standard rest-style end-point Thus a GET /party on the oracle will return all participant-party records.
179
173
  // We must filter the results based on the callbackEndpointType to make sure we remove records containing partySubIdOrType when we are in FSPIOP_CALLBACK_URL_PARTIES_GET mode:
180
- this.stepInProgress('filterOraclePartyList')
174
+ this.stepInProgress('#filterOraclePartyList')
181
175
  const { params } = this.inputs
182
- const callbackEndpointType = this.deps.partiesUtils.getPartyCbType(params.SubId)
183
- let filteredPartyList
184
-
185
- switch (callbackEndpointType) {
186
- case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_GET:
187
- filteredPartyList = response.data.partyList.filter(party => party.partySubIdOrType == null) // Filter records that DON'T contain a partySubIdOrType
188
- break
189
- case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_GET:
190
- filteredPartyList = response.data.partyList.filter(party => party.partySubIdOrType === params.SubId) // Filter records that match partySubIdOrType
191
- break
192
- default:
193
- filteredPartyList = response // Fallback to providing the standard list
194
- }
195
176
 
196
- if (!Array.isArray(filteredPartyList) || !filteredPartyList.length) {
177
+ const filteredPartyList = !params?.SubId
178
+ ? partyList.filter(party => party.partySubIdOrType == null) // Filter records that DON'T contain a partySubIdOrType
179
+ : partyList.filter(party => party.partySubIdOrType === params.SubId) // Filter records that match partySubIdOrType
180
+
181
+ if (!filteredPartyList.length) {
197
182
  throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.emptyFilteredPartyList)
198
183
  }
184
+ this.log.verbose('#filterOraclePartyList is done:', { filteredPartyList })
199
185
 
200
186
  return filteredPartyList
201
187
  }
@@ -338,13 +324,13 @@ class GetPartiesService extends BasePartiesService {
338
324
  log.verbose('needOracleValidation: ', { needValidation })
339
325
  if (!needValidation) return true
340
326
 
341
- const oracleResponse = await this.sendOracleDiscoveryRequest()
342
- if (!Array.isArray(oracleResponse?.data?.partyList) || oracleResponse.data.partyList.length === 0) {
327
+ const partyList = await this.sendOracleDiscoveryRequest()
328
+ if (partyList.length === 0) {
343
329
  log.warn('Oracle returned empty party list')
344
330
  return false
345
331
  }
346
332
 
347
- const isValid = oracleResponse.data.partyList.some(party => party.fspId === state.destination)
333
+ const isValid = partyList.some(party => party.fspId === state.destination)
348
334
  log.verbose('#validateLocalDestinationForExternalSource is done', { isValid })
349
335
  return isValid
350
336
  }
@@ -41,9 +41,9 @@ class PutPartiesErrorService extends BasePartiesService {
41
41
  return
42
42
  }
43
43
  } else {
44
- const schemeParticipant = await this.validateParticipant(this.state.destination)
45
- if (!schemeParticipant) {
46
- this.log.info('Need to cleanup oracle and forward SERVICE_CURRENTLY_UNAVAILABLE error')
44
+ const isExternal = await this.#isPartyFromExternalDfsp()
45
+ if (isExternal) {
46
+ this.log.info('Need to cleanup oracle and forward PARTY_RESOLUTION_FAILURE error')
47
47
  await this.cleanupOracle()
48
48
  await this.removeProxyGetPartiesTimeoutCache(alsReq)
49
49
  await this.#sendPartyResolutionErrorCallback()
@@ -79,6 +79,20 @@ class PutPartiesErrorService extends BasePartiesService {
79
79
  return super.sendErrorCallback({ errorInfo, headers, params })
80
80
  }
81
81
 
82
+ async #isPartyFromExternalDfsp () {
83
+ this.stepInProgress('#isPartyFromExternalDfsp')
84
+ const partyList = await super.sendOracleDiscoveryRequest()
85
+ if (!partyList.length) {
86
+ this.log.verbose('oracle returns empty partyList')
87
+ return false
88
+ }
89
+ // think, if we have several parties from oracle
90
+ const isExternal = !(await this.validateParticipant(partyList[0].fspId))
91
+ this.log.verbose('#isPartyFromExternalDfsp is done:', { isExternal, partyList })
92
+
93
+ return isExternal
94
+ }
95
+
82
96
  async #sendPartyResolutionErrorCallback () {
83
97
  this.stepInProgress('#sendPartyResolutionErrorCallback')
84
98
  const { headers, params } = this.inputs
@@ -958,11 +958,13 @@ describe('Parties Tests', () => {
958
958
  oracleEndpointCached.getOracleEndpointByType = sandbox.stub().resolves([
959
959
  { value: 'http://oracle.endpoint' }
960
960
  ])
961
- oracle.oracleRequest = sandbox.stub().resolves()
961
+ oracle.oracleRequest = sandbox.stub().resolves({
962
+ data: { partyList: [{ fspId: 'fspId' }] }
963
+ })
962
964
 
963
965
  await partiesDomain.putPartiesErrorByTypeAndID(headers, params, payload, '', null, null, proxyCache)
964
966
 
965
- expect(oracle.oracleRequest.callCount).toBe(1)
967
+ expect(oracle.oracleRequest.callCount).toBe(2)
966
968
  expect(oracle.oracleRequest.lastCall.args[1]).toBe(RestMethods.DELETE)
967
969
  expect(participant.sendRequest.callCount).toBe(0)
968
970
  expect(participant.sendErrorToParticipant.callCount).toBe(1)
@@ -25,36 +25,44 @@
25
25
  --------------
26
26
  ******/
27
27
 
28
- const { createMockDeps, oracleMock, participantMock } = require('./deps')
29
- // ↑ should be first require to mock external deps ↑
30
28
  const { PutPartiesErrorService } = require('#src/domain/parties/services/index')
29
+ const { createMockDeps, createOracleFacadeMock, createParticipantFacadeMock } = require('./deps')
31
30
  const fixtures = require('#test/fixtures/index')
32
31
 
33
32
  const { RestMethods, Headers } = PutPartiesErrorService.enums()
34
33
 
35
34
  describe('PutPartiesErrorService Tests -->', () => {
35
+ let oracle
36
+ let participant
37
+
36
38
  beforeEach(() => {
37
39
  jest.clearAllMocks()
40
+ oracle = createOracleFacadeMock()
41
+ participant = createParticipantFacadeMock()
38
42
  })
39
43
 
40
44
  test('should cleanup oracle and forward PARTY_RESOLUTION_FAILURE error for party from external dfsp', async () => {
41
- participantMock.validateParticipant = jest.fn().mockRejectedValue(new Error('No participant found')) // external participant
45
+ participant.validateParticipant = jest.fn().mockRejectedValue(new Error('No participant found')) // external participant
46
+ oracle.oracleRequest = jest.fn().mockResolvedValue({
47
+ data: { partyList: [{ fspId: 'fspId' }] }
48
+ })
42
49
  const destination = 'externalDfsp'
43
50
  const proxyDest = 'proxyDest'
44
- const deps = createMockDeps()
51
+ const deps = createMockDeps({ oracle, participant })
45
52
  deps.proxyCache.lookupProxyByDfspId = jest.fn().mockResolvedValue(proxyDest)
46
53
 
47
54
  const headers = fixtures.partiesCallHeadersDto({ destination, proxy: 'proxyA' })
48
55
  const params = fixtures.partiesParamsDto()
49
56
  const dataUri = fixtures.dataUriDto()
50
- const service = new PutPartiesErrorService(deps, { headers, params, dataUri })
51
57
 
58
+ const service = new PutPartiesErrorService(deps, { headers, params, dataUri })
52
59
  await service.handleRequest()
53
- expect(oracleMock.oracleRequest).toHaveBeenCalledTimes(1)
54
- expect(oracleMock.oracleRequest.mock.lastCall[1]).toBe(RestMethods.DELETE)
55
- expect(participantMock.sendErrorToParticipant).toHaveBeenCalledTimes(1)
56
- // eslint-disable-next-line no-unused-vars
57
- const [sentTo, _, payload, cbHeaders] = participantMock.sendErrorToParticipant.mock.lastCall
60
+
61
+ expect(oracle.oracleRequest).toHaveBeenCalledTimes(2)
62
+ expect(oracle.oracleRequest.mock.lastCall[1]).toBe(RestMethods.DELETE)
63
+ expect(participant.sendErrorToParticipant).toHaveBeenCalledTimes(1)
64
+
65
+ const [sentTo, , payload, cbHeaders] = participant.sendErrorToParticipant.mock.lastCall
58
66
  expect(sentTo).toBe(proxyDest)
59
67
  expect(cbHeaders[Headers.FSPIOP.DESTINATION]).toBe(destination)
60
68
  expect(payload.errorInformation.errorCode).toBe('2006')
@@ -62,8 +70,8 @@ describe('PutPartiesErrorService Tests -->', () => {
62
70
 
63
71
  test('should NOT cleanup oracle if destination is local', async () => {
64
72
  const destination = 'localDfsp'
65
- const deps = createMockDeps()
66
- deps.participant.validateParticipant = jest.fn().mockResolvedValue({})
73
+ participant.validateParticipant = jest.fn().mockResolvedValue({})
74
+ const deps = createMockDeps({ participant })
67
75
 
68
76
  const headers = fixtures.partiesCallHeadersDto({ destination })
69
77
  const params = fixtures.partiesParamsDto()
@@ -71,8 +79,8 @@ describe('PutPartiesErrorService Tests -->', () => {
71
79
  const service = new PutPartiesErrorService(deps, { headers, params, dataUri })
72
80
 
73
81
  await service.handleRequest()
74
- expect(oracleMock.oracleRequest).not.toHaveBeenCalled()
75
- expect(participantMock.sendErrorToParticipant).toHaveBeenCalledTimes(1)
76
- expect(participantMock.sendErrorToParticipant.mock.lastCall[0]).toBe(destination)
82
+ expect(oracle.oracleRequest).not.toHaveBeenCalled()
83
+ expect(participant.sendErrorToParticipant).toHaveBeenCalledTimes(1)
84
+ expect(participant.sendErrorToParticipant.mock.lastCall[0]).toBe(destination)
77
85
  })
78
86
  })