From c6c2dfd904192c928f438826bce7e89449bbdb3d Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 25 Aug 2020 10:19:47 +0530 Subject: [PATCH 001/114] feat: Handler logic for put participants --- .../handlers/openapi/mojaloop/participants.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/server/handlers/openapi/mojaloop/participants.ts b/src/server/handlers/openapi/mojaloop/participants.ts index 036d7c08..ef468276 100644 --- a/src/server/handlers/openapi/mojaloop/participants.ts +++ b/src/server/handlers/openapi/mojaloop/participants.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ /***** License -------------- @@ -27,7 +28,17 @@ import { Request, ResponseToolkit } from '@hapi/hapi' import { Handler, Context } from 'openapi-backend' import { logger } from '~/shared/logger' -export const put: Handler = async (context: Context, request: Request, h: ResponseToolkit) => { + +export const put: Handler = async ( + context: Context, + request: Request, + h: ResponseToolkit +) => { logger.logRequest(context, request, h) + // @ts-ignore + const participants = request.payload.participants + + // TODO: Implement this function + updateFirebaseParticipants(participants) return h.response().code(200) } From edccad07f0175e273d6e05735fa5b6cd7b8eab12 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 25 Aug 2020 15:05:33 +0530 Subject: [PATCH 002/114] feat: add outgoing postConsentRequests method in Client --- src/shared/ml-thirdparty-client/index.ts | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/shared/ml-thirdparty-client/index.ts b/src/shared/ml-thirdparty-client/index.ts index 30d3cd49..aadede4b 100644 --- a/src/shared/ml-thirdparty-client/index.ts +++ b/src/shared/ml-thirdparty-client/index.ts @@ -37,6 +37,7 @@ import Logger, { ThirdpartyRequests, MojaloopRequests, } from '@mojaloop/sdk-standard-components' +import SDKStandardComponents from '@mojaloop/sdk-standard-components' /** * A client object that abstracts out operations that could be performed in @@ -47,10 +48,9 @@ import Logger, { * when it wants to perform a certain operation. */ - export class Client { /** - * An optional simulator that is expected to be passed when using the + * An optional simulator that is expected to be passed when using the * simulator plugin. */ simulator?: Simulator @@ -74,7 +74,7 @@ export class Client { /** * Constructor for the Mojaloop client. - * + * * @param options a configuration object for the client. */ public constructor(options: Options) { @@ -157,4 +157,21 @@ export class Client { // TODO: Implement communication with Mojaloop. } + + public async postConsentRequests( + requestBody: SDKStandardComponents.PostConsentRequestsRequest + ): Promise { + if (this.simulator) { + // If the client is configured with a simulator, then it will not + // communicate with Mojaloop directly. Instead, it will only generate + // a random response that is injected to the internal routes. + // return this.simulator + } + + // TODO: Check Destination id + this.thirdpartyRequests.postConsentRequests( + requestBody, + this.options.participantId + ) + } } From deacbbb6dabaf002e7dbbe4212295bc531d276ca Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 25 Aug 2020 15:11:12 +0530 Subject: [PATCH 003/114] feat: create consents Handler --- src/server/plugins/internal/firestore.ts | 77 +++++++++++++++++++++--- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/src/server/plugins/internal/firestore.ts b/src/server/plugins/internal/firestore.ts index 1fa1b217..1529f54f 100644 --- a/src/server/plugins/internal/firestore.ts +++ b/src/server/plugins/internal/firestore.ts @@ -20,6 +20,7 @@ * Google - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ @@ -27,8 +28,14 @@ import { Plugin, Server } from '@hapi/hapi' import firebase from '~/lib/firebase' import { Transaction } from '~/models/transaction' +import { Consent } from '~/models/consent' -export type TransactionHandler = (server: Server, transaction: Transaction) => Promise +export type TransactionHandler = ( + server: Server, + transaction: Transaction +) => Promise + +export type ConsentHandler = (server: Server, consent: Consent) => Promise /** * An interface definition for options that need to be specfied to use this plugin. @@ -40,6 +47,11 @@ export interface Options { onUpdate?: TransactionHandler onRemove?: TransactionHandler } + consents: { + onCreate?: TransactionHandler + onUpdate?: TransactionHandler + onRemove?: TransactionHandler + } } } @@ -54,7 +66,10 @@ export interface Options { * @param options a configuration object for the plugin. * @returns a function to unsubscribe the listener. */ -const listenToTransactions = (server: Server, options: Options): (() => void) => { +const listenToTransactions = ( + server: Server, + options: Options +): (() => void) => { const transactionHandlers = options.handlers.transactions return firebase @@ -63,13 +78,59 @@ const listenToTransactions = (server: Server, options: Options): (() => void) => .onSnapshot((querySnapshot) => { querySnapshot.docChanges().forEach((change) => { if (change.type === 'added' && transactionHandlers.onCreate) { - transactionHandlers.onCreate(server, { id: change.doc.id, ...change.doc.data() }) - + transactionHandlers.onCreate(server, { + id: change.doc.id, + ...change.doc.data(), + }) } else if (change.type === 'modified' && transactionHandlers.onUpdate) { - transactionHandlers.onUpdate(server, { id: change.doc.id, ...change.doc.data() }) - + transactionHandlers.onUpdate(server, { + id: change.doc.id, + ...change.doc.data(), + }) } else if (change.type === 'removed' && transactionHandlers.onRemove) { - transactionHandlers.onRemove(server, { id: change.doc.id, ...change.doc.data() }) + transactionHandlers.onRemove(server, { + id: change.doc.id, + ...change.doc.data(), + }) + } + }) + }) +} + +/** + * Listens to events that happen in the "consents" collection. + * Note that when the server starts running, all existing documents in Firestore + * will be treated as a document that is created for the first time. The handler for + * `onCreate` consent must be able to differentiate whether a document is created in + * realtime or because it has persisted in the database when the server starts. + * + * @param server a server object as defined in the hapi library. + * @param options a configuration object for the plugin. + * @returns a function to unsubscribe the listener. + */ +const listenToConsents = (server: Server, options: Options): (() => void) => { + const consentHandlers = options.handlers.consents + + return firebase + .firestore() + .collection('consents') + .onSnapshot((querySnapshot) => { + querySnapshot.docChanges().forEach((change) => { + if (change.type === 'added' && consentHandlers.onCreate) { + consentHandlers.onCreate(server, { + id: change.doc.id, + ...change.doc.data(), + }) + } else if (change.type === 'modified' && consentHandlers.onUpdate) { + consentHandlers.onUpdate(server, { + id: change.doc.id, + ...change.doc.data(), + }) + } else if (change.type === 'removed' && consentHandlers.onRemove) { + consentHandlers.onRemove(server, { + id: change.doc.id, + ...change.doc.data(), + }) } }) }) @@ -84,10 +145,12 @@ export const Firestore: Plugin = { version: '1.0.0', register: async (server: Server, options: Options) => { const unsubscribeTransactions = listenToTransactions(server, options) + const unsubscribeConsents = listenToConsents(server, options) // Unsubscribe to the changes in Firebase when the server stops running. server.ext('onPreStop', (_: Server) => { unsubscribeTransactions() + unsubscribeConsents() }) }, } From 0f17193cfc4158d64c1673dbcc77aade260d9d6c Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 25 Aug 2020 15:37:20 +0530 Subject: [PATCH 004/114] refactor: fix spelling error in getConsentByID --- src/repositories/consent.ts | 4 +- src/server/handlers/firestore/consents.ts | 190 ++++++++++++++++++ src/server/handlers/firestore/transactions.ts | 2 +- 3 files changed, 193 insertions(+), 3 deletions(-) create mode 100644 src/server/handlers/firestore/consents.ts diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index 2a10730b..fafde893 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -35,11 +35,11 @@ export interface IConsentRepository { * * @param id Consent ID of the document that needs to be retrieved. */ - getByConsentId(id: string): Promise + getConsentById(id: string): Promise } export class FirebaseConsentRepository implements IConsentRepository { - async getByConsentId(id: string): Promise { + async getConsentById(id: string): Promise { return new Promise((resolve, reject) => { firebase .firestore() diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts new file mode 100644 index 00000000..01764f86 --- /dev/null +++ b/src/server/handlers/firestore/consents.ts @@ -0,0 +1,190 @@ +/***** + License + -------------- + Copyright © 2020 Mojaloop Foundation + The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Mojaloop Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Mojaloop Foundation + - Name Surname + + * Google + - Steven Wijaya + - Abhimanyu Kapur + -------------- + ******/ + +import * as uuid from 'uuid' +import { Server } from '@hapi/hapi' + +import * as utils from '~/lib/utils' +import { logger } from '~/shared/logger' +import { + AmountType, + AuthenticationResponseType, +} from '~/shared/ml-thirdparty-client/models/core' + +import { ConsentHandler } from '~/server/plugins/internal/firestore' +import { Consent } from '~/models/consent' + +import * as validator from './consents.validator' +import { consentRepository } from '~/repositories/consent' + +async function handleNewTransaction(_: Server, transaction: Transaction) { + // Assign a transactionRequestId to the document and set the initial + // status. This operation will create an event that triggers the execution + // of the onUpdate function. + consentRepository.updateById(transaction.id, { + transactionRequestId: uuid.v4(), + status: Status.PENDING_PARTY_LOOKUP, + }) +} + +async function handlePartyLookup(server: Server, transaction: Transaction) { + // Check whether the transaction document has all the necessary properties + // to perform a party lookup. + if (validator.isValidPartyLookup(transaction)) { + // Payee is guaranteed to be non-null by the validator. + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const payee = transaction.payee! + + server.app.mojaloopClient.getParties( + payee.partyIdInfo.partyIdType, + payee.partyIdInfo.partyIdentifier + ) + } +} + +async function handlePartyConfirmation( + server: Server, + transaction: Transaction +) { + // Upon receiving a callback from Mojaloop that contains information about + // the payee, the server will update all relevant transaction documents + // in the Firebase. However, we can just ignore all updates by the server + // and wait for the user to confirm the payee by keying in more details + // about the transaction (i.e., source account ID, consent ID, and + // transaction amount). + if (validator.isValidPayeeConfirmation(transaction)) { + // If the update contains all the necessary fields, process document + // to the next step by sending a transaction request to Mojaloop. + + try { + // The optional values are guaranteed to exist by the validator. + // eslint-disable @typescript-eslint/no-non-null-assertion + + const consent = await consentRepository.getConsentById( + transaction.consentId! + ) + + server.app.mojaloopClient.postTransactions({ + transactionRequestId: transaction.transactionRequestId!, + sourceAccountId: transaction.sourceAccountId!, + consentId: transaction.consentId!, + payee: transaction.payee!, + payer: consent.party!, + amountType: AmountType.RECEIVE, + amount: transaction.amount!, + transactionType: { + scenario: 'TRANSFER', + initiator: 'PAYER', + initiatorType: 'CONSUMER', + }, + expiration: utils.getTomorrowsDate().toISOString(), + }) + + // eslint-enable @typescript-eslint/no-non-null-assertion + } catch (err) { + logger.error(err) + } + } +} + +function toMojaloopResponseType( + type: ResponseType +): AuthenticationResponseType { + switch (type) { + case ResponseType.AUTHORIZED: + return AuthenticationResponseType.ENTERED + case ResponseType.REJECTED: + return AuthenticationResponseType.REJECTED + } +} + +async function handleAuthorization(server: Server, transaction: Transaction) { + if (validator.isValidAuthorization(transaction)) { + // If the update contains all the necessary fields, process document + // to the next step by sending an authorization to Mojaloop. + + // Convert to a response type that is understood by Mojaloop. + const mojaloopResponseType = toMojaloopResponseType( + transaction.responseType! + ) + + // The optional values are guaranteed to exist by the validator. + // eslint-disable @typescript-eslint/no-non-null-assertion + server.app.mojaloopClient.putAuthorizations( + transaction.transactionRequestId!, + { + responseType: mojaloopResponseType, + authenticationInfo: { + authentication: transaction.authentication!.type!, + authenticationValue: transaction.authentication!.value!, + }, + }, + transaction.transactionId + ) + // eslint-enable @typescript-eslint/no-non-null-assertion + } +} + +export const onCreate: TransactionHandler = async ( + server: Server, + transaction: Transaction +): Promise => { + if (transaction.status) { + // Skip transaction that has been processed previously. + // We need this because when the server starts for the first time, + // all existing documents in the Firebase will be treated as a new + // document. + return + } + + await handleNewTransaction(server, transaction) +} + +export const onUpdate: TransactionHandler = async ( + server: Server, + transaction: Transaction +): Promise => { + if (!transaction.status) { + // Status is expected to be null only when the document is created for the first + // time by the user. + logger.error('Invalid transaction update, undefined status.') + return + } + + switch (transaction.status) { + case Status.PENDING_PARTY_LOOKUP: + await handlePartyLookup(server, transaction) + break + + case Status.PENDING_PAYEE_CONFIRMATION: + await handlePartyConfirmation(server, transaction) + break + + case Status.AUTHORIZATION_REQUIRED: + await handleAuthorization(server, transaction) + break + } +} diff --git a/src/server/handlers/firestore/transactions.ts b/src/server/handlers/firestore/transactions.ts index 540fa716..0130b8cb 100644 --- a/src/server/handlers/firestore/transactions.ts +++ b/src/server/handlers/firestore/transactions.ts @@ -83,7 +83,7 @@ async function handlePartyConfirmation( // The optional values are guaranteed to exist by the validator. // eslint-disable @typescript-eslint/no-non-null-assertion - const consent = await consentRepository.getByConsentId( + const consent = await consentRepository.getConsentById( transaction.consentId! ) From 4fb2e870d00c466c5d5605af77072a16d0a0a62e Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 25 Aug 2020 15:38:12 +0530 Subject: [PATCH 005/114] feat: Add consentHandlers as default export --- src/server/handlers/firestore/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/server/handlers/firestore/index.ts b/src/server/handlers/firestore/index.ts index 1868d73f..8fe453c9 100644 --- a/src/server/handlers/firestore/index.ts +++ b/src/server/handlers/firestore/index.ts @@ -20,11 +20,14 @@ * Google - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ import * as transactionHandlers from './transactions' +import * as consentHandlers from './consents' export default { - transactions: transactionHandlers + transactions: transactionHandlers, + consents: consentHandlers, } From 5dbc21c7bf5029c0977cf68afc92d46e113cc82e Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 25 Aug 2020 15:39:02 +0530 Subject: [PATCH 006/114] feat: initialize consent handler in firestore --- src/server/handlers/firestore/consents.ts | 148 ---------------------- 1 file changed, 148 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 01764f86..3ec48250 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -40,151 +40,3 @@ import { Consent } from '~/models/consent' import * as validator from './consents.validator' import { consentRepository } from '~/repositories/consent' -async function handleNewTransaction(_: Server, transaction: Transaction) { - // Assign a transactionRequestId to the document and set the initial - // status. This operation will create an event that triggers the execution - // of the onUpdate function. - consentRepository.updateById(transaction.id, { - transactionRequestId: uuid.v4(), - status: Status.PENDING_PARTY_LOOKUP, - }) -} - -async function handlePartyLookup(server: Server, transaction: Transaction) { - // Check whether the transaction document has all the necessary properties - // to perform a party lookup. - if (validator.isValidPartyLookup(transaction)) { - // Payee is guaranteed to be non-null by the validator. - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const payee = transaction.payee! - - server.app.mojaloopClient.getParties( - payee.partyIdInfo.partyIdType, - payee.partyIdInfo.partyIdentifier - ) - } -} - -async function handlePartyConfirmation( - server: Server, - transaction: Transaction -) { - // Upon receiving a callback from Mojaloop that contains information about - // the payee, the server will update all relevant transaction documents - // in the Firebase. However, we can just ignore all updates by the server - // and wait for the user to confirm the payee by keying in more details - // about the transaction (i.e., source account ID, consent ID, and - // transaction amount). - if (validator.isValidPayeeConfirmation(transaction)) { - // If the update contains all the necessary fields, process document - // to the next step by sending a transaction request to Mojaloop. - - try { - // The optional values are guaranteed to exist by the validator. - // eslint-disable @typescript-eslint/no-non-null-assertion - - const consent = await consentRepository.getConsentById( - transaction.consentId! - ) - - server.app.mojaloopClient.postTransactions({ - transactionRequestId: transaction.transactionRequestId!, - sourceAccountId: transaction.sourceAccountId!, - consentId: transaction.consentId!, - payee: transaction.payee!, - payer: consent.party!, - amountType: AmountType.RECEIVE, - amount: transaction.amount!, - transactionType: { - scenario: 'TRANSFER', - initiator: 'PAYER', - initiatorType: 'CONSUMER', - }, - expiration: utils.getTomorrowsDate().toISOString(), - }) - - // eslint-enable @typescript-eslint/no-non-null-assertion - } catch (err) { - logger.error(err) - } - } -} - -function toMojaloopResponseType( - type: ResponseType -): AuthenticationResponseType { - switch (type) { - case ResponseType.AUTHORIZED: - return AuthenticationResponseType.ENTERED - case ResponseType.REJECTED: - return AuthenticationResponseType.REJECTED - } -} - -async function handleAuthorization(server: Server, transaction: Transaction) { - if (validator.isValidAuthorization(transaction)) { - // If the update contains all the necessary fields, process document - // to the next step by sending an authorization to Mojaloop. - - // Convert to a response type that is understood by Mojaloop. - const mojaloopResponseType = toMojaloopResponseType( - transaction.responseType! - ) - - // The optional values are guaranteed to exist by the validator. - // eslint-disable @typescript-eslint/no-non-null-assertion - server.app.mojaloopClient.putAuthorizations( - transaction.transactionRequestId!, - { - responseType: mojaloopResponseType, - authenticationInfo: { - authentication: transaction.authentication!.type!, - authenticationValue: transaction.authentication!.value!, - }, - }, - transaction.transactionId - ) - // eslint-enable @typescript-eslint/no-non-null-assertion - } -} - -export const onCreate: TransactionHandler = async ( - server: Server, - transaction: Transaction -): Promise => { - if (transaction.status) { - // Skip transaction that has been processed previously. - // We need this because when the server starts for the first time, - // all existing documents in the Firebase will be treated as a new - // document. - return - } - - await handleNewTransaction(server, transaction) -} - -export const onUpdate: TransactionHandler = async ( - server: Server, - transaction: Transaction -): Promise => { - if (!transaction.status) { - // Status is expected to be null only when the document is created for the first - // time by the user. - logger.error('Invalid transaction update, undefined status.') - return - } - - switch (transaction.status) { - case Status.PENDING_PARTY_LOOKUP: - await handlePartyLookup(server, transaction) - break - - case Status.PENDING_PAYEE_CONFIRMATION: - await handlePartyConfirmation(server, transaction) - break - - case Status.AUTHORIZATION_REQUIRED: - await handleAuthorization(server, transaction) - break - } -} From ed87a4975d0598cc1601b8cbd8cd4fed115074f3 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 25 Aug 2020 16:19:53 +0530 Subject: [PATCH 007/114] feat: add method to updateConsentById --- src/repositories/consent.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index fafde893..4141d495 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -19,7 +19,7 @@ - Name Surname * Google - - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ @@ -58,6 +58,10 @@ export class FirebaseConsentRepository implements IConsentRepository { }) }) } + + async updateConsentById(id: string, data: Consent): Promise { + await firebase.firestore().collection('consents').doc(id).update(data) + } } export const consentRepository: IConsentRepository = new FirebaseConsentRepository() From fe77c44861c735af59624b7865706b72d97f31eb Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 25 Aug 2020 16:23:02 +0530 Subject: [PATCH 008/114] feat: add updateConsentById method to interface --- src/repositories/consent.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index 4141d495..e3ce5ea0 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -30,6 +30,14 @@ import { Consent } from '~/models/consent' import { logger } from '~/shared/logger' export interface IConsentRepository { + /** + * Updates a consent document based on a unique identifier. + * + * @param id Id for the consent document that needs to be updated. + * @param data Document fields that are about to be updated. + */ + updateConsentById(id: string, data: Record): Promise + /** * Retrieves a consent document based on its consent ID. * @@ -59,7 +67,10 @@ export class FirebaseConsentRepository implements IConsentRepository { }) } - async updateConsentById(id: string, data: Consent): Promise { + async updateConsentById( + id: string, + data: Record + ): Promise { await firebase.firestore().collection('consents').doc(id).update(data) } } From 667363f9299fec2120ddc3c88a2866fdc0de30bd Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 25 Aug 2020 16:24:28 +0530 Subject: [PATCH 009/114] feat: Add method to handle creation of consent --- src/server/handlers/firestore/consents.ts | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 3ec48250..39774bf9 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -36,7 +36,32 @@ import { import { ConsentHandler } from '~/server/plugins/internal/firestore' import { Consent } from '~/models/consent' +import { Status } from '~/models/transaction' -import * as validator from './consents.validator' +// import * as validator from './consents.validator' import { consentRepository } from '~/repositories/consent' +async function handleNewConsent(_: Server, consent: Consent) { + // Assign a transactionRequestId to the document and set the initial + // status. This operation will create an event that triggers the execution + // of the onUpdate function. + consentRepository.updateConsentById(consent.id, { + consentRequestId: uuid.v4(), + status: Status.PENDING_PARTY_LOOKUP, + }) +} + +export const onCreate: ConsentHandler = async ( + server: Server, + consent: Consent +): Promise => { +// if (transaction.status) { +// // Skip transaction that has been processed previously. +// // We need this because when the server starts for the first time, +// // all existing documents in the Firebase will be treated as a new +// // document. +// return +// } + + await handleNewConsent(server, consent) +} From a35716e7a6fb7f7d470b399ef9a3c75582765635 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 25 Aug 2020 17:26:17 +0530 Subject: [PATCH 010/114] feat: implement handler for PUT consentRequests/{ID} --- .../handlers/openapi/mojaloop/consentRequests/{ID}.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts index c6d47a85..bbff39e3 100644 --- a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts @@ -26,8 +26,16 @@ import { Request, ResponseToolkit } from '@hapi/hapi' import { Handler, Context } from 'openapi-backend' import { logger } from '~/shared/logger' +import { consentRepository } from '~/repositories/consent' -export const put: Handler = async (context: Context, request: Request, h: ResponseToolkit) => { +export const put: Handler = async ( + context: Context, + request: Request, + h: ResponseToolkit +) => { logger.logRequest(context, request, h) + + const { id, authChannels, authUri, status } = context.request.body + consentRepository.updateConsentById(id, { authChannels, authUri, status }) return h.response().code(200) } From 858aec41eb74760749264b7c29746460e2b6b5bc Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 25 Aug 2020 17:36:11 +0530 Subject: [PATCH 011/114] feat: implement postConsent handler --- .../handlers/openapi/mojaloop/consents.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/server/handlers/openapi/mojaloop/consents.ts b/src/server/handlers/openapi/mojaloop/consents.ts index 2efd4197..5cba6f5d 100644 --- a/src/server/handlers/openapi/mojaloop/consents.ts +++ b/src/server/handlers/openapi/mojaloop/consents.ts @@ -26,8 +26,24 @@ import { Request, ResponseToolkit } from '@hapi/hapi' import { Handler, Context } from 'openapi-backend' import { logger } from '~/shared/logger' +import { consentRepository } from '~/repositories/consent' -export const post: Handler = async (context: Context, request: Request, h: ResponseToolkit) => { +export const post: Handler = async ( + context: Context, + request: Request, + h: ResponseToolkit +) => { logger.logRequest(context, request, h) + + const { id, initiatorId, participantId, scopes } = context.request.body + + consentRepository.updateConsentById(id, { + initiatorId, + participantId, + scopes, + // TODO: check how consent status field is being used + // TODO: Shift this to enum - if the field is required + status: 'CONSENT_GRANTED', + }) return h.response().code(202) } From c7f83a2cb2ed7138a91bc0e2e5ddb5f6bab6dbe2 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 26 Aug 2020 10:20:52 +0530 Subject: [PATCH 012/114] fix: status should not be taken from request body --- .../handlers/openapi/mojaloop/consentRequests/{ID}.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts index bbff39e3..8ffe80c8 100644 --- a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts @@ -35,7 +35,13 @@ export const put: Handler = async ( ) => { logger.logRequest(context, request, h) - const { id, authChannels, authUri, status } = context.request.body - consentRepository.updateConsentById(id, { authChannels, authUri, status }) + const { id, authChannels, authUri } = context.request.body + consentRepository.updateConsentById(id, { + authChannels, + authUri, + // TODO: check how consent status field is being used + // TODO: Shift this to enum - if the field is required + status: 'AUTHENTICATION_REQUIRED', + }) return h.response().code(200) } From d51fbe8c5f7f91b648782af8d0e69ea4efd5af59 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 26 Aug 2020 11:46:40 +0530 Subject: [PATCH 013/114] feat: create ConsentStatus enum and add field to consent object --- src/models/consent.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/models/consent.ts b/src/models/consent.ts index a91f2489..1e6c386c 100644 --- a/src/models/consent.ts +++ b/src/models/consent.ts @@ -25,6 +25,34 @@ import { Party } from '~/shared/ml-thirdparty-client/models/core' +export enum ConsentStatus { + /** + * Waiting for a callback from Mojaloop to give the payee information. + */ + PENDING_PARTY_LOOKUP = 'PENDING_PARTY_LOOKUP', + + /** + * Waiting for the user to confirm payee information and provide more + * details about the transaction. + */ + PENDING_PAYEE_CONFIRMATION = 'PENDING_PAYEE_CONFIRMATION', + + /** + * Waiting for the user to authorize the consent. + */ + AUTHORIZATION_REQUIRED = 'AUTHORIZATION_REQUIRED', + + /** + * The consent is authorized and active. + */ + ACTIVE = 'ACTIVE', + + /** + * The consent is revoked and no longer valid. + */ + REVOKED = 'REVOKED', +} + export interface Consent { /** * Internal id that is used to identify the transaction. @@ -41,4 +69,9 @@ export interface Consent { * Information about the party that is associated with the consent. */ party?: Party + + /** + * Information about the current status of the consent. + */ + status: ConsentStatus } From 67c8df5efaa6e088c98fdd08eb5caf3666a05162 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 26 Aug 2020 11:48:18 +0530 Subject: [PATCH 014/114] feat: allow consent status to be undefined(on creation) --- src/models/consent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/consent.ts b/src/models/consent.ts index 1e6c386c..545c71dd 100644 --- a/src/models/consent.ts +++ b/src/models/consent.ts @@ -73,5 +73,5 @@ export interface Consent { /** * Information about the current status of the consent. */ - status: ConsentStatus + status?: ConsentStatus } From b481c5f0f523581f99faf9b41b624eedd52b9343 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Fri, 28 Aug 2020 16:39:26 +0530 Subject: [PATCH 015/114] feat: Add update consent method to consent repository --- src/repositories/consent.ts | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index e3ce5ea0..077bfee6 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -44,6 +44,17 @@ export interface IConsentRepository { * @param id Consent ID of the document that needs to be retrieved. */ getConsentById(id: string): Promise + + /** + * Updates one or more consent documents based on the given conditions. + * + * @param conditions Conditions for the documents that need to be updated. + * @param data Document fields that are about to be updated. + */ + updateConsent( + conditions: Record, + data: Record + ): Promise } export class FirebaseConsentRepository implements IConsentRepository { @@ -73,6 +84,46 @@ export class FirebaseConsentRepository implements IConsentRepository { ): Promise { await firebase.firestore().collection('consents').doc(id).update(data) } + + async updateConsent( + conditions: Record, + data: Record + ): Promise { + let firestoreQuery: FirebaseFirestore.Query = firebase + .firestore() + .collection('consents') + + // Chain all of the given conditions to the query + for (const key in conditions) { + firestoreQuery = firestoreQuery.where(key, '==', conditions[key]) + } + + // Find and update all matching documents in Firebase that match the given conditions. + await firestoreQuery + .get() + .then((response) => { + // Create a batch to perform all of the updates using a single request. + // Firebase will also execute the updates atomically according to the + // API specification. + const batch = firebase.firestore().batch() + + // Iterate through all matching documents add them to the processing batch. + response.docs.forEach((doc) => { + batch.update( + // Put a reference to the document. + firebase.firestore().collection('consents').doc(doc.id), + // Specify the updated fields and their new values. + data + ) + }) + + // Commit the updates. + return batch.commit() + }) + .catch((err) => { + logger.error(err) + }) + } } export const consentRepository: IConsentRepository = new FirebaseConsentRepository() From 0d389e6062ee7797141d8a1c3daf786ad0a5bfa7 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Fri, 28 Aug 2020 16:45:20 +0530 Subject: [PATCH 016/114] feat: implement handler for PUT parties/{Type}/{ID} --- .../openapi/mojaloop/parties/{Type}/{ID}.ts | 66 +++++++++++++------ 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts index 6654c711..ab5d980f 100644 --- a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts @@ -30,37 +30,63 @@ import { PartiesTypeIDPutRequest } from '~/shared/ml-thirdparty-client/models/op import { Status } from '~/models/transaction' import { transactionRepository } from '~/repositories/transaction' +import { consentRepository } from '~/repositories/consent' +import { ConsentStatus } from '~/models/consent' /** * Handles callback from Mojaloop that specifies detailed info about a requested party. - * + * * @param context an object that contains detailed information about the incoming request. * @param request original request object as defined by the hapi library. * @param h original request toolkit as defined by the hapi libary. */ -export const put: Handler = async (context: Context, _: Request, h: ResponseToolkit): Promise => { +export const put: Handler = async ( + context: Context, + _: Request, + h: ResponseToolkit +): Promise => { // Retrieve the data that have been validated by the openapi-backend library. - let body = context.request.body as PartiesTypeIDPutRequest - let partyIdType = context.request.params.Type - let partyIdentifier = context.request.params.ID + const body = context.request.body as PartiesTypeIDPutRequest + const partyIdType = context.request.params.Type + const partyIdentifier = context.request.params.ID // Find all matching documents in Firebase that are waiting for the result of - // party lookup with the specified type and identifier. The execution of this - // function is expected to run asynchronously, so the server could quickly + // party lookup with the specified type and identifier. The execution of this + // function is expected to run asynchronously, so the server could quickly // give a response to Mojaloop. - transactionRepository.update( - // Conditions for the documents that need to be updated - { - "payee.partyIdInfo.partyIdType": partyIdType, - "payee.partyIdInfo.partyIdentifier": partyIdentifier, - "status": Status.PENDING_PARTY_LOOKUP, - }, - // Update the given field by their new values - { - payee: body.party, - status: Status.PENDING_PAYEE_CONFIRMATION, - } - ) + + if (partyIdType === 'OPAQUE') { + // Update Consents + consentRepository.updateConsent( + // Conditions for the documents that need to be updated + { + 'payee.partyIdInfo.partyIdType': partyIdType, + 'payee.partyIdInfo.partyIdentifier': partyIdentifier, + status: ConsentStatus.PENDING_PARTY_LOOKUP, + }, + // Update the given field by their new values + { + party: body.party, + accounts: body.accounts, + status: Status.PENDING_PAYEE_CONFIRMATION, + } + ) + } else { + // Update Transactions + transactionRepository.update( + // Conditions for the documents that need to be updated + { + 'payee.partyIdInfo.partyIdType': partyIdType, + 'payee.partyIdInfo.partyIdentifier': partyIdentifier, + status: Status.PENDING_PARTY_LOOKUP, + }, + // Update the given field by their new values + { + payee: body.party, + status: Status.PENDING_PAYEE_CONFIRMATION, + } + ) + } // Return "200 OK" as defined by the Mojaloop API for successful request. return h.response().code(200) From ff99ecbc051a9cc197fe0dae9ffa6d9f69f60400 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Fri, 28 Aug 2020 17:01:21 +0530 Subject: [PATCH 017/114] feat: Implement handler for PATCH consents/{ID} --- src/server/handlers/openapi/mojaloop/consents/{ID}.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts index a14d392c..dd33fd82 100644 --- a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts @@ -26,13 +26,16 @@ import { Request, ResponseToolkit } from '@hapi/hapi' import { Handler, Context } from 'openapi-backend' import { logger } from '~/shared/logger' +import { consentRepository } from '~/repositories/consent' export const put: Handler = async (context: Context, request: Request, h: ResponseToolkit) => { logger.logRequest(context, request, h) return h.response().code(200) } -export const remove: Handler = async (context: Context, request: Request, h: ResponseToolkit) => { +export const patch: Handler = async (context: Context, request: Request, h: ResponseToolkit) => { logger.logRequest(context, request, h) + // Updates consent fields patched + consentRepository.updateConsentById(request.params.id, context.request.body) return h.response().code(200) } From 6466f1eaeca0e18a5a84ac688272ff56bc2132d3 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Fri, 28 Aug 2020 17:02:09 +0530 Subject: [PATCH 018/114] feat: implement PUT consents/{ID} --- .../handlers/openapi/mojaloop/consents/{ID}.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts index dd33fd82..a970dfc4 100644 --- a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts @@ -28,12 +28,22 @@ import { Handler, Context } from 'openapi-backend' import { logger } from '~/shared/logger' import { consentRepository } from '~/repositories/consent' -export const put: Handler = async (context: Context, request: Request, h: ResponseToolkit) => { +export const put: Handler = async ( + context: Context, + request: Request, + h: ResponseToolkit +) => { logger.logRequest(context, request, h) + // Updates consent fields + consentRepository.updateConsentById(request.params.id, context.request.body) return h.response().code(200) } -export const patch: Handler = async (context: Context, request: Request, h: ResponseToolkit) => { +export const patch: Handler = async ( + context: Context, + request: Request, + h: ResponseToolkit +) => { logger.logRequest(context, request, h) // Updates consent fields patched consentRepository.updateConsentById(request.params.id, context.request.body) From ea4fa3abdda1ec202ae97fd68b07e5c29a51c45e Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 31 Aug 2020 10:45:01 +0530 Subject: [PATCH 019/114] feat: add methods to consent Handler --- src/server/handlers/firestore/consents.ts | 101 +++++++++++++++++++--- 1 file changed, 87 insertions(+), 14 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 39774bf9..555e2943 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ /***** License -------------- @@ -25,43 +26,115 @@ ******/ import * as uuid from 'uuid' -import { Server } from '@hapi/hapi' +import { Server, server } from '@hapi/hapi' -import * as utils from '~/lib/utils' import { logger } from '~/shared/logger' import { - AmountType, AuthenticationResponseType, } from '~/shared/ml-thirdparty-client/models/core' import { ConsentHandler } from '~/server/plugins/internal/firestore' -import { Consent } from '~/models/consent' -import { Status } from '~/models/transaction' +import { Consent, ConsentStatus } from '~/models/consent' // import * as validator from './consents.validator' import { consentRepository } from '~/repositories/consent' async function handleNewConsent(_: Server, consent: Consent) { - // Assign a transactionRequestId to the document and set the initial + // Assign a consentRequestId to the document and set the initial // status. This operation will create an event that triggers the execution // of the onUpdate function. consentRepository.updateConsentById(consent.id, { consentRequestId: uuid.v4(), - status: Status.PENDING_PARTY_LOOKUP, + status: ConsentStatus.PENDING_PARTY_LOOKUP, }) } +async function handlePartyLookup(server: Server, consent: Consent) { + // Check whether the consent document has all the necessary properties + // to perform a party lookup. + // if (validator.isValidPartyLookup(transaction)) { + // Payee is guaranteed to be non-null by the validator. + + server.app.mojaloopClient.getParties( + // @ts-ignore + consent.party.partyIdInfo.partyIdType, + // @ts-ignore + consent.party.partyIdInfo.partyIdentifier + ) + // } +} + +async function handleConsentRequest( + server: Server, + consent: Consent +) { + // Upon receiving a callback from Mojaloop that contains information about + // the payee, the server will update all relevant transaction documents + // in the Firebase. However, we can just ignore all updates by the server + // and wait for the user to confirm the payee by keying in more details + // about the transaction (i.e., source account ID, consent ID, and + // transaction amount). + // if (validator.isValidPayeeConfirmation(consent)) { + // If the update contains all the necessary fields, process document + // to the next step by sending a transaction request to Mojaloop. + + try { + // The optional values are guaranteed to exist by the validator. + // eslint-disable @typescript-eslint/no-non-null-assertion + + consent = await consentRepository.getConsentById( + consent.consentId! + ) + + server.app.mojaloopClient.postConsentRequests({ + id: consent.id!, + initiatorId: string, + accountIds: string[], + authChannels: TAuthChannel[], + scopes: string[], + callbackUri: string, + }) + + // eslint-enable @typescript-eslint/no-non-null-assertion + } catch (err) { + logger.error(err) + } + // } +} + export const onCreate: ConsentHandler = async ( server: Server, consent: Consent ): Promise => { -// if (transaction.status) { -// // Skip transaction that has been processed previously. -// // We need this because when the server starts for the first time, -// // all existing documents in the Firebase will be treated as a new -// // document. -// return -// } + if (consent.status) { + // Skip transaction that has been processed previously. + // We need this because when the server starts for the first time, + // all existing documents in the Firebase will be treated as a new + // document. + return + } await handleNewConsent(server, consent) } + +export const onUpdate: ConsentHandler = async ( + server: Server, + consent: Consent +): Promise => { + if (!consent.status) { + // Status is expected to be null only when the document is created for the first + // time by the user. + logger.error('Invalid consent, undefined status.') + return + } + + switch (consent.status) { + case ConsentStatus.PENDING_PARTY_LOOKUP: + await handlePartyLookup(server, consent) + break + + case ConsentStatus.AUTHORIZATION_REQUIRED: + await handleAuthorization(server, consent) + break + } +} From 2cf44914d602b1761b738488b987e0c09fa1e11f Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 01:33:02 +0530 Subject: [PATCH 020/114] feat: Add/update ConsentStatus enum --- src/models/consent.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/models/consent.ts b/src/models/consent.ts index 87fb2957..fbf96168 100644 --- a/src/models/consent.ts +++ b/src/models/consent.ts @@ -40,18 +40,28 @@ export enum ConsentStatus { * Waiting for the user to confirm payee information and provide more * details about the transaction. */ - PENDING_PAYEE_CONFIRMATION = 'PENDING_PAYEE_CONFIRMATION', + PENDING_PARTY_CONFIRMATION = 'PENDING_PARTY_CONFIRMATION', /** * Waiting for the user to authorize the consent. */ - AUTHORIZATION_REQUIRED = 'AUTHORIZATION_REQUIRED', + AUTHENTICATION_REQUIRED = 'AUTHENTICATION_REQUIRED', /** - * The consent is authorized and active. + * The consent is granted and active. */ ACTIVE = 'ACTIVE', + /** + * The consent is ACTIVE and challenge has been generated + */ + CHALLENGE_GENERATED = 'CHALLENGE_GENERATED', + + /** + * The consent is ACTIVE and challenge has been verified + */ + CHALLENGE_VERIFIED = 'CHALLENGE_VERIFIED', + /** * The consent is revoked and no longer valid. */ From 844776244169dcd25b52c67d4b6a015f28e25e4e Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 01:48:09 +0530 Subject: [PATCH 021/114] feat: implement all linking related firestore handlers --- src/server/handlers/firestore/consents.ts | 144 +++++++++++++++++----- 1 file changed, 110 insertions(+), 34 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 555e2943..499f4562 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -26,12 +26,9 @@ ******/ import * as uuid from 'uuid' -import { Server, server } from '@hapi/hapi' +import { Server } from '@hapi/hapi' import { logger } from '~/shared/logger' -import { - AuthenticationResponseType, -} from '~/shared/ml-thirdparty-client/models/core' import { ConsentHandler } from '~/server/plugins/internal/firestore' import { Consent, ConsentStatus } from '~/models/consent' @@ -64,44 +61,111 @@ async function handlePartyLookup(server: Server, consent: Consent) { // } } -async function handleConsentRequest( - server: Server, - consent: Consent -) { +async function handleAuthentication(server: Server, consent: Consent) { + if ( + !consent.authToken || + !consent.scopes || + !consent.initiatorId || + !consent.party + ) { + throw new Error('Consent Object Missing Fields') + } + + try { + server.app.mojaloopClient.putConsentRequests( + consent.id, + { + initiatorId: consent.initiatorId, + authChannels: consent.authChannels, + scopes: consent.scopes, + // TODO: FIGURE OUT FROM WHERE TO GET + callbackUri: '', + authToken: consent.authToken, + }, + consent.party.partyIdInfo.fspId + ) + } catch (error) { + logger.error(error) + } +} + +async function handleConsentRequest(server: Server, consent: Consent) { // Upon receiving a callback from Mojaloop that contains information about // the payee, the server will update all relevant transaction documents // in the Firebase. However, we can just ignore all updates by the server // and wait for the user to confirm the payee by keying in more details // about the transaction (i.e., source account ID, consent ID, and // transaction amount). + // if (validator.isValidPayeeConfirmation(consent)) { - // If the update contains all the necessary fields, process document - // to the next step by sending a transaction request to Mojaloop. - - try { - // The optional values are guaranteed to exist by the validator. - // eslint-disable @typescript-eslint/no-non-null-assertion - - consent = await consentRepository.getConsentById( - consent.consentId! - ) - - server.app.mojaloopClient.postConsentRequests({ - id: consent.id!, - initiatorId: string, - accountIds: string[], - authChannels: TAuthChannel[], - scopes: string[], - callbackUri: string, - }) - - // eslint-enable @typescript-eslint/no-non-null-assertion - } catch (err) { - logger.error(err) - } + // If the update contains all the necessary fields, process document + // to the next step by sending a transaction request to Mojaloop. + + if (!consent.authChannels || !consent.scopes || !consent.initiatorId) { + throw new Error('Consent Object Missing Fields') + } + + try { + // The optional values are guaranteed to exist by the validator. + // eslint-disable @typescript-eslint/no-non-null-assertion + + server.app.mojaloopClient.postConsentRequests( + { + initiatorId: consent.initiatorId, + scopes: consent.scopes, + authChannels: consent.authChannels, + id: consent.id, + authUri: consent.authUri, + // TODO: FIGURE OUT FROM WHERE TO GET + callbackUri: '', + }, + consent.party.partyIdInfo.fspId + ) + + // eslint-enable @typescript-eslint/no-non-null-assertion + } catch (err) { + logger.error(err) + } // } } +async function handleChallengeGeneration(server: Server, consent: Consent) { + if (!consent.consentId || !consent.party) { + throw new Error('Consent Object Missing Fields') + } + + try { + server.app.mojaloopClient.postGenerateChallengeForConsent( + consent.consentId, + consent.party.partyIdInfo.fspId + ) + } catch (error) { + logger.error(error) + } +} + +async function handleSignedChallenge(server: Server, consent: Consent) { + // TODO: Replace with validator + if (!consent.credential || !consent.party) { + throw new Error('Consent Object Missing Fields') + } + + try { + server.app.mojaloopClient.putConsentId( + consent.consentId, + { + requestId: consent.id, + initiatorId: consent.initiatorId, + scopes: consent.scopes, + credential: consent.credential, + }, + consent.party.partyIdInfo.fspId + ) + } catch (error) { + logger.error(error) + } +} + export const onCreate: ConsentHandler = async ( server: Server, consent: Consent @@ -133,8 +197,20 @@ export const onUpdate: ConsentHandler = async ( await handlePartyLookup(server, consent) break - case ConsentStatus.AUTHORIZATION_REQUIRED: - await handleAuthorization(server, consent) + case ConsentStatus.PENDING_PARTY_CONFIRMATION: + await handleConsentRequest(server, consent) + break + + case ConsentStatus.AUTHENTICATION_REQUIRED: + await handleAuthentication(server, consent) + break + + case ConsentStatus.ACTIVE: + await handleChallengeGeneration(server, consent) + break + + case ConsentStatus.CHALLENGE_VERIFIED: + await handleSignedChallenge(server, consent) break } } From bf7d3c8c6fccfe465010ca565a3f8d59928c46f1 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 01:49:47 +0530 Subject: [PATCH 022/114] feat: Use ConsentStatus enum instead of hardcoding value --- src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts | 5 ++--- src/server/handlers/openapi/mojaloop/consents.ts | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts index 8ffe80c8..f760139c 100644 --- a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts @@ -27,6 +27,7 @@ import { Request, ResponseToolkit } from '@hapi/hapi' import { Handler, Context } from 'openapi-backend' import { logger } from '~/shared/logger' import { consentRepository } from '~/repositories/consent' +import { ConsentStatus } from '~/models/consent' export const put: Handler = async ( context: Context, @@ -39,9 +40,7 @@ export const put: Handler = async ( consentRepository.updateConsentById(id, { authChannels, authUri, - // TODO: check how consent status field is being used - // TODO: Shift this to enum - if the field is required - status: 'AUTHENTICATION_REQUIRED', + status: ConsentStatus.AUTHENTICATION_REQUIRED, }) return h.response().code(200) } diff --git a/src/server/handlers/openapi/mojaloop/consents.ts b/src/server/handlers/openapi/mojaloop/consents.ts index 5cba6f5d..d466eba1 100644 --- a/src/server/handlers/openapi/mojaloop/consents.ts +++ b/src/server/handlers/openapi/mojaloop/consents.ts @@ -27,6 +27,7 @@ import { Request, ResponseToolkit } from '@hapi/hapi' import { Handler, Context } from 'openapi-backend' import { logger } from '~/shared/logger' import { consentRepository } from '~/repositories/consent' +import { ConsentStatus } from '~/models/consent' export const post: Handler = async ( context: Context, @@ -41,9 +42,7 @@ export const post: Handler = async ( initiatorId, participantId, scopes, - // TODO: check how consent status field is being used - // TODO: Shift this to enum - if the field is required - status: 'CONSENT_GRANTED', + status: ConsentStatus.ACTIVE, }) return h.response().code(202) } From 49812bba394f5e673404703eeaf29202b7466658 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 10:53:10 +0530 Subject: [PATCH 023/114] fix: Correct ConsentStatus Enum used --- src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts index ab5d980f..50ea3916 100644 --- a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts @@ -68,7 +68,7 @@ export const put: Handler = async ( { party: body.party, accounts: body.accounts, - status: Status.PENDING_PAYEE_CONFIRMATION, + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, } ) } else { From a20f0dc6315471fa22fa90f4c657cb74fe8e0bae Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 10:53:46 +0530 Subject: [PATCH 024/114] feat: Add/Update handlers in index --- src/server/handlers/openapi/app/index.ts | 2 ++ src/server/handlers/openapi/mojaloop/index.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/server/handlers/openapi/app/index.ts b/src/server/handlers/openapi/app/index.ts index 5f7f0570..4faa7a95 100644 --- a/src/server/handlers/openapi/app/index.ts +++ b/src/server/handlers/openapi/app/index.ts @@ -24,7 +24,9 @@ ******/ import * as Health from '../health' +import * as MojaloopConsentsById from './consents/{ID}' export const apiHandlers = { getHealth: Health.get, + deleteConsentsById: MojaloopConsentsById.remove, } diff --git a/src/server/handlers/openapi/mojaloop/index.ts b/src/server/handlers/openapi/mojaloop/index.ts index 9a74fc5b..5d243ca2 100644 --- a/src/server/handlers/openapi/mojaloop/index.ts +++ b/src/server/handlers/openapi/mojaloop/index.ts @@ -41,7 +41,7 @@ export const apiHandlers = { postAuthorizations: MojaloopAuthorizations.post, postConsents: MojaloopConsents.post, putConsentsById: MojaloopConsentsById.put, - deleteConsentsById: MojaloopConsentsById.remove, + patchConsentsById: MojaloopConsentsById.patch, putConsentRequestsById: MojaloopConsentRequestsById.put, putParticipants: MojaloopParticipants.put, putParticipantsError: MojaloopParticipantsError.put, From 9a49e03465bb02d1ea67c8f99c68a4879a1f46ab Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 10:54:59 +0530 Subject: [PATCH 025/114] feat: Implement app-side handler for DELETE consents/{ID} --- .../handlers/openapi/app/consents/{ID}.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/server/handlers/openapi/app/consents/{ID}.ts diff --git a/src/server/handlers/openapi/app/consents/{ID}.ts b/src/server/handlers/openapi/app/consents/{ID}.ts new file mode 100644 index 00000000..f24030dc --- /dev/null +++ b/src/server/handlers/openapi/app/consents/{ID}.ts @@ -0,0 +1,40 @@ +/***** + License + -------------- + Copyright © 2020 Mojaloop Foundation + The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Mojaloop Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Mojaloop Foundation + - Name Surname + + * Google + - Abhimanyu Kapur + -------------- + ******/ + +import { Request, ResponseToolkit } from '@hapi/hapi' +import { Handler, Context } from 'openapi-backend' +import { logger } from '~/shared/logger' + +// TODO: Change to delete ? +export const remove: Handler = async ( + context: Context, + request: Request, + h: ResponseToolkit +) => { + logger.logRequest(context, request, h) + // Make outgoing POST consents/{ID}/revoke request to Mojaloop + server.app.mojaloopClient.postRevokeConsent() + return h.response().code(200) +} From ba3ed53fb7f60983f374ecf993150994eaf62b90 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 11:04:32 +0530 Subject: [PATCH 026/114] style: updating licence --- src/repositories/consent.ts | 2 +- src/server/handlers/openapi/app/index.ts | 1 + src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts | 1 + src/server/handlers/openapi/mojaloop/consents.ts | 1 + src/server/handlers/openapi/mojaloop/consents/{ID}.ts | 1 + src/server/handlers/openapi/mojaloop/index.ts | 1 + src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts | 1 + 7 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index 077bfee6..d950c7aa 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -45,7 +45,7 @@ export interface IConsentRepository { */ getConsentById(id: string): Promise - /** + /** * Updates one or more consent documents based on the given conditions. * * @param conditions Conditions for the documents that need to be updated. diff --git a/src/server/handlers/openapi/app/index.ts b/src/server/handlers/openapi/app/index.ts index 4faa7a95..98fc00b6 100644 --- a/src/server/handlers/openapi/app/index.ts +++ b/src/server/handlers/openapi/app/index.ts @@ -20,6 +20,7 @@ * Google - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ diff --git a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts index f760139c..c8b93004 100644 --- a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts @@ -20,6 +20,7 @@ * Google - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ diff --git a/src/server/handlers/openapi/mojaloop/consents.ts b/src/server/handlers/openapi/mojaloop/consents.ts index d466eba1..1a5917cc 100644 --- a/src/server/handlers/openapi/mojaloop/consents.ts +++ b/src/server/handlers/openapi/mojaloop/consents.ts @@ -20,6 +20,7 @@ * Google - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ diff --git a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts index a970dfc4..4ad36782 100644 --- a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts @@ -20,6 +20,7 @@ * Google - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ diff --git a/src/server/handlers/openapi/mojaloop/index.ts b/src/server/handlers/openapi/mojaloop/index.ts index 5d243ca2..4deab839 100644 --- a/src/server/handlers/openapi/mojaloop/index.ts +++ b/src/server/handlers/openapi/mojaloop/index.ts @@ -20,6 +20,7 @@ * Google - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ diff --git a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts index 50ea3916..dd142f8d 100644 --- a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts @@ -20,6 +20,7 @@ * Google - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ From 6c28ba5d47abb073a5873834629e9640be01d5a4 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 12:20:10 +0530 Subject: [PATCH 027/114] feat: add consent validator for firestore handlers --- src/server/handlers/firestore/consents.ts | 28 ++--- .../handlers/firestore/consents.validator.ts | 117 ++++++++++++++++++ 2 files changed, 128 insertions(+), 17 deletions(-) create mode 100644 src/server/handlers/firestore/consents.validator.ts diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 499f4562..e32ec402 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -33,8 +33,8 @@ import { logger } from '~/shared/logger' import { ConsentHandler } from '~/server/plugins/internal/firestore' import { Consent, ConsentStatus } from '~/models/consent' -// import * as validator from './consents.validator' import { consentRepository } from '~/repositories/consent' +import * as validator from './consents.validator' async function handleNewConsent(_: Server, consent: Consent) { // Assign a consentRequestId to the document and set the initial @@ -49,7 +49,10 @@ async function handleNewConsent(_: Server, consent: Consent) { async function handlePartyLookup(server: Server, consent: Consent) { // Check whether the consent document has all the necessary properties // to perform a party lookup. - // if (validator.isValidPartyLookup(transaction)) { + if (!validator.isValidPartyLookup(consent)) { + throw new Error('Consent Object Missing Fields') + } + // Payee is guaranteed to be non-null by the validator. server.app.mojaloopClient.getParties( @@ -62,12 +65,7 @@ async function handlePartyLookup(server: Server, consent: Consent) { } async function handleAuthentication(server: Server, consent: Consent) { - if ( - !consent.authToken || - !consent.scopes || - !consent.initiatorId || - !consent.party - ) { + if (!validator.isValidAuthentication(consent)) { throw new Error('Consent Object Missing Fields') } @@ -78,7 +76,7 @@ async function handleAuthentication(server: Server, consent: Consent) { initiatorId: consent.initiatorId, authChannels: consent.authChannels, scopes: consent.scopes, - // TODO: FIGURE OUT FROM WHERE TO GET + // TODO: FIGURE OUT FROM WHERE TO GET THIS callbackUri: '', authToken: consent.authToken, }, @@ -97,13 +95,10 @@ async function handleConsentRequest(server: Server, consent: Consent) { // about the transaction (i.e., source account ID, consent ID, and // transaction amount). - // if (validator.isValidPayeeConfirmation(consent)) { - // If the update contains all the necessary fields, process document - // to the next step by sending a transaction request to Mojaloop. - - if (!consent.authChannels || !consent.scopes || !consent.initiatorId) { + if (!validator.isValidAuthentication(consent)) { throw new Error('Consent Object Missing Fields') } + // If the update contains all the necessary fields, process document try { // The optional values are guaranteed to exist by the validator. @@ -130,7 +125,7 @@ async function handleConsentRequest(server: Server, consent: Consent) { } async function handleChallengeGeneration(server: Server, consent: Consent) { - if (!consent.consentId || !consent.party) { + if (!validator.isValidChallengeGeneration(consent)) { throw new Error('Consent Object Missing Fields') } @@ -145,8 +140,7 @@ async function handleChallengeGeneration(server: Server, consent: Consent) { } async function handleSignedChallenge(server: Server, consent: Consent) { - // TODO: Replace with validator - if (!consent.credential || !consent.party) { + if (!validator.isValidSignedChallenge(consent)) { throw new Error('Consent Object Missing Fields') } diff --git a/src/server/handlers/firestore/consents.validator.ts b/src/server/handlers/firestore/consents.validator.ts new file mode 100644 index 00000000..cab1d68a --- /dev/null +++ b/src/server/handlers/firestore/consents.validator.ts @@ -0,0 +1,117 @@ +/***** + License + -------------- + Copyright © 2020 Mojaloop Foundation + The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Mojaloop Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Mojaloop Foundation + - Name Surname + + * Google + - Abhimanyu Kapur + -------------- + ******/ + +import { Consent } from '~/models/consent' + +/** + * Checks whether a consent document has all the necessary fields to perform + * a party lookup. + * + * @param consent the object representation of a consent that is stored + * on Firebase. + */ +export const isValidPartyLookup = (consent: Consent): boolean => { + if ( + consent?.party?.partyIdInfo && + consent.party.partyIdInfo.partyIdType && + consent.party.partyIdInfo.partyIdentifier + ) { + return true + } + return false +} + +/** + * Checks whether a consent document has all the necessary fields to be + * processed as a consent request. + * + * @param consent the object representation of a consent that is stored + * on Firebase. + */ +export const isValidAuthentication = (consent: Consent): boolean => { + if ( + consent.consentRequestId && + consent.consentId && + consent.party && + consent.initiatorId && + consent.authChannels && + consent.authToken + ) { + return true + } + return false +} + +/** + * Checks whether a consent document has all the necessary fields to be + * processed as a consent authorization. + * + * @param consent the object representation of a consent that is stored + * on Firebase. + */ +export const isValidConsentRequest = (consent: Consent): boolean => { + if ( + consent.authChannels && + consent.scopes && + consent.initiatorId && + consent.party + ) { + return true + } + return false +} + +/** + * Checks whether a consent document has all the necessary fields to be + * processed as a consent authorization. + * + * @param consent the object representation of a consent that is stored + * on Firebase. + */ +export const isValidChallengeGeneration = (consent: Consent): boolean => { + if (consent.consentId && consent.party) { + return true + } + return false +} + +/** + * Checks whether a consent document has all the necessary fields to be + * processed as a consent authorization. + * + * @param consent the object representation of a consent that is stored + * on Firebase. + */ +export const isValidSignedChallenge = (consent: Consent): boolean => { + if ( + consent.credential && + consent.party && + consent.scopes && + consent.initiatorId + ) { + return true + } + return false +} From 15e7a60cc6a3ad093894a624d1442a3416942e71 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 12:20:33 +0530 Subject: [PATCH 028/114] refactor: remove postConsentRequests method - implemented in separate PR --- src/shared/ml-thirdparty-client/index.ts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/shared/ml-thirdparty-client/index.ts b/src/shared/ml-thirdparty-client/index.ts index aadede4b..86dcca5e 100644 --- a/src/shared/ml-thirdparty-client/index.ts +++ b/src/shared/ml-thirdparty-client/index.ts @@ -157,21 +157,4 @@ export class Client { // TODO: Implement communication with Mojaloop. } - - public async postConsentRequests( - requestBody: SDKStandardComponents.PostConsentRequestsRequest - ): Promise { - if (this.simulator) { - // If the client is configured with a simulator, then it will not - // communicate with Mojaloop directly. Instead, it will only generate - // a random response that is injected to the internal routes. - // return this.simulator - } - - // TODO: Check Destination id - this.thirdpartyRequests.postConsentRequests( - requestBody, - this.options.participantId - ) - } } From 1639024b80eb6a6ef4261fa9f9c814b3965fc88c Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 12:32:09 +0530 Subject: [PATCH 029/114] fix: Corrected validator method descriptions and updated validator method calls in handler --- src/server/handlers/firestore/consents.ts | 8 +------- src/server/handlers/firestore/consents.validator.ts | 11 ++++++----- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index e32ec402..8a52cc3c 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -88,14 +88,8 @@ async function handleAuthentication(server: Server, consent: Consent) { } async function handleConsentRequest(server: Server, consent: Consent) { - // Upon receiving a callback from Mojaloop that contains information about - // the payee, the server will update all relevant transaction documents - // in the Firebase. However, we can just ignore all updates by the server - // and wait for the user to confirm the payee by keying in more details - // about the transaction (i.e., source account ID, consent ID, and - // transaction amount). - if (!validator.isValidAuthentication(consent)) { + if (!validator.isValidConsentRequest(consent)) { throw new Error('Consent Object Missing Fields') } // If the update contains all the necessary fields, process document diff --git a/src/server/handlers/firestore/consents.validator.ts b/src/server/handlers/firestore/consents.validator.ts index cab1d68a..958fe475 100644 --- a/src/server/handlers/firestore/consents.validator.ts +++ b/src/server/handlers/firestore/consents.validator.ts @@ -45,7 +45,7 @@ export const isValidPartyLookup = (consent: Consent): boolean => { /** * Checks whether a consent document has all the necessary fields to be - * processed as a consent request. + * processed as an authenticated consent request. * * @param consent the object representation of a consent that is stored * on Firebase. @@ -66,7 +66,7 @@ export const isValidAuthentication = (consent: Consent): boolean => { /** * Checks whether a consent document has all the necessary fields to be - * processed as a consent authorization. + * processed as a consent request. * * @param consent the object representation of a consent that is stored * on Firebase. @@ -76,7 +76,8 @@ export const isValidConsentRequest = (consent: Consent): boolean => { consent.authChannels && consent.scopes && consent.initiatorId && - consent.party + consent.party && + consent.authUri ) { return true } @@ -85,7 +86,7 @@ export const isValidConsentRequest = (consent: Consent): boolean => { /** * Checks whether a consent document has all the necessary fields to be - * processed as a consent authorization. + * processed as a request to generate challenge for a consent. * * @param consent the object representation of a consent that is stored * on Firebase. @@ -99,7 +100,7 @@ export const isValidChallengeGeneration = (consent: Consent): boolean => { /** * Checks whether a consent document has all the necessary fields to be - * processed as a consent authorization. + * processed as a signed consent request. * * @param consent the object representation of a consent that is stored * on Firebase. From 3946c488106541fe3c0ee6560c48eb97b388a95c Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 12:32:28 +0530 Subject: [PATCH 030/114] chore: linting fix --- src/server/handlers/firestore/consents.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 8a52cc3c..e7aef458 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -88,7 +88,6 @@ async function handleAuthentication(server: Server, consent: Consent) { } async function handleConsentRequest(server: Server, consent: Consent) { - if (!validator.isValidConsentRequest(consent)) { throw new Error('Consent Object Missing Fields') } From 8920d4437a18689b1e96eeb06ad1df46244ed52a Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 16:17:51 +0530 Subject: [PATCH 031/114] feat: Create participant repository and implement replace method --- src/repositories/participants.ts | 80 ++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/repositories/participants.ts diff --git a/src/repositories/participants.ts b/src/repositories/participants.ts new file mode 100644 index 00000000..df4356a5 --- /dev/null +++ b/src/repositories/participants.ts @@ -0,0 +1,80 @@ +/***** + License + -------------- + Copyright © 2020 Mojaloop Foundation + The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Mojaloop Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Mojaloop Foundation + - Name Surname + + * Google + - Steven Wijaya + - Abhimanyu Kapur + -------------- + ******/ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import firebase from '~/lib/firebase' +import { logger } from '~/shared/logger' + +export interface IParticipantRepository { + /** + * Replace existing participants list with new list. + * + * @param data Documents that are about to be added. + */ + replace(data: Record): Promise +} + +export class FirebaseParticipantRepository implements IParticipantRepository { + // TODO: Confirm data Type + async replace(data: Record): Promise { + const collectionRef: FirebaseFirestore.CollectionReference = firebase + .firestore() + .collection('participants') + + // Find and update all matching documents in Firebase that match the given conditions. + await collectionRef + .get() + .then(async (response) => { + // Create a batch to perform all of the updates using a single request. + // Firebase will also execute the updates atomically according to the + // API specification. + const batch = firebase.firestore().batch() + + const batchSize = response.size + if (batchSize > 0) { + // If previous participants list exists, delete it + + // Iterate through all matching documents add them to the processing batch. + response.docs.forEach((doc) => { + batch.delete(doc.ref) + }) + } + // Iterate through received participants list and add them to the processing batch. + data.array.forEach((participant: any) => { + batch.set(collectionRef.doc(), participant) + }) + + // Commit the updates. + return batch.commit() + }) + .catch((err) => { + logger.error(err) + }) + } +} + +export const participantRepository: IParticipantRepository = new FirebaseParticipantRepository() From ad2a59a46eb5a90418ae1955c928bce2ec4fa8cd Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 16:19:03 +0530 Subject: [PATCH 032/114] feat: implement PUT participants Handler --- src/server/handlers/openapi/mojaloop/participants.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/server/handlers/openapi/mojaloop/participants.ts b/src/server/handlers/openapi/mojaloop/participants.ts index 21513db1..8d37b072 100644 --- a/src/server/handlers/openapi/mojaloop/participants.ts +++ b/src/server/handlers/openapi/mojaloop/participants.ts @@ -21,13 +21,14 @@ * Google - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ import { Request, ResponseToolkit } from '@hapi/hapi' import { Handler, Context } from 'openapi-backend' import { logger } from '~/shared/logger' - +import { participantRepository } from '~/repositories/participants' export const put: Handler = async ( context: Context, @@ -38,7 +39,7 @@ export const put: Handler = async ( // @ts-ignore const participants = request.payload.participants - // TODO: Implement this function - updateFirebaseParticipants(participants) + // Replace existing participants list with received list + participantRepository.replace(participants) return h.response().code(200) } From 62c373552e4e44454de9f26a5f25fc7e6158dfd4 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 16:32:14 +0530 Subject: [PATCH 033/114] fix: add non-null assertions --- src/server/handlers/firestore/consents.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index e7aef458..022ccabf 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/ban-ts-comment */ /***** License @@ -53,13 +54,11 @@ async function handlePartyLookup(server: Server, consent: Consent) { throw new Error('Consent Object Missing Fields') } - // Payee is guaranteed to be non-null by the validator. + // Party is guaranteed to be non-null by the validator. server.app.mojaloopClient.getParties( - // @ts-ignore - consent.party.partyIdInfo.partyIdType, - // @ts-ignore - consent.party.partyIdInfo.partyIdentifier + consent.party!.partyIdInfo.partyIdType, + consent.party!.partyIdInfo.partyIdentifier ) // } } @@ -80,7 +79,7 @@ async function handleAuthentication(server: Server, consent: Consent) { callbackUri: '', authToken: consent.authToken, }, - consent.party.partyIdInfo.fspId + consent.party!.partyIdInfo.fspId ) } catch (error) { logger.error(error) From d989d75c0cd514d5668b0e61b2f62391edff1c51 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 1 Sep 2020 17:34:09 +0530 Subject: [PATCH 034/114] chore: bump sdk-standard-components to 11.3.1 + audit fix --- package-lock.json | 249 +++++++++++++++++++++++++++++++--------------- package.json | 2 +- 2 files changed, 168 insertions(+), 83 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3049def0..a85b12b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -684,16 +684,37 @@ "dev": true, "requires": { "conventional-changelog-conventionalcommits": "4.2.3" + }, + "dependencies": { + "conventional-changelog-conventionalcommits": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.3.tgz", + "integrity": "sha512-atGa+R4vvEhb8N/8v3IoW59gCBJeeFiX6uIbPu876ENAmkMwsenyn0R21kdDHJFLQdy6zW4J6b4xN8KI3b9oww==", + "dev": true, + "requires": { + "compare-func": "^1.3.1", + "lodash": "^4.17.15", + "q": "^1.5.1" + } + } } }, "@commitlint/ensure": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-9.0.1.tgz", - "integrity": "sha512-z8SEkfbn0lMnAtt7Hp3A8hE3CRCDsg+Eu3Xj1UJakOyCPJgHE1/vEyM2DO2dxTXVKuttiHeLDnUSHCxklm78Ng==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-9.1.2.tgz", + "integrity": "sha512-hwQICwpNSTsZgj/1/SdPvYAzhwjwgCJI4vLbT879+Jc+AJ6sj2bUDGw/F89vzgKz1VnaMm4D65bNhoWhG3pdhQ==", "dev": true, "requires": { - "@commitlint/types": "^9.0.1", - "lodash": "^4.17.15" + "@commitlint/types": "^9.1.2", + "lodash": "^4.17.19" + }, + "dependencies": { + "@commitlint/types": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-9.1.2.tgz", + "integrity": "sha512-r3fwVbVH+M8W0qYlBBZFsUwKe6NT5qvz+EmU7sr8VeN1cQ63z+3cfXyTo7WGGEMEgKiT0jboNAK3b1FZp8k9LQ==", + "dev": true + } } }, "@commitlint/execute-rule": { @@ -764,33 +785,47 @@ } }, "@commitlint/is-ignored": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-9.0.1.tgz", - "integrity": "sha512-doGBfQgbsi48Hc48runGdN0TQFvf5XZizck8cylQdGG/3w+YwX9WkplEor7cvz8pmmuD6PpfpdukHSKlR8KmHQ==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-9.1.2.tgz", + "integrity": "sha512-423W/+Ro+Cc8cg81+t9gds1EscMZNjnGT31nKDvxVxJxXiXQsYYoFEQbU+nfUrRGQsUikEgEJ3ppVGr1linvcQ==", "dev": true, "requires": { - "@commitlint/types": "^9.0.1", - "semver": "7.1.3" + "@commitlint/types": "^9.1.2", + "semver": "7.3.2" }, "dependencies": { + "@commitlint/types": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-9.1.2.tgz", + "integrity": "sha512-r3fwVbVH+M8W0qYlBBZFsUwKe6NT5qvz+EmU7sr8VeN1cQ63z+3cfXyTo7WGGEMEgKiT0jboNAK3b1FZp8k9LQ==", + "dev": true + }, "semver": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz", - "integrity": "sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true } } }, "@commitlint/lint": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-9.0.1.tgz", - "integrity": "sha512-EAn4E6aGWZ96Dg9LN28kdELqkyFOAUGlXWmanMdWxGFGdOf24ZHzlVsbr/Yb1oSBUE2KVvAF5W2Mzn2+Ge5rOg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-9.1.2.tgz", + "integrity": "sha512-XvggqHZ4XSTKOgzJhCzz52cWRRO57QQnEviwGj0qnD4jdwC+8h2u9LNZwoa2tGAuaNM3nSm//wNK7FRZhgiiFA==", "dev": true, "requires": { - "@commitlint/is-ignored": "^9.0.1", - "@commitlint/parse": "^9.0.1", - "@commitlint/rules": "^9.0.1", - "@commitlint/types": "^9.0.1" + "@commitlint/is-ignored": "^9.1.2", + "@commitlint/parse": "^9.1.2", + "@commitlint/rules": "^9.1.2", + "@commitlint/types": "^9.1.2" + }, + "dependencies": { + "@commitlint/types": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-9.1.2.tgz", + "integrity": "sha512-r3fwVbVH+M8W0qYlBBZFsUwKe6NT5qvz+EmU7sr8VeN1cQ63z+3cfXyTo7WGGEMEgKiT0jboNAK3b1FZp8k9LQ==", + "dev": true + } } }, "@commitlint/load": { @@ -867,15 +902,15 @@ } }, "@commitlint/message": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-9.0.1.tgz", - "integrity": "sha512-9rKnOeBV5s5hnV895aE3aMgciC27kAjkV9BYVQOWRjZdXHFZxa+OZ94mkMp+Hcr61W++fox1JJpPiTuCTDX3TQ==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-9.1.2.tgz", + "integrity": "sha512-ndlx5z7bPVLG347oYJUHuQ41eTcsw+aUYT1ZwQyci0Duy2atpuoeeSw9SuM1PjufzRCpb6ExzFEgGzcCRKAJsg==", "dev": true }, "@commitlint/parse": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-9.0.1.tgz", - "integrity": "sha512-O39yMSMFdBtqwyM5Ld7RT6OGeI7jiXB9UUb09liIXIkltaZZo6CeoBD9hyfRWpaw81SiGL4OwHzp92mYVHLmow==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-9.1.2.tgz", + "integrity": "sha512-d+/VYbkotctW+lzDpus/R6xTerOqFQkW1myH+3PwnqYSE6JU/uHT4MlZNGJBv8pX9SPlR66t6X9puFobqtezEw==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", @@ -914,21 +949,29 @@ } }, "@commitlint/rules": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-9.0.1.tgz", - "integrity": "sha512-K9IiQzF/C2tP/0mQUPSkOtmAEUleRQhZK1NFLVbsd6r4uobaczjPSYvEH+cuSHlD9b3Ori7PRiTgVBAZTH5ORQ==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-9.1.2.tgz", + "integrity": "sha512-1vecFuzqVqjiT57ocXq1bL8V6GEF1NZs3BR0dQzObaqHftImIxBVII299gasckTkcuxNc8M+7XxZyKxUthukpQ==", "dev": true, "requires": { - "@commitlint/ensure": "^9.0.1", - "@commitlint/message": "^9.0.1", - "@commitlint/to-lines": "^9.0.1", - "@commitlint/types": "^9.0.1" + "@commitlint/ensure": "^9.1.2", + "@commitlint/message": "^9.1.2", + "@commitlint/to-lines": "^9.1.2", + "@commitlint/types": "^9.1.2" + }, + "dependencies": { + "@commitlint/types": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-9.1.2.tgz", + "integrity": "sha512-r3fwVbVH+M8W0qYlBBZFsUwKe6NT5qvz+EmU7sr8VeN1cQ63z+3cfXyTo7WGGEMEgKiT0jboNAK3b1FZp8k9LQ==", + "dev": true + } } }, "@commitlint/to-lines": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-9.0.1.tgz", - "integrity": "sha512-FHiXPhFgGnvekF4rhyl1daHimEHkr81pxbHAmWG/0SOCehFr5THsWGoUYNNBMF7rdwUuVq4tXJpEOFiWBGKigg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-9.1.2.tgz", + "integrity": "sha512-o4zWcMf9EnzA3MOqx01780SgrKq5hqDJmUBPk30g6an0XcDuDy3OSZHHTJFdzsg4V9FjC4OY44sFeK7GN7NaxQ==", "dev": true }, "@commitlint/top-level": { @@ -2451,9 +2494,9 @@ } }, "@mojaloop/sdk-standard-components": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.0.0.tgz", - "integrity": "sha512-PWVbrs+8RFea4ZM5UQonr0/fyHxyH6OfmtOD5q+J/RAy42j+9IpBywVVK2jYdMS4HnJnHGT6EOjBA63HsSk+xw==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.3.1.tgz", + "integrity": "sha512-1Tbkm9fAAKcz60PONbB5jQh+IVPxd0Z7Qh6ISKDs53t+8rW0wr3hs0f6fcbOBOmsxYolTAwmxiouooay4fmDyg==", "requires": { "base64url": "3.0.1", "fast-safe-stringify": "^2.0.7", @@ -3489,24 +3532,18 @@ "dev": true }, "audit-resolve-core": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/audit-resolve-core/-/audit-resolve-core-1.1.7.tgz", - "integrity": "sha512-9nLm9SgyMbMv86X5a/E6spcu3V+suceHF6Pg4BwjPqfxWBKDvISagJH9Ji592KihqBev4guKFO3BiNEVNnqh3A==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/audit-resolve-core/-/audit-resolve-core-1.1.8.tgz", + "integrity": "sha512-F3IWaxu1Xw4OokmtG9hkmsKoJt8DQS7RZvot52zXHsANKvzFRMKVNTP1DAz1ztlRGmJx1XV16PcE+6m35bYoTA==", "dev": true, "requires": { "concat-stream": "^1.6.2", "debug": "^4.1.1", "djv": "^2.1.2", "spawn-shell": "^2.1.0", - "yargs-parser": "^10.1.0" + "yargs-parser": "^18.1.3" }, "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -3515,15 +3552,6 @@ "requires": { "ms": "^2.1.1" } - }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } } } }, @@ -4452,13 +4480,25 @@ } }, "conventional-changelog-angular": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.10.tgz", - "integrity": "sha512-k7RPPRs0vp8+BtPsM9uDxRl6KcgqtCJmzRD1wRtgqmhQ96g8ifBGo9O/TZBG23jqlXS/rg8BKRDELxfnQQGiaA==", + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.11.tgz", + "integrity": "sha512-nSLypht/1yEflhuTogC03i7DX7sOrXGsRn14g131Potqi6cbGbGEE9PSDEHKldabB6N76HiSyw9Ph+kLmC04Qw==", "dev": true, "requires": { - "compare-func": "^1.3.1", + "compare-func": "^2.0.0", "q": "^1.5.1" + }, + "dependencies": { + "compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + } } }, "conventional-changelog-atom": { @@ -4486,30 +4526,42 @@ "dev": true }, "conventional-changelog-conventionalcommits": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.3.tgz", - "integrity": "sha512-atGa+R4vvEhb8N/8v3IoW59gCBJeeFiX6uIbPu876ENAmkMwsenyn0R21kdDHJFLQdy6zW4J6b4xN8KI3b9oww==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.4.0.tgz", + "integrity": "sha512-ybvx76jTh08tpaYrYn/yd0uJNLt5yMrb1BphDe4WBredMlvPisvMghfpnJb6RmRNcqXeuhR6LfGZGewbkRm9yA==", "dev": true, "requires": { - "compare-func": "^1.3.1", + "compare-func": "^2.0.0", "lodash": "^4.17.15", "q": "^1.5.1" + }, + "dependencies": { + "compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + } } }, "conventional-changelog-core": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.1.7.tgz", - "integrity": "sha512-UBvSrQR2RdKbSQKh7RhueiiY4ZAIOW3+CSWdtKOwRv+KxIMNFKm1rOcGBFx0eA8AKhGkkmmacoTWJTqyz7Q0VA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.0.tgz", + "integrity": "sha512-8+xMvN6JvdDtPbGBqA7oRNyZD4od1h/SIzrWqHcKZjitbVXrFpozEeyn4iI4af1UwdrabQpiZMaV07fPUTGd4w==", "dev": true, "requires": { "add-stream": "^1.0.0", - "conventional-changelog-writer": "^4.0.16", + "conventional-changelog-writer": "^4.0.17", "conventional-commits-parser": "^3.1.0", "dateformat": "^3.0.0", "get-pkg-repo": "^1.0.0", "git-raw-commits": "2.0.0", "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^4.0.0", + "git-semver-tags": "^4.1.0", "lodash": "^4.17.15", "normalize-package-data": "^2.3.5", "q": "^1.5.1", @@ -4520,9 +4572,9 @@ }, "dependencies": { "git-semver-tags": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.0.0.tgz", - "integrity": "sha512-LajaAWLYVBff+1NVircURJFL8TQ3EMIcLAfHisWYX/nPoMwnTYfWAznQDmMujlLqoD12VtLmoSrF1sQ5MhimEQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.0.tgz", + "integrity": "sha512-TcxAGeo03HdErzKzi4fDD+xEL7gi8r2Y5YSxH6N2XYdVSV5UkBwfrt7Gqo1b+uSHCjy/sa9Y6BBBxxFLxfbhTg==", "dev": true, "requires": { "meow": "^7.0.0", @@ -4632,13 +4684,25 @@ } }, "conventional-changelog-jshint": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.7.tgz", - "integrity": "sha512-qHA8rmwUnLiIxANJbz650+NVzqDIwNtc0TcpIa0+uekbmKHttidvQ1dGximU3vEDdoJVKFgR3TXFqYuZmYy9ZQ==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.8.tgz", + "integrity": "sha512-hB/iI0IiZwnZ+seYI+qEQ4b+EMQSEC8jGIvhO2Vpz1E5p8FgLz75OX8oB1xJWl+s4xBMB6f8zJr0tC/BL7YOjw==", "dev": true, "requires": { - "compare-func": "^1.3.1", + "compare-func": "^2.0.0", "q": "^1.5.1" + }, + "dependencies": { + "compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + } } }, "conventional-changelog-preset-loader": { @@ -4648,12 +4712,12 @@ "dev": true }, "conventional-changelog-writer": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.16.tgz", - "integrity": "sha512-jmU1sDJDZpm/dkuFxBeRXvyNcJQeKhGtVcFFkwTphUAzyYWcwz2j36Wcv+Mv2hU3tpvLMkysOPXJTLO55AUrYQ==", + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.17.tgz", + "integrity": "sha512-IKQuK3bib/n032KWaSb8YlBFds+aLmzENtnKtxJy3+HqDq5kohu3g/UdNbIHeJWygfnEbZjnCKFxAW0y7ArZAw==", "dev": true, "requires": { - "compare-func": "^1.3.1", + "compare-func": "^2.0.0", "conventional-commits-filter": "^2.0.6", "dateformat": "^3.0.0", "handlebars": "^4.7.6", @@ -4665,6 +4729,16 @@ "through2": "^3.0.0" }, "dependencies": { + "compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -16090,6 +16164,17 @@ "yargs": "15.3.1" }, "dependencies": { + "conventional-changelog-conventionalcommits": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.3.tgz", + "integrity": "sha512-atGa+R4vvEhb8N/8v3IoW59gCBJeeFiX6uIbPu876ENAmkMwsenyn0R21kdDHJFLQdy6zW4J6b4xN8KI3b9oww==", + "dev": true, + "requires": { + "compare-func": "^1.3.1", + "lodash": "^4.17.15", + "q": "^1.5.1" + } + }, "figures": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", diff --git a/package.json b/package.json index 17501b96..977e4bb3 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "@hapi/hapi": "^19.1.1", "@hapi/inert": "^6.0.1", "@hapi/vision": "^6.0.0", - "@mojaloop/sdk-standard-components": "^11.0.0", + "@mojaloop/sdk-standard-components": "^11.3.1", "@types/uuid": "^8.0.0", "convict": "^6.0.0", "dotenv": "^8.2.0", From de20706d55d1f7019f0e052495bac8e2b96cb1c0 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 11:16:00 +0530 Subject: [PATCH 035/114] fix: add non-null assertions --- src/server/handlers/firestore/consents.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 022ccabf..b17e6ee7 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -106,7 +106,7 @@ async function handleConsentRequest(server: Server, consent: Consent) { // TODO: FIGURE OUT FROM WHERE TO GET callbackUri: '', }, - consent.party.partyIdInfo.fspId + consent.party!.partyIdInfo.fspId ) // eslint-enable @typescript-eslint/no-non-null-assertion @@ -124,7 +124,7 @@ async function handleChallengeGeneration(server: Server, consent: Consent) { try { server.app.mojaloopClient.postGenerateChallengeForConsent( consent.consentId, - consent.party.partyIdInfo.fspId + consent.party!.partyIdInfo.fspId ) } catch (error) { logger.error(error) @@ -145,7 +145,7 @@ async function handleSignedChallenge(server: Server, consent: Consent) { scopes: consent.scopes, credential: consent.credential, }, - consent.party.partyIdInfo.fspId + consent.party!.partyIdInfo.fspId ) } catch (error) { logger.error(error) From e7d481a57d2d5cf7b868387f37ab19ebcc9bf522 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 11:17:02 +0530 Subject: [PATCH 036/114] fix: Incorrect handler type + method names + unneeded import --- src/server/plugins/internal/firestore.ts | 6 +++--- src/shared/ml-thirdparty-client/index.ts | 1 - test/unit/server/handlers/firestore/transactions.test.ts | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/server/plugins/internal/firestore.ts b/src/server/plugins/internal/firestore.ts index 1529f54f..ac5482fb 100644 --- a/src/server/plugins/internal/firestore.ts +++ b/src/server/plugins/internal/firestore.ts @@ -48,9 +48,9 @@ export interface Options { onRemove?: TransactionHandler } consents: { - onCreate?: TransactionHandler - onUpdate?: TransactionHandler - onRemove?: TransactionHandler + onCreate?: ConsentHandler + onUpdate?: ConsentHandler + onRemove?: ConsentHandler } } } diff --git a/src/shared/ml-thirdparty-client/index.ts b/src/shared/ml-thirdparty-client/index.ts index 86dcca5e..fa835efb 100644 --- a/src/shared/ml-thirdparty-client/index.ts +++ b/src/shared/ml-thirdparty-client/index.ts @@ -37,7 +37,6 @@ import Logger, { ThirdpartyRequests, MojaloopRequests, } from '@mojaloop/sdk-standard-components' -import SDKStandardComponents from '@mojaloop/sdk-standard-components' /** * A client object that abstracts out operations that could be performed in diff --git a/test/unit/server/handlers/firestore/transactions.test.ts b/test/unit/server/handlers/firestore/transactions.test.ts index ca56c6d5..910efc44 100644 --- a/test/unit/server/handlers/firestore/transactions.test.ts +++ b/test/unit/server/handlers/firestore/transactions.test.ts @@ -186,7 +186,7 @@ describe('Handlers for transaction documents in Firebase', () => { const consentData = createStubConsentData() const consentRepositorySpy = jest - .spyOn(consentRepository, 'getByConsentId') + .spyOn(consentRepository, 'getConsentById') .mockImplementation(() => new Promise((resolve) => resolve(consentData))) // Mock the expected transaction request being sent. From c4f54b5fa597663bd5522e3d3551066061a39c1e Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 11:30:09 +0530 Subject: [PATCH 037/114] fix: add casting to avoid typescript errors --- src/server/handlers/firestore/consents.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index b17e6ee7..4b43277f 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -36,6 +36,7 @@ import { Consent, ConsentStatus } from '~/models/consent' import { consentRepository } from '~/repositories/consent' import * as validator from './consents.validator' +import { TCredentialScope, TAuthChannel } from '@mojaloop/sdk-standard-components' async function handleNewConsent(_: Server, consent: Consent) { // Assign a consentRequestId to the document and set the initial @@ -72,14 +73,15 @@ async function handleAuthentication(server: Server, consent: Consent) { server.app.mojaloopClient.putConsentRequests( consent.id, { - initiatorId: consent.initiatorId, - authChannels: consent.authChannels, - scopes: consent.scopes, + initiatorId: consent.initiatorId as string, + authChannels: consent.authChannels as TAuthChannel[], + scopes: consent.scopes as TCredentialScope[], + authUri: consent.authUri as string, // TODO: FIGURE OUT FROM WHERE TO GET THIS callbackUri: '', - authToken: consent.authToken, + authToken: consent.authToken as string, }, - consent.party!.partyIdInfo.fspId + consent.party!.partyIdInfo.fspId as string ) } catch (error) { logger.error(error) @@ -98,15 +100,14 @@ async function handleConsentRequest(server: Server, consent: Consent) { server.app.mojaloopClient.postConsentRequests( { - initiatorId: consent.initiatorId, - scopes: consent.scopes, - authChannels: consent.authChannels, + initiatorId: consent.initiatorId as string, + scopes: consent.scopes as TCredentialScope[], + authChannels: consent.authChannels as TAuthChannel[], id: consent.id, - authUri: consent.authUri, // TODO: FIGURE OUT FROM WHERE TO GET callbackUri: '', }, - consent.party!.partyIdInfo.fspId + consent.party!.partyIdInfo.fspId as string ) // eslint-enable @typescript-eslint/no-non-null-assertion @@ -138,7 +139,7 @@ async function handleSignedChallenge(server: Server, consent: Consent) { try { server.app.mojaloopClient.putConsentId( - consent.consentId, + consent.consentId as string, { requestId: consent.id, initiatorId: consent.initiatorId, From a12c6735dac8d2dfd4b33cae3c00226e612aa153 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 13:47:53 +0530 Subject: [PATCH 038/114] feat: Following unlinking diagram update, implement unlinking using firebase handler Remove App endpoint handler for unlinking Make new ConsentStatus enum option Create consent Validator method for unlinking Implement unlinking request handler for firestore --- src/models/consent.ts | 5 +++ src/server/handlers/firestore/consents.ts | 25 +++++++++++- .../handlers/firestore/consents.validator.ts | 14 +++++++ .../handlers/openapi/app/consents/{ID}.ts | 40 ------------------- src/server/handlers/openapi/app/index.ts | 2 - src/shared/ml-thirdparty-client/index.ts | 4 +- 6 files changed, 46 insertions(+), 44 deletions(-) delete mode 100644 src/server/handlers/openapi/app/consents/{ID}.ts diff --git a/src/models/consent.ts b/src/models/consent.ts index fbf96168..e75abf14 100644 --- a/src/models/consent.ts +++ b/src/models/consent.ts @@ -66,6 +66,11 @@ export enum ConsentStatus { * The consent is revoked and no longer valid. */ REVOKED = 'REVOKED', + + /** + * The consent is requested to be revoked for unlinking. + */ + REVOKE_REQUESTED = 'REVOKE_REQUESTED', } export interface Consent { diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 4b43277f..4434c3b2 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -36,7 +36,10 @@ import { Consent, ConsentStatus } from '~/models/consent' import { consentRepository } from '~/repositories/consent' import * as validator from './consents.validator' -import { TCredentialScope, TAuthChannel } from '@mojaloop/sdk-standard-components' +import { + TCredentialScope, + TAuthChannel, +} from '@mojaloop/sdk-standard-components' async function handleNewConsent(_: Server, consent: Consent) { // Assign a consentRequestId to the document and set the initial @@ -153,6 +156,22 @@ async function handleSignedChallenge(server: Server, consent: Consent) { } } +async function handleRevokingConsent(server: Server, consent: Consent) { + if (!validator.isValidRevokeConsent(consent)) { + throw new Error('Consent Object Missing Fields') + } + + try { + // Make outgoing POST consents/{ID}/revoke request to Mojaloop + server.app.mojaloopClient.postRevokeConsent( + consent.consentId as string, + consent.party!.partyIdInfo.fspId as string + ) + } catch (error) { + logger.error(error) + } +} + export const onCreate: ConsentHandler = async ( server: Server, consent: Consent @@ -199,5 +218,9 @@ export const onUpdate: ConsentHandler = async ( case ConsentStatus.CHALLENGE_VERIFIED: await handleSignedChallenge(server, consent) break + + case ConsentStatus.REVOKE_REQUESTED: + await handleRevokingConsent(server, consent) + break } } diff --git a/src/server/handlers/firestore/consents.validator.ts b/src/server/handlers/firestore/consents.validator.ts index 958fe475..2984e24a 100644 --- a/src/server/handlers/firestore/consents.validator.ts +++ b/src/server/handlers/firestore/consents.validator.ts @@ -116,3 +116,17 @@ export const isValidSignedChallenge = (consent: Consent): boolean => { } return false } + +/** + * Checks whether a consent document has all the necessary fields to be + * processed as revoke consent request. + * + * @param consent the object representation of a consent that is stored + * on Firebase. + */ +export const isValidRevokeConsent = (consent: Consent): boolean => { + if (consent.consentId && consent.party && consent.party.partyIdInfo.fspId) { + return true + } + return false +} diff --git a/src/server/handlers/openapi/app/consents/{ID}.ts b/src/server/handlers/openapi/app/consents/{ID}.ts deleted file mode 100644 index f24030dc..00000000 --- a/src/server/handlers/openapi/app/consents/{ID}.ts +++ /dev/null @@ -1,40 +0,0 @@ -/***** - License - -------------- - Copyright © 2020 Mojaloop Foundation - The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - Contributors - -------------- - This is the official list of the Mojaloop project contributors for this file. - Names of the original copyright holders (individuals or organizations) - should be listed with a '*' in the first column. People who have - contributed from an organization can be listed under the organization - that actually holds the copyright for their contributions (see the - Mojaloop Foundation organization for an example). Those individuals should have - their names indented and be marked with a '-'. Email address can be added - optionally within square brackets . - * Mojaloop Foundation - - Name Surname - - * Google - - Abhimanyu Kapur - -------------- - ******/ - -import { Request, ResponseToolkit } from '@hapi/hapi' -import { Handler, Context } from 'openapi-backend' -import { logger } from '~/shared/logger' - -// TODO: Change to delete ? -export const remove: Handler = async ( - context: Context, - request: Request, - h: ResponseToolkit -) => { - logger.logRequest(context, request, h) - // Make outgoing POST consents/{ID}/revoke request to Mojaloop - server.app.mojaloopClient.postRevokeConsent() - return h.response().code(200) -} diff --git a/src/server/handlers/openapi/app/index.ts b/src/server/handlers/openapi/app/index.ts index 98fc00b6..671750ad 100644 --- a/src/server/handlers/openapi/app/index.ts +++ b/src/server/handlers/openapi/app/index.ts @@ -25,9 +25,7 @@ ******/ import * as Health from '../health' -import * as MojaloopConsentsById from './consents/{ID}' export const apiHandlers = { getHealth: Health.get, - deleteConsentsById: MojaloopConsentsById.remove, } diff --git a/src/shared/ml-thirdparty-client/index.ts b/src/shared/ml-thirdparty-client/index.ts index 82624683..9d450bc3 100644 --- a/src/shared/ml-thirdparty-client/index.ts +++ b/src/shared/ml-thirdparty-client/index.ts @@ -242,10 +242,12 @@ export class Client { * Performs a request to revoke the Consent object and unlink * * @param _consentId identifier of consent as defined by Mojaloop API. + * @param destParticipantId ID of destination - to be used when sending request */ // eslint-disable-next-line @typescript-eslint/no-unused-vars public async postRevokeConsent( - _consentId: string + _consentId: string, + _destParticipantId: string ): Promise { // TODO: Add once implemented in sdk-standard components // Placeholder below From c72cf120b4f34add7fcc04ee6e14d3c000d2b304 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 14:47:59 +0530 Subject: [PATCH 039/114] docs: Added patchConsentsById to yaml files --- src/interface/mojaloop.yaml | 13 +++++++++---- src/interface/shared.yaml | 9 +++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/interface/mojaloop.yaml b/src/interface/mojaloop.yaml index f389026d..0fb8c444 100644 --- a/src/interface/mojaloop.yaml +++ b/src/interface/mojaloop.yaml @@ -270,12 +270,17 @@ paths: $ref: '../../node_modules/@mojaloop/api-snippets/v1.0/openapi3/responses/index.yaml#/501' 503: $ref: '../../node_modules/@mojaloop/api-snippets/v1.0/openapi3/responses/index.yaml#/503' - delete: + patch: tags: - consents - summary: '[Mojaloop Callback] Result of deleting the specified consent' - description: Result of deleting the specified consent - operationId: deleteConsentsById + summary: '[Mojaloop Callback] Result of patching the specified consent (used in unlinking)' + description: Result of patching the specified consent (used in unlinking) + operationId: patchConsentsById + requestBody: + content: + application/json: + schema: + $ref: 'shared.yaml#/components/schemas/PatchConsentsByIdRequest' responses: 200: $ref: '../../node_modules/@mojaloop/api-snippets/v1.0/openapi3/responses/index.yaml#/200' diff --git a/src/interface/shared.yaml b/src/interface/shared.yaml index f1e66450..4a0a6e80 100644 --- a/src/interface/shared.yaml +++ b/src/interface/shared.yaml @@ -98,6 +98,15 @@ components: name: type: string description: Data model for the complex type Participant. + PatchConsentsByIdRequest: + title: PutConsentsByIdRequest + type: object + properties: + status: + type: string + revokedAt: + type: string + description: Data model for the complex type PatchConsentsByIdRequest. PostAuthorizationsRequest: title: PostAuthorizationsRequest type: object From 617b344cb5476c9064ebf2117503a8c1d9191d3e Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 14:48:19 +0530 Subject: [PATCH 040/114] fix: necessary casting --- src/server/handlers/firestore/consents.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 4434c3b2..aed8ceb0 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -39,6 +39,7 @@ import * as validator from './consents.validator' import { TCredentialScope, TAuthChannel, + TCredential, } from '@mojaloop/sdk-standard-components' async function handleNewConsent(_: Server, consent: Consent) { @@ -127,8 +128,8 @@ async function handleChallengeGeneration(server: Server, consent: Consent) { try { server.app.mojaloopClient.postGenerateChallengeForConsent( - consent.consentId, - consent.party!.partyIdInfo.fspId + consent.consentId as string, + consent.party!.partyIdInfo.fspId as string ) } catch (error) { logger.error(error) @@ -145,11 +146,12 @@ async function handleSignedChallenge(server: Server, consent: Consent) { consent.consentId as string, { requestId: consent.id, - initiatorId: consent.initiatorId, - scopes: consent.scopes, - credential: consent.credential, + initiatorId: consent.initiatorId as string, + participantId: consent.participantId as string, + scopes: consent.scopes as TCredentialScope[], + credential: consent.credential as TCredential, }, - consent.party!.partyIdInfo.fspId + consent.party!.partyIdInfo.fspId as string ) } catch (error) { logger.error(error) From 3e1d3347137a27660e302178f80d3a5498b67a42 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 14:48:34 +0530 Subject: [PATCH 041/114] fix: add checks to validator for fspId --- src/server/handlers/firestore/consents.validator.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/server/handlers/firestore/consents.validator.ts b/src/server/handlers/firestore/consents.validator.ts index 2984e24a..4b1c7c3e 100644 --- a/src/server/handlers/firestore/consents.validator.ts +++ b/src/server/handlers/firestore/consents.validator.ts @@ -55,6 +55,7 @@ export const isValidAuthentication = (consent: Consent): boolean => { consent.consentRequestId && consent.consentId && consent.party && + consent.party.partyIdInfo.fspId && consent.initiatorId && consent.authChannels && consent.authToken @@ -77,6 +78,7 @@ export const isValidConsentRequest = (consent: Consent): boolean => { consent.scopes && consent.initiatorId && consent.party && + consent.party.partyIdInfo.fspId && consent.authUri ) { return true @@ -92,7 +94,7 @@ export const isValidConsentRequest = (consent: Consent): boolean => { * on Firebase. */ export const isValidChallengeGeneration = (consent: Consent): boolean => { - if (consent.consentId && consent.party) { + if (consent.consentId && consent.party && consent.party.partyIdInfo.fspId) { return true } return false @@ -109,8 +111,10 @@ export const isValidSignedChallenge = (consent: Consent): boolean => { if ( consent.credential && consent.party && + consent.party.partyIdInfo.fspId && consent.scopes && - consent.initiatorId + consent.initiatorId && + consent.participantId ) { return true } From 9d3517f31786e94d64fad33e47f801586fd9ae39 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 14:49:01 +0530 Subject: [PATCH 042/114] fix: misc small merge conflict issues --- .../openapi/mojaloop/consents/{ID}.ts | 5 +++- src/shared/ml-thirdparty-client/index.ts | 4 +++- .../shared/ml-thirdparty-client/index.test.ts | 24 +++++++++++++------ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts index 4ad36782..8bd62a6c 100644 --- a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts @@ -47,6 +47,9 @@ export const patch: Handler = async ( ) => { logger.logRequest(context, request, h) // Updates consent fields patched - consentRepository.updateConsentById(request.params.id, context.request.body) + consentRepository.updateConsentById( + context.request.params.id as string, + context.request.body + ) return h.response().code(200) } diff --git a/src/shared/ml-thirdparty-client/index.ts b/src/shared/ml-thirdparty-client/index.ts index 9d450bc3..b90b4ea0 100644 --- a/src/shared/ml-thirdparty-client/index.ts +++ b/src/shared/ml-thirdparty-client/index.ts @@ -209,10 +209,12 @@ export class Client { * Performs a request to generate a challenge for FIDO registration * * @param _consentId identifier of consent as defined by Mojaloop API. + * @param destParticipantId ID of destination - to be used when sending request */ public async postGenerateChallengeForConsent( // eslint-disable-next-line @typescript-eslint/no-unused-vars - _consentId: string + _consentId: string, + _destParticipantId: string ): Promise { // TODO: Add once implemented in sdk-standard components // Placeholder below diff --git a/test/unit/shared/ml-thirdparty-client/index.test.ts b/test/unit/shared/ml-thirdparty-client/index.test.ts index 5fe52a54..077f87a7 100644 --- a/test/unit/shared/ml-thirdparty-client/index.test.ts +++ b/test/unit/shared/ml-thirdparty-client/index.test.ts @@ -181,7 +181,10 @@ describe('Mojaloop third-party client', () => { client.postTransactions(transactionRequestData, destParticipantId) // Assert - expect(postTransactionsSpy).toBeCalledWith(transactionRequestData, destParticipantId) + expect(postTransactionsSpy).toBeCalledWith( + transactionRequestData, + destParticipantId + ) }) it('Should throw Not Implemented error, attempting to perform transaction authorization request', (): void => { @@ -230,7 +233,10 @@ describe('Mojaloop third-party client', () => { client.postConsentRequests(postConsentRequestRequest, destParticipantId) // Assert - expect(postConsentRequestsSpy).toBeCalledWith(postConsentRequestRequest, destParticipantId) + expect(postConsentRequestsSpy).toBeCalledWith( + postConsentRequestRequest, + destParticipantId + ) }) it('Should perform a put request for authenticated consent', (): void => { @@ -256,7 +262,7 @@ describe('Mojaloop third-party client', () => { it('Should throw Not Implemented error, attempting to perform a request to generate a challenge for consent,', (): void => { expect( - client.postGenerateChallengeForConsent(consentId) + client.postGenerateChallengeForConsent(consentId, destParticipantId) ).rejects.toThrowError('Not Implemented Yet') // TODO: Use this test once implemented @@ -282,13 +288,17 @@ describe('Mojaloop third-party client', () => { client.putConsentId(consentId, putConsentRequest, destParticipantId) // Assert - expect(putConsentIdSpy).toBeCalledWith(consentId, putConsentRequest, destParticipantId) + expect(putConsentIdSpy).toBeCalledWith( + consentId, + putConsentRequest, + destParticipantId + ) }) it('Should throw Not Implemented error, attempting to perform a post request to revoke a given consent,', (): void => { - expect(client.postRevokeConsent(consentId)).rejects.toThrowError( - 'Not Implemented Yet' - ) + expect( + client.postRevokeConsent(consentId, destParticipantId) + ).rejects.toThrowError('Not Implemented Yet') // TODO: Use this test once implemented // // Arrange From 7a0136d17681f877005bab3d3927d070fd0822ed Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 15:04:45 +0530 Subject: [PATCH 043/114] fix: accessing from request instead of context --- src/server/handlers/openapi/mojaloop/participants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/handlers/openapi/mojaloop/participants.ts b/src/server/handlers/openapi/mojaloop/participants.ts index 8d37b072..2c046505 100644 --- a/src/server/handlers/openapi/mojaloop/participants.ts +++ b/src/server/handlers/openapi/mojaloop/participants.ts @@ -37,7 +37,7 @@ export const put: Handler = async ( ) => { logger.logRequest(context, request, h) // @ts-ignore - const participants = request.payload.participants + const participants = context.request.body.participants // Replace existing participants list with received list participantRepository.replace(participants) From 60542996246c05b49166ea952cc40e5cf421450c Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 15:05:01 +0530 Subject: [PATCH 044/114] test: Unit tests for PUT participants --- .../openapi/mojaloop/participants.test.ts | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 test/unit/server/handlers/openapi/mojaloop/participants.test.ts diff --git a/test/unit/server/handlers/openapi/mojaloop/participants.test.ts b/test/unit/server/handlers/openapi/mojaloop/participants.test.ts new file mode 100644 index 00000000..88dfc68a --- /dev/null +++ b/test/unit/server/handlers/openapi/mojaloop/participants.test.ts @@ -0,0 +1,98 @@ +/***** + License + -------------- + Copyright © 2020 Mojaloop Foundation + The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Mojaloop Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Mojaloop Foundation + - Name Surname + + * Google + - Abhimanyu Kapur + -------------- + ******/ + +import { ResponseToolkit, ResponseObject } from '@hapi/hapi' + +import { participantRepository } from '~/repositories/participants' +import { Context } from 'openapi-backend' + +import * as ParticipantHandlers from '~/server/handlers/openapi/mojaloop/participants' + +import config from '~/lib/config' +import { ParticipantFactory } from '~/shared/ml-thirdparty-simulator/factories/participant' + +// Mock the factories to consistently return the hardcoded values. +jest.mock('~/shared/ml-thirdparty-simulator/factories/participant') + +// Mock logger to prevent handlers from logging incoming request +jest.mock('~/shared/logger', () => ({ + logger: { + logRequest: jest.fn().mockImplementation(), + }, +})) + +// Mock firebase to prevent transaction repository from opening the connection. +jest.mock('~/lib/firebase') + +const mockRequest = jest.fn().mockImplementation() + +const mockResponseToolkit = ({ + response: (): ResponseObject => { + return ({ + code: (num: number): ResponseObject => { + return (num as unknown) as ResponseObject + }, + } as unknown) as ResponseObject + }, +} as unknown) as ResponseToolkit + +describe('/parties/{Type}/{ID}', () => { + beforeEach(() => { + jest.clearAllMocks() + jest.clearAllTimers() + }) + + describe('PUT operation', () => { + const requestBody = { participants: ParticipantFactory.getParticipants() } + + const context = ({ + request: { + headers: { + host: 'mojaloop.' + config.get('hostname'), + 'content-type': 'application/json', + 'content-length': JSON.stringify(requestBody).length, + }, + params: {}, + body: requestBody, + }, + } as unknown) as Context + + const participantRepositorySpy = jest + .spyOn(participantRepository, 'replace') + .mockImplementation() + + it('Should return 200 and update data in Firebase', async () => { + const response = await ParticipantHandlers.put( + context, + mockRequest, + mockResponseToolkit + ) + + expect(participantRepositorySpy).toBeCalledWith(requestBody.participants) + + expect(response).toBe(200) + }) + }) +}) From a08412475d4b5d4d81403141a97c06e0f9c2ec36 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 15:23:19 +0530 Subject: [PATCH 045/114] test: Unit Test for POST consents handler --- .../openapi/mojaloop/consents.test.ts | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 test/unit/server/handlers/openapi/mojaloop/consents.test.ts diff --git a/test/unit/server/handlers/openapi/mojaloop/consents.test.ts b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts new file mode 100644 index 00000000..fe4f09eb --- /dev/null +++ b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts @@ -0,0 +1,130 @@ +/***** + License + -------------- + Copyright © 2020 Mojaloop Foundation + The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Mojaloop Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Mojaloop Foundation + - Name Surname + + * Google + - Abhimanyu Kapur + -------------- + ******/ + +import { ResponseToolkit, ResponseObject } from '@hapi/hapi' + +import { consentRepository } from '~/repositories/consent' +import { Context } from 'openapi-backend' + +import * as ConsentHandlers from '~/server/handlers/openapi/mojaloop/consents' + +import config from '~/lib/config' +import { ConsentFactory } from '~/shared/ml-thirdparty-simulator/factories/consents' +import SDKStandardComponents from '@mojaloop/sdk-standard-components' +import { ConsentStatus } from '~/models/consent' + +// Mock the factories to consistently return the hardcoded values. +jest.mock('~/shared/ml-thirdparty-simulator/factories/consents') + +// Mock logger to prevent handlers from logging incoming request +jest.mock('~/shared/logger', () => ({ + logger: { + logRequest: jest.fn().mockImplementation(), + }, +})) + +// Mock firebase to prevent transaction repository from opening the connection. +jest.mock('~/lib/firebase') + +const mockRequest = jest.fn().mockImplementation() + +const mockResponseToolkit = ({ + response: (): ResponseObject => { + return ({ + code: (num: number): ResponseObject => { + return (num as unknown) as ResponseObject + }, + } as unknown) as ResponseObject + }, +} as unknown) as ResponseToolkit + +const consentRequestId = '111' + +const putConsentRequestRequest: SDKStandardComponents.PutConsentRequestsRequest = { + initiatorId: 'pispA', + authChannels: ['WEB', 'OTP'], + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + callbackUri: 'https://pisp.com', + authUri: 'https://dfspAuth.com', + authToken: 'secret-token', +} + +describe('/parties/{Type}/{ID}', () => { + beforeEach(() => { + jest.clearAllMocks() + jest.clearAllTimers() + }) + + describe('POST operation', () => { + const requestBody = ConsentFactory.createPostConsentRequest( + consentRequestId, + putConsentRequestRequest + ) + + const context = ({ + request: { + headers: { + host: 'mojaloop.' + config.get('hostname'), + 'content-type': 'application/json', + 'content-length': JSON.stringify(requestBody).length, + }, + params: {}, + body: requestBody, + }, + } as unknown) as Context + + const consentRepositorySpy = jest + .spyOn(consentRepository, 'updateConsentById') + .mockImplementation() + + it('Should return 200 and update data in Firebase', async () => { + const response = await ConsentHandlers.post( + context, + mockRequest, + mockResponseToolkit + ) + + const { id, initiatorId, participantId, scopes } = context.request.body + + expect(consentRepositorySpy).toBeCalledWith(id, { + initiatorId, + participantId, + scopes, + status: ConsentStatus.ACTIVE, + }) + + expect(response).toBe(202) + }) + }) +}) From 9b4fa2a38bac760d7da2762f7430f235c82895ab Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 15:30:50 +0530 Subject: [PATCH 046/114] test: Unit tests for PUT/PATCH consents/{ID} --- .../openapi/mojaloop/consents/{ID}.test.ts | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts diff --git a/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts b/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts new file mode 100644 index 00000000..c6604009 --- /dev/null +++ b/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts @@ -0,0 +1,130 @@ +/***** + License + -------------- + Copyright © 2020 Mojaloop Foundation + The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Mojaloop Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Mojaloop Foundation + - Name Surname + + * Google + - Abhimanyu Kapur + -------------- + ******/ + +import { ResponseToolkit, ResponseObject } from '@hapi/hapi' + +import { consentRepository } from '~/repositories/consent' +import { Context } from 'openapi-backend' + +import * as ConsentHandlers from '~/server/handlers/openapi/mojaloop/consents/{ID}' + +import config from '~/lib/config' +import { ConsentFactory } from '~/shared/ml-thirdparty-simulator/factories/consents' + +// Mock the factories to consistently return the hardcoded values. +jest.mock('~/shared/ml-thirdparty-simulator/factories/consents') + +// Mock logger to prevent handlers from logging incoming request +jest.mock('~/shared/logger', () => ({ + logger: { + logRequest: jest.fn().mockImplementation(), + }, +})) + +// Mock firebase to prevent transaction repository from opening the connection. +jest.mock('~/lib/firebase') + +const mockRequest = jest.fn().mockImplementation() + +const mockResponseToolkit = ({ + response: (): ResponseObject => { + return ({ + code: (num: number): ResponseObject => { + return (num as unknown) as ResponseObject + }, + } as unknown) as ResponseObject + }, +} as unknown) as ResponseToolkit + +describe('/consents/{ID}', () => { + beforeEach(() => { + jest.clearAllMocks() + jest.clearAllTimers() + }) + + describe('PUT operation', () => { + const requestBody = ConsentFactory.createPutConsentIdRequest() + + const context = ({ + request: { + headers: { + host: 'mojaloop.' + config.get('hostname'), + 'content-type': 'application/json', + 'content-length': JSON.stringify(requestBody).length, + }, + params: { id: '99' }, + body: requestBody, + }, + } as unknown) as Context + + const consentRepositorySpy = jest + .spyOn(consentRepository, 'updateConsentById') + .mockImplementation() + + it('Should return 200 and update data in Firebase', async () => { + const response = await ConsentHandlers.put( + context, + mockRequest, + mockResponseToolkit + ) + + expect(consentRepositorySpy).toBeCalledWith('99', requestBody) + + expect(response).toBe(200) + }) + }) + + describe('PATCH operation', () => { + const requestBody = ConsentFactory.createPatchConsentRevokeRequest() + + const context = ({ + request: { + headers: { + host: 'mojaloop.' + config.get('hostname'), + 'content-type': 'application/json', + 'content-length': JSON.stringify(requestBody).length, + }, + params: { id: '99' }, + body: requestBody, + }, + } as unknown) as Context + + const consentRepositorySpy = jest + .spyOn(consentRepository, 'updateConsentById') + .mockImplementation() + + it('Should return 200 and update data in Firebase', async () => { + const response = await ConsentHandlers.put( + context, + mockRequest, + mockResponseToolkit + ) + + expect(consentRepositorySpy).toBeCalledWith('99', requestBody) + + expect(response).toBe(200) + }) + }) +}) From 742b0573c330fc06ad2581c039283aeaebead027 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 15:31:04 +0530 Subject: [PATCH 047/114] fix: Necessary casting --- src/server/handlers/openapi/mojaloop/consents/{ID}.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts index 8bd62a6c..bbb887ef 100644 --- a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts @@ -36,7 +36,10 @@ export const put: Handler = async ( ) => { logger.logRequest(context, request, h) // Updates consent fields - consentRepository.updateConsentById(request.params.id, context.request.body) + consentRepository.updateConsentById( + context.request.params.id as string, + context.request.body + ) return h.response().code(200) } From de996597b45de8cf37ae0ea6ddd348d237a7e47f Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 15:31:23 +0530 Subject: [PATCH 048/114] fix: Correct test description --- test/unit/server/handlers/openapi/mojaloop/consents.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/server/handlers/openapi/mojaloop/consents.test.ts b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts index fe4f09eb..8db64208 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consents.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts @@ -80,7 +80,7 @@ const putConsentRequestRequest: SDKStandardComponents.PutConsentRequestsRequest authToken: 'secret-token', } -describe('/parties/{Type}/{ID}', () => { +describe('/consents', () => { beforeEach(() => { jest.clearAllMocks() jest.clearAllTimers() From 8e3bb4bd155f6bd55ad194aca8de26b65fedd34c Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 15:39:17 +0530 Subject: [PATCH 049/114] refactor: using variables instead of harcoding ID --- .../handlers/openapi/mojaloop/consents/{ID}.test.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts b/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts index c6604009..338e8f26 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts @@ -90,7 +90,10 @@ describe('/consents/{ID}', () => { mockResponseToolkit ) - expect(consentRepositorySpy).toBeCalledWith('99', requestBody) + expect(consentRepositorySpy).toBeCalledWith( + context.request.params.id, + requestBody + ) expect(response).toBe(200) }) @@ -122,7 +125,10 @@ describe('/consents/{ID}', () => { mockResponseToolkit ) - expect(consentRepositorySpy).toBeCalledWith('99', requestBody) + expect(consentRepositorySpy).toBeCalledWith( + context.request.params.id, + requestBody + ) expect(response).toBe(200) }) From 3442dc5496bdc06036087e613225781063efd28c Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 15:44:55 +0530 Subject: [PATCH 050/114] fix: Correct extraction of ID from request params --- src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts index c8b93004..a3b64ba9 100644 --- a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts @@ -37,7 +37,8 @@ export const put: Handler = async ( ) => { logger.logRequest(context, request, h) - const { id, authChannels, authUri } = context.request.body + const id = context.request.params.id as string + const { authChannels, authUri } = context.request.body consentRepository.updateConsentById(id, { authChannels, authUri, From 2d267afb196e845b8c738834b0a4fab6cbec2eea Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 15:45:50 +0530 Subject: [PATCH 051/114] test: Unit test for PUT consentRequests/{ID} handler --- .../mojaloop/consentRequests/{ID}.test.ts | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts diff --git a/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts b/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts new file mode 100644 index 00000000..ebd7dc74 --- /dev/null +++ b/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts @@ -0,0 +1,125 @@ +/***** + License + -------------- + Copyright © 2020 Mojaloop Foundation + The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Mojaloop Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Mojaloop Foundation + - Name Surname + + * Google + - Abhimanyu Kapur + -------------- + ******/ + +import { ResponseToolkit, ResponseObject } from '@hapi/hapi' + +import { consentRepository } from '~/repositories/consent' +import { Context } from 'openapi-backend' + +import * as ConsentHandlers from '~/server/handlers/openapi/mojaloop/consentRequests/{ID}' + +import config from '~/lib/config' +import { ConsentFactory } from '~/shared/ml-thirdparty-simulator/factories/consents' +import SDKStandardComponents from '@mojaloop/sdk-standard-components' +import { ConsentStatus } from '~/models/consent' + +// Mock the factories to consistently return the hardcoded values. +jest.mock('~/shared/ml-thirdparty-simulator/factories/consents') + +// Mock logger to prevent handlers from logging incoming request +jest.mock('~/shared/logger', () => ({ + logger: { + logRequest: jest.fn().mockImplementation(), + }, +})) + +// Mock firebase to prevent transaction repository from opening the connection. +jest.mock('~/lib/firebase') + +const mockRequest = jest.fn().mockImplementation() + +const mockResponseToolkit = ({ + response: (): ResponseObject => { + return ({ + code: (num: number): ResponseObject => { + return (num as unknown) as ResponseObject + }, + } as unknown) as ResponseObject + }, +} as unknown) as ResponseToolkit + +const postConsentRequestRequest: SDKStandardComponents.PostConsentRequestsRequest = { + id: '111', + initiatorId: 'pispA', + authChannels: ['WEB', 'OTP'], + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + callbackUri: 'https://pisp.com', +} + +describe('/consentRequests/{ID}', () => { + beforeEach(() => { + jest.clearAllMocks() + jest.clearAllTimers() + }) + + describe('PUT operation', () => { + const requestBody = ConsentFactory.createPutConsentRequestIdRequest( + postConsentRequestRequest + ) + + const context = ({ + request: { + headers: { + host: 'mojaloop.' + config.get('hostname'), + 'content-type': 'application/json', + 'content-length': JSON.stringify(requestBody).length, + }, + params: { id: '99' }, + body: requestBody, + }, + } as unknown) as Context + + const consentRepositorySpy = jest + .spyOn(consentRepository, 'updateConsentById') + .mockImplementation() + + it('Should return 200 and update data in Firebase', async () => { + const response = await ConsentHandlers.put( + context, + mockRequest, + mockResponseToolkit + ) + + const { authChannels, authUri } = requestBody + + expect(consentRepositorySpy).toBeCalledWith(context.request.params.id, { + authChannels, + authUri, + status: ConsentStatus.AUTHENTICATION_REQUIRED, + }) + + expect(response).toBe(200) + }) + }) +}) From c6db8885b660cdd86df841b0c1e0a0f71b722ac8 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 15:50:39 +0530 Subject: [PATCH 052/114] docs: adding comment justifying design decision --- src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts index dd142f8d..dbcd58ea 100644 --- a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts @@ -57,7 +57,8 @@ export const put: Handler = async ( // give a response to Mojaloop. if (partyIdType === 'OPAQUE') { - // Update Consents + // Update Consents as OPAQUE is the type during linking when we're fetching the accounts + // available for linking from a pre-determined DFSP consentRepository.updateConsent( // Conditions for the documents that need to be updated { From 4e383a97175d35475833ce4e3e032f34f8dcc8b2 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 16:49:48 +0530 Subject: [PATCH 053/114] feat: add callbackUri to config --- src/lib/config.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/config.ts b/src/lib/config.ts index c4572a2d..95fa2d24 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -108,6 +108,13 @@ const config = convict({ default: 'pisp', env: 'MOJALOOP_PARTICIPANT_ID', }, + // TODO: Replace placeholder + callbackUri: { + doc: 'The callback URI sent by PISP deeplinked with the app', + format: String, + default: 'PLACEHOLDER', + env: 'MOJALOOP_CALLBACK_URI', + }, endpoints: { default: { doc: 'Default endpoint to communicate with Mojaloop', From 5b901da11e44a9ae05663d09e8182bc290623174 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 2 Sep 2020 16:51:04 +0530 Subject: [PATCH 054/114] refactor: Replace callbackUri values with config callbackUri --- src/server/handlers/firestore/consents.ts | 5 +++-- .../handlers/openapi/mojaloop/consentRequests/{ID}.test.ts | 2 +- test/unit/server/handlers/openapi/mojaloop/consents.test.ts | 2 +- test/unit/shared/ml-thirdparty-client/index.test.ts | 2 +- test/unit/shared/ml-thirdparty-simulator/index.test.ts | 4 ++-- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index aed8ceb0..2f72c3db 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -41,6 +41,7 @@ import { TAuthChannel, TCredential, } from '@mojaloop/sdk-standard-components' +import config from '~/lib/config' async function handleNewConsent(_: Server, consent: Consent) { // Assign a consentRequestId to the document and set the initial @@ -82,7 +83,7 @@ async function handleAuthentication(server: Server, consent: Consent) { scopes: consent.scopes as TCredentialScope[], authUri: consent.authUri as string, // TODO: FIGURE OUT FROM WHERE TO GET THIS - callbackUri: '', + callbackUri: config.get('mojaloop').callbackUri, authToken: consent.authToken as string, }, consent.party!.partyIdInfo.fspId as string @@ -109,7 +110,7 @@ async function handleConsentRequest(server: Server, consent: Consent) { authChannels: consent.authChannels as TAuthChannel[], id: consent.id, // TODO: FIGURE OUT FROM WHERE TO GET - callbackUri: '', + callbackUri: config.get('mojaloop').callbackUri, }, consent.party!.partyIdInfo.fspId as string ) diff --git a/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts b/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts index ebd7dc74..c69d15b1 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts @@ -74,7 +74,7 @@ const postConsentRequestRequest: SDKStandardComponents.PostConsentRequestsReques actions: ['account.getAccess'], }, ], - callbackUri: 'https://pisp.com', + callbackUri: config.get('mojaloop').callbackUri, } describe('/consentRequests/{ID}', () => { diff --git a/test/unit/server/handlers/openapi/mojaloop/consents.test.ts b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts index 8db64208..968edb4a 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consents.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts @@ -75,7 +75,7 @@ const putConsentRequestRequest: SDKStandardComponents.PutConsentRequestsRequest actions: ['account.getAccess'], }, ], - callbackUri: 'https://pisp.com', + callbackUri: config.get('mojaloop').callbackUri, authUri: 'https://dfspAuth.com', authToken: 'secret-token', } diff --git a/test/unit/shared/ml-thirdparty-client/index.test.ts b/test/unit/shared/ml-thirdparty-client/index.test.ts index 077f87a7..af6a0c25 100644 --- a/test/unit/shared/ml-thirdparty-client/index.test.ts +++ b/test/unit/shared/ml-thirdparty-client/index.test.ts @@ -116,7 +116,7 @@ const putConsentRequestRequest: SDKStandardComponents.PutConsentRequestsRequest initiatorId: 'pispA', authChannels: ['WEB', 'OTP'], scopes, - callbackUri: 'https://pisp.com', + callbackUri: config.get('mojaloop').callbackUri, authUri: 'https://dfspAuth.com', authToken: 'secret-token', } diff --git a/test/unit/shared/ml-thirdparty-simulator/index.test.ts b/test/unit/shared/ml-thirdparty-simulator/index.test.ts index 207da8a5..bf280495 100644 --- a/test/unit/shared/ml-thirdparty-simulator/index.test.ts +++ b/test/unit/shared/ml-thirdparty-simulator/index.test.ts @@ -104,7 +104,7 @@ const postConsentRequestRequest: SDKStandardComponents.PostConsentRequestsReques initiatorId: 'pispA', authChannels: ['WEB', 'OTP'], scopes, - callbackUri: 'https://pisp.com', + callbackUri: config.get('mojaloop').callbackUri, } const putConsentRequestRequest: SDKStandardComponents.PutConsentRequestsRequest = { @@ -112,7 +112,7 @@ const putConsentRequestRequest: SDKStandardComponents.PutConsentRequestsRequest initiatorId: 'pispA', authChannels: ['WEB', 'OTP'], scopes, - callbackUri: 'https://pisp.com', + callbackUri: config.get('mojaloop').callbackUri, authUri: 'https://dfspAuth.com', authToken: 'secret-token', } From 7cd1b374301ff920463fdfdfc81c92f94ad5c492 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 7 Sep 2020 09:34:48 +0530 Subject: [PATCH 055/114] chore: bumped sdk-standard-components + central-services shared --- package-lock.json | 808 +++++++++++++++++++++++++++++++++++++++------- package.json | 3 +- 2 files changed, 689 insertions(+), 122 deletions(-) diff --git a/package-lock.json b/package-lock.json index 186bbed0..e925f307 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1285,7 +1285,6 @@ "version": "0.5.4", "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.4.tgz", "integrity": "sha512-HTM4QpI9B2XFkPz7pjwMyMgZchJ93TVkL3kWPW8GDMDKYxsMnmf4w2TNMJK7+KNiYHS5cJrCEAFlF+AwtXWVPA==", - "optional": true, "requires": { "lodash.camelcase": "^4.3.0", "protobufjs": "^6.8.6" @@ -1583,6 +1582,15 @@ "@hapi/hoek": "^9.0.0" } }, + "@hapi/validate": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-1.1.2.tgz", + "integrity": "sha512-ojg3iE/haKh8aCZFObkOzuJ1vQ8NP+EiuibliJKe01IMstBPXQc4Xl08+8zqAL+iZSZKp1TaWdwaNSzq8HIMKA==", + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0" + } + }, "@hapi/vise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@hapi/vise/-/vise-4.0.0.tgz", @@ -2493,6 +2501,29 @@ } } }, + "@mojaloop/central-services-error-handling": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-error-handling/-/central-services-error-handling-10.6.0.tgz", + "integrity": "sha512-93Jbz/CWNxMiA6/x+KmQezf7C/K3etIAwmXdeAjR9BBDM9xJt1nGfRDovXJZzqV5pTgh9ytGen7A3ub6oVqcQA==", + "requires": { + "@mojaloop/sdk-standard-components": "10.3.2", + "lodash": "4.17.19" + }, + "dependencies": { + "@mojaloop/sdk-standard-components": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-10.3.2.tgz", + "integrity": "sha512-O5DqUL+ncS718nFDFUMx8QO0pmTmg+/CNYuaXPrFfHDgf8c05mgSjg6Z8wt69Auwph6WXWaNjKTQRqZG2/BDdQ==", + "requires": { + "base64url": "3.0.1", + "fast-safe-stringify": "^2.0.7", + "ilp-packet": "2.2.0", + "jsonwebtoken": "8.5.1", + "jws": "4.0.0" + } + } + } + }, "@mojaloop/central-services-logger": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/@mojaloop/central-services-logger/-/central-services-logger-10.6.0.tgz", @@ -2503,10 +2534,125 @@ "winston": "3.3.3" } }, + "@mojaloop/central-services-metrics": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-metrics/-/central-services-metrics-9.5.0.tgz", + "integrity": "sha512-4wba5JCNhmevBEHAPl+BmMqTmfT/7lOxbuRlziyAFhcySrZpCQhINMwyGm1CmNlldsDtp8rHaL5inQzKAGsBXA==", + "requires": { + "prom-client": "11.5.3" + } + }, + "@mojaloop/central-services-shared": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-shared/-/central-services-shared-11.3.2.tgz", + "integrity": "sha512-2ZAZsYpZgp50O9h6cqtUjC3ozIjFDqjCmduyUaxk9BjfInTBTG+8SMZNrzhWKVGm2wgDmTpSpvo778g3GPyGdQ==", + "requires": { + "@hapi/catbox": "11.1.1", + "@hapi/catbox-memory": "5.0.0", + "@mojaloop/central-services-error-handling": "10.6.0", + "@mojaloop/central-services-logger": "10.6.0", + "@mojaloop/central-services-metrics": "9.5.0", + "@mojaloop/event-sdk": "10.6.0", + "ajv": "6.12.4", + "ajv-keywords": "3.5.2", + "axios": "0.20.0", + "base64url": "3.0.1", + "clone": "2.1.2", + "data-urls": "2.0.0", + "dotenv": "8.2.0", + "env-var": "6.3.0", + "immutable": "3.8.2", + "lodash": "4.17.20", + "mustache": "4.0.1", + "openapi-backend": "3.5.2", + "raw-body": "2.4.1", + "uuid4": "2.0.2" + }, + "dependencies": { + "@hapi/catbox": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@hapi/catbox/-/catbox-11.1.1.tgz", + "integrity": "sha512-u/8HvB7dD/6X8hsZIpskSDo4yMKpHxFd7NluoylhGrL6cUfYxdQPnvUp9YU2C6F9hsyBVLGulBd9vBN1ebfXOQ==", + "requires": { + "@hapi/boom": "9.x.x", + "@hapi/hoek": "9.x.x", + "@hapi/podium": "4.x.x", + "@hapi/validate": "1.x.x" + } + }, + "ajv": { + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "openapi-backend": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/openapi-backend/-/openapi-backend-3.5.2.tgz", + "integrity": "sha512-B6VptLEvyDstDd2bY+7/Lk6IK1syEzHMyAZG7U4A+UiGLD+/NN39axVhFD+8ulBjo037AcrZ3OeQzoMV+nigPQ==", + "requires": { + "ajv": "^6.10.0", + "bath-es5": "^3.0.3", + "cookie": "^0.4.0", + "lodash": "^4.17.15", + "mock-json-schema": "^1.0.7", + "openapi-schema-validation": "^0.4.2", + "openapi-types": "^1.3.4", + "qs": "^6.9.3", + "swagger-parser": "^9.0.1" + } + }, + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" + } + } + }, + "@mojaloop/event-sdk": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/@mojaloop/event-sdk/-/event-sdk-10.6.0.tgz", + "integrity": "sha512-mDVow/3WDILDUF2v32fqcOZAoRQCOZX8D2fJF3kHvZLGthU9ydNPHK118aVibw76XAyq6E6UbxHMXg3ZUPBlhg==", + "requires": { + "@grpc/proto-loader": "0.5.4", + "@mojaloop/central-services-logger": "10.6.0", + "brototype": "0.0.6", + "error-callsites": "2.0.3", + "grpc": "1.24.3", + "lodash": "4.17.19", + "moment": "2.27.0", + "parse-strings-in-object": "2.0.0", + "protobufjs": "6.9.0", + "rc": "1.2.8", + "serialize-error": "4.1.0", + "sinon": "9.0.2", + "traceparent": "1.0.0", + "tslib": "2.0.0", + "uuid4": "2.0.2", + "winston": "3.3.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.0.tgz", + "integrity": "sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==" + } + } + }, "@mojaloop/sdk-standard-components": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.3.1.tgz", - "integrity": "sha512-1Tbkm9fAAKcz60PONbB5jQh+IVPxd0Z7Qh6ISKDs53t+8rW0wr3hs0f6fcbOBOmsxYolTAwmxiouooay4fmDyg==", + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.5.0.tgz", + "integrity": "sha512-xmui3sf0Bo8V59vNqCm+aj+K8ZUMgRyyiTNrFHJqTZCRQRv+zSF2pU2Q/7VwRYA/OhU4ngETdzV9/M6Y7IGAKQ==", "requires": { "base64url": "3.0.1", "fast-safe-stringify": "^2.0.7", @@ -2614,32 +2760,27 @@ "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", - "optional": true + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" }, "@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "optional": true + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" }, "@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "optional": true + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" }, "@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", - "optional": true + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" }, "@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "optional": true, "requires": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -2648,32 +2789,27 @@ "@protobufjs/float": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", - "optional": true + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" }, "@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", - "optional": true + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" }, "@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", - "optional": true + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" }, "@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", - "optional": true + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" }, "@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", - "optional": true + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" }, "@sindresorhus/is": { "version": "0.14.0", @@ -2685,7 +2821,6 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz", "integrity": "sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==", - "dev": true, "requires": { "type-detect": "4.0.8" } @@ -2694,11 +2829,34 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" } }, + "@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.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.1.0.tgz", + "integrity": "sha512-42nyaQOVunX5Pm6GRJobmzbS7iLI+fhERITnETXzzwDZh+TtDr/Au3yAvXVjFmZ4wEUaE4Y3NFZfKv0bV0cbtg==", + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" + }, "@szmarczak/http-timer": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", @@ -2760,6 +2918,15 @@ "integrity": "sha512-PH7bfkt1nu4pnlxz+Ws+wwJJF1HE12W3ia+Iace2JT7q56DLH3hbyjOJyNHJYRxk3PkKaC36fHfHKyeG1rMgCA==", "dev": true }, + "@types/bytebuffer": { + "version": "5.0.41", + "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.41.tgz", + "integrity": "sha512-Mdrv4YcaHvpkx25ksqqFaezktx3yZRcd51GZY0rY/9avyaqZdiT/GiWRhfrJhMpgzXqTOSHgGvsumGxJFNiZZA==", + "requires": { + "@types/long": "*", + "@types/node": "*" + } + }, "@types/catbox": { "version": "10.0.6", "resolved": "https://registry.npmjs.org/@types/catbox/-/catbox-10.0.6.tgz", @@ -2963,8 +3130,7 @@ "@types/long": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==", - "optional": true + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, "@types/mime-db": { "version": "1.43.0", @@ -3186,14 +3352,12 @@ "abab": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", - "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", - "dev": true + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==" }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "abort-controller": { "version": "3.0.0", @@ -3299,6 +3463,11 @@ "uri-js": "^4.2.2" } }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" + }, "ansi-align": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", @@ -3359,8 +3528,7 @@ "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "ansi-styles": { "version": "3.2.1", @@ -3384,14 +3552,12 @@ "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "are-we-there-yet": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "dev": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -3491,6 +3657,15 @@ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", "dev": true }, + "ascli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz", + "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=", + "requires": { + "colour": "~0.7.1", + "optjs": "~3.2.2" + } + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -3586,6 +3761,14 @@ "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==", "dev": true }, + "axios": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", + "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, "babel-jest": { "version": "26.1.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.1.0.tgz", @@ -3723,8 +3906,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base": { "version": "0.11.2", @@ -3822,6 +4004,11 @@ "file-uri-to-path": "1.0.0" } }, + "bintrees": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", + "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" + }, "boxen": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", @@ -3894,7 +4081,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3909,6 +4095,11 @@ "fill-range": "^7.0.1" } }, + "brototype": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/brototype/-/brototype-0.0.6.tgz", + "integrity": "sha1-mz8HNkeDOXuPHEvuehQZk1ZuS0Q=" + }, "browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", @@ -3966,6 +4157,26 @@ "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", "dev": true }, + "bytebuffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", + "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", + "requires": { + "long": "~3" + }, + "dependencies": { + "long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" + } + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, "cacache": { "version": "15.0.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.4.tgz", @@ -4281,6 +4492,11 @@ } } }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + }, "clone-response": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", @@ -4299,8 +4515,7 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "collect-v8-coverage": { "version": "1.0.1", @@ -4364,6 +4579,11 @@ "text-hex": "1.0.x" } }, + "colour": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz", + "integrity": "sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=" + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -4430,8 +4650,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", @@ -4461,8 +4680,7 @@ "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "contains-path": { "version": "0.1.0", @@ -5125,7 +5343,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, "requires": { "abab": "^2.0.3", "whatwg-mimetype": "^2.3.0", @@ -5148,7 +5365,6 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -5326,14 +5542,12 @@ "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, "detect-indent": { "version": "6.0.0", @@ -5341,6 +5555,11 @@ "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", "dev": true }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -5368,8 +5587,7 @@ "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" }, "diff-sequences": { "version": "25.2.6", @@ -5566,12 +5784,22 @@ "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==", "dev": true }, + "env-var": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/env-var/-/env-var-6.3.0.tgz", + "integrity": "sha512-gaNzDZuVaJQJlP2SigAZLu/FieZN5MzdN7lgHNehESwlRanHwGQ/WUtJ7q//dhrj3aGBZM45yEaKOuvSJaf4mA==" + }, "err-code": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", "dev": true }, + "error-callsites": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/error-callsites/-/error-callsites-2.0.3.tgz", + "integrity": "sha512-v036z4IEffZFE5kBkV5/F2MzhLnG0vuDyN+VXpzCf4yWXvX/1WJCI0A+TGTr8HWzBfCw5k8gr9rwAo09V+obTA==" + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -6501,6 +6729,11 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, + "follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -6577,8 +6810,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "2.1.3", @@ -6601,7 +6833,6 @@ "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -6616,14 +6847,12 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6632,7 +6861,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6643,7 +6871,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7304,7 +7531,6 @@ "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -7457,6 +7683,106 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "dev": true }, + "grpc": { + "version": "1.24.3", + "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.24.3.tgz", + "integrity": "sha512-EDemzuZTfhM0hgrXqC4PtR76O3t+hTIYJYR5vgiW0yt2WJqo4mhxUqZUirzUQz34Psz7dbLp38C6Cl7Ij2vXRQ==", + "requires": { + "@types/bytebuffer": "^5.0.40", + "lodash.camelcase": "^4.3.0", + "lodash.clone": "^4.5.0", + "nan": "^2.13.2", + "node-pre-gyp": "^0.15.0", + "protobufjs": "^5.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "protobufjs": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.3.tgz", + "integrity": "sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA==", + "requires": { + "ascli": "~1", + "bytebuffer": "~5", + "glob": "^7.0.5", + "yargs": "^3.10.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "requires": { + "camelcase": "^2.0.1", + "cliui": "^3.0.3", + "decamelize": "^1.1.1", + "os-locale": "^1.4.0", + "string-width": "^1.0.1", + "window-size": "^0.1.4", + "y18n": "^3.2.0" + } + } + } + }, "gtoken": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.4.tgz", @@ -7551,8 +7877,7 @@ "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, "has-value": { "version": "1.0.0", @@ -7660,6 +7985,18 @@ "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", "dev": true }, + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, "http-parser-js": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz", @@ -7862,7 +8199,6 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -7877,7 +8213,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", - "dev": true, "requires": { "minimatch": "^3.0.4" } @@ -7905,6 +8240,11 @@ } } }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" + }, "import-fresh": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", @@ -8012,7 +8352,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -8131,6 +8470,11 @@ "loose-envify": "^1.0.0" } }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -12496,6 +12840,11 @@ "verror": "1.10.0" } }, + "just-extend": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", + "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==" + }, "jwa": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", @@ -12550,6 +12899,14 @@ "package-json": "^6.3.0" } }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "^1.0.0" + } + }, "left-pad": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", @@ -12910,8 +13267,12 @@ "lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", - "optional": true + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "lodash.clone": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", + "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=" }, "lodash.clonedeep": { "version": "4.5.0", @@ -12984,8 +13345,7 @@ "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" }, "lodash.template": { "version": "4.5.0", @@ -13145,8 +13505,7 @@ "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", - "optional": true + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "loose-envify": { "version": "1.4.0", @@ -13461,7 +13820,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -13588,7 +13946,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "dev": true, "requires": { "minipass": "^2.9.0" }, @@ -13597,7 +13954,6 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "dev": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -13630,7 +13986,6 @@ "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, "requires": { "minimist": "^1.2.5" } @@ -13650,11 +14005,21 @@ "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", "dev": true }, + "moment": { + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", + "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "mustache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.0.1.tgz", + "integrity": "sha512-yL5VE97+OXn4+Er3THSmTdCFCtx5hHWzrolvH+JObZnUYwuaG7XV+Ch4fR2cIrcYI0tFHxS7iyFYl14bW8y2sA==" + }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -13664,9 +14029,7 @@ "nan": { "version": "2.14.1", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", - "dev": true, - "optional": true + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" }, "nanomatch": { "version": "1.2.13", @@ -13699,6 +14062,16 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "needle": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.2.tgz", + "integrity": "sha512-LbRIwS9BfkPvNwNHlsA41Q29kL2L/6VaOJ0qisM5lLWsTV3nP15abO5ITL6L81zqFhzjRKDAYjpcBcwM0AVvLQ==", + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, "neo-async": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", @@ -13717,6 +14090,18 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "nise": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", + "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", + "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" + } + }, "node-alias": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/node-alias/-/node-alias-1.0.4.tgz", @@ -13900,11 +14285,75 @@ } } }, + "node-pre-gyp": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz", + "integrity": "sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.3", + "needle": "^2.5.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + }, + "dependencies": { + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "requires": { + "minipass": "^2.6.0" + } + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + } + } + }, "nopt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "dev": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" @@ -13966,7 +14415,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", - "dev": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } @@ -14132,8 +14580,7 @@ "npm-normalize-package-bin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" }, "npm-package-arg": { "version": "8.0.1", @@ -14241,7 +14688,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -14258,8 +14704,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nwsapi": { "version": "2.2.0", @@ -14276,8 +14721,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-copy": { "version": "0.1.0", @@ -14468,23 +14912,33 @@ "word-wrap": "~1.2.3" } }, + "optjs": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz", + "integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4=" + }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "^1.0.0" + } }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "osenv": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -14661,8 +15115,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-key": { "version": "2.0.1", @@ -14686,6 +15139,21 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", @@ -14850,6 +15318,14 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "prom-client": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-11.5.3.tgz", + "integrity": "sha512-iz22FmTbtkyL2vt0MdDFY+kWof+S9UB/NACxSn2aJcewtw+EERsen0urSkZ2WrHseNdydsvcxCTAnPcSMZZv4Q==", + "requires": { + "tdigest": "^0.1.1" + } + }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -14880,7 +15356,6 @@ "version": "6.9.0", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.9.0.tgz", "integrity": "sha512-LlGVfEWDXoI/STstRDdZZKb/qusoAWUnmLg9R8OLSO473mBLWHowx8clbX5/+mKDEI+v7GzjoK9tRPZMMcoTrg==", - "optional": true, "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -14900,8 +15375,7 @@ "@types/node": { "version": "13.13.13", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.13.tgz", - "integrity": "sha512-UfvBE9oRCAJVzfR+3eWm/sdLFe/qroAPEXP3GPJ1SehQiEVgZT6NQZWYbPMiJ3UdcKM06v4j+S1lTcdWCmw+3g==", - "optional": true + "integrity": "sha512-UfvBE9oRCAJVzfR+3eWm/sdLFe/qroAPEXP3GPJ1SehQiEVgZT6NQZWYbPMiJ3UdcKM06v4j+S1lTcdWCmw+3g==" } } }, @@ -14988,6 +15462,22 @@ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, + "random-poly-fill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/random-poly-fill/-/random-poly-fill-1.0.1.tgz", + "integrity": "sha512-bMOL0hLfrNs52+EHtIPIXxn2PxYwXb0qjnKruTjXiM/sKfYqj506aB2plFwWW1HN+ri724bAVVGparh4AtlJKw==" + }, + "raw-body": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", + "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.3", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -15438,7 +15928,6 @@ "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, "requires": { "glob": "^7.1.3" } @@ -15481,8 +15970,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sane": { "version": "4.1.0", @@ -15628,8 +16116,7 @@ "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "saxes": { "version": "5.0.1", @@ -15643,8 +16130,7 @@ "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" }, "semver-compare": { "version": "1.0.0", @@ -15681,11 +16167,25 @@ "integrity": "sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA==", "dev": true }, + "serialize-error": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-4.1.0.tgz", + "integrity": "sha512-5j9GgyGsP9vV9Uj1S0lDCvlsd+gc2LEPVK7HHHte7IyPwOD4lVQFeaX143gx3U5AnoCi+wbcb3mvaxVysjpxEw==", + "requires": { + "type-fest": "^0.3.0" + }, + "dependencies": { + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==" + } + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "set-value": { "version": "2.0.1", @@ -15710,6 +16210,11 @@ } } }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -15772,6 +16277,35 @@ } } }, + "sinon": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.2.tgz", + "integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==", + "requires": { + "@sinonjs/commons": "^1.7.2", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.0.3", + "diff": "^4.0.2", + "nise": "^4.0.1", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -16272,6 +16806,11 @@ } } }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", @@ -16687,6 +17226,14 @@ } } }, + "tdigest": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", + "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", + "requires": { + "bintrees": "1.0.1" + } + }, "teeny-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-6.0.3.tgz", @@ -16850,6 +17397,11 @@ "is-number": "^7.0.0" } }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, "tough-cookie": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", @@ -16865,11 +17417,18 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", - "dev": true, "requires": { "punycode": "^2.1.1" } }, + "traceparent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/traceparent/-/traceparent-1.0.0.tgz", + "integrity": "sha512-b/hAbgx57pANQ6cg2eBguY3oxD6FGVLI1CC2qoi01RmHR7AYpQHPXTig9FkzbWohEsVuHENZHP09aXuw3/LM+w==", + "requires": { + "random-poly-fill": "^1.0.1" + } + }, "trim-newlines": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", @@ -16996,8 +17555,7 @@ "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" }, "type-fest": { "version": "0.8.1", @@ -17087,6 +17645,11 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -17251,6 +17814,11 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz", "integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==" }, + "uuid4": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uuid4/-/uuid4-2.0.2.tgz", + "integrity": "sha512-TzsQS8sN1B2m9WojyNp0X/3JL8J2RScnrAJnooNPL6lq3lA02/XdoWysyUgI6rAif0DzkkWk51N6OggujPy2RA==" + }, "v8-compile-cache": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", @@ -17377,14 +17945,12 @@ "whatwg-mimetype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" }, "whatwg-url": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.1.0.tgz", "integrity": "sha512-vEIkwNi9Hqt4TV9RdnaBPNt+E2Sgmo3gePebCRgZ1R7g6d23+53zCTnuB0amKI4AXq6VM8jj2DUAa0S1vjJxkw==", - "dev": true, "requires": { "lodash.sortby": "^4.7.0", "tr46": "^2.0.2", @@ -17394,8 +17960,7 @@ "webidl-conversions": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==" } } }, @@ -17463,7 +18028,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, "requires": { "string-width": "^1.0.2 || 2" }, @@ -17471,14 +18035,12 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -17488,7 +18050,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, "requires": { "ansi-regex": "^3.0.0" } @@ -17504,6 +18065,11 @@ "string-width": "^4.0.0" } }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" + }, "winston": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", diff --git a/package.json b/package.json index a14fb9e9..5aecc9b4 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,8 @@ "@hapi/inert": "^6.0.1", "@hapi/vision": "^6.0.0", "@mojaloop/central-services-logger": "^10.6.0", - "@mojaloop/sdk-standard-components": "^11.3.1", + "@mojaloop/central-services-shared": "^11.3.2", + "@mojaloop/sdk-standard-components": "^11.5.0", "@types/uuid": "^8.0.0", "convict": "^6.0.0", "dotenv": "^8.2.0", From 2362262d315242033337f5bf7a3daa17d3afa0fe Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 7 Sep 2020 09:40:33 +0530 Subject: [PATCH 056/114] fix: Correct capitalization in context.request.params.ID --- src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts | 2 +- src/server/handlers/openapi/mojaloop/consents/{ID}.ts | 4 ++-- .../handlers/openapi/mojaloop/consentRequests/{ID}.test.ts | 2 +- .../server/handlers/openapi/mojaloop/consents/{ID}.test.ts | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts index a3b64ba9..a2c154ca 100644 --- a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts @@ -37,7 +37,7 @@ export const put: Handler = async ( ) => { logger.logRequest(context, request, h) - const id = context.request.params.id as string + const id = context.request.params.ID as string const { authChannels, authUri } = context.request.body consentRepository.updateConsentById(id, { authChannels, diff --git a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts index bbb887ef..ef5300b1 100644 --- a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts @@ -37,7 +37,7 @@ export const put: Handler = async ( logger.logRequest(context, request, h) // Updates consent fields consentRepository.updateConsentById( - context.request.params.id as string, + context.request.params.ID as string, context.request.body ) return h.response().code(200) @@ -51,7 +51,7 @@ export const patch: Handler = async ( logger.logRequest(context, request, h) // Updates consent fields patched consentRepository.updateConsentById( - context.request.params.id as string, + context.request.params.ID as string, context.request.body ) return h.response().code(200) diff --git a/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts b/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts index c69d15b1..9a7476ed 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts @@ -113,7 +113,7 @@ describe('/consentRequests/{ID}', () => { const { authChannels, authUri } = requestBody - expect(consentRepositorySpy).toBeCalledWith(context.request.params.id, { + expect(consentRepositorySpy).toBeCalledWith(context.request.params.ID, { authChannels, authUri, status: ConsentStatus.AUTHENTICATION_REQUIRED, diff --git a/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts b/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts index 338e8f26..c1b7beb5 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts @@ -91,7 +91,7 @@ describe('/consents/{ID}', () => { ) expect(consentRepositorySpy).toBeCalledWith( - context.request.params.id, + context.request.params.ID, requestBody ) @@ -126,7 +126,7 @@ describe('/consents/{ID}', () => { ) expect(consentRepositorySpy).toBeCalledWith( - context.request.params.id, + context.request.params.ID, requestBody ) From e0e837e5cd9bcaffac1b7b522dbea64484ffeb5e Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 7 Sep 2020 09:47:07 +0530 Subject: [PATCH 057/114] fix: Correct types used in participant repository --- src/repositories/participants.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/repositories/participants.ts b/src/repositories/participants.ts index df4356a5..ecfbaeb4 100644 --- a/src/repositories/participants.ts +++ b/src/repositories/participants.ts @@ -28,6 +28,7 @@ import firebase from '~/lib/firebase' import { logger } from '~/shared/logger' +import { Participant } from '~/shared/ml-thirdparty-client/models/core' export interface IParticipantRepository { /** @@ -35,12 +36,12 @@ export interface IParticipantRepository { * * @param data Documents that are about to be added. */ - replace(data: Record): Promise + replace(data: Participant[]): Promise } export class FirebaseParticipantRepository implements IParticipantRepository { // TODO: Confirm data Type - async replace(data: Record): Promise { + async replace(data: Participant[]): Promise { const collectionRef: FirebaseFirestore.CollectionReference = firebase .firestore() .collection('participants') From b07ee42a9e29533adad7841cc14683c8bfcf5a87 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 7 Sep 2020 11:14:04 +0530 Subject: [PATCH 058/114] fix: Use correct types within Participant repository methods --- src/repositories/participants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/repositories/participants.ts b/src/repositories/participants.ts index ecfbaeb4..88c31364 100644 --- a/src/repositories/participants.ts +++ b/src/repositories/participants.ts @@ -65,7 +65,7 @@ export class FirebaseParticipantRepository implements IParticipantRepository { }) } // Iterate through received participants list and add them to the processing batch. - data.array.forEach((participant: any) => { + data.forEach((participant: Participant) => { batch.set(collectionRef.doc(), participant) }) From 5b145d9afc9f64402aff33dd979f6b2a05e78e72 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 7 Sep 2020 11:39:07 +0530 Subject: [PATCH 059/114] feat: Add OPAQUE to PartyIdType enum --- src/shared/ml-thirdparty-client/models/core/parties.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/shared/ml-thirdparty-client/models/core/parties.ts b/src/shared/ml-thirdparty-client/models/core/parties.ts index c68ecd98..bf9be42e 100644 --- a/src/shared/ml-thirdparty-client/models/core/parties.ts +++ b/src/shared/ml-thirdparty-client/models/core/parties.ts @@ -23,7 +23,7 @@ -------------- ******/ -import { Currency } from './transactions'; +import { Currency } from './transactions' /** * Data model for the complex type Account. @@ -91,6 +91,13 @@ export interface PartyComplexName { * The allowed values for the enumeration of party identifier type. */ export enum PartyIdType { + // TODO: Confirm other possible uses for OPAQUE and + // fill out docstring + /** + * Type for Consent Requests + */ + OPAQUE = 'OPAQUE', + /** * An MSISDN (Mobile Station International Subscriber Directory Number, * that is, the phone number) is used as reference to a participant. From 3bdb3d4f9b94c27be767ec658a02ee0390b8703a Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 7 Sep 2020 11:39:36 +0530 Subject: [PATCH 060/114] style: remove unneeded TODO comment --- src/server/handlers/firestore/consents.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 2f72c3db..6ddf5f34 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -82,7 +82,6 @@ async function handleAuthentication(server: Server, consent: Consent) { authChannels: consent.authChannels as TAuthChannel[], scopes: consent.scopes as TCredentialScope[], authUri: consent.authUri as string, - // TODO: FIGURE OUT FROM WHERE TO GET THIS callbackUri: config.get('mojaloop').callbackUri, authToken: consent.authToken as string, }, @@ -109,7 +108,6 @@ async function handleConsentRequest(server: Server, consent: Consent) { scopes: consent.scopes as TCredentialScope[], authChannels: consent.authChannels as TAuthChannel[], id: consent.id, - // TODO: FIGURE OUT FROM WHERE TO GET callbackUri: config.get('mojaloop').callbackUri, }, consent.party!.partyIdInfo.fspId as string From c56f7a1d6af1a228bed8fb9e220915ac5f42d476 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 7 Sep 2020 11:40:21 +0530 Subject: [PATCH 061/114] refactor: Add needed imports + switch to using enum over strings --- src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts | 3 ++- test/unit/shared/ml-thirdparty-client/index.test.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts index dbcd58ea..db999102 100644 --- a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts @@ -33,6 +33,7 @@ import { Status } from '~/models/transaction' import { transactionRepository } from '~/repositories/transaction' import { consentRepository } from '~/repositories/consent' import { ConsentStatus } from '~/models/consent' +import { PartyIdType } from '~/shared/ml-thirdparty-client/models/core' /** * Handles callback from Mojaloop that specifies detailed info about a requested party. @@ -56,7 +57,7 @@ export const put: Handler = async ( // function is expected to run asynchronously, so the server could quickly // give a response to Mojaloop. - if (partyIdType === 'OPAQUE') { + if (partyIdType === PartyIdType.OPAQUE) { // Update Consents as OPAQUE is the type during linking when we're fetching the accounts // available for linking from a pre-determined DFSP consentRepository.updateConsent( diff --git a/test/unit/shared/ml-thirdparty-client/index.test.ts b/test/unit/shared/ml-thirdparty-client/index.test.ts index af6a0c25..f8263943 100644 --- a/test/unit/shared/ml-thirdparty-client/index.test.ts +++ b/test/unit/shared/ml-thirdparty-client/index.test.ts @@ -39,6 +39,7 @@ import { ThirdPartyTransactionRequest, } from '~/shared/ml-thirdparty-client/models/openapi' import SDKStandardComponents from '@mojaloop/sdk-standard-components' +import config from '~/lib/config' const transactionRequestData: ThirdPartyTransactionRequest = { transactionRequestId: '888', From d86d39f63241b5d15c06b8f830a62578b39abc74 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 7 Sep 2020 11:41:37 +0530 Subject: [PATCH 062/114] test: Add unit tests for consents firestore handlers --- .../handlers/firestore/consents.test.ts | 326 ++++++++++++++++++ 1 file changed, 326 insertions(+) create mode 100644 test/unit/server/handlers/firestore/consents.test.ts diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts new file mode 100644 index 00000000..b30da120 --- /dev/null +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -0,0 +1,326 @@ +/***** + License + -------------- + Copyright © 2020 Mojaloop Foundation + The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Mojaloop Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Mojaloop Foundation + - Name Surname + + * Google + - Steven Wijaya + -------------- + ******/ + +import { Server } from '@hapi/hapi' + +import config from '~/lib/config' + +import createServer from '~/server/create' +import * as consentsHandler from '~/server/handlers/firestore/consents' + +import { consentRepository } from '~/repositories/consent' +import * as Validator from '~/server/handlers/firestore/consents.validator' +import { Consent, ConsentStatus } from '~/models/consent' +import { + PartyIdType, + Currency, +} from '~/shared/ml-thirdparty-client/models/core' +import SDKStandardComponents, { + TAuthChannel, + TCredentialScope, +} from '@mojaloop/sdk-standard-components' + +// Mock firebase to prevent server from listening to the changes. +jest.mock('~/lib/firebase') + +// Mock uuid to consistently return the provided value. +jest.mock('uuid', () => ({ + v4: jest.fn().mockImplementation(() => '12345'), +})) + +// Mock utils to consistently return the provided value. +jest.mock('~/lib/utils', () => ({ + getTomorrowsDate: jest.fn().mockImplementation(() => { + return new Date(100) + }), +})) + +const documentId = '111' + +describe('Handlers for consent documents in Firebase', () => { + let server: Server + + beforeAll(async () => { + server = await createServer(config) + }) + + beforeEach(() => { + jest.clearAllMocks() + }) + + afterEach(() => { + jest.clearAllTimers() + }) + + it('Should set status and consentRequestId for new consent', () => { + const consentRepositorySpy = jest.spyOn( + consentRepository, + 'updateConsentById' + ) + + consentsHandler.onCreate(server, { + id: '111', + userId: 'bob123', + party: { + partyIdInfo: { + partyIdType: PartyIdType.OPAQUE, + partyIdentifier: 'bob1234', + fspId: 'fspb', + }, + }, + }) + + expect(consentRepositorySpy).toBeCalledWith('111', { + consentRequestId: '12345', + status: ConsentStatus.PENDING_PARTY_LOOKUP, + }) + }) + + it('Should perform party lookup when all necessary fields are set', async () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'getParties') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidPartyLookup') + .mockReturnValue(true) + + const consentPartyLookup: Consent = { + id: documentId, + userId: 'bob123', + party: { + partyIdInfo: { + partyIdType: PartyIdType.OPAQUE, + partyIdentifier: 'bob1234', + }, + }, + consentRequestId: '12345', + status: ConsentStatus.PENDING_PARTY_LOOKUP, + } + + await consentsHandler.onUpdate(server, consentPartyLookup) + + expect(validatorSpy).toBeCalledWith(consentPartyLookup) + expect(mojaloopClientSpy).toBeCalledWith(PartyIdType.OPAQUE, 'bob1234') + }) + + it('Should initiate consent request request when all necessary fields are set', async () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postConsentRequests') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidConsentRequest') + .mockReturnValue(true) + + // Mock consent data that would be given by Firebase + const consentConsentRequest: Consent = { + id: documentId, + userId: 'bob123', + party: { + partyIdInfo: { + partyIdType: PartyIdType.OPAQUE, + partyIdentifier: 'bob1234', + fspId: 'fspb', + }, + }, + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + consentRequestId: '12345', + authChannels: ['WEB'], + accounts: [ + { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, + { id: 'bob.bbbbb.fspb', currency: Currency.USD }, + ], + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + } + + // Mock the expected transaction request being sent. + const consentRequest: SDKStandardComponents.PostConsentRequestsRequest = { + initiatorId: consentConsentRequest.initiatorId as string, + id: consentConsentRequest.id, + scopes: consentConsentRequest.scopes as TCredentialScope[], + authChannels: consentConsentRequest.authChannels as TAuthChannel[], + callbackUri: config.get('mojaloop').callbackUri, + } + + await consentsHandler.onUpdate(server, consentConsentRequest) + + expect(mojaloopClientSpy).toBeCalledWith( + consentRequest, + consentConsentRequest.party?.partyIdInfo.fspId + ) + expect(validatorSpy).toBeCalledWith(consentConsentRequest) + }) + + it('Should initiate challenge generation request when all necessary fields are set', async () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postGenerateChallengeForConsent') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidChallengeGeneration') + .mockReturnValue(true) + + // Mock consent data that would be given by Firebase + const consentGenerateChallenge: Consent = { + id: '111', + consentId: '2323', + party: { + partyIdInfo: { + partyIdType: PartyIdType.MSISDN, + partyIdentifier: '+1-222-222-2222', + fspId: 'fspb', + }, + }, + status: ConsentStatus.ACTIVE, + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + consentRequestId: '12345', + authChannels: ['WEB'], + accounts: [ + { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, + { id: 'bob.bbbbb.fspb', currency: Currency.USD }, + ], + } + + await consentsHandler.onUpdate(server, consentGenerateChallenge) + + expect(validatorSpy).toBeCalledWith(consentGenerateChallenge) + expect(mojaloopClientSpy).toBeCalledWith( + consentGenerateChallenge.consentId, + consentGenerateChallenge.party?.partyIdInfo.fspId + ) + }) + + it('Should initiate PUT consent/{ID} request when challenge has been signed and all necessary fields are set', async () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'putConsentId') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidSignedChallenge') + .mockReturnValue(true) + + // Mock the expected transaction request being sent. + const consentVerifiedChallenge = { + id: '111', + consentId: '2323', + initiatorId: 'pispa', + participantId: 'pispb', + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + party: { + partyIdInfo: { + partyIdType: PartyIdType.MSISDN, + partyIdentifier: '+1-222-222-2222', + fspId: 'fspb', + }, + }, + status: ConsentStatus.CHALLENGE_VERIFIED, + credential: { + id: '9876', + credentialType: 'FIDO' as const, + status: 'VERIFIED' as const, + challenge: { + payload: 'string_representing_challenge_payload', + signature: 'string_representing_challenge_signature', + }, + payload: 'string_representing_credential_payload', + }, + } + + await consentsHandler.onUpdate(server, consentVerifiedChallenge) + + expect(validatorSpy).toBeCalledWith(consentVerifiedChallenge) + expect(mojaloopClientSpy).toBeCalledWith( + consentVerifiedChallenge.consentId, + { + requestId: consentVerifiedChallenge.id, + initiatorId: consentVerifiedChallenge.initiatorId, + participantId: consentVerifiedChallenge.participantId, + scopes: consentVerifiedChallenge.scopes, + credential: consentVerifiedChallenge.credential, + }, + consentVerifiedChallenge.party.partyIdInfo.fspId + ) + }) + + it('Should initiate consent revoke request when all necessary fields are set', async () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postRevokeConsent') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidRevokeConsent') + .mockReturnValue(true) + + // Mock the expected transaction request being sent. + const consentRevokeRequested = { + id: '111', + consentId: '2323', + party: { + partyIdInfo: { + partyIdType: PartyIdType.MSISDN, + partyIdentifier: '+1-222-222-2222', + fspId: 'fspb', + }, + }, + status: ConsentStatus.REVOKE_REQUESTED, + } + + await consentsHandler.onUpdate(server, consentRevokeRequested) + + expect(validatorSpy).toBeCalledWith(consentRevokeRequested) + expect(mojaloopClientSpy).toBeCalledWith( + consentRevokeRequested.consentId, + consentRevokeRequested.party.partyIdInfo.fspId + ) + }) +}) From e638cabfcb354cb84b4df67463d9712867488ae3 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 7 Sep 2020 16:18:50 +0530 Subject: [PATCH 063/114] test: Ignore testing for src/shared/ml-thirdparty-client/models/core/index As it is just exporting from other files in the directory --- src/shared/ml-thirdparty-client/models/openapi/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/ml-thirdparty-client/models/openapi/index.ts b/src/shared/ml-thirdparty-client/models/openapi/index.ts index 28e6966b..e48c3fc0 100644 --- a/src/shared/ml-thirdparty-client/models/openapi/index.ts +++ b/src/shared/ml-thirdparty-client/models/openapi/index.ts @@ -1,3 +1,4 @@ +/* istanbul ignore file */ /***** License -------------- From cb78424971facc54c7f6a68bc1e1899483e62855 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 7 Sep 2020 16:19:19 +0530 Subject: [PATCH 064/114] fix: Checks for fspId in party --- src/server/handlers/firestore/consents.validator.ts | 9 +++++---- test/unit/server/handlers/firestore/consents.test.ts | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/server/handlers/firestore/consents.validator.ts b/src/server/handlers/firestore/consents.validator.ts index 4b1c7c3e..25fedc50 100644 --- a/src/server/handlers/firestore/consents.validator.ts +++ b/src/server/handlers/firestore/consents.validator.ts @@ -55,6 +55,7 @@ export const isValidAuthentication = (consent: Consent): boolean => { consent.consentRequestId && consent.consentId && consent.party && + consent.party.partyIdInfo && consent.party.partyIdInfo.fspId && consent.initiatorId && consent.authChannels && @@ -78,7 +79,7 @@ export const isValidConsentRequest = (consent: Consent): boolean => { consent.scopes && consent.initiatorId && consent.party && - consent.party.partyIdInfo.fspId && + consent.party.partyIdInfo?.fspId && consent.authUri ) { return true @@ -94,7 +95,7 @@ export const isValidConsentRequest = (consent: Consent): boolean => { * on Firebase. */ export const isValidChallengeGeneration = (consent: Consent): boolean => { - if (consent.consentId && consent.party && consent.party.partyIdInfo.fspId) { + if (consent.consentId && consent.party && consent.party.partyIdInfo?.fspId) { return true } return false @@ -111,7 +112,7 @@ export const isValidSignedChallenge = (consent: Consent): boolean => { if ( consent.credential && consent.party && - consent.party.partyIdInfo.fspId && + consent.party.partyIdInfo?.fspId && consent.scopes && consent.initiatorId && consent.participantId @@ -129,7 +130,7 @@ export const isValidSignedChallenge = (consent: Consent): boolean => { * on Firebase. */ export const isValidRevokeConsent = (consent: Consent): boolean => { - if (consent.consentId && consent.party && consent.party.partyIdInfo.fspId) { + if (consent.consentId && consent.party && consent.party.partyIdInfo?.fspId) { return true } return false diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index b30da120..0a9084f4 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -19,7 +19,7 @@ - Name Surname * Google - - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ From cc55900bec0b01b2b0db3078ed93d28cd7f8e604 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 7 Sep 2020 16:40:00 +0530 Subject: [PATCH 065/114] test: refactor to improve test readability and add structure --- .../handlers/firestore/consents.test.ts | 494 +++++++++--------- 1 file changed, 255 insertions(+), 239 deletions(-) diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index 0a9084f4..d0885aa4 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -74,253 +74,269 @@ describe('Handlers for consent documents in Firebase', () => { jest.clearAllTimers() }) - it('Should set status and consentRequestId for new consent', () => { - const consentRepositorySpy = jest.spyOn( - consentRepository, - 'updateConsentById' - ) - - consentsHandler.onCreate(server, { - id: '111', - userId: 'bob123', - party: { - partyIdInfo: { - partyIdType: PartyIdType.OPAQUE, - partyIdentifier: 'bob1234', - fspId: 'fspb', + describe('OnCreate', () => { + it('Should set status and consentRequestId for new consent', () => { + const consentRepositorySpy = jest.spyOn( + consentRepository, + 'updateConsentById' + ) + + consentsHandler.onCreate(server, { + id: '111', + userId: 'bob123', + party: { + partyIdInfo: { + partyIdType: PartyIdType.OPAQUE, + partyIdentifier: 'bob1234', + fspId: 'fspb', + }, }, - }, - }) + }) - expect(consentRepositorySpy).toBeCalledWith('111', { - consentRequestId: '12345', - status: ConsentStatus.PENDING_PARTY_LOOKUP, + expect(consentRepositorySpy).toBeCalledWith('111', { + consentRequestId: '12345', + status: ConsentStatus.PENDING_PARTY_LOOKUP, + }) }) }) - it('Should perform party lookup when all necessary fields are set', async () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'getParties') - .mockImplementation() - - const validatorSpy = jest - .spyOn(Validator, 'isValidPartyLookup') - .mockReturnValue(true) - - const consentPartyLookup: Consent = { - id: documentId, - userId: 'bob123', - party: { - partyIdInfo: { - partyIdType: PartyIdType.OPAQUE, - partyIdentifier: 'bob1234', - }, - }, - consentRequestId: '12345', - status: ConsentStatus.PENDING_PARTY_LOOKUP, - } - - await consentsHandler.onUpdate(server, consentPartyLookup) - - expect(validatorSpy).toBeCalledWith(consentPartyLookup) - expect(mojaloopClientSpy).toBeCalledWith(PartyIdType.OPAQUE, 'bob1234') - }) - - it('Should initiate consent request request when all necessary fields are set', async () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'postConsentRequests') - .mockImplementation() - - const validatorSpy = jest - .spyOn(Validator, 'isValidConsentRequest') - .mockReturnValue(true) - - // Mock consent data that would be given by Firebase - const consentConsentRequest: Consent = { - id: documentId, - userId: 'bob123', - party: { - partyIdInfo: { - partyIdType: PartyIdType.OPAQUE, - partyIdentifier: 'bob1234', - fspId: 'fspb', - }, - }, - scopes: [ - { - accountId: 'as2342', - actions: ['account.getAccess', 'account.transferMoney'], - }, - { - accountId: 'as22', - actions: ['account.getAccess'], - }, - ], - consentRequestId: '12345', - authChannels: ['WEB'], - accounts: [ - { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, - { id: 'bob.bbbbb.fspb', currency: Currency.USD }, - ], - status: ConsentStatus.PENDING_PARTY_CONFIRMATION, - } - - // Mock the expected transaction request being sent. - const consentRequest: SDKStandardComponents.PostConsentRequestsRequest = { - initiatorId: consentConsentRequest.initiatorId as string, - id: consentConsentRequest.id, - scopes: consentConsentRequest.scopes as TCredentialScope[], - authChannels: consentConsentRequest.authChannels as TAuthChannel[], - callbackUri: config.get('mojaloop').callbackUri, - } - - await consentsHandler.onUpdate(server, consentConsentRequest) - - expect(mojaloopClientSpy).toBeCalledWith( - consentRequest, - consentConsentRequest.party?.partyIdInfo.fspId - ) - expect(validatorSpy).toBeCalledWith(consentConsentRequest) - }) - - it('Should initiate challenge generation request when all necessary fields are set', async () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'postGenerateChallengeForConsent') - .mockImplementation() - - const validatorSpy = jest - .spyOn(Validator, 'isValidChallengeGeneration') - .mockReturnValue(true) - - // Mock consent data that would be given by Firebase - const consentGenerateChallenge: Consent = { - id: '111', - consentId: '2323', - party: { - partyIdInfo: { - partyIdType: PartyIdType.MSISDN, - partyIdentifier: '+1-222-222-2222', - fspId: 'fspb', - }, - }, - status: ConsentStatus.ACTIVE, - scopes: [ - { - accountId: 'as2342', - actions: ['account.getAccess', 'account.transferMoney'], - }, - { - accountId: 'as22', - actions: ['account.getAccess'], - }, - ], - consentRequestId: '12345', - authChannels: ['WEB'], - accounts: [ - { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, - { id: 'bob.bbbbb.fspb', currency: Currency.USD }, - ], - } - - await consentsHandler.onUpdate(server, consentGenerateChallenge) - - expect(validatorSpy).toBeCalledWith(consentGenerateChallenge) - expect(mojaloopClientSpy).toBeCalledWith( - consentGenerateChallenge.consentId, - consentGenerateChallenge.party?.partyIdInfo.fspId - ) - }) + describe('OnUpdate', () => { + describe('Party Lookup', () => { + it('Should perform party lookup when all necessary fields are set', async () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'getParties') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidPartyLookup') + .mockReturnValue(true) + + const consentPartyLookup: Consent = { + id: documentId, + userId: 'bob123', + party: { + partyIdInfo: { + partyIdType: PartyIdType.OPAQUE, + partyIdentifier: 'bob1234', + }, + }, + consentRequestId: '12345', + status: ConsentStatus.PENDING_PARTY_LOOKUP, + } + + await consentsHandler.onUpdate(server, consentPartyLookup) + + expect(validatorSpy).toBeCalledWith(consentPartyLookup) + expect(mojaloopClientSpy).toBeCalledWith(PartyIdType.OPAQUE, 'bob1234') + }) + }) - it('Should initiate PUT consent/{ID} request when challenge has been signed and all necessary fields are set', async () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'putConsentId') - .mockImplementation() - - const validatorSpy = jest - .spyOn(Validator, 'isValidSignedChallenge') - .mockReturnValue(true) - - // Mock the expected transaction request being sent. - const consentVerifiedChallenge = { - id: '111', - consentId: '2323', - initiatorId: 'pispa', - participantId: 'pispb', - scopes: [ - { - accountId: 'as2342', - actions: ['account.getAccess', 'account.transferMoney'], - }, - { - accountId: 'as22', - actions: ['account.getAccess'], - }, - ], - party: { - partyIdInfo: { - partyIdType: PartyIdType.MSISDN, - partyIdentifier: '+1-222-222-2222', - fspId: 'fspb', - }, - }, - status: ConsentStatus.CHALLENGE_VERIFIED, - credential: { - id: '9876', - credentialType: 'FIDO' as const, - status: 'VERIFIED' as const, - challenge: { - payload: 'string_representing_challenge_payload', - signature: 'string_representing_challenge_signature', - }, - payload: 'string_representing_credential_payload', - }, - } - - await consentsHandler.onUpdate(server, consentVerifiedChallenge) - - expect(validatorSpy).toBeCalledWith(consentVerifiedChallenge) - expect(mojaloopClientSpy).toBeCalledWith( - consentVerifiedChallenge.consentId, - { - requestId: consentVerifiedChallenge.id, - initiatorId: consentVerifiedChallenge.initiatorId, - participantId: consentVerifiedChallenge.participantId, - scopes: consentVerifiedChallenge.scopes, - credential: consentVerifiedChallenge.credential, - }, - consentVerifiedChallenge.party.partyIdInfo.fspId - ) - }) + describe('Authentication', () => {}) + + describe('Consent Request', () => { + it('Should initiate consent request request when all necessary fields are set', async () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postConsentRequests') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidConsentRequest') + .mockReturnValue(true) + + // Mock consent data that would be given by Firebase + const consentConsentRequest: Consent = { + id: documentId, + userId: 'bob123', + party: { + partyIdInfo: { + partyIdType: PartyIdType.OPAQUE, + partyIdentifier: 'bob1234', + fspId: 'fspb', + }, + }, + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + consentRequestId: '12345', + authChannels: ['WEB'], + accounts: [ + { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, + { id: 'bob.bbbbb.fspb', currency: Currency.USD }, + ], + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + } + + // Mock the expected transaction request being sent. + const consentRequest: SDKStandardComponents.PostConsentRequestsRequest = { + initiatorId: consentConsentRequest.initiatorId as string, + id: consentConsentRequest.id, + scopes: consentConsentRequest.scopes as TCredentialScope[], + authChannels: consentConsentRequest.authChannels as TAuthChannel[], + callbackUri: config.get('mojaloop').callbackUri, + } + + await consentsHandler.onUpdate(server, consentConsentRequest) + + expect(mojaloopClientSpy).toBeCalledWith( + consentRequest, + consentConsentRequest.party?.partyIdInfo.fspId + ) + expect(validatorSpy).toBeCalledWith(consentConsentRequest) + }) + }) - it('Should initiate consent revoke request when all necessary fields are set', async () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'postRevokeConsent') - .mockImplementation() - - const validatorSpy = jest - .spyOn(Validator, 'isValidRevokeConsent') - .mockReturnValue(true) - - // Mock the expected transaction request being sent. - const consentRevokeRequested = { - id: '111', - consentId: '2323', - party: { - partyIdInfo: { - partyIdType: PartyIdType.MSISDN, - partyIdentifier: '+1-222-222-2222', - fspId: 'fspb', - }, - }, - status: ConsentStatus.REVOKE_REQUESTED, - } + describe('Challenge Generation Request', () => { + it('Should initiate challenge generation request when all necessary fields are set', async () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postGenerateChallengeForConsent') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidChallengeGeneration') + .mockReturnValue(true) + + // Mock consent data that would be given by Firebase + const consentGenerateChallenge: Consent = { + id: '111', + consentId: '2323', + party: { + partyIdInfo: { + partyIdType: PartyIdType.MSISDN, + partyIdentifier: '+1-222-222-2222', + fspId: 'fspb', + }, + }, + status: ConsentStatus.ACTIVE, + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + consentRequestId: '12345', + authChannels: ['WEB'], + accounts: [ + { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, + { id: 'bob.bbbbb.fspb', currency: Currency.USD }, + ], + } + + await consentsHandler.onUpdate(server, consentGenerateChallenge) + + expect(validatorSpy).toBeCalledWith(consentGenerateChallenge) + expect(mojaloopClientSpy).toBeCalledWith( + consentGenerateChallenge.consentId, + consentGenerateChallenge.party?.partyIdInfo.fspId + ) + }) + }) - await consentsHandler.onUpdate(server, consentRevokeRequested) + describe('Signed Challenge', () => { + it('Should initiate PUT consent/{ID} request when challenge has been signed and all necessary fields are set', async () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'putConsentId') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidSignedChallenge') + .mockReturnValue(true) + + // Mock the expected transaction request being sent. + const consentVerifiedChallenge = { + id: '111', + consentId: '2323', + initiatorId: 'pispa', + participantId: 'pispb', + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + party: { + partyIdInfo: { + partyIdType: PartyIdType.MSISDN, + partyIdentifier: '+1-222-222-2222', + fspId: 'fspb', + }, + }, + status: ConsentStatus.CHALLENGE_VERIFIED, + credential: { + id: '9876', + credentialType: 'FIDO' as const, + status: 'VERIFIED' as const, + challenge: { + payload: 'string_representing_challenge_payload', + signature: 'string_representing_challenge_signature', + }, + payload: 'string_representing_credential_payload', + }, + } + + await consentsHandler.onUpdate(server, consentVerifiedChallenge) + + expect(validatorSpy).toBeCalledWith(consentVerifiedChallenge) + expect(mojaloopClientSpy).toBeCalledWith( + consentVerifiedChallenge.consentId, + { + requestId: consentVerifiedChallenge.id, + initiatorId: consentVerifiedChallenge.initiatorId, + participantId: consentVerifiedChallenge.participantId, + scopes: consentVerifiedChallenge.scopes, + credential: consentVerifiedChallenge.credential, + }, + consentVerifiedChallenge.party.partyIdInfo.fspId + ) + }) + }) - expect(validatorSpy).toBeCalledWith(consentRevokeRequested) - expect(mojaloopClientSpy).toBeCalledWith( - consentRevokeRequested.consentId, - consentRevokeRequested.party.partyIdInfo.fspId - ) + describe('Request to Revoke Consent ', () => { + it('Should initiate consent revoke request when all necessary fields are set', async () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postRevokeConsent') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidRevokeConsent') + .mockReturnValue(true) + + // Mock the expected transaction request being sent. + const consentRevokeRequested = { + id: '111', + consentId: '2323', + party: { + partyIdInfo: { + partyIdType: PartyIdType.MSISDN, + partyIdentifier: '+1-222-222-2222', + fspId: 'fspb', + }, + }, + status: ConsentStatus.REVOKE_REQUESTED, + } + + await consentsHandler.onUpdate(server, consentRevokeRequested) + + expect(validatorSpy).toBeCalledWith(consentRevokeRequested) + expect(mojaloopClientSpy).toBeCalledWith( + consentRevokeRequested.consentId, + consentRevokeRequested.party.partyIdInfo.fspId + ) + }) + }) }) }) From af6e3af9d7ec9be9bc4b74b41c0598bbc31ea27a Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 8 Sep 2020 10:21:07 +0530 Subject: [PATCH 066/114] test: add unit tests for consent validators --- .../firestore/consents.validator.test.ts | 711 ++++++++++++++++++ 1 file changed, 711 insertions(+) create mode 100644 test/unit/server/handlers/firestore/consents.validator.test.ts diff --git a/test/unit/server/handlers/firestore/consents.validator.test.ts b/test/unit/server/handlers/firestore/consents.validator.test.ts new file mode 100644 index 00000000..a0fd4c37 --- /dev/null +++ b/test/unit/server/handlers/firestore/consents.validator.test.ts @@ -0,0 +1,711 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +/***** + License + -------------- + Copyright © 2020 Mojaloop Foundation + The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Mojaloop Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Mojaloop Foundation + - Name Surname + + * Google + - Abhimanyu Kapur + -------------- + ******/ + +import * as Validator from '~/server/handlers/firestore/consents.validator' +import { ConsentStatus } from '~/models/consent' +import { + PartyIdType, + Currency, +} from '~/shared/ml-thirdparty-client/models/core' +import SDKStandardComponents from '@mojaloop/sdk-standard-components' + +const id = '111' +const consentId = 'abc123' +const userId = 'bob123' +const scopes = [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, +] +const party = { + partyIdInfo: { + partyIdType: PartyIdType.OPAQUE, + partyIdentifier: 'bob1234', + }, +} +const partyWithFSPId = { + partyIdInfo: { + partyIdType: PartyIdType.MSISDN, + partyIdentifier: '+1-222-222-2222', + fspId: 'fspb', + }, +} +const consentRequestId = '12345' +const authChannels: SDKStandardComponents.TAuthChannel[] = ['WEB'] +const accounts = [ + { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, + { id: 'bob.bbbbb.fspb', currency: Currency.USD }, +] +const initiatorId = 'pispa' +const authUri = 'http//auth.com' +const authToken = '' +const participantId = 'pispb' +const credential = { + id: '9876', + credentialType: 'FIDO' as const, + status: 'VERIFIED' as const, + challenge: { + payload: 'string_representing_challenge_payload', + signature: 'string_representing_challenge_signature', + }, + payload: 'string_representing_credential_payload', +} + +describe('Validators for different consents used in requests', () => { + describe('isValidPartyLookup', () => { + it('Should return true if all necessary fields are present', () => { + expect( + Validator.isValidPartyLookup({ + id, + userId, + party, + status: ConsentStatus.PENDING_PARTY_LOOKUP, + }) + ).toBe(true) + }) + + it('Should return false if party, partyIdInfo, partyIdType and/or partyIdentifier is not present', () => { + expect( + Validator.isValidPartyLookup({ + id, + userId, + status: ConsentStatus.PENDING_PARTY_LOOKUP, + }) + ).toBe(false) + + expect( + Validator.isValidPartyLookup({ + id, + userId, + // @ts-ignore + party: {}, + status: ConsentStatus.PENDING_PARTY_LOOKUP, + }) + ).toBe(false) + + expect( + Validator.isValidPartyLookup({ + id, + userId, + party: { + // @ts-ignore + partyIdInfo: {}, + }, + status: ConsentStatus.PENDING_PARTY_LOOKUP, + }) + ).toBe(false) + + expect( + Validator.isValidPartyLookup({ + id, + userId, + party: { + // @ts-ignore + partyIdInfo: { + partyIdentifier: 'bob1234', + }, + }, + status: ConsentStatus.PENDING_PARTY_LOOKUP, + }) + ).toBe(false) + + expect( + Validator.isValidPartyLookup({ + id, + userId, + party: { + // @ts-ignore + partyIdInfo: { + partyIdType: PartyIdType.OPAQUE, + }, + }, + status: ConsentStatus.PENDING_PARTY_LOOKUP, + }) + ).toBe(false) + }) + }) + + describe('isValidConsentRequest', () => { + it('Should return true if all necessary fields are present', () => { + expect( + Validator.isValidConsentRequest({ + id, + userId, + initiatorId, + party: partyWithFSPId, + scopes, + authUri, + consentRequestId, + authChannels, + accounts, + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + }) + ).toBe(true) + }) + + it('Should return false if party or partyIdInfo or fspId is not present', () => { + expect( + Validator.isValidConsentRequest({ + id, + initiatorId, + authUri, + userId, + party, + scopes, + consentRequestId, + authChannels, + accounts, + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + }) + ).toBe(false) + + expect( + Validator.isValidConsentRequest({ + id, + initiatorId, + userId, + scopes, + authUri, + consentRequestId, + authChannels, + accounts, + // @ts-ignore + party: {}, + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + }) + ).toBe(false) + + expect( + Validator.isValidConsentRequest({ + id, + userId, + initiatorId, + scopes, + authUri, + consentRequestId, + authChannels, + accounts, + party: { + // @ts-ignore + partyIdInfo: {}, + }, + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + }) + ).toBe(false) + }) + + it('Should return false if authChannels is not present', () => { + expect( + Validator.isValidConsentRequest({ + id, + initiatorId, + userId, + authUri, + party: partyWithFSPId, + scopes, + consentRequestId, + accounts, + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + }) + ).toBe(false) + }) + + it('Should return false if scopes are not present', () => { + expect( + Validator.isValidConsentRequest({ + id, + userId, + authUri, + initiatorId, + party: partyWithFSPId, + authChannels, + consentRequestId, + accounts, + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + }) + ).toBe(false) + }) + + it('Should return false if initiator ID is not present', () => { + expect( + Validator.isValidConsentRequest({ + id, + userId, + authUri, + scopes, + party: partyWithFSPId, + authChannels, + consentRequestId, + accounts, + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + }) + ).toBe(false) + }) + + it('Should return false if authURI is not present', () => { + expect( + Validator.isValidConsentRequest({ + id, + userId, + scopes, + party: partyWithFSPId, + authChannels, + consentRequestId, + accounts, + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + }) + ).toBe(false) + }) + }) + + describe('isValidAuthentication', () => { + it('Should return true if all necessary fields are present', () => { + expect( + Validator.isValidAuthentication({ + id, + userId, + consentId, + initiatorId, + party: partyWithFSPId, + scopes, + authToken, + consentRequestId, + authChannels, + accounts, + status: ConsentStatus.AUTHENTICATION_REQUIRED, + }) + ).toBe(true) + }) + + it('Should return false if party or partyIdInfo or fspId is not present', () => { + expect( + Validator.isValidAuthentication({ + id, + initiatorId, + authUri, + consentId, + authToken, + userId, + party, + scopes, + consentRequestId, + authChannels, + accounts, + status: ConsentStatus.AUTHENTICATION_REQUIRED, + }) + ).toBe(false) + + expect( + Validator.isValidAuthentication({ + id, + initiatorId, + userId, + scopes, + authUri, + consentRequestId, + authChannels, + accounts, + // @ts-ignore + party: {}, + status: ConsentStatus.AUTHENTICATION_REQUIRED, + }) + ).toBe(false) + + expect( + Validator.isValidConsentRequest({ + id, + userId, + initiatorId, + scopes, + consentId, + authToken, + authUri, + consentRequestId, + authChannels, + accounts, + party: { + // @ts-ignore + partyIdInfo: {}, + }, + status: ConsentStatus.AUTHENTICATION_REQUIRED, + }) + ).toBe(false) + }) + + it('Should return false if authChannels is not present', () => { + expect( + Validator.isValidAuthentication({ + id, + initiatorId, + userId, + consentId, + authToken, + party: partyWithFSPId, + scopes, + consentRequestId, + accounts, + status: ConsentStatus.AUTHENTICATION_REQUIRED, + }) + ).toBe(false) + }) + + it('Should return false if auth token are not present', () => { + expect( + Validator.isValidAuthentication({ + id, + userId, + authUri, + consentId, + initiatorId, + party: partyWithFSPId, + authChannels, + consentRequestId, + accounts, + status: ConsentStatus.AUTHENTICATION_REQUIRED, + }) + ).toBe(false) + }) + + it('Should return false if consent ID is not present', () => { + expect( + Validator.isValidAuthentication({ + id, + userId, + scopes, + authToken, + initiatorId, + party: partyWithFSPId, + authChannels, + consentRequestId, + accounts, + status: ConsentStatus.AUTHENTICATION_REQUIRED, + }) + ).toBe(false) + }) + + it('Should return false if initiator ID is not present', () => { + expect( + Validator.isValidAuthentication({ + id, + userId, + scopes, + authToken, + consentId, + party: partyWithFSPId, + authChannels, + consentRequestId, + accounts, + status: ConsentStatus.AUTHENTICATION_REQUIRED, + }) + ).toBe(false) + }) + }) + + describe('isValidChallengeGeneration', () => { + it('Should return true if all necessary fields are present', () => { + expect( + Validator.isValidChallengeGeneration({ + id, + consentId, + party: partyWithFSPId, + status: ConsentStatus.ACTIVE, + scopes, + consentRequestId, + authChannels, + accounts, + }) + ).toBe(true) + }) + + it('Should return false if party or partyIdInfo or fspId is not present', () => { + expect( + Validator.isValidChallengeGeneration({ + id, + initiatorId, + consentId, + userId, + party, + scopes, + consentRequestId, + authChannels, + accounts, + status: ConsentStatus.ACTIVE, + }) + ).toBe(false) + + expect( + Validator.isValidChallengeGeneration({ + id, + initiatorId, + consentId, + userId, + scopes, + consentRequestId, + authChannels, + accounts, + // @ts-ignore + party: {}, + status: ConsentStatus.ACTIVE, + }) + ).toBe(false) + + expect( + Validator.isValidChallengeGeneration({ + id, + userId, + initiatorId, + scopes, + consentId, + consentRequestId, + authChannels, + accounts, + party: { + // @ts-ignore + partyIdInfo: {}, + }, + status: ConsentStatus.ACTIVE, + }) + ).toBe(false) + }) + + it('Should return false if consent ID is not present', () => { + expect( + Validator.isValidRevokeConsent({ + id, + userId, + initiatorId, + party: partyWithFSPId, + status: ConsentStatus.ACTIVE, + }) + ).toBe(false) + }) + }) + + describe('isValidSignedChallenge', () => { + it('Should return true if all necessary fields are present', () => { + expect( + Validator.isValidSignedChallenge({ + id, + consentId, + initiatorId, + party: partyWithFSPId, + scopes, + participantId, + credential, + status: ConsentStatus.CHALLENGE_GENERATED, + }) + ).toBe(true) + }) + + it('Should return false if party or partyIdInfo or fspId is not present', () => { + expect( + Validator.isValidSignedChallenge({ + id, + initiatorId, + authUri, + consentId, + credential, + participantId, + authToken, + userId, + party, + scopes, + consentRequestId, + status: ConsentStatus.CHALLENGE_GENERATED, + }) + ).toBe(false) + + expect( + Validator.isValidSignedChallenge({ + id, + initiatorId, + userId, + scopes, + credential, + participantId, + consentRequestId, + authChannels, + accounts, + // @ts-ignore + party: {}, + status: ConsentStatus.CHALLENGE_GENERATED, + }) + ).toBe(false) + + expect( + Validator.isValidSignedChallenge({ + id, + userId, + initiatorId, + scopes, + consentId, + credential, + participantId, + consentRequestId, + authChannels, + accounts, + party: { + // @ts-ignore + partyIdInfo: {}, + }, + status: ConsentStatus.CHALLENGE_GENERATED, + }) + ).toBe(false) + }) + + it('Should return false if credential is not present', () => { + expect( + Validator.isValidSignedChallenge({ + id, + initiatorId, + userId, + consentId, + participantId, + party: partyWithFSPId, + scopes, + consentRequestId, + accounts, + status: ConsentStatus.CHALLENGE_GENERATED, + }) + ).toBe(false) + }) + + it('Should return false if initiator ID is not present', () => { + expect( + Validator.isValidSignedChallenge({ + id, + userId, + authUri, + scopes, + party: partyWithFSPId, + authChannels, + consentRequestId, + accounts, + status: ConsentStatus.CHALLENGE_GENERATED, + }) + ).toBe(false) + }) + + it('Should return false if participant ID is not present', () => { + expect( + Validator.isValidAuthentication({ + id, + userId, + scopes, + authToken, + credential, + initiatorId, + party: partyWithFSPId, + consentRequestId, + status: ConsentStatus.AUTHENTICATION_REQUIRED, + }) + ).toBe(false) + }) + }) + + describe('isValidRevokeConsent', () => { + it('Should return true if all necessary fields are present', () => { + expect( + Validator.isValidRevokeConsent({ + id, + userId, + consentId, + initiatorId, + party: partyWithFSPId, + status: ConsentStatus.REVOKE_REQUESTED, + }) + ).toBe(true) + }) + + it('Should return false if party or partyIdInfo or fspId is not present', () => { + expect( + Validator.isValidRevokeConsent({ + id, + initiatorId, + consentId, + userId, + party, + scopes, + consentRequestId, + authChannels, + accounts, + status: ConsentStatus.REVOKE_REQUESTED, + }) + ).toBe(false) + + expect( + Validator.isValidRevokeConsent({ + id, + initiatorId, + consentId, + userId, + scopes, + consentRequestId, + authChannels, + accounts, + // @ts-ignore + party: {}, + status: ConsentStatus.REVOKE_REQUESTED, + }) + ).toBe(false) + + expect( + Validator.isValidConsentRequest({ + id, + userId, + initiatorId, + scopes, + consentId, + consentRequestId, + authChannels, + accounts, + party: { + // @ts-ignore + partyIdInfo: {}, + }, + status: ConsentStatus.REVOKE_REQUESTED, + }) + ).toBe(false) + }) + + it('Should return false if consent ID is not present', () => { + expect( + Validator.isValidRevokeConsent({ + id, + userId, + initiatorId, + party: partyWithFSPId, + status: ConsentStatus.REVOKE_REQUESTED, + }) + ).toBe(false) + }) + }) +}) From edaa06787a74e873c0a58ef66f1315f1ca72fc8b Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 8 Sep 2020 12:05:42 +0530 Subject: [PATCH 067/114] test: Add unit tests for error cases + refactor mocking for clarity --- .../handlers/firestore/consents.test.ts | 549 +++++++++++++----- 1 file changed, 394 insertions(+), 155 deletions(-) diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index d0885aa4..5e45b8ed 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -51,11 +51,8 @@ jest.mock('uuid', () => ({ })) // Mock utils to consistently return the provided value. -jest.mock('~/lib/utils', () => ({ - getTomorrowsDate: jest.fn().mockImplementation(() => { - return new Date(100) - }), -})) +// jest.mock('~/shared/logger', () => ({ +// })) const documentId = '111' @@ -102,14 +99,38 @@ describe('Handlers for consent documents in Firebase', () => { describe('OnUpdate', () => { describe('Party Lookup', () => { + // Mocked Methods + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'getParties') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidPartyLookup') + .mockReturnValue(true) + + // Mock consent data that would be given by Firebase + const consentPartyLookup: Consent = { + id: documentId, + userId: 'bob123', + party: { + partyIdInfo: { + partyIdType: PartyIdType.OPAQUE, + partyIdentifier: 'bob1234', + }, + }, + consentRequestId: '12345', + status: ConsentStatus.PENDING_PARTY_LOOKUP, + } + it('Should perform party lookup when all necessary fields are set', async () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'getParties') - .mockImplementation() + await consentsHandler.onUpdate(server, consentPartyLookup) - const validatorSpy = jest - .spyOn(Validator, 'isValidPartyLookup') - .mockReturnValue(true) + expect(validatorSpy).toBeCalledWith(consentPartyLookup) + expect(mojaloopClientSpy).toBeCalledWith(PartyIdType.OPAQUE, 'bob1234') + }) + + it('Should throw an error if Validator returns false', async () => { + validatorSpy.mockReturnValueOnce(false) const consentPartyLookup: Consent = { id: documentId, @@ -120,67 +141,193 @@ describe('Handlers for consent documents in Firebase', () => { partyIdentifier: 'bob1234', }, }, - consentRequestId: '12345', status: ConsentStatus.PENDING_PARTY_LOOKUP, } + await expect( + consentsHandler.onUpdate(server, consentPartyLookup) + ).rejects.toThrowError('Consent Object Missing Fields') + + expect(validatorSpy).toBeCalledWith(consentPartyLookup) + expect(mojaloopClientSpy).not.toBeCalled() + }) + + it('Should throw an error if mojaloop client throws error', async () => { + mojaloopClientSpy.mockImplementation(() => { + throw new Error('Client not connected') + }) + await consentsHandler.onUpdate(server, consentPartyLookup) expect(validatorSpy).toBeCalledWith(consentPartyLookup) expect(mojaloopClientSpy).toBeCalledWith(PartyIdType.OPAQUE, 'bob1234') + expect() }) }) - describe('Authentication', () => {}) + describe('Authentication', () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'putConsentRequests') + .mockImplementation() - describe('Consent Request', () => { + const validatorSpy = jest + .spyOn(Validator, 'isValidAuthentication') + .mockReturnValue(true) + + // Mock consent data that would be given by Firebase + const consentAuthentication: Consent = { + id: documentId, + userId: 'bob123', + initiatorId: 'pispa', + party: { + partyIdInfo: { + partyIdType: PartyIdType.MSISDN, + partyIdentifier: 'bob1234', + fspId: 'fspb', + }, + }, + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + consentRequestId: '12345', + authChannels: ['WEB'], + authUri: 'http//auth.com', + authToken: '', + accounts: [ + { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, + { id: 'bob.bbbbb.fspb', currency: Currency.USD }, + ], + status: ConsentStatus.AUTHENTICATION_REQUIRED, + } + + // Mock the expected transaction request being sent. + const request: SDKStandardComponents.PutConsentRequestsRequest = { + initiatorId: consentAuthentication.initiatorId as string, + scopes: consentAuthentication.scopes as TCredentialScope[], + authChannels: consentAuthentication.authChannels as TAuthChannel[], + callbackUri: config.get('mojaloop').callbackUri, + authToken: consentAuthentication.authToken as string, + authUri: consentAuthentication.authUri as string, + } it('Should initiate consent request request when all necessary fields are set', async () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'postConsentRequests') - .mockImplementation() + await consentsHandler.onUpdate(server, consentAuthentication) - const validatorSpy = jest - .spyOn(Validator, 'isValidConsentRequest') - .mockReturnValue(true) + expect(mojaloopClientSpy).toBeCalledWith( + consentAuthentication.id, + request, + consentAuthentication.party?.partyIdInfo.fspId + ) + expect(validatorSpy).toBeCalledWith(consentAuthentication) + }) - // Mock consent data that would be given by Firebase - const consentConsentRequest: Consent = { - id: documentId, - userId: 'bob123', - party: { - partyIdInfo: { - partyIdType: PartyIdType.OPAQUE, - partyIdentifier: 'bob1234', - fspId: 'fspb', - }, + it('Should throw an error if Validator returns false', async () => { + validatorSpy.mockReturnValueOnce(false) + + await expect( + consentsHandler.onUpdate(server, consentAuthentication) + ).rejects.toThrowError('Consent Object Missing Fields') + + expect(validatorSpy).toBeCalledWith(consentAuthentication) + expect(mojaloopClientSpy).not.toBeCalled() + }) + + it('Should log an error if mojaloop client throws error', async () => { + mojaloopClientSpy.mockImplementation(() => { + throw new Error('Client not connected') + }) + + await consentsHandler.onUpdate(server, consentAuthentication) + + expect(mojaloopClientSpy).toBeCalledWith( + consentAuthentication.id, + request, + consentAuthentication.party?.partyIdInfo.fspId + ) + expect(validatorSpy).toBeCalledWith(consentAuthentication) + expect() + }) + }) + + describe('Consent Request', () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postConsentRequests') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidConsentRequest') + .mockReturnValue(true) + + // Mock consent data that would be given by Firebase + const consentConsentRequest: Consent = { + id: documentId, + userId: 'bob123', + party: { + partyIdInfo: { + partyIdType: PartyIdType.OPAQUE, + partyIdentifier: 'bob1234', + fspId: 'fspb', }, - scopes: [ - { - accountId: 'as2342', - actions: ['account.getAccess', 'account.transferMoney'], - }, - { - accountId: 'as22', - actions: ['account.getAccess'], - }, - ], - consentRequestId: '12345', - authChannels: ['WEB'], - accounts: [ - { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, - { id: 'bob.bbbbb.fspb', currency: Currency.USD }, - ], - status: ConsentStatus.PENDING_PARTY_CONFIRMATION, - } + }, + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + consentRequestId: '12345', + authChannels: ['WEB'], + accounts: [ + { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, + { id: 'bob.bbbbb.fspb', currency: Currency.USD }, + ], + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + } + + // Mock the expected request being sent. + const consentRequest: SDKStandardComponents.PostConsentRequestsRequest = { + initiatorId: consentConsentRequest.initiatorId as string, + id: consentConsentRequest.id, + scopes: consentConsentRequest.scopes as TCredentialScope[], + authChannels: consentConsentRequest.authChannels as TAuthChannel[], + callbackUri: config.get('mojaloop').callbackUri, + } - // Mock the expected transaction request being sent. - const consentRequest: SDKStandardComponents.PostConsentRequestsRequest = { - initiatorId: consentConsentRequest.initiatorId as string, - id: consentConsentRequest.id, - scopes: consentConsentRequest.scopes as TCredentialScope[], - authChannels: consentConsentRequest.authChannels as TAuthChannel[], - callbackUri: config.get('mojaloop').callbackUri, - } + it('Should initiate consent request request when all necessary fields are set', async () => { + await consentsHandler.onUpdate(server, consentConsentRequest) + + expect(mojaloopClientSpy).toBeCalledWith( + consentRequest, + consentConsentRequest.party?.partyIdInfo.fspId + ) + expect(validatorSpy).toBeCalledWith(consentConsentRequest) + }) + + it('Should throw an error if Validator returns false', async () => { + validatorSpy.mockReturnValueOnce(false) + + await expect( + consentsHandler.onUpdate(server, consentConsentRequest) + ).rejects.toThrowError('Consent Object Missing Fields') + + expect(validatorSpy).toBeCalledWith(consentConsentRequest) + expect(mojaloopClientSpy).not.toBeCalled() + }) + + it('Should log an error if mojaloop client throws error', async () => { + mojaloopClientSpy.mockImplementation(() => { + throw new Error('Client not connected') + }) await consentsHandler.onUpdate(server, consentConsentRequest) @@ -189,48 +336,73 @@ describe('Handlers for consent documents in Firebase', () => { consentConsentRequest.party?.partyIdInfo.fspId ) expect(validatorSpy).toBeCalledWith(consentConsentRequest) + expect() }) }) describe('Challenge Generation Request', () => { - it('Should initiate challenge generation request when all necessary fields are set', async () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'postGenerateChallengeForConsent') - .mockImplementation() - - const validatorSpy = jest - .spyOn(Validator, 'isValidChallengeGeneration') - .mockReturnValue(true) - - // Mock consent data that would be given by Firebase - const consentGenerateChallenge: Consent = { - id: '111', - consentId: '2323', - party: { - partyIdInfo: { - partyIdType: PartyIdType.MSISDN, - partyIdentifier: '+1-222-222-2222', - fspId: 'fspb', - }, + // Mocked Methods + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postGenerateChallengeForConsent') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidChallengeGeneration') + .mockReturnValue(true) + + // Mock consent data that would be given by Firebase + const consentGenerateChallenge: Consent = { + id: '111', + consentId: '2323', + party: { + partyIdInfo: { + partyIdType: PartyIdType.MSISDN, + partyIdentifier: '+1-222-222-2222', + fspId: 'fspb', }, - status: ConsentStatus.ACTIVE, - scopes: [ - { - accountId: 'as2342', - actions: ['account.getAccess', 'account.transferMoney'], - }, - { - accountId: 'as22', - actions: ['account.getAccess'], - }, - ], - consentRequestId: '12345', - authChannels: ['WEB'], - accounts: [ - { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, - { id: 'bob.bbbbb.fspb', currency: Currency.USD }, - ], - } + }, + status: ConsentStatus.ACTIVE, + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + consentRequestId: '12345', + authChannels: ['WEB'], + accounts: [ + { id: 'bob.aaaaa.fspb', currency: Currency.SGD }, + { id: 'bob.bbbbb.fspb', currency: Currency.USD }, + ], + } + + it('Should initiate challenge generation request when all necessary fields are set', async () => { + await consentsHandler.onUpdate(server, consentGenerateChallenge) + + expect(validatorSpy).toBeCalledWith(consentGenerateChallenge) + expect(mojaloopClientSpy).toBeCalledWith( + consentGenerateChallenge.consentId, + consentGenerateChallenge.party?.partyIdInfo.fspId + ) + }) + + it('Should throw an error if Validator returns false', async () => { + validatorSpy.mockReturnValueOnce(false) + + await consentsHandler.onUpdate(server, consentGenerateChallenge) + + expect(validatorSpy).toBeCalledWith(consentGenerateChallenge) + expect(mojaloopClientSpy).not.toBeCalled() + }) + + it('Should log an error if mojaloop client throws error', async () => { + mojaloopClientSpy.mockImplementation(() => { + throw new Error('Client not connected') + }) await consentsHandler.onUpdate(server, consentGenerateChallenge) @@ -239,54 +411,92 @@ describe('Handlers for consent documents in Firebase', () => { consentGenerateChallenge.consentId, consentGenerateChallenge.party?.partyIdInfo.fspId ) + expect() }) }) describe('Signed Challenge', () => { + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'putConsentId') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidSignedChallenge') + .mockReturnValue(true) + + // Mock the expected transaction request being sent. + const consentVerifiedChallenge = { + id: '111', + consentId: '2323', + initiatorId: 'pispa', + participantId: 'pispb', + scopes: [ + { + accountId: 'as2342', + actions: ['account.getAccess', 'account.transferMoney'], + }, + { + accountId: 'as22', + actions: ['account.getAccess'], + }, + ], + party: { + partyIdInfo: { + partyIdType: PartyIdType.MSISDN, + partyIdentifier: '+1-222-222-2222', + fspId: 'fspb', + }, + }, + status: ConsentStatus.CHALLENGE_VERIFIED, + credential: { + id: '9876', + credentialType: 'FIDO' as const, + status: 'VERIFIED' as const, + challenge: { + payload: 'string_representing_challenge_payload', + signature: 'string_representing_challenge_signature', + }, + payload: 'string_representing_credential_payload', + }, + } it('Should initiate PUT consent/{ID} request when challenge has been signed and all necessary fields are set', async () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'putConsentId') - .mockImplementation() - - const validatorSpy = jest - .spyOn(Validator, 'isValidSignedChallenge') - .mockReturnValue(true) - - // Mock the expected transaction request being sent. - const consentVerifiedChallenge = { - id: '111', - consentId: '2323', - initiatorId: 'pispa', - participantId: 'pispb', - scopes: [ - { - accountId: 'as2342', - actions: ['account.getAccess', 'account.transferMoney'], - }, - { - accountId: 'as22', - actions: ['account.getAccess'], - }, - ], - party: { - partyIdInfo: { - partyIdType: PartyIdType.MSISDN, - partyIdentifier: '+1-222-222-2222', - fspId: 'fspb', - }, + await consentsHandler.onUpdate(server, consentVerifiedChallenge) + + expect(validatorSpy).toBeCalledWith(consentVerifiedChallenge) + expect(mojaloopClientSpy).toBeCalledWith( + consentVerifiedChallenge.consentId, + { + requestId: consentVerifiedChallenge.id, + initiatorId: consentVerifiedChallenge.initiatorId, + participantId: consentVerifiedChallenge.participantId, + scopes: consentVerifiedChallenge.scopes, + credential: consentVerifiedChallenge.credential, }, - status: ConsentStatus.CHALLENGE_VERIFIED, - credential: { - id: '9876', - credentialType: 'FIDO' as const, - status: 'VERIFIED' as const, - challenge: { - payload: 'string_representing_challenge_payload', - signature: 'string_representing_challenge_signature', - }, - payload: 'string_representing_credential_payload', + consentVerifiedChallenge.party.partyIdInfo.fspId + ) + }) + + it('Should throw an error if Validator returns false', async () => { + await consentsHandler.onUpdate(server, consentVerifiedChallenge) + + expect(validatorSpy).toBeCalledWith(consentVerifiedChallenge) + expect(mojaloopClientSpy).toBeCalledWith( + consentVerifiedChallenge.consentId, + { + requestId: consentVerifiedChallenge.id, + initiatorId: consentVerifiedChallenge.initiatorId, + participantId: consentVerifiedChallenge.participantId, + scopes: consentVerifiedChallenge.scopes, + credential: consentVerifiedChallenge.credential, }, - } + consentVerifiedChallenge.party.partyIdInfo.fspId + ) + }) + + it('Should log an error if mojaloop client throws error', async () => { + mojaloopClientSpy.mockImplementation(() => { + throw new Error('Client not connected') + }) await consentsHandler.onUpdate(server, consentVerifiedChallenge) @@ -302,33 +512,61 @@ describe('Handlers for consent documents in Firebase', () => { }, consentVerifiedChallenge.party.partyIdInfo.fspId ) + expect() }) }) describe('Request to Revoke Consent ', () => { - it('Should initiate consent revoke request when all necessary fields are set', async () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'postRevokeConsent') - .mockImplementation() - - const validatorSpy = jest - .spyOn(Validator, 'isValidRevokeConsent') - .mockReturnValue(true) - - // Mock the expected transaction request being sent. - const consentRevokeRequested = { - id: '111', - consentId: '2323', - party: { - partyIdInfo: { - partyIdType: PartyIdType.MSISDN, - partyIdentifier: '+1-222-222-2222', - fspId: 'fspb', - }, + // Mocked Methods + const mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postRevokeConsent') + .mockImplementation() + + const validatorSpy = jest + .spyOn(Validator, 'isValidRevokeConsent') + .mockReturnValue(true) + + // Mock the expected transaction request being sent. + const consentRevokeRequested = { + id: '111', + consentId: '2323', + party: { + partyIdInfo: { + partyIdType: PartyIdType.MSISDN, + partyIdentifier: '+1-222-222-2222', + fspId: 'fspb', }, - status: ConsentStatus.REVOKE_REQUESTED, - } + }, + status: ConsentStatus.REVOKE_REQUESTED, + } + + it('Should initiate consent revoke request when all necessary fields are set', async () => { + await consentsHandler.onUpdate(server, consentRevokeRequested) + + expect(validatorSpy).toBeCalledWith(consentRevokeRequested) + expect(mojaloopClientSpy).toBeCalledWith( + consentRevokeRequested.consentId, + consentRevokeRequested.party.partyIdInfo.fspId + ) + }) + + it('Should throw an error if Validator returns false', async () => { + validatorSpy.mockReturnValueOnce(false) + + await consentsHandler.onUpdate(server, consentRevokeRequested) + + expect(validatorSpy).toBeCalledWith(consentRevokeRequested) + expect(mojaloopClientSpy).toBeCalledWith( + consentRevokeRequested.consentId, + consentRevokeRequested.party.partyIdInfo.fspId + ) + }) + it('Should log an error if mojaloop client throws error', async () => { + mojaloopClientSpy.mockImplementation(() => { + throw new Error('Client not connected') + }) + await consentsHandler.onUpdate(server, consentRevokeRequested) expect(validatorSpy).toBeCalledWith(consentRevokeRequested) @@ -336,6 +574,7 @@ describe('Handlers for consent documents in Firebase', () => { consentRevokeRequested.consentId, consentRevokeRequested.party.partyIdInfo.fspId ) + expect() }) }) }) From 7e767077570ba65ae870b6827acb3fe7d2ecb107 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 8 Sep 2020 12:09:30 +0530 Subject: [PATCH 068/114] chore: bump @mojaloop/sdk-standard-components version to 11.5.1 --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index e925f307..6780a71a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2650,9 +2650,9 @@ } }, "@mojaloop/sdk-standard-components": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.5.0.tgz", - "integrity": "sha512-xmui3sf0Bo8V59vNqCm+aj+K8ZUMgRyyiTNrFHJqTZCRQRv+zSF2pU2Q/7VwRYA/OhU4ngETdzV9/M6Y7IGAKQ==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.5.1.tgz", + "integrity": "sha512-p6LaQnFsTKs8W+gIk0WFtofNTYfYXAB1Ncph0RHzEHNtZFzZoAY2NSS7Iyv+yWeTm36PmNe+wNfmjjaqlerIpA==", "requires": { "base64url": "3.0.1", "fast-safe-stringify": "^2.0.7", diff --git a/package.json b/package.json index 5aecc9b4..6609f928 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "@hapi/vision": "^6.0.0", "@mojaloop/central-services-logger": "^10.6.0", "@mojaloop/central-services-shared": "^11.3.2", - "@mojaloop/sdk-standard-components": "^11.5.0", + "@mojaloop/sdk-standard-components": "^11.5.1", "@types/uuid": "^8.0.0", "convict": "^6.0.0", "dotenv": "^8.2.0", From 253eebbfd2efcdb1f78d58737b11eb7b9e7cfa84 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 8 Sep 2020 12:34:30 +0530 Subject: [PATCH 069/114] refactor: switch to sdk-standard-components logger for mojaloop client --- src/shared/ml-thirdparty-client/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/ml-thirdparty-client/index.ts b/src/shared/ml-thirdparty-client/index.ts index b90b4ea0..b3b9ee37 100644 --- a/src/shared/ml-thirdparty-client/index.ts +++ b/src/shared/ml-thirdparty-client/index.ts @@ -35,11 +35,11 @@ import { } from './models/openapi' // import Logger from '@mojaloop/central-services-logger' -import { logger as Logger } from '~/shared/logger' +// import { logger as Logger } from '~/shared/logger' import SDKStandardComponents, { // TODO: Once implemented in sdk-standard-components, use this logger - // Logger, + Logger, ThirdpartyRequests, MojaloopRequests, } from '@mojaloop/sdk-standard-components' From a51a5c40f59ba8ca57577a742c96d5ceba2755a1 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 8 Sep 2020 12:37:00 +0530 Subject: [PATCH 070/114] chore: Remove unneeded TODOs and comments --- src/repositories/participants.ts | 1 - src/shared/ml-thirdparty-client/index.ts | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/repositories/participants.ts b/src/repositories/participants.ts index 88c31364..75892c33 100644 --- a/src/repositories/participants.ts +++ b/src/repositories/participants.ts @@ -40,7 +40,6 @@ export interface IParticipantRepository { } export class FirebaseParticipantRepository implements IParticipantRepository { - // TODO: Confirm data Type async replace(data: Participant[]): Promise { const collectionRef: FirebaseFirestore.CollectionReference = firebase .firestore() diff --git a/src/shared/ml-thirdparty-client/index.ts b/src/shared/ml-thirdparty-client/index.ts index b3b9ee37..e5f89f91 100644 --- a/src/shared/ml-thirdparty-client/index.ts +++ b/src/shared/ml-thirdparty-client/index.ts @@ -34,11 +34,7 @@ import { ThirdPartyTransactionRequest, } from './models/openapi' -// import Logger from '@mojaloop/central-services-logger' -// import { logger as Logger } from '~/shared/logger' - import SDKStandardComponents, { - // TODO: Once implemented in sdk-standard-components, use this logger Logger, ThirdpartyRequests, MojaloopRequests, From 09e33775ac0654c6afa9e1d5de98761794b206ba Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 8 Sep 2020 13:16:58 +0530 Subject: [PATCH 071/114] fix: Add error handling + remove unneeded comments --- src/server/handlers/firestore/consents.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 6ddf5f34..8cd9f354 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -61,12 +61,14 @@ async function handlePartyLookup(server: Server, consent: Consent) { } // Party is guaranteed to be non-null by the validator. - - server.app.mojaloopClient.getParties( - consent.party!.partyIdInfo.partyIdType, - consent.party!.partyIdInfo.partyIdentifier - ) - // } + try { + server.app.mojaloopClient.getParties( + consent.party!.partyIdInfo.partyIdType, + consent.party!.partyIdInfo.partyIdentifier + ) + } catch (error) { + logger.error(error) + } } async function handleAuthentication(server: Server, consent: Consent) { @@ -100,7 +102,6 @@ async function handleConsentRequest(server: Server, consent: Consent) { try { // The optional values are guaranteed to exist by the validator. - // eslint-disable @typescript-eslint/no-non-null-assertion server.app.mojaloopClient.postConsentRequests( { @@ -112,12 +113,9 @@ async function handleConsentRequest(server: Server, consent: Consent) { }, consent.party!.partyIdInfo.fspId as string ) - - // eslint-enable @typescript-eslint/no-non-null-assertion } catch (err) { logger.error(err) } - // } } async function handleChallengeGeneration(server: Server, consent: Consent) { From b31fce9497d4d2f70ad19712a17e16718ac5093f Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 8 Sep 2020 13:18:36 +0530 Subject: [PATCH 072/114] test: Add logger mocking and implement tests for client error --- .../handlers/firestore/consents.test.ts | 131 +++++++++++------- 1 file changed, 82 insertions(+), 49 deletions(-) diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index 5e45b8ed..c1e583cd 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -41,6 +41,7 @@ import SDKStandardComponents, { TAuthChannel, TCredentialScope, } from '@mojaloop/sdk-standard-components' +import { logger } from '~/shared/logger' // Mock firebase to prevent server from listening to the changes. jest.mock('~/lib/firebase') @@ -50,14 +51,18 @@ jest.mock('uuid', () => ({ v4: jest.fn().mockImplementation(() => '12345'), })) -// Mock utils to consistently return the provided value. -// jest.mock('~/shared/logger', () => ({ -// })) +// Mock logger to prevent handlers from logging incoming request +jest.mock('~/shared/logger', () => ({ + logger: { + error: jest.fn().mockImplementation(), + }, +})) const documentId = '111' describe('Handlers for consent documents in Firebase', () => { let server: Server + // let loggerErrorSpy: jest.SpyInstance beforeAll(async () => { server = await createServer(config) @@ -65,6 +70,7 @@ describe('Handlers for consent documents in Firebase', () => { beforeEach(() => { jest.clearAllMocks() + // loggerErrorSpy = jest.spyOn(logger, 'error') }) afterEach(() => { @@ -100,9 +106,7 @@ describe('Handlers for consent documents in Firebase', () => { describe('OnUpdate', () => { describe('Party Lookup', () => { // Mocked Methods - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'getParties') - .mockImplementation() + let mojaloopClientSpy: jest.SpyInstance const validatorSpy = jest .spyOn(Validator, 'isValidPartyLookup') @@ -122,6 +126,12 @@ describe('Handlers for consent documents in Firebase', () => { status: ConsentStatus.PENDING_PARTY_LOOKUP, } + beforeAll(() => { + mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'getParties') + .mockImplementation() + }) + it('Should perform party lookup when all necessary fields are set', async () => { await consentsHandler.onUpdate(server, consentPartyLookup) @@ -152,23 +162,22 @@ describe('Handlers for consent documents in Firebase', () => { expect(mojaloopClientSpy).not.toBeCalled() }) - it('Should throw an error if mojaloop client throws error', async () => { - mojaloopClientSpy.mockImplementation(() => { - throw new Error('Client not connected') + it('Should log an error if mojaloop client throws error', async () => { + const loggerErrorSpy = jest.spyOn(logger, 'error').mockImplementation() + mojaloopClientSpy.mockImplementationOnce(() => { + throw Error('Client not connected') }) await consentsHandler.onUpdate(server, consentPartyLookup) expect(validatorSpy).toBeCalledWith(consentPartyLookup) expect(mojaloopClientSpy).toBeCalledWith(PartyIdType.OPAQUE, 'bob1234') - expect() + expect(loggerErrorSpy).toBeCalledWith(new Error('Client not connected')) }) }) describe('Authentication', () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'putConsentRequests') - .mockImplementation() + let mojaloopClientSpy: jest.SpyInstance const validatorSpy = jest .spyOn(Validator, 'isValidAuthentication') @@ -216,6 +225,13 @@ describe('Handlers for consent documents in Firebase', () => { authToken: consentAuthentication.authToken as string, authUri: consentAuthentication.authUri as string, } + + beforeAll(() => { + mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'putConsentRequests') + .mockImplementation() + }) + it('Should initiate consent request request when all necessary fields are set', async () => { await consentsHandler.onUpdate(server, consentAuthentication) @@ -239,6 +255,7 @@ describe('Handlers for consent documents in Firebase', () => { }) it('Should log an error if mojaloop client throws error', async () => { + const loggerErrorSpy = jest.spyOn(logger, 'error').mockImplementation() mojaloopClientSpy.mockImplementation(() => { throw new Error('Client not connected') }) @@ -251,14 +268,12 @@ describe('Handlers for consent documents in Firebase', () => { consentAuthentication.party?.partyIdInfo.fspId ) expect(validatorSpy).toBeCalledWith(consentAuthentication) - expect() + expect(loggerErrorSpy).toBeCalledWith(new Error('Client not connected')) }) }) describe('Consent Request', () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'postConsentRequests') - .mockImplementation() + let mojaloopClientSpy: jest.SpyInstance const validatorSpy = jest .spyOn(Validator, 'isValidConsentRequest') @@ -303,6 +318,12 @@ describe('Handlers for consent documents in Firebase', () => { callbackUri: config.get('mojaloop').callbackUri, } + beforeAll(() => { + mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postConsentRequests') + .mockImplementation() + }) + it('Should initiate consent request request when all necessary fields are set', async () => { await consentsHandler.onUpdate(server, consentConsentRequest) @@ -325,6 +346,7 @@ describe('Handlers for consent documents in Firebase', () => { }) it('Should log an error if mojaloop client throws error', async () => { + const loggerErrorSpy = jest.spyOn(logger, 'error').mockImplementation() mojaloopClientSpy.mockImplementation(() => { throw new Error('Client not connected') }) @@ -336,15 +358,13 @@ describe('Handlers for consent documents in Firebase', () => { consentConsentRequest.party?.partyIdInfo.fspId ) expect(validatorSpy).toBeCalledWith(consentConsentRequest) - expect() + expect(loggerErrorSpy).toBeCalledWith(new Error('Client not connected')) }) }) describe('Challenge Generation Request', () => { // Mocked Methods - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'postGenerateChallengeForConsent') - .mockImplementation() + let mojaloopClientSpy: jest.SpyInstance const validatorSpy = jest .spyOn(Validator, 'isValidChallengeGeneration') @@ -380,6 +400,12 @@ describe('Handlers for consent documents in Firebase', () => { ], } + beforeAll(() => { + mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postGenerateChallengeForConsent') + .mockImplementation() + }) + it('Should initiate challenge generation request when all necessary fields are set', async () => { await consentsHandler.onUpdate(server, consentGenerateChallenge) @@ -393,13 +419,16 @@ describe('Handlers for consent documents in Firebase', () => { it('Should throw an error if Validator returns false', async () => { validatorSpy.mockReturnValueOnce(false) - await consentsHandler.onUpdate(server, consentGenerateChallenge) + await expect( + consentsHandler.onUpdate(server, consentGenerateChallenge) + ).rejects.toThrowError('Consent Object Missing Fields') expect(validatorSpy).toBeCalledWith(consentGenerateChallenge) expect(mojaloopClientSpy).not.toBeCalled() }) it('Should log an error if mojaloop client throws error', async () => { + const loggerErrorSpy = jest.spyOn(logger, 'error').mockImplementation() mojaloopClientSpy.mockImplementation(() => { throw new Error('Client not connected') }) @@ -411,14 +440,12 @@ describe('Handlers for consent documents in Firebase', () => { consentGenerateChallenge.consentId, consentGenerateChallenge.party?.partyIdInfo.fspId ) - expect() + expect(loggerErrorSpy).toBeCalledWith(new Error('Client not connected')) }) }) describe('Signed Challenge', () => { - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'putConsentId') - .mockImplementation() + let mojaloopClientSpy: jest.SpyInstance const validatorSpy = jest .spyOn(Validator, 'isValidSignedChallenge') @@ -459,6 +486,13 @@ describe('Handlers for consent documents in Firebase', () => { payload: 'string_representing_credential_payload', }, } + + beforeAll(() => { + mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'putConsentId') + .mockImplementation() + }) + it('Should initiate PUT consent/{ID} request when challenge has been signed and all necessary fields are set', async () => { await consentsHandler.onUpdate(server, consentVerifiedChallenge) @@ -477,23 +511,18 @@ describe('Handlers for consent documents in Firebase', () => { }) it('Should throw an error if Validator returns false', async () => { - await consentsHandler.onUpdate(server, consentVerifiedChallenge) + validatorSpy.mockReturnValueOnce(false) + + await expect( + consentsHandler.onUpdate(server, consentVerifiedChallenge) + ).rejects.toThrowError('Consent Object Missing Fields') expect(validatorSpy).toBeCalledWith(consentVerifiedChallenge) - expect(mojaloopClientSpy).toBeCalledWith( - consentVerifiedChallenge.consentId, - { - requestId: consentVerifiedChallenge.id, - initiatorId: consentVerifiedChallenge.initiatorId, - participantId: consentVerifiedChallenge.participantId, - scopes: consentVerifiedChallenge.scopes, - credential: consentVerifiedChallenge.credential, - }, - consentVerifiedChallenge.party.partyIdInfo.fspId - ) + expect(mojaloopClientSpy).not.toBeCalled() }) it('Should log an error if mojaloop client throws error', async () => { + const loggerErrorSpy = jest.spyOn(logger, 'error').mockImplementation() mojaloopClientSpy.mockImplementation(() => { throw new Error('Client not connected') }) @@ -512,15 +541,13 @@ describe('Handlers for consent documents in Firebase', () => { }, consentVerifiedChallenge.party.partyIdInfo.fspId ) - expect() + expect(loggerErrorSpy).toBeCalledWith(new Error('Client not connected')) }) }) describe('Request to Revoke Consent ', () => { // Mocked Methods - const mojaloopClientSpy = jest - .spyOn(server.app.mojaloopClient, 'postRevokeConsent') - .mockImplementation() + let mojaloopClientSpy: jest.SpyInstance const validatorSpy = jest .spyOn(Validator, 'isValidRevokeConsent') @@ -540,6 +567,12 @@ describe('Handlers for consent documents in Firebase', () => { status: ConsentStatus.REVOKE_REQUESTED, } + beforeAll(() => { + mojaloopClientSpy = jest + .spyOn(server.app.mojaloopClient, 'postRevokeConsent') + .mockImplementation() + }) + it('Should initiate consent revoke request when all necessary fields are set', async () => { await consentsHandler.onUpdate(server, consentRevokeRequested) @@ -553,20 +586,20 @@ describe('Handlers for consent documents in Firebase', () => { it('Should throw an error if Validator returns false', async () => { validatorSpy.mockReturnValueOnce(false) - await consentsHandler.onUpdate(server, consentRevokeRequested) + await expect( + consentsHandler.onUpdate(server, consentRevokeRequested) + ).rejects.toThrowError('Consent Object Missing Fields') expect(validatorSpy).toBeCalledWith(consentRevokeRequested) - expect(mojaloopClientSpy).toBeCalledWith( - consentRevokeRequested.consentId, - consentRevokeRequested.party.partyIdInfo.fspId - ) + expect(mojaloopClientSpy).not.toBeCalled() }) it('Should log an error if mojaloop client throws error', async () => { + const loggerErrorSpy = jest.spyOn(logger, 'error').mockImplementation() mojaloopClientSpy.mockImplementation(() => { throw new Error('Client not connected') }) - + await consentsHandler.onUpdate(server, consentRevokeRequested) expect(validatorSpy).toBeCalledWith(consentRevokeRequested) @@ -574,7 +607,7 @@ describe('Handlers for consent documents in Firebase', () => { consentRevokeRequested.consentId, consentRevokeRequested.party.partyIdInfo.fspId ) - expect() + expect(loggerErrorSpy).toBeCalledWith(new Error('Client not connected')) }) }) }) From e4ae20bcce3e1eacb10ec6512ad567975064fb76 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 8 Sep 2020 13:25:19 +0530 Subject: [PATCH 073/114] fix: linter warnings --- .../factories/participant.ts | 16 ++++++++-------- .../factories/transfer.ts | 13 ++++++++----- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/shared/ml-thirdparty-simulator/factories/participant.ts b/src/shared/ml-thirdparty-simulator/factories/participant.ts index d4f99dbd..e65709ec 100644 --- a/src/shared/ml-thirdparty-simulator/factories/participant.ts +++ b/src/shared/ml-thirdparty-simulator/factories/participant.ts @@ -34,12 +34,12 @@ export class ParticipantFactory { /** * Number of participants that will be generated by the simulator. The value * must be a positive integer. If not set, the default value is 10. - * - * Note that this variable must be set before `getParticipants()` is called, - * otherwise, changing the value will not have any effect since the list of + * + * Note that this variable must be set before `getParticipants()` is called, + * otherwise, changing the value will not have any effect since the list of * participants is stored within the `participants` field. */ - public static numOfParticipants: number = 10 + public static numOfParticipants = 10 /** * List of participants that is stored internally within the `ParticipantFactory`. @@ -49,7 +49,7 @@ export class ParticipantFactory { /** * Returns the list of participants for the simulator. * The participants will only be generated once when this function is called - * for the first time. Afterward, the list will be stored internally for + * for the first time. Afterward, the list will be stored internally for * subsequent usage. */ public static getParticipants() { @@ -60,11 +60,11 @@ export class ParticipantFactory { } private static createParticipants() { - for (var i = 0; i < ParticipantFactory.numOfParticipants; i++) { + for (let i = 0; i < ParticipantFactory.numOfParticipants; i++) { // Generate a random participant - let participant: Participant = { + const participant: Participant = { fspId: faker.finance.bic(), - name: faker.company.companyName() + name: faker.company.companyName(), } ParticipantFactory.participants.push(participant) diff --git a/src/shared/ml-thirdparty-simulator/factories/transfer.ts b/src/shared/ml-thirdparty-simulator/factories/transfer.ts index 2718da07..f889aa26 100644 --- a/src/shared/ml-thirdparty-simulator/factories/transfer.ts +++ b/src/shared/ml-thirdparty-simulator/factories/transfer.ts @@ -28,21 +28,24 @@ import * as faker from 'faker' import { AuthorizationsPutIdRequest, TransferIDPutRequest, -} from '~/shared/ml-thirdparty-client/models/openapi'; +} from '~/shared/ml-thirdparty-client/models/openapi' -import { TransferState } from '~/shared/ml-thirdparty-client/models/core'; +import { TransferState } from '~/shared/ml-thirdparty-client/models/core' export class TransferFactory { /** * Creates a `PUT /transfers/{ID}` request body that is normally sent * by Mojaloop as a callback to inform about the transfer result. - * + * * @param _ transaction request id of the corresponsing authorization. * @param __ an authorization object as defined by the Mojaloop API. * @param transactionId transaction id to be associated with the transfer object. */ - public static createTransferIdPutRequest(_: string, - __: AuthorizationsPutIdRequest, transactionId: string): TransferIDPutRequest { + public static createTransferIdPutRequest( + _: string, + __: AuthorizationsPutIdRequest, + transactionId: string + ): TransferIDPutRequest { return { transactionId, fulfilment: faker.random.alphaNumeric(43), From 21d7cb246060fc408b93624c170a64e2adad6e3a Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 8 Sep 2020 13:26:46 +0530 Subject: [PATCH 074/114] feat: Add flags to ignore testing for repository and factory methods --- src/repositories/consent.ts | 2 ++ src/repositories/participants.ts | 2 ++ src/repositories/transaction.ts | 2 ++ src/shared/ml-thirdparty-simulator/factories/consents.ts | 2 ++ src/shared/ml-thirdparty-simulator/factories/participant.ts | 2 ++ src/shared/ml-thirdparty-simulator/factories/party.ts | 3 +++ 6 files changed, 13 insertions(+) diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index d950c7aa..b7206bc4 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -24,6 +24,8 @@ ******/ /* eslint-disable @typescript-eslint/no-explicit-any */ +/* istanbul ignore file */ +// TODO: Testing will covered in separate ticket import firebase from '~/lib/firebase' import { Consent } from '~/models/consent' diff --git a/src/repositories/participants.ts b/src/repositories/participants.ts index 75892c33..8546715a 100644 --- a/src/repositories/participants.ts +++ b/src/repositories/participants.ts @@ -25,6 +25,8 @@ ******/ /* eslint-disable @typescript-eslint/no-explicit-any */ +/* istanbul ignore file */ +// TODO: Testing will covered in separate ticket import firebase from '~/lib/firebase' import { logger } from '~/shared/logger' diff --git a/src/repositories/transaction.ts b/src/repositories/transaction.ts index 333ee844..38dd19f5 100644 --- a/src/repositories/transaction.ts +++ b/src/repositories/transaction.ts @@ -24,6 +24,8 @@ ******/ /* eslint-disable @typescript-eslint/no-explicit-any */ +/* istanbul ignore file */ +// TODO: Testing will covered in separate ticket import firebase from '~/lib/firebase' import { logger } from '~/shared/logger' diff --git a/src/shared/ml-thirdparty-simulator/factories/consents.ts b/src/shared/ml-thirdparty-simulator/factories/consents.ts index e0538e71..4d427d6c 100644 --- a/src/shared/ml-thirdparty-simulator/factories/consents.ts +++ b/src/shared/ml-thirdparty-simulator/factories/consents.ts @@ -23,6 +23,8 @@ - Abhimanyu Kapur -------------- ******/ +/* istanbul ignore file */ +// TODO: Confirm if testing necessary for factory methods import * as faker from 'faker' diff --git a/src/shared/ml-thirdparty-simulator/factories/participant.ts b/src/shared/ml-thirdparty-simulator/factories/participant.ts index e65709ec..ea1ee4b4 100644 --- a/src/shared/ml-thirdparty-simulator/factories/participant.ts +++ b/src/shared/ml-thirdparty-simulator/factories/participant.ts @@ -22,6 +22,8 @@ - Steven Wijaya -------------- ******/ +/* istanbul ignore file */ +// TODO: Confirm if testing necessary for factory methods import * as faker from 'faker' diff --git a/src/shared/ml-thirdparty-simulator/factories/party.ts b/src/shared/ml-thirdparty-simulator/factories/party.ts index 724c09ec..fd00abe4 100644 --- a/src/shared/ml-thirdparty-simulator/factories/party.ts +++ b/src/shared/ml-thirdparty-simulator/factories/party.ts @@ -23,6 +23,9 @@ -------------- ******/ +/* istanbul ignore file */ +// TODO: Confirm if testing necessary for factory methods + import * as faker from 'faker' import { PartyIdType, Party, Account, Currency } from '~/shared/ml-thirdparty-client/models/core' import { PartiesTypeIDPutRequest } from '~/shared/ml-thirdparty-client/models/openapi' From 64b590a0add81d506e92dea64d8378182998691a Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 8 Sep 2020 14:01:39 +0530 Subject: [PATCH 075/114] refactor: Change ConsentStatus enum values according to linking diagrams --- src/models/consent.ts | 5 +++-- src/server/handlers/firestore/consents.ts | 4 ++-- src/server/handlers/openapi/mojaloop/consents.ts | 2 +- test/unit/server/handlers/firestore/consents.test.ts | 4 ++-- .../handlers/firestore/consents.validator.test.ts | 10 +++++----- .../server/handlers/openapi/mojaloop/consents.test.ts | 2 +- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/models/consent.ts b/src/models/consent.ts index e75abf14..3ecbf1e2 100644 --- a/src/models/consent.ts +++ b/src/models/consent.ts @@ -20,6 +20,7 @@ * Google - Steven Wijaya + - Abhimanyu Kapur -------------- ******/ @@ -50,7 +51,7 @@ export enum ConsentStatus { /** * The consent is granted and active. */ - ACTIVE = 'ACTIVE', + CONSENT_GRANTED = 'CONSENT_GRANTED', /** * The consent is ACTIVE and challenge has been generated @@ -60,7 +61,7 @@ export enum ConsentStatus { /** * The consent is ACTIVE and challenge has been verified */ - CHALLENGE_VERIFIED = 'CHALLENGE_VERIFIED', + ACTIVE = 'ACTIVE', /** * The consent is revoked and no longer valid. diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 8cd9f354..1fc6605b 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -210,11 +210,11 @@ export const onUpdate: ConsentHandler = async ( await handleAuthentication(server, consent) break - case ConsentStatus.ACTIVE: + case ConsentStatus.CONSENT_GRANTED: await handleChallengeGeneration(server, consent) break - case ConsentStatus.CHALLENGE_VERIFIED: + case ConsentStatus.ACTIVE: await handleSignedChallenge(server, consent) break diff --git a/src/server/handlers/openapi/mojaloop/consents.ts b/src/server/handlers/openapi/mojaloop/consents.ts index 1a5917cc..6a76d652 100644 --- a/src/server/handlers/openapi/mojaloop/consents.ts +++ b/src/server/handlers/openapi/mojaloop/consents.ts @@ -43,7 +43,7 @@ export const post: Handler = async ( initiatorId, participantId, scopes, - status: ConsentStatus.ACTIVE, + status: ConsentStatus.CONSENT_GRANTED, }) return h.response().code(202) } diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index c1e583cd..90094cbd 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -381,7 +381,7 @@ describe('Handlers for consent documents in Firebase', () => { fspId: 'fspb', }, }, - status: ConsentStatus.ACTIVE, + status: ConsentStatus.CONSENT_GRANTED, scopes: [ { accountId: 'as2342', @@ -474,7 +474,7 @@ describe('Handlers for consent documents in Firebase', () => { fspId: 'fspb', }, }, - status: ConsentStatus.CHALLENGE_VERIFIED, + status: ConsentStatus.ACTIVE, credential: { id: '9876', credentialType: 'FIDO' as const, diff --git a/test/unit/server/handlers/firestore/consents.validator.test.ts b/test/unit/server/handlers/firestore/consents.validator.test.ts index a0fd4c37..ad059777 100644 --- a/test/unit/server/handlers/firestore/consents.validator.test.ts +++ b/test/unit/server/handlers/firestore/consents.validator.test.ts @@ -436,7 +436,7 @@ describe('Validators for different consents used in requests', () => { id, consentId, party: partyWithFSPId, - status: ConsentStatus.ACTIVE, + status: ConsentStatus.CONSENT_GRANTED, scopes, consentRequestId, authChannels, @@ -457,7 +457,7 @@ describe('Validators for different consents used in requests', () => { consentRequestId, authChannels, accounts, - status: ConsentStatus.ACTIVE, + status: ConsentStatus.CONSENT_GRANTED, }) ).toBe(false) @@ -473,7 +473,7 @@ describe('Validators for different consents used in requests', () => { accounts, // @ts-ignore party: {}, - status: ConsentStatus.ACTIVE, + status: ConsentStatus.CONSENT_GRANTED, }) ).toBe(false) @@ -491,7 +491,7 @@ describe('Validators for different consents used in requests', () => { // @ts-ignore partyIdInfo: {}, }, - status: ConsentStatus.ACTIVE, + status: ConsentStatus.CONSENT_GRANTED, }) ).toBe(false) }) @@ -503,7 +503,7 @@ describe('Validators for different consents used in requests', () => { userId, initiatorId, party: partyWithFSPId, - status: ConsentStatus.ACTIVE, + status: ConsentStatus.CONSENT_GRANTED, }) ).toBe(false) }) diff --git a/test/unit/server/handlers/openapi/mojaloop/consents.test.ts b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts index 968edb4a..70078b38 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consents.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts @@ -121,7 +121,7 @@ describe('/consents', () => { initiatorId, participantId, scopes, - status: ConsentStatus.ACTIVE, + status: ConsentStatus.CONSENT_GRANTED, }) expect(response).toBe(202) From 52dfc3995a7f7d26824d00eb0a09fa1204ec500b Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 8 Sep 2020 14:21:02 +0530 Subject: [PATCH 076/114] test: Add unit tests for firestore consent handlers --- .../handlers/firestore/consents.test.ts | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index 90094cbd..acc265b4 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -78,12 +78,26 @@ describe('Handlers for consent documents in Firebase', () => { }) describe('OnCreate', () => { - it('Should set status and consentRequestId for new consent', () => { - const consentRepositorySpy = jest.spyOn( - consentRepository, - 'updateConsentById' - ) + // Set spies + const consentRepositorySpy = jest.spyOn( + consentRepository, + 'updateConsentById' + ) + + it('Should log an error and return, if status field exists', async () => { + const consentWithStatus = { + id: '111', + consentId: 'acv', + userId: 'bob123', + status: ConsentStatus.PENDING_PARTY_CONFIRMATION, + } + + await consentsHandler.onCreate(server, consentWithStatus) + + expect(consentRepositorySpy).not.toBeCalled() + }) + it('Should set status and consentRequestId for new consent', () => { consentsHandler.onCreate(server, { id: '111', userId: 'bob123', @@ -104,6 +118,21 @@ describe('Handlers for consent documents in Firebase', () => { }) describe('OnUpdate', () => { + it('Should log an error and return, if status field is missing', async () => { + const loggerErrorSpy = jest.spyOn(logger, 'error').mockImplementation() + const consentNoStatus = { + id: '111', + consentId: 'acv', + userId: 'bob123', + } + + await consentsHandler.onUpdate(server, consentNoStatus) + + expect(loggerErrorSpy).toBeCalledWith( + 'Invalid consent, undefined status.' + ) + }) + describe('Party Lookup', () => { // Mocked Methods let mojaloopClientSpy: jest.SpyInstance From 60113d4737c793387fa9221b53c10e1873d86c1d Mon Sep 17 00:00:00 2001 From: Abhimanyu Kapur <38531241+akapur99@users.noreply.github.com> Date: Tue, 8 Sep 2020 15:31:56 +0530 Subject: [PATCH 077/114] Update src/repositories/consent.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Marzec <2881004+eoln@users.noreply.github.com> --- src/repositories/consent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index b7206bc4..ca016fd5 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -54,7 +54,7 @@ export interface IConsentRepository { * @param data Document fields that are about to be updated. */ updateConsent( - conditions: Record, + conditions: Record, data: Record ): Promise } From 544d991d955addee98d5b4895115e38eb285bf38 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 9 Sep 2020 11:31:42 +0530 Subject: [PATCH 078/114] refactor: Remove disabling of any type and replace any with unknown in repositories --- src/repositories/consent.ts | 13 ++++++------- src/repositories/participants.ts | 1 - src/repositories/transaction.ts | 9 ++++----- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index b7206bc4..040584cb 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -23,7 +23,6 @@ -------------- ******/ -/* eslint-disable @typescript-eslint/no-explicit-any */ /* istanbul ignore file */ // TODO: Testing will covered in separate ticket @@ -38,7 +37,7 @@ export interface IConsentRepository { * @param id Id for the consent document that needs to be updated. * @param data Document fields that are about to be updated. */ - updateConsentById(id: string, data: Record): Promise + updateConsentById(id: string, data: Record): Promise /** * Retrieves a consent document based on its consent ID. @@ -54,8 +53,8 @@ export interface IConsentRepository { * @param data Document fields that are about to be updated. */ updateConsent( - conditions: Record, - data: Record + conditions: Record, + data: Record ): Promise } @@ -82,14 +81,14 @@ export class FirebaseConsentRepository implements IConsentRepository { async updateConsentById( id: string, - data: Record + data: Record ): Promise { await firebase.firestore().collection('consents').doc(id).update(data) } async updateConsent( - conditions: Record, - data: Record + conditions: Record, + data: Record ): Promise { let firestoreQuery: FirebaseFirestore.Query = firebase .firestore() diff --git a/src/repositories/participants.ts b/src/repositories/participants.ts index 8546715a..c764fc39 100644 --- a/src/repositories/participants.ts +++ b/src/repositories/participants.ts @@ -24,7 +24,6 @@ -------------- ******/ -/* eslint-disable @typescript-eslint/no-explicit-any */ /* istanbul ignore file */ // TODO: Testing will covered in separate ticket diff --git a/src/repositories/transaction.ts b/src/repositories/transaction.ts index 38dd19f5..53c6b0ca 100644 --- a/src/repositories/transaction.ts +++ b/src/repositories/transaction.ts @@ -23,7 +23,6 @@ -------------- ******/ -/* eslint-disable @typescript-eslint/no-explicit-any */ /* istanbul ignore file */ // TODO: Testing will covered in separate ticket @@ -37,7 +36,7 @@ export interface ITransactionRepository { * @param id Id for the transaction document that needs to be updated. * @param data Document fields that are about to be updated. */ - updateById(id: string, data: Record): Promise + updateById(id: string, data: Record): Promise /** * Updates one or more transaction documents based on the given conditions. @@ -46,13 +45,13 @@ export interface ITransactionRepository { * @param data Document fields that are about to be updated. */ update( - conditions: Record, - data: Record + conditions: Record, + data: Record ): Promise } export class FirebaseTransactionRepository implements ITransactionRepository { - async updateById(id: string, data: Record): Promise { + async updateById(id: string, data: Record): Promise { await firebase.firestore().collection('transactions').doc(id).update(data) } From 64ce4b67b9a86bc493ec631e628a8e2176ffb1a2 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 9 Sep 2020 11:39:55 +0530 Subject: [PATCH 079/114] refactor: Use enums when referencing http codes + update responseToolKit mocking --- .../openapi/mojaloop/authorizations.test.ts | 23 +++++++++++-------- .../mojaloop/consentRequests/{ID}.test.ts | 14 +++++++---- .../openapi/mojaloop/consents.test.ts | 13 +++++++---- .../openapi/mojaloop/consents/{ID}.test.ts | 15 ++++++++---- .../openapi/mojaloop/participants.test.ts | 13 +++++++---- .../mojaloop/parties/{Type}/{ID}.test.ts | 22 ++++++++++-------- .../openapi/mojaloop/transfers/{ID}.test.ts | 21 ++++++++++------- 7 files changed, 77 insertions(+), 44 deletions(-) diff --git a/test/unit/server/handlers/openapi/mojaloop/authorizations.test.ts b/test/unit/server/handlers/openapi/mojaloop/authorizations.test.ts index 55d8cee5..cf22cc66 100644 --- a/test/unit/server/handlers/openapi/mojaloop/authorizations.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/authorizations.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ /***** License -------------- @@ -25,6 +26,7 @@ import { ResponseToolkit, ResponseObject } from '@hapi/hapi' import { Context } from 'openapi-backend' +import { Enum } from '@mojaloop/central-services-shared' import { PartyFactory } from '~/shared/ml-thirdparty-simulator/factories/party' @@ -54,15 +56,18 @@ jest.mock('~/lib/firebase') const mockRequest = jest.fn().mockImplementation() -const mockResponseToolkit = { +// @ts-ignore +const mockResponseToolkit: ResponseToolkit = { response: (): ResponseObject => { - return { + return ({ code: (num: number): ResponseObject => { - return num as unknown as ResponseObject - } - } as unknown as ResponseObject - } -} as unknown as ResponseToolkit + return ({ + statusCode: num, + } as unknown) as ResponseObject + }, + } as unknown) as ResponseObject + }, +} /** * Mock data for transaction request. @@ -129,7 +134,7 @@ describe('/authorizations', () => { .spyOn(transactionRepository, 'update') .mockImplementation() - it('Should return 200 and update data in Firebase', async () => { + it('Should return 202 and update data in Firebase', async () => { const response = await Authorizations.post( context, mockRequest, @@ -151,7 +156,7 @@ describe('/authorizations', () => { } ) - expect(response).toBe(202) + expect(response.statusCode).toBe(Enum.Http.ReturnCodes.ACCEPTED.CODE) }) }) }) diff --git a/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts b/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts index 9a7476ed..4262dd99 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ /***** License -------------- @@ -27,6 +28,7 @@ import { ResponseToolkit, ResponseObject } from '@hapi/hapi' import { consentRepository } from '~/repositories/consent' import { Context } from 'openapi-backend' +import { Enum } from '@mojaloop/central-services-shared' import * as ConsentHandlers from '~/server/handlers/openapi/mojaloop/consentRequests/{ID}' @@ -50,16 +52,18 @@ jest.mock('~/lib/firebase') const mockRequest = jest.fn().mockImplementation() -const mockResponseToolkit = ({ +// @ts-ignore +const mockResponseToolkit: ResponseToolkit = { response: (): ResponseObject => { return ({ code: (num: number): ResponseObject => { - return (num as unknown) as ResponseObject + return ({ + statusCode: num, + } as unknown) as ResponseObject }, } as unknown) as ResponseObject }, -} as unknown) as ResponseToolkit - +} const postConsentRequestRequest: SDKStandardComponents.PostConsentRequestsRequest = { id: '111', initiatorId: 'pispA', @@ -119,7 +123,7 @@ describe('/consentRequests/{ID}', () => { status: ConsentStatus.AUTHENTICATION_REQUIRED, }) - expect(response).toBe(200) + expect(response.statusCode).toBe(Enum.Http.ReturnCodes.OK.CODE) }) }) }) diff --git a/test/unit/server/handlers/openapi/mojaloop/consents.test.ts b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts index 70078b38..da6f4597 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consents.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ /***** License -------------- @@ -27,6 +28,7 @@ import { ResponseToolkit, ResponseObject } from '@hapi/hapi' import { consentRepository } from '~/repositories/consent' import { Context } from 'openapi-backend' +import { Enum } from '@mojaloop/central-services-shared' import * as ConsentHandlers from '~/server/handlers/openapi/mojaloop/consents' @@ -50,15 +52,18 @@ jest.mock('~/lib/firebase') const mockRequest = jest.fn().mockImplementation() -const mockResponseToolkit = ({ +// @ts-ignore +const mockResponseToolkit: ResponseToolkit = { response: (): ResponseObject => { return ({ code: (num: number): ResponseObject => { - return (num as unknown) as ResponseObject + return ({ + statusCode: num, + } as unknown) as ResponseObject }, } as unknown) as ResponseObject }, -} as unknown) as ResponseToolkit +} const consentRequestId = '111' @@ -124,7 +129,7 @@ describe('/consents', () => { status: ConsentStatus.CONSENT_GRANTED, }) - expect(response).toBe(202) + expect(response.statusCode).toBe(Enum.Http.ReturnCodes.ACCEPTED.CODE) }) }) }) diff --git a/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts b/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts index c1b7beb5..f45c0dfd 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consents/{ID}.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ /***** License -------------- @@ -27,6 +28,7 @@ import { ResponseToolkit, ResponseObject } from '@hapi/hapi' import { consentRepository } from '~/repositories/consent' import { Context } from 'openapi-backend' +import { Enum } from '@mojaloop/central-services-shared' import * as ConsentHandlers from '~/server/handlers/openapi/mojaloop/consents/{ID}' @@ -48,15 +50,18 @@ jest.mock('~/lib/firebase') const mockRequest = jest.fn().mockImplementation() -const mockResponseToolkit = ({ +// @ts-ignore +const mockResponseToolkit: ResponseToolkit = { response: (): ResponseObject => { return ({ code: (num: number): ResponseObject => { - return (num as unknown) as ResponseObject + return ({ + statusCode: num, + } as unknown) as ResponseObject }, } as unknown) as ResponseObject }, -} as unknown) as ResponseToolkit +} describe('/consents/{ID}', () => { beforeEach(() => { @@ -95,7 +100,7 @@ describe('/consents/{ID}', () => { requestBody ) - expect(response).toBe(200) + expect(response.statusCode).toBe(Enum.Http.ReturnCodes.OK.CODE) }) }) @@ -130,7 +135,7 @@ describe('/consents/{ID}', () => { requestBody ) - expect(response).toBe(200) + expect(response.statusCode).toBe(Enum.Http.ReturnCodes.OK.CODE) }) }) }) diff --git a/test/unit/server/handlers/openapi/mojaloop/participants.test.ts b/test/unit/server/handlers/openapi/mojaloop/participants.test.ts index 88dfc68a..3e8af26b 100644 --- a/test/unit/server/handlers/openapi/mojaloop/participants.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/participants.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ /***** License -------------- @@ -27,6 +28,7 @@ import { ResponseToolkit, ResponseObject } from '@hapi/hapi' import { participantRepository } from '~/repositories/participants' import { Context } from 'openapi-backend' +import { Enum } from '@mojaloop/central-services-shared' import * as ParticipantHandlers from '~/server/handlers/openapi/mojaloop/participants' @@ -48,15 +50,18 @@ jest.mock('~/lib/firebase') const mockRequest = jest.fn().mockImplementation() -const mockResponseToolkit = ({ +// @ts-ignore +const mockResponseToolkit: ResponseToolkit = { response: (): ResponseObject => { return ({ code: (num: number): ResponseObject => { - return (num as unknown) as ResponseObject + return ({ + statusCode: num, + } as unknown) as ResponseObject }, } as unknown) as ResponseObject }, -} as unknown) as ResponseToolkit +} describe('/parties/{Type}/{ID}', () => { beforeEach(() => { @@ -92,7 +97,7 @@ describe('/parties/{Type}/{ID}', () => { expect(participantRepositorySpy).toBeCalledWith(requestBody.participants) - expect(response).toBe(200) + expect(response.statusCode).toBe(Enum.Http.ReturnCodes.OK.CODE) }) }) }) diff --git a/test/unit/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.test.ts b/test/unit/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.test.ts index c37a83f5..e876b659 100644 --- a/test/unit/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ /***** License -------------- @@ -27,6 +28,7 @@ import { ResponseToolkit, ResponseObject } from '@hapi/hapi' import { PartyFactory } from '~/shared/ml-thirdparty-simulator/factories/party' import { PartyIdType } from '~/shared/ml-thirdparty-client/models/core' +import { Enum } from '@mojaloop/central-services-shared' import { transactionRepository } from '~/repositories/transaction' import * as PartiesByTypeAndIdHandlers from '~/server/handlers/openapi/mojaloop/parties/{Type}/{ID}' @@ -51,16 +53,18 @@ jest.mock('~/lib/firebase') const mockRequest = jest.fn().mockImplementation() -const mockResponseToolkit = { +// @ts-ignore +const mockResponseToolkit: ResponseToolkit = { response: (): ResponseObject => { - return { + return ({ code: (num: number): ResponseObject => { - return num as unknown as ResponseObject - } - } as unknown as ResponseObject - } -} as unknown as ResponseToolkit - + return ({ + statusCode: num, + } as unknown) as ResponseObject + }, + } as unknown) as ResponseObject + }, +} describe('/parties/{Type}/{ID}', () => { beforeEach(() => { jest.clearAllMocks() @@ -102,7 +106,7 @@ describe('/parties/{Type}/{ID}', () => { } ) - expect(response).toBe(200) + expect(response.statusCode).toBe(Enum.Http.ReturnCodes.OK.CODE) }) }) }) diff --git a/test/unit/server/handlers/openapi/mojaloop/transfers/{ID}.test.ts b/test/unit/server/handlers/openapi/mojaloop/transfers/{ID}.test.ts index d0bcde2b..ba45ab05 100644 --- a/test/unit/server/handlers/openapi/mojaloop/transfers/{ID}.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/transfers/{ID}.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ /***** License -------------- @@ -25,6 +26,7 @@ import { ResponseToolkit, ResponseObject } from '@hapi/hapi' import { Context } from 'openapi-backend' +import { Enum } from '@mojaloop/central-services-shared' import { AuthenticationResponseType, AuthenticationType } from '~/shared/ml-thirdparty-client/models/core' import { AuthorizationsPutIdRequest } from '~/shared/ml-thirdparty-client/models/openapi' @@ -50,15 +52,18 @@ jest.mock('~/lib/firebase') const mockRequest = jest.fn().mockImplementation() -const mockResponseToolkit = { +// @ts-ignore +const mockResponseToolkit: ResponseToolkit = { response: (): ResponseObject => { - return { + return ({ code: (num: number): ResponseObject => { - return num as unknown as ResponseObject - } - } as unknown as ResponseObject - } -} as unknown as ResponseToolkit + return ({ + statusCode: num, + } as unknown) as ResponseObject + }, + } as unknown) as ResponseObject + }, +} describe('/transfers/{ID}', () => { beforeEach(() => { @@ -107,7 +112,7 @@ describe('/transfers/{ID}', () => { } ) - expect(response).toBe(200) + expect(response.statusCode).toBe(Enum.Http.ReturnCodes.OK.CODE) }) }) }) From a54c40e72f1b2c7e31f16b86f37a8d246f21aee7 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 9 Sep 2020 12:13:35 +0530 Subject: [PATCH 080/114] feat: update ambient.d.ts --- ambient.d.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ambient.d.ts b/ambient.d.ts index e74c770a..9bffadc5 100644 --- a/ambient.d.ts +++ b/ambient.d.ts @@ -26,13 +26,17 @@ declare module '@mojaloop/central-services-shared' -// declare module '@hapi/hapi' { -// import { Client } from '~/shared/ml-thirdparty-client' +declare module '@hapi/hapi' { + import { Client } from '~/shared/ml-thirdparty-client' -// interface ServerApplicationState { -// mojaloopClient: Client -// } -// } + interface ServerApplicationState { + mojaloopClient: Client + } + + interface Server { + app: ServerApplicationState + } +} // declare module '@mojaloop/sdk-standard-components' { // interface response { From c3e5940f6ce6dd8f96679fb0c3f5e7b4724dd5ef Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 9 Sep 2020 12:13:51 +0530 Subject: [PATCH 081/114] feat: utilize new error classes --- src/server/handlers/firestore/consents.ts | 13 +++++++------ .../server/handlers/firestore/consents.test.ts | 17 +++++++++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 1fc6605b..0f56c5a6 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -42,6 +42,7 @@ import { TCredential, } from '@mojaloop/sdk-standard-components' import config from '~/lib/config' +import { MissingConsentFieldsError } from '~/models/errors' async function handleNewConsent(_: Server, consent: Consent) { // Assign a consentRequestId to the document and set the initial @@ -57,7 +58,7 @@ async function handlePartyLookup(server: Server, consent: Consent) { // Check whether the consent document has all the necessary properties // to perform a party lookup. if (!validator.isValidPartyLookup(consent)) { - throw new Error('Consent Object Missing Fields') + throw new MissingConsentFieldsError(consent) } // Party is guaranteed to be non-null by the validator. @@ -73,7 +74,7 @@ async function handlePartyLookup(server: Server, consent: Consent) { async function handleAuthentication(server: Server, consent: Consent) { if (!validator.isValidAuthentication(consent)) { - throw new Error('Consent Object Missing Fields') + throw new MissingConsentFieldsError(consent) } try { @@ -96,7 +97,7 @@ async function handleAuthentication(server: Server, consent: Consent) { async function handleConsentRequest(server: Server, consent: Consent) { if (!validator.isValidConsentRequest(consent)) { - throw new Error('Consent Object Missing Fields') + throw new MissingConsentFieldsError(consent) } // If the update contains all the necessary fields, process document @@ -120,7 +121,7 @@ async function handleConsentRequest(server: Server, consent: Consent) { async function handleChallengeGeneration(server: Server, consent: Consent) { if (!validator.isValidChallengeGeneration(consent)) { - throw new Error('Consent Object Missing Fields') + throw new MissingConsentFieldsError(consent) } try { @@ -135,7 +136,7 @@ async function handleChallengeGeneration(server: Server, consent: Consent) { async function handleSignedChallenge(server: Server, consent: Consent) { if (!validator.isValidSignedChallenge(consent)) { - throw new Error('Consent Object Missing Fields') + throw new MissingConsentFieldsError(consent) } try { @@ -157,7 +158,7 @@ async function handleSignedChallenge(server: Server, consent: Consent) { async function handleRevokingConsent(server: Server, consent: Consent) { if (!validator.isValidRevokeConsent(consent)) { - throw new Error('Consent Object Missing Fields') + throw new MissingConsentFieldsError(consent) } try { diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index acc265b4..1cc43134 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -42,6 +42,7 @@ import SDKStandardComponents, { TCredentialScope, } from '@mojaloop/sdk-standard-components' import { logger } from '~/shared/logger' +import { MissingConsentFieldsError } from '~/models/errors' // Mock firebase to prevent server from listening to the changes. jest.mock('~/lib/firebase') @@ -185,7 +186,7 @@ describe('Handlers for consent documents in Firebase', () => { await expect( consentsHandler.onUpdate(server, consentPartyLookup) - ).rejects.toThrowError('Consent Object Missing Fields') + ).rejects.toThrow(new MissingConsentFieldsError(consentPartyLookup)) expect(validatorSpy).toBeCalledWith(consentPartyLookup) expect(mojaloopClientSpy).not.toBeCalled() @@ -277,7 +278,7 @@ describe('Handlers for consent documents in Firebase', () => { await expect( consentsHandler.onUpdate(server, consentAuthentication) - ).rejects.toThrowError('Consent Object Missing Fields') + ).rejects.toThrow(new MissingConsentFieldsError(consentAuthentication)) expect(validatorSpy).toBeCalledWith(consentAuthentication) expect(mojaloopClientSpy).not.toBeCalled() @@ -368,7 +369,7 @@ describe('Handlers for consent documents in Firebase', () => { await expect( consentsHandler.onUpdate(server, consentConsentRequest) - ).rejects.toThrowError('Consent Object Missing Fields') + ).rejects.toThrow(new MissingConsentFieldsError(consentConsentRequest)) expect(validatorSpy).toBeCalledWith(consentConsentRequest) expect(mojaloopClientSpy).not.toBeCalled() @@ -450,7 +451,9 @@ describe('Handlers for consent documents in Firebase', () => { await expect( consentsHandler.onUpdate(server, consentGenerateChallenge) - ).rejects.toThrowError('Consent Object Missing Fields') + ).rejects.toThrow( + new MissingConsentFieldsError(consentGenerateChallenge) + ) expect(validatorSpy).toBeCalledWith(consentGenerateChallenge) expect(mojaloopClientSpy).not.toBeCalled() @@ -544,7 +547,9 @@ describe('Handlers for consent documents in Firebase', () => { await expect( consentsHandler.onUpdate(server, consentVerifiedChallenge) - ).rejects.toThrowError('Consent Object Missing Fields') + ).rejects.toThrow( + new MissingConsentFieldsError(consentVerifiedChallenge) + ) expect(validatorSpy).toBeCalledWith(consentVerifiedChallenge) expect(mojaloopClientSpy).not.toBeCalled() @@ -617,7 +622,7 @@ describe('Handlers for consent documents in Firebase', () => { await expect( consentsHandler.onUpdate(server, consentRevokeRequested) - ).rejects.toThrowError('Consent Object Missing Fields') + ).rejects.toThrow(new MissingConsentFieldsError(consentRevokeRequested)) expect(validatorSpy).toBeCalledWith(consentRevokeRequested) expect(mojaloopClientSpy).not.toBeCalled() From d33bacc6dad932cca669b6188d2840e68d35b3fc Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 9 Sep 2020 12:18:59 +0530 Subject: [PATCH 082/114] fix: remove incorrect declaration --- ambient.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ambient.d.ts b/ambient.d.ts index 9bffadc5..e239801e 100644 --- a/ambient.d.ts +++ b/ambient.d.ts @@ -33,9 +33,9 @@ declare module '@hapi/hapi' { mojaloopClient: Client } - interface Server { - app: ServerApplicationState - } + // interface Server { + // app: ServerApplicationState + // } } // declare module '@mojaloop/sdk-standard-components' { From 944f0a55e3bf54cdcb9536c407bfcb9b6a1697ac Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 9 Sep 2020 12:19:13 +0530 Subject: [PATCH 083/114] fix: change any to unknown type --- src/repositories/transaction.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/repositories/transaction.ts b/src/repositories/transaction.ts index 53c6b0ca..2f6d92f9 100644 --- a/src/repositories/transaction.ts +++ b/src/repositories/transaction.ts @@ -56,8 +56,8 @@ export class FirebaseTransactionRepository implements ITransactionRepository { } async update( - conditions: Record, - data: Record + conditions: Record, + data: Record ): Promise { let firestoreQuery: FirebaseFirestore.Query = firebase .firestore() From c7992b17218dfd0e06521d308ee981eedeb91ade Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 9 Sep 2020 12:33:51 +0530 Subject: [PATCH 084/114] refactor: undo previous changes If this doesn't work - revert all ambient.d.ts changes and start from scratch --- ambient.d.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ambient.d.ts b/ambient.d.ts index e239801e..bb6c4b59 100644 --- a/ambient.d.ts +++ b/ambient.d.ts @@ -26,17 +26,17 @@ declare module '@mojaloop/central-services-shared' -declare module '@hapi/hapi' { - import { Client } from '~/shared/ml-thirdparty-client' +// declare module '@hapi/hapi' { +// import { Client } from '~/shared/ml-thirdparty-client' - interface ServerApplicationState { - mojaloopClient: Client - } +// interface ServerApplicationState { +// mojaloopClient: Client +// } - // interface Server { - // app: ServerApplicationState - // } -} +// // interface Server { +// // app: ServerApplicationState +// // } +// } // declare module '@mojaloop/sdk-standard-components' { // interface response { From 1b7e717d4522f79f8af6e899c1768e6e746ceaed Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 9 Sep 2020 16:51:00 +0530 Subject: [PATCH 085/114] fix: Remove unnecessary `await` usage --- src/repositories/consent.ts | 2 +- src/repositories/participants.ts | 2 +- src/repositories/transaction.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index 040584cb..017f5202 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -100,7 +100,7 @@ export class FirebaseConsentRepository implements IConsentRepository { } // Find and update all matching documents in Firebase that match the given conditions. - await firestoreQuery + firestoreQuery .get() .then((response) => { // Create a batch to perform all of the updates using a single request. diff --git a/src/repositories/participants.ts b/src/repositories/participants.ts index c764fc39..6efb53c6 100644 --- a/src/repositories/participants.ts +++ b/src/repositories/participants.ts @@ -47,7 +47,7 @@ export class FirebaseParticipantRepository implements IParticipantRepository { .collection('participants') // Find and update all matching documents in Firebase that match the given conditions. - await collectionRef + collectionRef .get() .then(async (response) => { // Create a batch to perform all of the updates using a single request. diff --git a/src/repositories/transaction.ts b/src/repositories/transaction.ts index 2f6d92f9..1458de25 100644 --- a/src/repositories/transaction.ts +++ b/src/repositories/transaction.ts @@ -69,7 +69,7 @@ export class FirebaseTransactionRepository implements ITransactionRepository { } // Find and update all matching documents in Firebase that match the given conditions. - await firestoreQuery + firestoreQuery .get() .then((response) => { // Create a batch to perform all of the updates using a single request. From bcea9d037e4920258892e80971ebc35acc968cb0 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Wed, 9 Sep 2020 16:51:21 +0530 Subject: [PATCH 086/114] fix: Declaration and import issues in ambient.d.ts --- ambient.d.ts | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/ambient.d.ts b/ambient.d.ts index bb6c4b59..a62347cd 100644 --- a/ambient.d.ts +++ b/ambient.d.ts @@ -24,24 +24,20 @@ -------------- ******/ -declare module '@mojaloop/central-services-shared' - -// declare module '@hapi/hapi' { -// import { Client } from '~/shared/ml-thirdparty-client' +declare type Client = import('~/shared/ml-thirdparty-client').Client -// interface ServerApplicationState { -// mojaloopClient: Client -// } +declare module '@mojaloop/central-services-shared' -// // interface Server { -// // app: ServerApplicationState -// // } -// } +declare module '@hapi/hapi' { + interface ServerApplicationState { + mojaloopClient: Client + } +} -// declare module '@mojaloop/sdk-standard-components' { -// interface response { -// statusCode: number -// headers: Record -// data: Record -// } -// } +declare module '@mojaloop/sdk-standard-components' { + interface response { + statusCode: number + headers: Record + data: Record + } +} From 32bd566b2c537ea40c48a8608349bcbbc98f80a3 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Thu, 10 Sep 2020 13:05:23 +0530 Subject: [PATCH 087/114] feat: Create declarations.d.ts file and add to tsconfig --- ambient.d.ts | 4 +--- declarations.d.ts | 27 +++++++++++++++++++++++++++ tsconfig.build.json | 1 + tsconfig.json | 1 + 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 declarations.d.ts diff --git a/ambient.d.ts b/ambient.d.ts index a62347cd..f7cd8cc4 100644 --- a/ambient.d.ts +++ b/ambient.d.ts @@ -24,9 +24,7 @@ -------------- ******/ -declare type Client = import('~/shared/ml-thirdparty-client').Client - -declare module '@mojaloop/central-services-shared' +import { Client } from '~/shared/ml-thirdparty-client' declare module '@hapi/hapi' { interface ServerApplicationState { diff --git a/declarations.d.ts b/declarations.d.ts new file mode 100644 index 00000000..d3140015 --- /dev/null +++ b/declarations.d.ts @@ -0,0 +1,27 @@ +/***** + License + -------------- + Copyright © 2020 Mojaloop Foundation + The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + Contributors + -------------- + This is the official list of the Mojaloop project contributors for this file. + Names of the original copyright holders (individuals or organizations) + should be listed with a '*' in the first column. People who have + contributed from an organization can be listed under the organization + that actually holds the copyright for their contributions (see the + Mojaloop Foundation organization for an example). Those individuals should have + their names indented and be marked with a '-'. Email address can be added + optionally within square brackets . + * Mojaloop Foundation + - Name Surname + + * Google + - Steven Wijaya + - Abhimanyu Kapur + -------------- + ******/ + +declare module '@mojaloop/central-services-shared' diff --git a/tsconfig.build.json b/tsconfig.build.json index 177ebb00..62827276 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -3,6 +3,7 @@ "include": [ "src", "ambient.d.ts", + "declarations.d.ts", ], "exclude": [ "coverage", diff --git a/tsconfig.json b/tsconfig.json index 43ef6cf7..9a9bdbd0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,7 @@ "include": [ "src", "test", + "declarations.d.ts", "ambient.d.ts", "commitlint.config.js", "jest.bdd.config.js", From 34caefccc3b29ddc63c445e1c0440a4cbb52b5e5 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Fri, 11 Sep 2020 13:42:27 +0530 Subject: [PATCH 088/114] chore: bump sdk-standard-components to v 11.5.2 + audit fix --- package-lock.json | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6780a71a..e521ce1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2650,9 +2650,9 @@ } }, "@mojaloop/sdk-standard-components": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.5.1.tgz", - "integrity": "sha512-p6LaQnFsTKs8W+gIk0WFtofNTYfYXAB1Ncph0RHzEHNtZFzZoAY2NSS7Iyv+yWeTm36PmNe+wNfmjjaqlerIpA==", + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.5.2.tgz", + "integrity": "sha512-CZWXJlMFQo9TMQtwQuQu7sFO/ajY6FrUNhnxjaN/rz6zcX+fofvy7W6DENz3LKqSKiF9n5wljzZPzIIVtVA6gQ==", "requires": { "base64url": "3.0.1", "fast-safe-stringify": "^2.0.7", @@ -14155,9 +14155,9 @@ } }, "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", "optional": true }, "node-forge": { diff --git a/package.json b/package.json index 6609f928..ac5987c3 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "@hapi/vision": "^6.0.0", "@mojaloop/central-services-logger": "^10.6.0", "@mojaloop/central-services-shared": "^11.3.2", - "@mojaloop/sdk-standard-components": "^11.5.1", + "@mojaloop/sdk-standard-components": "^11.5.2", "@types/uuid": "^8.0.0", "convict": "^6.0.0", "dotenv": "^8.2.0", From 363e0c765226631eb2bc34681fddf2fb64fb194d Mon Sep 17 00:00:00 2001 From: akapur99 Date: Fri, 11 Sep 2020 14:33:45 +0530 Subject: [PATCH 089/114] refactor: firestore consent handlers - to follow new StateServer interface --- src/server/handlers/firestore/consents.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 0f56c5a6..ce40d187 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -27,8 +27,6 @@ ******/ import * as uuid from 'uuid' -import { Server } from '@hapi/hapi' - import { logger } from '~/shared/logger' import { ConsentHandler } from '~/server/plugins/internal/firestore' @@ -44,7 +42,7 @@ import { import config from '~/lib/config' import { MissingConsentFieldsError } from '~/models/errors' -async function handleNewConsent(_: Server, consent: Consent) { +async function handleNewConsent(_: StateServer, consent: Consent) { // Assign a consentRequestId to the document and set the initial // status. This operation will create an event that triggers the execution // of the onUpdate function. @@ -54,7 +52,7 @@ async function handleNewConsent(_: Server, consent: Consent) { }) } -async function handlePartyLookup(server: Server, consent: Consent) { +async function handlePartyLookup(server: StateServer, consent: Consent) { // Check whether the consent document has all the necessary properties // to perform a party lookup. if (!validator.isValidPartyLookup(consent)) { @@ -72,7 +70,7 @@ async function handlePartyLookup(server: Server, consent: Consent) { } } -async function handleAuthentication(server: Server, consent: Consent) { +async function handleAuthentication(server: StateServer, consent: Consent) { if (!validator.isValidAuthentication(consent)) { throw new MissingConsentFieldsError(consent) } @@ -95,7 +93,7 @@ async function handleAuthentication(server: Server, consent: Consent) { } } -async function handleConsentRequest(server: Server, consent: Consent) { +async function handleConsentRequest(server: StateServer, consent: Consent) { if (!validator.isValidConsentRequest(consent)) { throw new MissingConsentFieldsError(consent) } @@ -119,7 +117,7 @@ async function handleConsentRequest(server: Server, consent: Consent) { } } -async function handleChallengeGeneration(server: Server, consent: Consent) { +async function handleChallengeGeneration(server: StateServer, consent: Consent) { if (!validator.isValidChallengeGeneration(consent)) { throw new MissingConsentFieldsError(consent) } @@ -134,7 +132,7 @@ async function handleChallengeGeneration(server: Server, consent: Consent) { } } -async function handleSignedChallenge(server: Server, consent: Consent) { +async function handleSignedChallenge(server: StateServer, consent: Consent) { if (!validator.isValidSignedChallenge(consent)) { throw new MissingConsentFieldsError(consent) } @@ -156,7 +154,7 @@ async function handleSignedChallenge(server: Server, consent: Consent) { } } -async function handleRevokingConsent(server: Server, consent: Consent) { +async function handleRevokingConsent(server: StateServer, consent: Consent) { if (!validator.isValidRevokeConsent(consent)) { throw new MissingConsentFieldsError(consent) } @@ -173,7 +171,7 @@ async function handleRevokingConsent(server: Server, consent: Consent) { } export const onCreate: ConsentHandler = async ( - server: Server, + server: StateServer, consent: Consent ): Promise => { if (consent.status) { @@ -188,7 +186,7 @@ export const onCreate: ConsentHandler = async ( } export const onUpdate: ConsentHandler = async ( - server: Server, + server: StateServer, consent: Consent ): Promise => { if (!consent.status) { From 165439e4666f72f559ff50f698015ed15be2d08f Mon Sep 17 00:00:00 2001 From: akapur99 Date: Fri, 11 Sep 2020 14:44:36 +0530 Subject: [PATCH 090/114] refactor: tests and files to follow new ambient declaration of StateServer --- src/server/run.ts | 5 ++--- test/unit/index.test.ts | 5 ++--- test/unit/server/handlers/firestore/consents.test.ts | 4 +--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/server/run.ts b/src/server/run.ts index cccc4d92..78e5a43e 100644 --- a/src/server/run.ts +++ b/src/server/run.ts @@ -23,12 +23,11 @@ -------------- ******/ -import { Server } from '@hapi/hapi' import { ServiceConfig } from '../lib/config' import create from './create' import start from './start' -export default async function run(config: ServiceConfig): Promise { +export default async function run(config: ServiceConfig): Promise { const server = await create(config) - return start(server) + return start(server) as Promise } diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index 8579f2b4..7927ed76 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -25,7 +25,6 @@ import index from '~/index' import Config from '~/lib/config' -import { Server } from '@hapi/hapi' // Mock firebase to prevent server from listening to the changes. jest.mock('~/lib/firebase') @@ -37,10 +36,10 @@ describe('index', (): void => { }) describe('api routes', (): void => { - let server: Server + let server: StateServer beforeAll( - async (): Promise => { + async (): Promise => { server = await index.server.run(Config) return server } diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index 1cc43134..9bdb8303 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -23,8 +23,6 @@ -------------- ******/ -import { Server } from '@hapi/hapi' - import config from '~/lib/config' import createServer from '~/server/create' @@ -62,7 +60,7 @@ jest.mock('~/shared/logger', () => ({ const documentId = '111' describe('Handlers for consent documents in Firebase', () => { - let server: Server + let server: StateServer // let loggerErrorSpy: jest.SpyInstance beforeAll(async () => { From dd63e6392d819cfa55d496029d5c0aa24097de08 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Fri, 11 Sep 2020 14:53:34 +0530 Subject: [PATCH 091/114] Revert "feat: Create declarations.d.ts file and add to tsconfig" This reverts commit 32bd566b2c537ea40c48a8608349bcbbc98f80a3. --- declarations.d.ts | 27 --------------------------- tsconfig.build.json | 1 - tsconfig.json | 1 - 3 files changed, 29 deletions(-) delete mode 100644 declarations.d.ts diff --git a/declarations.d.ts b/declarations.d.ts deleted file mode 100644 index d3140015..00000000 --- a/declarations.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -/***** - License - -------------- - Copyright © 2020 Mojaloop Foundation - The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the 'License') and you may not use these files except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - Contributors - -------------- - This is the official list of the Mojaloop project contributors for this file. - Names of the original copyright holders (individuals or organizations) - should be listed with a '*' in the first column. People who have - contributed from an organization can be listed under the organization - that actually holds the copyright for their contributions (see the - Mojaloop Foundation organization for an example). Those individuals should have - their names indented and be marked with a '-'. Email address can be added - optionally within square brackets . - * Mojaloop Foundation - - Name Surname - - * Google - - Steven Wijaya - - Abhimanyu Kapur - -------------- - ******/ - -declare module '@mojaloop/central-services-shared' diff --git a/tsconfig.build.json b/tsconfig.build.json index 62827276..177ebb00 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -3,7 +3,6 @@ "include": [ "src", "ambient.d.ts", - "declarations.d.ts", ], "exclude": [ "coverage", diff --git a/tsconfig.json b/tsconfig.json index 9a9bdbd0..43ef6cf7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,6 @@ "include": [ "src", "test", - "declarations.d.ts", "ambient.d.ts", "commitlint.config.js", "jest.bdd.config.js", From 5f037ed1582dab15ed83acbcc96489798615daf4 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 14 Sep 2020 15:35:57 +0530 Subject: [PATCH 092/114] refactor: Use optional chaining in validators and merge 2 identical methods Refactor tests and consent firestore handler to change name of methods merged Methods merge - isValidRevokeConsent, isValidChallengeGeneration --- src/server/handlers/firestore/consents.ts | 4 +- .../handlers/firestore/consents.validator.ts | 66 +++++-------------- .../handlers/firestore/consents.test.ts | 4 +- .../firestore/consents.validator.test.ts | 18 ++--- 4 files changed, 30 insertions(+), 62 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index ce40d187..6fa49460 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -118,7 +118,7 @@ async function handleConsentRequest(server: StateServer, consent: Consent) { } async function handleChallengeGeneration(server: StateServer, consent: Consent) { - if (!validator.isValidChallengeGeneration(consent)) { + if (!validator.isValidGenerateChallengeOrRevokeConsent(consent)) { throw new MissingConsentFieldsError(consent) } @@ -155,7 +155,7 @@ async function handleSignedChallenge(server: StateServer, consent: Consent) { } async function handleRevokingConsent(server: StateServer, consent: Consent) { - if (!validator.isValidRevokeConsent(consent)) { + if (!validator.isValidGenerateChallengeOrRevokeConsent(consent)) { throw new MissingConsentFieldsError(consent) } diff --git a/src/server/handlers/firestore/consents.validator.ts b/src/server/handlers/firestore/consents.validator.ts index 25fedc50..f8fac167 100644 --- a/src/server/handlers/firestore/consents.validator.ts +++ b/src/server/handlers/firestore/consents.validator.ts @@ -33,14 +33,10 @@ import { Consent } from '~/models/consent' * on Firebase. */ export const isValidPartyLookup = (consent: Consent): boolean => { - if ( - consent?.party?.partyIdInfo && - consent.party.partyIdInfo.partyIdType && + return !!( + consent?.party?.partyIdInfo?.partyIdType && consent.party.partyIdInfo.partyIdentifier - ) { - return true - } - return false + ) } /** @@ -51,19 +47,14 @@ export const isValidPartyLookup = (consent: Consent): boolean => { * on Firebase. */ export const isValidAuthentication = (consent: Consent): boolean => { - if ( + return !!( + consent?.party?.partyIdInfo?.fspId && consent.consentRequestId && consent.consentId && - consent.party && - consent.party.partyIdInfo && - consent.party.partyIdInfo.fspId && consent.initiatorId && consent.authChannels && consent.authToken - ) { - return true - } - return false + ) } /** @@ -74,31 +65,13 @@ export const isValidAuthentication = (consent: Consent): boolean => { * on Firebase. */ export const isValidConsentRequest = (consent: Consent): boolean => { - if ( + return !!( + consent?.party?.partyIdInfo?.fspId && consent.authChannels && consent.scopes && consent.initiatorId && - consent.party && - consent.party.partyIdInfo?.fspId && consent.authUri - ) { - return true - } - return false -} - -/** - * Checks whether a consent document has all the necessary fields to be - * processed as a request to generate challenge for a consent. - * - * @param consent the object representation of a consent that is stored - * on Firebase. - */ -export const isValidChallengeGeneration = (consent: Consent): boolean => { - if (consent.consentId && consent.party && consent.party.partyIdInfo?.fspId) { - return true - } - return false + ) } /** @@ -109,29 +82,24 @@ export const isValidChallengeGeneration = (consent: Consent): boolean => { * on Firebase. */ export const isValidSignedChallenge = (consent: Consent): boolean => { - if ( + return !!( + consent?.party?.partyIdInfo?.fspId && consent.credential && - consent.party && - consent.party.partyIdInfo?.fspId && consent.scopes && consent.initiatorId && consent.participantId - ) { - return true - } - return false + ) } /** * Checks whether a consent document has all the necessary fields to be - * processed as revoke consent request. + * processed as revoke consent request or a request to generate challenge for a consent. * * @param consent the object representation of a consent that is stored * on Firebase. */ -export const isValidRevokeConsent = (consent: Consent): boolean => { - if (consent.consentId && consent.party && consent.party.partyIdInfo?.fspId) { - return true - } - return false +export const isValidGenerateChallengeOrRevokeConsent = ( + consent: Consent +): boolean => { + return !!(consent?.party?.partyIdInfo?.fspId && consent.consentId) } diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index 9bdb8303..cdbbb6e4 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -395,7 +395,7 @@ describe('Handlers for consent documents in Firebase', () => { let mojaloopClientSpy: jest.SpyInstance const validatorSpy = jest - .spyOn(Validator, 'isValidChallengeGeneration') + .spyOn(Validator, 'isValidGenerateChallengeOrRevokeConsent') .mockReturnValue(true) // Mock consent data that would be given by Firebase @@ -582,7 +582,7 @@ describe('Handlers for consent documents in Firebase', () => { let mojaloopClientSpy: jest.SpyInstance const validatorSpy = jest - .spyOn(Validator, 'isValidRevokeConsent') + .spyOn(Validator, 'isValidGenerateChallengeOrRevokeConsent') .mockReturnValue(true) // Mock the expected transaction request being sent. diff --git a/test/unit/server/handlers/firestore/consents.validator.test.ts b/test/unit/server/handlers/firestore/consents.validator.test.ts index ad059777..866e97bd 100644 --- a/test/unit/server/handlers/firestore/consents.validator.test.ts +++ b/test/unit/server/handlers/firestore/consents.validator.test.ts @@ -432,7 +432,7 @@ describe('Validators for different consents used in requests', () => { describe('isValidChallengeGeneration', () => { it('Should return true if all necessary fields are present', () => { expect( - Validator.isValidChallengeGeneration({ + Validator.isValidGenerateChallengeOrRevokeConsent({ id, consentId, party: partyWithFSPId, @@ -447,7 +447,7 @@ describe('Validators for different consents used in requests', () => { it('Should return false if party or partyIdInfo or fspId is not present', () => { expect( - Validator.isValidChallengeGeneration({ + Validator.isValidGenerateChallengeOrRevokeConsent({ id, initiatorId, consentId, @@ -462,7 +462,7 @@ describe('Validators for different consents used in requests', () => { ).toBe(false) expect( - Validator.isValidChallengeGeneration({ + Validator.isValidGenerateChallengeOrRevokeConsent({ id, initiatorId, consentId, @@ -478,7 +478,7 @@ describe('Validators for different consents used in requests', () => { ).toBe(false) expect( - Validator.isValidChallengeGeneration({ + Validator.isValidGenerateChallengeOrRevokeConsent({ id, userId, initiatorId, @@ -498,7 +498,7 @@ describe('Validators for different consents used in requests', () => { it('Should return false if consent ID is not present', () => { expect( - Validator.isValidRevokeConsent({ + Validator.isValidGenerateChallengeOrRevokeConsent({ id, userId, initiatorId, @@ -634,7 +634,7 @@ describe('Validators for different consents used in requests', () => { describe('isValidRevokeConsent', () => { it('Should return true if all necessary fields are present', () => { expect( - Validator.isValidRevokeConsent({ + Validator.isValidGenerateChallengeOrRevokeConsent({ id, userId, consentId, @@ -647,7 +647,7 @@ describe('Validators for different consents used in requests', () => { it('Should return false if party or partyIdInfo or fspId is not present', () => { expect( - Validator.isValidRevokeConsent({ + Validator.isValidGenerateChallengeOrRevokeConsent({ id, initiatorId, consentId, @@ -662,7 +662,7 @@ describe('Validators for different consents used in requests', () => { ).toBe(false) expect( - Validator.isValidRevokeConsent({ + Validator.isValidGenerateChallengeOrRevokeConsent({ id, initiatorId, consentId, @@ -698,7 +698,7 @@ describe('Validators for different consents used in requests', () => { it('Should return false if consent ID is not present', () => { expect( - Validator.isValidRevokeConsent({ + Validator.isValidGenerateChallengeOrRevokeConsent({ id, userId, initiatorId, From a0b02f273537152b8ebc5970d467b4ff948925b9 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 14 Sep 2020 15:36:14 +0530 Subject: [PATCH 093/114] chore: bump sdk-standard-components to v11.5.3 --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index e521ce1c..bd1b2dac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2650,9 +2650,9 @@ } }, "@mojaloop/sdk-standard-components": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.5.2.tgz", - "integrity": "sha512-CZWXJlMFQo9TMQtwQuQu7sFO/ajY6FrUNhnxjaN/rz6zcX+fofvy7W6DENz3LKqSKiF9n5wljzZPzIIVtVA6gQ==", + "version": "11.6.0", + "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.6.0.tgz", + "integrity": "sha512-ZU6/roi+s1WBBfMbfqkYSKnhuMUU3APFACzcbKo3DLc5dgqDkZw0gdtctUUuta4r3IG84BkHUO8r0Obfav8KSg==", "requires": { "base64url": "3.0.1", "fast-safe-stringify": "^2.0.7", diff --git a/package.json b/package.json index ac5987c3..bc1e050d 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "@hapi/vision": "^6.0.0", "@mojaloop/central-services-logger": "^10.6.0", "@mojaloop/central-services-shared": "^11.3.2", - "@mojaloop/sdk-standard-components": "^11.5.2", + "@mojaloop/sdk-standard-components": "^11.6.0", "@types/uuid": "^8.0.0", "convict": "^6.0.0", "dotenv": "^8.2.0", From 75bff6f91cad94963661e57eaca51ffedfe2fe37 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 14 Sep 2020 15:38:00 +0530 Subject: [PATCH 094/114] style: modify TODO comment --- src/shared/ml-thirdparty-client/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shared/ml-thirdparty-client/index.ts b/src/shared/ml-thirdparty-client/index.ts index 6a441d41..dd8def20 100644 --- a/src/shared/ml-thirdparty-client/index.ts +++ b/src/shared/ml-thirdparty-client/index.ts @@ -145,8 +145,10 @@ export class Client { _requestBody: AuthorizationsPutIdRequest, _destParticipantId: string ): Promise { - // TODO: Implement communication with Mojaloop. - // Placeholder below + // TODO: Replace placeholder with commented implementation + // once implemented in sdk-standard-components + + // Placeholder throw new NotImplementedError() // return this.thirdpartyRequests.putThirdpartyRequestsTransactionsAuthorizations( From 42d38a06547bf567b1781a3e2325c936efd48719 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 14 Sep 2020 15:46:25 +0530 Subject: [PATCH 095/114] refactor: Replace unneeded type casting with non-null assertion --- src/server/handlers/firestore/consents.ts | 55 +++++++++---------- .../handlers/firestore/consents.test.ts | 22 ++++---- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 6fa49460..69a90b47 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -34,11 +34,6 @@ import { Consent, ConsentStatus } from '~/models/consent' import { consentRepository } from '~/repositories/consent' import * as validator from './consents.validator' -import { - TCredentialScope, - TAuthChannel, - TCredential, -} from '@mojaloop/sdk-standard-components' import config from '~/lib/config' import { MissingConsentFieldsError } from '~/models/errors' @@ -59,7 +54,7 @@ async function handlePartyLookup(server: StateServer, consent: Consent) { throw new MissingConsentFieldsError(consent) } - // Party is guaranteed to be non-null by the validator. + // Fields are guaranteed to be non-null by the validator. try { server.app.mojaloopClient.getParties( consent.party!.partyIdInfo.partyIdType, @@ -75,18 +70,19 @@ async function handleAuthentication(server: StateServer, consent: Consent) { throw new MissingConsentFieldsError(consent) } + // Fields are guaranteed to be non-null by the validator. try { server.app.mojaloopClient.putConsentRequests( consent.id, { - initiatorId: consent.initiatorId as string, - authChannels: consent.authChannels as TAuthChannel[], - scopes: consent.scopes as TCredentialScope[], - authUri: consent.authUri as string, + initiatorId: consent.initiatorId!, + authChannels: consent.authChannels!, + scopes: consent.scopes!, + authUri: consent.authUri!, callbackUri: config.get('mojaloop').callbackUri, - authToken: consent.authToken as string, + authToken: consent.authToken!, }, - consent.party!.partyIdInfo.fspId as string + consent.party!.partyIdInfo.fspId! ) } catch (error) { logger.error(error) @@ -100,17 +96,16 @@ async function handleConsentRequest(server: StateServer, consent: Consent) { // If the update contains all the necessary fields, process document try { - // The optional values are guaranteed to exist by the validator. - + // Fields are guaranteed to be non-null by the validator. server.app.mojaloopClient.postConsentRequests( { - initiatorId: consent.initiatorId as string, - scopes: consent.scopes as TCredentialScope[], - authChannels: consent.authChannels as TAuthChannel[], + initiatorId: consent.initiatorId!, + scopes: consent.scopes!, + authChannels: consent.authChannels!, id: consent.id, callbackUri: config.get('mojaloop').callbackUri, }, - consent.party!.partyIdInfo.fspId as string + consent.party!.partyIdInfo.fspId! ) } catch (err) { logger.error(err) @@ -123,9 +118,10 @@ async function handleChallengeGeneration(server: StateServer, consent: Consent) } try { + // Fields are guaranteed to be non-null by the validator. server.app.mojaloopClient.postGenerateChallengeForConsent( - consent.consentId as string, - consent.party!.partyIdInfo.fspId as string + consent.consentId!, + consent.party!.partyIdInfo.fspId! ) } catch (error) { logger.error(error) @@ -138,16 +134,17 @@ async function handleSignedChallenge(server: StateServer, consent: Consent) { } try { + // Fields are guaranteed to be non-null by the validator. server.app.mojaloopClient.putConsentId( - consent.consentId as string, + consent.consentId!, { requestId: consent.id, - initiatorId: consent.initiatorId as string, - participantId: consent.participantId as string, - scopes: consent.scopes as TCredentialScope[], - credential: consent.credential as TCredential, + initiatorId: consent.initiatorId!, + participantId: consent.participantId!, + scopes: consent.scopes!, + credential: consent.credential!, }, - consent.party!.partyIdInfo.fspId as string + consent.party!.partyIdInfo.fspId! ) } catch (error) { logger.error(error) @@ -160,10 +157,10 @@ async function handleRevokingConsent(server: StateServer, consent: Consent) { } try { - // Make outgoing POST consents/{ID}/revoke request to Mojaloop + // Fields are guaranteed to be non-null by the validator. server.app.mojaloopClient.postRevokeConsent( - consent.consentId as string, - consent.party!.partyIdInfo.fspId as string + consent.consentId!, + consent.party!.partyIdInfo.fspId! ) } catch (error) { logger.error(error) diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index cdbbb6e4..170c892e 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ /***** License -------------- @@ -35,10 +36,7 @@ import { PartyIdType, Currency, } from '~/shared/ml-thirdparty-client/models/core' -import SDKStandardComponents, { - TAuthChannel, - TCredentialScope, -} from '@mojaloop/sdk-standard-components' +import SDKStandardComponents from '@mojaloop/sdk-standard-components' import { logger } from '~/shared/logger' import { MissingConsentFieldsError } from '~/models/errors' @@ -246,12 +244,12 @@ describe('Handlers for consent documents in Firebase', () => { // Mock the expected transaction request being sent. const request: SDKStandardComponents.PutConsentRequestsRequest = { - initiatorId: consentAuthentication.initiatorId as string, - scopes: consentAuthentication.scopes as TCredentialScope[], - authChannels: consentAuthentication.authChannels as TAuthChannel[], + initiatorId: consentAuthentication.initiatorId!, + scopes: consentAuthentication.scopes!, + authChannels: consentAuthentication.authChannels!, callbackUri: config.get('mojaloop').callbackUri, - authToken: consentAuthentication.authToken as string, - authUri: consentAuthentication.authUri as string, + authToken: consentAuthentication.authToken!, + authUri: consentAuthentication.authUri!, } beforeAll(() => { @@ -339,10 +337,10 @@ describe('Handlers for consent documents in Firebase', () => { // Mock the expected request being sent. const consentRequest: SDKStandardComponents.PostConsentRequestsRequest = { - initiatorId: consentConsentRequest.initiatorId as string, + initiatorId: consentConsentRequest.initiatorId!, id: consentConsentRequest.id, - scopes: consentConsentRequest.scopes as TCredentialScope[], - authChannels: consentConsentRequest.authChannels as TAuthChannel[], + scopes: consentConsentRequest.scopes!, + authChannels: consentConsentRequest.authChannels!, callbackUri: config.get('mojaloop').callbackUri, } From dda5baaa76cc6f084341ef9fb22de0afe100a1ad Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 14 Sep 2020 16:35:00 +0530 Subject: [PATCH 096/114] refactor: Change name of callbackUri in config to pispCallbackUri --- src/lib/config.ts | 2 +- src/server/handlers/firestore/consents.ts | 4 ++-- test/unit/server/handlers/firestore/consents.test.ts | 4 ++-- .../handlers/openapi/mojaloop/consentRequests/{ID}.test.ts | 2 +- test/unit/server/handlers/openapi/mojaloop/consents.test.ts | 2 +- test/unit/shared/ml-thirdparty-client/index.test.ts | 2 +- test/unit/shared/ml-thirdparty-simulator/index.test.ts | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/lib/config.ts b/src/lib/config.ts index 95fa2d24..b33b0c6e 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -109,7 +109,7 @@ const config = convict({ env: 'MOJALOOP_PARTICIPANT_ID', }, // TODO: Replace placeholder - callbackUri: { + pispCallbackUri: { doc: 'The callback URI sent by PISP deeplinked with the app', format: String, default: 'PLACEHOLDER', diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 69a90b47..6bd786ae 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -79,7 +79,7 @@ async function handleAuthentication(server: StateServer, consent: Consent) { authChannels: consent.authChannels!, scopes: consent.scopes!, authUri: consent.authUri!, - callbackUri: config.get('mojaloop').callbackUri, + callbackUri: config.get('mojaloop').pispCallbackUri, authToken: consent.authToken!, }, consent.party!.partyIdInfo.fspId! @@ -103,7 +103,7 @@ async function handleConsentRequest(server: StateServer, consent: Consent) { scopes: consent.scopes!, authChannels: consent.authChannels!, id: consent.id, - callbackUri: config.get('mojaloop').callbackUri, + callbackUri: config.get('mojaloop').pispCallbackUri, }, consent.party!.partyIdInfo.fspId! ) diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index 170c892e..61e4d44f 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -247,7 +247,7 @@ describe('Handlers for consent documents in Firebase', () => { initiatorId: consentAuthentication.initiatorId!, scopes: consentAuthentication.scopes!, authChannels: consentAuthentication.authChannels!, - callbackUri: config.get('mojaloop').callbackUri, + callbackUri: config.get('mojaloop').pispCallbackUri, authToken: consentAuthentication.authToken!, authUri: consentAuthentication.authUri!, } @@ -341,7 +341,7 @@ describe('Handlers for consent documents in Firebase', () => { id: consentConsentRequest.id, scopes: consentConsentRequest.scopes!, authChannels: consentConsentRequest.authChannels!, - callbackUri: config.get('mojaloop').callbackUri, + callbackUri: config.get('mojaloop').pispCallbackUri, } beforeAll(() => { diff --git a/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts b/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts index 4262dd99..9b2f21ac 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consentRequests/{ID}.test.ts @@ -78,7 +78,7 @@ const postConsentRequestRequest: SDKStandardComponents.PostConsentRequestsReques actions: ['account.getAccess'], }, ], - callbackUri: config.get('mojaloop').callbackUri, + callbackUri: config.get('mojaloop').pispCallbackUri, } describe('/consentRequests/{ID}', () => { diff --git a/test/unit/server/handlers/openapi/mojaloop/consents.test.ts b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts index da6f4597..58bcc59a 100644 --- a/test/unit/server/handlers/openapi/mojaloop/consents.test.ts +++ b/test/unit/server/handlers/openapi/mojaloop/consents.test.ts @@ -80,7 +80,7 @@ const putConsentRequestRequest: SDKStandardComponents.PutConsentRequestsRequest actions: ['account.getAccess'], }, ], - callbackUri: config.get('mojaloop').callbackUri, + callbackUri: config.get('mojaloop').pispCallbackUri, authUri: 'https://dfspAuth.com', authToken: 'secret-token', } diff --git a/test/unit/shared/ml-thirdparty-client/index.test.ts b/test/unit/shared/ml-thirdparty-client/index.test.ts index 2b91f284..807845d6 100644 --- a/test/unit/shared/ml-thirdparty-client/index.test.ts +++ b/test/unit/shared/ml-thirdparty-client/index.test.ts @@ -118,7 +118,7 @@ const putConsentRequestRequest: SDKStandardComponents.PutConsentRequestsRequest initiatorId: 'pispA', authChannels: ['WEB', 'OTP'], scopes, - callbackUri: config.get('mojaloop').callbackUri, + callbackUri: config.get('mojaloop').pispCallbackUri, authUri: 'https://dfspAuth.com', authToken: 'secret-token', } diff --git a/test/unit/shared/ml-thirdparty-simulator/index.test.ts b/test/unit/shared/ml-thirdparty-simulator/index.test.ts index 56cc63dd..a6fdef43 100644 --- a/test/unit/shared/ml-thirdparty-simulator/index.test.ts +++ b/test/unit/shared/ml-thirdparty-simulator/index.test.ts @@ -104,7 +104,7 @@ const postConsentRequestRequest: SDKStandardComponents.PostConsentRequestsReques initiatorId: 'pispA', authChannels: ['WEB', 'OTP'], scopes, - callbackUri: config.get('mojaloop').callbackUri, + callbackUri: config.get('mojaloop').pispCallbackUri, } const putConsentRequestRequest: SDKStandardComponents.PutConsentRequestsRequest = { @@ -112,7 +112,7 @@ const putConsentRequestRequest: SDKStandardComponents.PutConsentRequestsRequest initiatorId: 'pispA', authChannels: ['WEB', 'OTP'], scopes, - callbackUri: config.get('mojaloop').callbackUri, + callbackUri: config.get('mojaloop').pispCallbackUri, authUri: 'https://dfspAuth.com', authToken: 'secret-token', } From 175390350471aa8180ca83e9c40dfac539b17377 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 14 Sep 2020 17:48:12 +0530 Subject: [PATCH 097/114] chore: Add flags to ignore BDD testing which is covered in separate ticket #1702 --- src/repositories/consent.ts | 2 +- src/repositories/participants.ts | 2 +- src/repositories/transaction.ts | 2 +- src/server/handlers/firestore/consents.ts | 2 ++ src/server/handlers/firestore/transactions.ts | 2 ++ src/shared/ml-thirdparty-client/index.ts | 2 ++ src/shared/ml-thirdparty-simulator/index.ts | 2 ++ 7 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index 017f5202..047a0b98 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -24,7 +24,7 @@ ******/ /* istanbul ignore file */ -// TODO: Testing will covered in separate ticket +// TODO: BDD Testing will covered in separate ticket #1702 import firebase from '~/lib/firebase' import { Consent } from '~/models/consent' diff --git a/src/repositories/participants.ts b/src/repositories/participants.ts index 6efb53c6..a62e662e 100644 --- a/src/repositories/participants.ts +++ b/src/repositories/participants.ts @@ -25,7 +25,7 @@ ******/ /* istanbul ignore file */ -// TODO: Testing will covered in separate ticket +// TODO: BDD Testing will covered in separate ticket #1702 import firebase from '~/lib/firebase' import { logger } from '~/shared/logger' diff --git a/src/repositories/transaction.ts b/src/repositories/transaction.ts index 1458de25..edfea49f 100644 --- a/src/repositories/transaction.ts +++ b/src/repositories/transaction.ts @@ -24,7 +24,7 @@ ******/ /* istanbul ignore file */ -// TODO: Testing will covered in separate ticket +// TODO: BDD Testing will covered in separate ticket #1702 import firebase from '~/lib/firebase' import { logger } from '~/shared/logger' diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 6bd786ae..f4b00e88 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -25,6 +25,8 @@ - Abhimanyu Kapur -------------- ******/ +/* istanbul ignore file */ +// TODO: BDD Testing will covered in separate ticket #1702 import * as uuid from 'uuid' import { logger } from '~/shared/logger' diff --git a/src/server/handlers/firestore/transactions.ts b/src/server/handlers/firestore/transactions.ts index 87f40bd5..1da746fd 100644 --- a/src/server/handlers/firestore/transactions.ts +++ b/src/server/handlers/firestore/transactions.ts @@ -23,6 +23,8 @@ - Abhimanyu Kapur -------------- ******/ +/* istanbul ignore file */ +// TODO: Testing will covered in separate ticket import * as uuid from 'uuid' diff --git a/src/shared/ml-thirdparty-client/index.ts b/src/shared/ml-thirdparty-client/index.ts index dd8def20..503e7abc 100644 --- a/src/shared/ml-thirdparty-client/index.ts +++ b/src/shared/ml-thirdparty-client/index.ts @@ -24,6 +24,8 @@ - Abhimanyu Kapur -------------- ******/ +/* istanbul ignore file */ +// TODO: BDD Testing will covered in separate ticket #1702 import { Simulator } from '~/shared/ml-thirdparty-simulator' import { PartyIdType } from './models/core' diff --git a/src/shared/ml-thirdparty-simulator/index.ts b/src/shared/ml-thirdparty-simulator/index.ts index 87429f16..3953d5d8 100644 --- a/src/shared/ml-thirdparty-simulator/index.ts +++ b/src/shared/ml-thirdparty-simulator/index.ts @@ -23,6 +23,8 @@ - Abhimanyu Kapur -------------- ******/ +/* istanbul ignore file */ +// TODO: BDD Testing will covered in separate ticket #1702 import { ServerInjectResponse } from '@hapi/hapi' import * as faker from 'faker' From f8217a9b920a502ce8a85ba50dfe0a8b80a489c5 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 15 Sep 2020 10:58:37 +0530 Subject: [PATCH 098/114] feat: Throw InvalidConsentStatus Error if default case reached in firestore handler Unit test for the same --- src/models/errors.ts | 5 +++++ src/server/handlers/firestore/consents.ts | 4 +++- .../server/handlers/firestore/consents.test.ts | 17 ++++++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/models/errors.ts b/src/models/errors.ts index 66f421cb..4ebe2dde 100644 --- a/src/models/errors.ts +++ b/src/models/errors.ts @@ -37,3 +37,8 @@ export class MissingConsentFieldsError extends Error { this.consent = consent } } +export class InvalidConsentStatusError extends Error { + public constructor(consentStatus: string) { + super(`Invalid Consent Status Provided! Status: ${consentStatus}`) + } +} diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index f4b00e88..5af588be 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -37,7 +37,7 @@ import { Consent, ConsentStatus } from '~/models/consent' import { consentRepository } from '~/repositories/consent' import * as validator from './consents.validator' import config from '~/lib/config' -import { MissingConsentFieldsError } from '~/models/errors' +import { MissingConsentFieldsError, InvalidConsentStatusError } from '~/models/errors' async function handleNewConsent(_: StateServer, consent: Consent) { // Assign a consentRequestId to the document and set the initial @@ -219,5 +219,7 @@ export const onUpdate: ConsentHandler = async ( case ConsentStatus.REVOKE_REQUESTED: await handleRevokingConsent(server, consent) break + default: + throw new InvalidConsentStatusError(consent.status) } } diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index 61e4d44f..62a5a57c 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -38,7 +38,7 @@ import { } from '~/shared/ml-thirdparty-client/models/core' import SDKStandardComponents from '@mojaloop/sdk-standard-components' import { logger } from '~/shared/logger' -import { MissingConsentFieldsError } from '~/models/errors' +import { MissingConsentFieldsError, InvalidConsentStatusError } from '~/models/errors' // Mock firebase to prevent server from listening to the changes. jest.mock('~/lib/firebase') @@ -130,6 +130,21 @@ describe('Handlers for consent documents in Firebase', () => { ) }) + it('Should throw a InvalidConsentStatusErrro, if status field does not match any ConsentStatus enum', async () => { + const consentInvalidStatus = { + id: '111', + status: 'invalid' as ConsentStatus, + consentId: 'acv', + userId: 'bob123', + } + + expect( + consentsHandler.onUpdate(server, consentInvalidStatus) + ).rejects.toThrow( + new InvalidConsentStatusError(consentInvalidStatus.status) + ) + }) + describe('Party Lookup', () => { // Mocked Methods let mojaloopClientSpy: jest.SpyInstance From b4af4fb8ada89f6fac896919b5439c8add96de01 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 15 Sep 2020 11:01:15 +0530 Subject: [PATCH 099/114] refactor: removed unneeded extra variable --- src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts index a2c154ca..b8b5e392 100644 --- a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts @@ -37,9 +37,8 @@ export const put: Handler = async ( ) => { logger.logRequest(context, request, h) - const id = context.request.params.ID as string const { authChannels, authUri } = context.request.body - consentRepository.updateConsentById(id, { + consentRepository.updateConsentById(context.request.params.ID as string, { authChannels, authUri, status: ConsentStatus.AUTHENTICATION_REQUIRED, From 6a587450a65e31321aa786aabab1d801f9275ff9 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 15 Sep 2020 11:10:08 +0530 Subject: [PATCH 100/114] refactor: Remove request logging for handlers which have been implemented --- src/server/handlers/firestore/transactions.ts | 1 + .../handlers/openapi/mojaloop/consentRequests/{ID}.ts | 5 +---- src/server/handlers/openapi/mojaloop/consents.ts | 5 +---- src/server/handlers/openapi/mojaloop/consents/{ID}.ts | 7 ++----- src/server/handlers/openapi/mojaloop/participants.ts | 4 +--- 5 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/server/handlers/firestore/transactions.ts b/src/server/handlers/firestore/transactions.ts index 1da746fd..2d6f8ed1 100644 --- a/src/server/handlers/firestore/transactions.ts +++ b/src/server/handlers/firestore/transactions.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ /***** License -------------- diff --git a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts index b8b5e392..7c55497e 100644 --- a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts @@ -26,17 +26,14 @@ import { Request, ResponseToolkit } from '@hapi/hapi' import { Handler, Context } from 'openapi-backend' -import { logger } from '~/shared/logger' import { consentRepository } from '~/repositories/consent' import { ConsentStatus } from '~/models/consent' export const put: Handler = async ( context: Context, - request: Request, + _request: Request, h: ResponseToolkit ) => { - logger.logRequest(context, request, h) - const { authChannels, authUri } = context.request.body consentRepository.updateConsentById(context.request.params.ID as string, { authChannels, diff --git a/src/server/handlers/openapi/mojaloop/consents.ts b/src/server/handlers/openapi/mojaloop/consents.ts index 6a76d652..73368e44 100644 --- a/src/server/handlers/openapi/mojaloop/consents.ts +++ b/src/server/handlers/openapi/mojaloop/consents.ts @@ -26,17 +26,14 @@ import { Request, ResponseToolkit } from '@hapi/hapi' import { Handler, Context } from 'openapi-backend' -import { logger } from '~/shared/logger' import { consentRepository } from '~/repositories/consent' import { ConsentStatus } from '~/models/consent' export const post: Handler = async ( context: Context, - request: Request, + _request: Request, h: ResponseToolkit ) => { - logger.logRequest(context, request, h) - const { id, initiatorId, participantId, scopes } = context.request.body consentRepository.updateConsentById(id, { diff --git a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts index ef5300b1..2672fe95 100644 --- a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts @@ -26,15 +26,13 @@ import { Request, ResponseToolkit } from '@hapi/hapi' import { Handler, Context } from 'openapi-backend' -import { logger } from '~/shared/logger' import { consentRepository } from '~/repositories/consent' export const put: Handler = async ( context: Context, - request: Request, + _request: Request, h: ResponseToolkit ) => { - logger.logRequest(context, request, h) // Updates consent fields consentRepository.updateConsentById( context.request.params.ID as string, @@ -45,10 +43,9 @@ export const put: Handler = async ( export const patch: Handler = async ( context: Context, - request: Request, + _request: Request, h: ResponseToolkit ) => { - logger.logRequest(context, request, h) // Updates consent fields patched consentRepository.updateConsentById( context.request.params.ID as string, diff --git a/src/server/handlers/openapi/mojaloop/participants.ts b/src/server/handlers/openapi/mojaloop/participants.ts index 2c046505..64b90768 100644 --- a/src/server/handlers/openapi/mojaloop/participants.ts +++ b/src/server/handlers/openapi/mojaloop/participants.ts @@ -27,15 +27,13 @@ import { Request, ResponseToolkit } from '@hapi/hapi' import { Handler, Context } from 'openapi-backend' -import { logger } from '~/shared/logger' import { participantRepository } from '~/repositories/participants' export const put: Handler = async ( context: Context, - request: Request, + _request: Request, h: ResponseToolkit ) => { - logger.logRequest(context, request, h) // @ts-ignore const participants = context.request.body.participants From 4fd24e6b241c8fb8d7ae971328d2c4edd5a6bcc3 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 15 Sep 2020 11:11:14 +0530 Subject: [PATCH 101/114] fix: REplace any type with unknown --- src/shared/logger/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shared/logger/index.ts b/src/shared/logger/index.ts index 7f52baf1..8e6c7d49 100644 --- a/src/shared/logger/index.ts +++ b/src/shared/logger/index.ts @@ -40,8 +40,8 @@ export interface ResponseLogged extends ResponseObject { } export interface BaseLogger { - info: (message: string, ...meta: any[]) => any - error: (messsage: string, ...meta: any[]) => any + info: (message: string, ...meta: unknown[]) => unknown + error: (messsage: string, ...meta: unknown[]) => unknown } export class Logger { @@ -74,11 +74,11 @@ export class Logger { } } - info(message: string, ...meta: any[]) { + info(message: string, ...meta: unknown[]) { this._logger.info(message, ...meta) } - error(message: string, ...meta: any[]) { + error(message: string, ...meta: unknown[]) { this._logger.error(message, ...meta) } } From d14415b9dfd1b6f5574e66a006195711057763db Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 15 Sep 2020 11:15:22 +0530 Subject: [PATCH 102/114] fix: remove ts-ignore --- src/server/handlers/openapi/mojaloop/participants.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/server/handlers/openapi/mojaloop/participants.ts b/src/server/handlers/openapi/mojaloop/participants.ts index 64b90768..005711a5 100644 --- a/src/server/handlers/openapi/mojaloop/participants.ts +++ b/src/server/handlers/openapi/mojaloop/participants.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ /***** License -------------- @@ -34,7 +33,6 @@ export const put: Handler = async ( _request: Request, h: ResponseToolkit ) => { - // @ts-ignore const participants = context.request.body.participants // Replace existing participants list with received list From 7072fc00b44c42b497892d02d7188d4581acb009 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 15 Sep 2020 14:35:48 +0530 Subject: [PATCH 103/114] feat: Add consent ID to invalidConsentStatusError for clarity --- src/models/errors.ts | 6 ++++-- src/server/handlers/firestore/consents.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/models/errors.ts b/src/models/errors.ts index 4ebe2dde..5b9ffe96 100644 --- a/src/models/errors.ts +++ b/src/models/errors.ts @@ -38,7 +38,9 @@ export class MissingConsentFieldsError extends Error { } } export class InvalidConsentStatusError extends Error { - public constructor(consentStatus: string) { - super(`Invalid Consent Status Provided! Status: ${consentStatus}`) + public constructor(consentStatus: string, consentId?: string) { + super( + `Invalid Consent Status Provided! ID: ${consentId} | Status: ${consentStatus}` + ) } } diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 5af588be..9fe6d545 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -220,6 +220,6 @@ export const onUpdate: ConsentHandler = async ( await handleRevokingConsent(server, consent) break default: - throw new InvalidConsentStatusError(consent.status) + throw new InvalidConsentStatusError(consent.status, consent.id) } } From e36cdeb5c481df68b45ade95cf65a39038c45666 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 15 Sep 2020 14:36:53 +0530 Subject: [PATCH 104/114] style: Add comments explaining decision to not await async code --- src/server/handlers/firestore/consents.ts | 2 ++ src/server/handlers/firestore/transactions.ts | 1 + src/server/handlers/openapi/mojaloop/authorizations.ts | 3 ++- src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts | 1 + src/server/handlers/openapi/mojaloop/consents.ts | 1 + src/server/handlers/openapi/mojaloop/consents/{ID}.ts | 2 ++ src/server/handlers/openapi/mojaloop/participants.ts | 1 + src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts | 3 +++ src/server/handlers/openapi/mojaloop/transfers/{ID}.ts | 3 ++- 9 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 9fe6d545..79b994a3 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -43,6 +43,8 @@ async function handleNewConsent(_: StateServer, consent: Consent) { // Assign a consentRequestId to the document and set the initial // status. This operation will create an event that triggers the execution // of the onUpdate function. + + // Not await-ing promise to resolve - code is executed asynchronously consentRepository.updateConsentById(consent.id, { consentRequestId: uuid.v4(), status: ConsentStatus.PENDING_PARTY_LOOKUP, diff --git a/src/server/handlers/firestore/transactions.ts b/src/server/handlers/firestore/transactions.ts index 2d6f8ed1..d6ea1296 100644 --- a/src/server/handlers/firestore/transactions.ts +++ b/src/server/handlers/firestore/transactions.ts @@ -50,6 +50,7 @@ async function handleNewTransaction(_: StateServer, transaction: Transaction) { // Assign a transactionRequestId to the document and set the initial // status. This operation will create an event that triggers the execution // of the onUpdate function. + // Not await-ing promise to resolve - code is executed asynchronously transactionRepository.updateById(transaction.id, { transactionRequestId: uuid.v4(), status: Status.PENDING_PARTY_LOOKUP, diff --git a/src/server/handlers/openapi/mojaloop/authorizations.ts b/src/server/handlers/openapi/mojaloop/authorizations.ts index f21b0bba..67e79901 100644 --- a/src/server/handlers/openapi/mojaloop/authorizations.ts +++ b/src/server/handlers/openapi/mojaloop/authorizations.ts @@ -32,8 +32,9 @@ import { transactionRepository } from '~/repositories/transaction' import { Status } from '~/models/transaction' export const post: Handler = async (context: Context, _: Request, h: ResponseToolkit) => { - let body = context.request.body as AuthorizationsPostRequest + const body = context.request.body as AuthorizationsPostRequest + // Not await-ing promise to resolve - code is executed asynchronously transactionRepository.update( { transactionRequestId: body.transactionRequestId, diff --git a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts index 7c55497e..1fd0e11a 100644 --- a/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consentRequests/{ID}.ts @@ -35,6 +35,7 @@ export const put: Handler = async ( h: ResponseToolkit ) => { const { authChannels, authUri } = context.request.body + // Not await-ing promise to resolve - code is executed asynchronously consentRepository.updateConsentById(context.request.params.ID as string, { authChannels, authUri, diff --git a/src/server/handlers/openapi/mojaloop/consents.ts b/src/server/handlers/openapi/mojaloop/consents.ts index 73368e44..3490f28d 100644 --- a/src/server/handlers/openapi/mojaloop/consents.ts +++ b/src/server/handlers/openapi/mojaloop/consents.ts @@ -36,6 +36,7 @@ export const post: Handler = async ( ) => { const { id, initiatorId, participantId, scopes } = context.request.body + // Not await-ing promise to resolve - code is executed asynchronously consentRepository.updateConsentById(id, { initiatorId, participantId, diff --git a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts index 2672fe95..e07df5ad 100644 --- a/src/server/handlers/openapi/mojaloop/consents/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/consents/{ID}.ts @@ -34,6 +34,7 @@ export const put: Handler = async ( h: ResponseToolkit ) => { // Updates consent fields + // Not await-ing promise to resolve - code is executed asynchronously consentRepository.updateConsentById( context.request.params.ID as string, context.request.body @@ -47,6 +48,7 @@ export const patch: Handler = async ( h: ResponseToolkit ) => { // Updates consent fields patched + // Not await-ing promise to resolve - code is executed asynchronously consentRepository.updateConsentById( context.request.params.ID as string, context.request.body diff --git a/src/server/handlers/openapi/mojaloop/participants.ts b/src/server/handlers/openapi/mojaloop/participants.ts index 005711a5..2d01e7b3 100644 --- a/src/server/handlers/openapi/mojaloop/participants.ts +++ b/src/server/handlers/openapi/mojaloop/participants.ts @@ -36,6 +36,7 @@ export const put: Handler = async ( const participants = context.request.body.participants // Replace existing participants list with received list + // Not await-ing promise to resolve - code is executed asynchronously participantRepository.replace(participants) return h.response().code(200) } diff --git a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts index db999102..56199178 100644 --- a/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/parties/{Type}/{ID}.ts @@ -60,6 +60,8 @@ export const put: Handler = async ( if (partyIdType === PartyIdType.OPAQUE) { // Update Consents as OPAQUE is the type during linking when we're fetching the accounts // available for linking from a pre-determined DFSP + + // Not await-ing promise to resolve - code is executed asynchronously consentRepository.updateConsent( // Conditions for the documents that need to be updated { @@ -76,6 +78,7 @@ export const put: Handler = async ( ) } else { // Update Transactions + // Not await-ing promise to resolve - code is executed asynchronously transactionRepository.update( // Conditions for the documents that need to be updated { diff --git a/src/server/handlers/openapi/mojaloop/transfers/{ID}.ts b/src/server/handlers/openapi/mojaloop/transfers/{ID}.ts index ae948f51..328be552 100644 --- a/src/server/handlers/openapi/mojaloop/transfers/{ID}.ts +++ b/src/server/handlers/openapi/mojaloop/transfers/{ID}.ts @@ -32,8 +32,9 @@ import { Status } from '~/models/transaction' import { transactionRepository } from '~/repositories/transaction' export const put: Handler = async (context: Context, _: Request, h: ResponseToolkit) => { - let body = context.request.body as TransferIDPutRequest + const body = context.request.body as TransferIDPutRequest + // Not await-ing promise to resolve - code is executed asynchronously transactionRepository.update( { transactionId: body.transactionId, From 69f4718633d86bad27958788aa46bb8c0439f5e7 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 15 Sep 2020 18:14:11 +0530 Subject: [PATCH 105/114] refactor: Change method names to more accurately reflect function --- src/server/handlers/firestore/consents.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index 79b994a3..ff036f53 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -51,7 +51,7 @@ async function handleNewConsent(_: StateServer, consent: Consent) { }) } -async function handlePartyLookup(server: StateServer, consent: Consent) { +async function initiatePartyLookup(server: StateServer, consent: Consent) { // Check whether the consent document has all the necessary properties // to perform a party lookup. if (!validator.isValidPartyLookup(consent)) { @@ -69,7 +69,7 @@ async function handlePartyLookup(server: StateServer, consent: Consent) { } } -async function handleAuthentication(server: StateServer, consent: Consent) { +async function initiateAuthentication(server: StateServer, consent: Consent) { if (!validator.isValidAuthentication(consent)) { throw new MissingConsentFieldsError(consent) } @@ -93,7 +93,7 @@ async function handleAuthentication(server: StateServer, consent: Consent) { } } -async function handleConsentRequest(server: StateServer, consent: Consent) { +async function initiateConsentRequest(server: StateServer, consent: Consent) { if (!validator.isValidConsentRequest(consent)) { throw new MissingConsentFieldsError(consent) } @@ -116,7 +116,7 @@ async function handleConsentRequest(server: StateServer, consent: Consent) { } } -async function handleChallengeGeneration(server: StateServer, consent: Consent) { +async function initiateChallengeGeneration(server: StateServer, consent: Consent) { if (!validator.isValidGenerateChallengeOrRevokeConsent(consent)) { throw new MissingConsentFieldsError(consent) } @@ -155,7 +155,7 @@ async function handleSignedChallenge(server: StateServer, consent: Consent) { } } -async function handleRevokingConsent(server: StateServer, consent: Consent) { +async function initiateRevokingConsent(server: StateServer, consent: Consent) { if (!validator.isValidGenerateChallengeOrRevokeConsent(consent)) { throw new MissingConsentFieldsError(consent) } @@ -199,19 +199,19 @@ export const onUpdate: ConsentHandler = async ( switch (consent.status) { case ConsentStatus.PENDING_PARTY_LOOKUP: - await handlePartyLookup(server, consent) + await initiatePartyLookup(server, consent) break case ConsentStatus.PENDING_PARTY_CONFIRMATION: - await handleConsentRequest(server, consent) + await initiateConsentRequest(server, consent) break case ConsentStatus.AUTHENTICATION_REQUIRED: - await handleAuthentication(server, consent) + await initiateAuthentication(server, consent) break case ConsentStatus.CONSENT_GRANTED: - await handleChallengeGeneration(server, consent) + await initiateChallengeGeneration(server, consent) break case ConsentStatus.ACTIVE: @@ -219,7 +219,7 @@ export const onUpdate: ConsentHandler = async ( break case ConsentStatus.REVOKE_REQUESTED: - await handleRevokingConsent(server, consent) + await initiateRevokingConsent(server, consent) break default: throw new InvalidConsentStatusError(consent.status, consent.id) From 501af914a430eb59ec04c2c80c0c6361da245881 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Thu, 17 Sep 2020 13:11:12 +0530 Subject: [PATCH 106/114] refactor: awaiting batch commits in repositories Making internal methods async --- src/repositories/consent.ts | 37 +++++++++++++++++--------------- src/repositories/participants.ts | 3 ++- src/repositories/transaction.ts | 5 +++-- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index 047a0b98..4d1c3bce 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -102,25 +102,28 @@ export class FirebaseConsentRepository implements IConsentRepository { // Find and update all matching documents in Firebase that match the given conditions. firestoreQuery .get() - .then((response) => { - // Create a batch to perform all of the updates using a single request. - // Firebase will also execute the updates atomically according to the - // API specification. - const batch = firebase.firestore().batch() + .then( + async (response): Promise => { + // Create a batch to perform all of the updates using a single request. + // Firebase will also execute the updates atomically according to the + // API specification. + const batch = firebase.firestore().batch() - // Iterate through all matching documents add them to the processing batch. - response.docs.forEach((doc) => { - batch.update( - // Put a reference to the document. - firebase.firestore().collection('consents').doc(doc.id), - // Specify the updated fields and their new values. - data - ) - }) + // Iterate through all matching documents add them to the processing batch. + response.docs.forEach((doc) => { + batch.update( + // Put a reference to the document. + firebase.firestore().collection('consents').doc(doc.id), + // Specify the updated fields and their new values. + data + ) + }) - // Commit the updates. - return batch.commit() - }) + // Commit the updates. + await batch.commit() + return undefined + } + ) .catch((err) => { logger.error(err) }) diff --git a/src/repositories/participants.ts b/src/repositories/participants.ts index a62e662e..6006dc7a 100644 --- a/src/repositories/participants.ts +++ b/src/repositories/participants.ts @@ -70,7 +70,8 @@ export class FirebaseParticipantRepository implements IParticipantRepository { }) // Commit the updates. - return batch.commit() + await batch.commit() + return undefined }) .catch((err) => { logger.error(err) diff --git a/src/repositories/transaction.ts b/src/repositories/transaction.ts index edfea49f..57e6ecae 100644 --- a/src/repositories/transaction.ts +++ b/src/repositories/transaction.ts @@ -71,7 +71,7 @@ export class FirebaseTransactionRepository implements ITransactionRepository { // Find and update all matching documents in Firebase that match the given conditions. firestoreQuery .get() - .then((response) => { + .then(async (response) => { // Create a batch to perform all of the updates using a single request. // Firebase will also execute the updates atomically according to the // API specification. @@ -88,7 +88,8 @@ export class FirebaseTransactionRepository implements ITransactionRepository { }) // Commit the updates. - return batch.commit() + await batch.commit() + return undefined }) .catch((err) => { logger.error(err) From a5a8874c5798dd84703975b70f21f73807bbead5 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Thu, 17 Sep 2020 14:57:51 +0530 Subject: [PATCH 107/114] chore: bump sdk standard components to v 11.8.0 --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index bd1b2dac..b960d31e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2650,9 +2650,9 @@ } }, "@mojaloop/sdk-standard-components": { - "version": "11.6.0", - "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.6.0.tgz", - "integrity": "sha512-ZU6/roi+s1WBBfMbfqkYSKnhuMUU3APFACzcbKo3DLc5dgqDkZw0gdtctUUuta4r3IG84BkHUO8r0Obfav8KSg==", + "version": "11.8.0", + "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.8.0.tgz", + "integrity": "sha512-0Z4EgQDVOFt1ToRb5E0Eh/6lHFsksZ63HM10jm7n/RJ++AKDLso2WbfFtxkbsbAWkCC3dnfzsnE7KL9FLeWAeA==", "requires": { "base64url": "3.0.1", "fast-safe-stringify": "^2.0.7", diff --git a/package.json b/package.json index bc1e050d..0dc04a90 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "@hapi/vision": "^6.0.0", "@mojaloop/central-services-logger": "^10.6.0", "@mojaloop/central-services-shared": "^11.3.2", - "@mojaloop/sdk-standard-components": "^11.6.0", + "@mojaloop/sdk-standard-components": "^11.8.0", "@types/uuid": "^8.0.0", "convict": "^6.0.0", "dotenv": "^8.2.0", From 0e2a6f5e03366528d22be8160bb322de19c48323 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Thu, 17 Sep 2020 15:03:29 +0530 Subject: [PATCH 108/114] fix: Make id a required variable for InvalidConsentStatusError Change variable naming for clarity --- src/models/errors.ts | 6 ++---- src/server/handlers/firestore/consents.ts | 1 + test/unit/server/handlers/firestore/consents.test.ts | 5 ++++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/models/errors.ts b/src/models/errors.ts index 5b9ffe96..6a99baf2 100644 --- a/src/models/errors.ts +++ b/src/models/errors.ts @@ -38,9 +38,7 @@ export class MissingConsentFieldsError extends Error { } } export class InvalidConsentStatusError extends Error { - public constructor(consentStatus: string, consentId?: string) { - super( - `Invalid Consent Status Provided! ID: ${consentId} | Status: ${consentStatus}` - ) + public constructor(status: string, id: string) { + super(`Invalid Consent Status Provided! ID: ${id} | Status: ${status}`) } } diff --git a/src/server/handlers/firestore/consents.ts b/src/server/handlers/firestore/consents.ts index ff036f53..8e5723e2 100644 --- a/src/server/handlers/firestore/consents.ts +++ b/src/server/handlers/firestore/consents.ts @@ -221,6 +221,7 @@ export const onUpdate: ConsentHandler = async ( case ConsentStatus.REVOKE_REQUESTED: await initiateRevokingConsent(server, consent) break + default: throw new InvalidConsentStatusError(consent.status, consent.id) } diff --git a/test/unit/server/handlers/firestore/consents.test.ts b/test/unit/server/handlers/firestore/consents.test.ts index 62a5a57c..07b92330 100644 --- a/test/unit/server/handlers/firestore/consents.test.ts +++ b/test/unit/server/handlers/firestore/consents.test.ts @@ -141,7 +141,10 @@ describe('Handlers for consent documents in Firebase', () => { expect( consentsHandler.onUpdate(server, consentInvalidStatus) ).rejects.toThrow( - new InvalidConsentStatusError(consentInvalidStatus.status) + new InvalidConsentStatusError( + consentInvalidStatus.status, + consentInvalidStatus.id + ) ) }) From ca24cbe8a883b01d037c45029956c3ab1262b38a Mon Sep 17 00:00:00 2001 From: akapur99 Date: Thu, 17 Sep 2020 15:13:44 +0530 Subject: [PATCH 109/114] refactor: Use try/catch instead of .then/.catch for promise handling in repositories --- src/repositories/consent.ts | 61 +++++++++++++++----------------- src/repositories/participants.ts | 55 ++++++++++++++-------------- src/repositories/transaction.ts | 59 +++++++++++++++--------------- 3 files changed, 82 insertions(+), 93 deletions(-) diff --git a/src/repositories/consent.ts b/src/repositories/consent.ts index 4d1c3bce..9db0d952 100644 --- a/src/repositories/consent.ts +++ b/src/repositories/consent.ts @@ -90,43 +90,38 @@ export class FirebaseConsentRepository implements IConsentRepository { conditions: Record, data: Record ): Promise { - let firestoreQuery: FirebaseFirestore.Query = firebase - .firestore() - .collection('consents') - - // Chain all of the given conditions to the query - for (const key in conditions) { - firestoreQuery = firestoreQuery.where(key, '==', conditions[key]) - } + try { + let firestoreQuery: FirebaseFirestore.Query = firebase + .firestore() + .collection('consents') - // Find and update all matching documents in Firebase that match the given conditions. - firestoreQuery - .get() - .then( - async (response): Promise => { - // Create a batch to perform all of the updates using a single request. - // Firebase will also execute the updates atomically according to the - // API specification. - const batch = firebase.firestore().batch() + // Chain all of the given conditions to the query + for (const key in conditions) { + firestoreQuery = firestoreQuery.where(key, '==', conditions[key]) + } - // Iterate through all matching documents add them to the processing batch. - response.docs.forEach((doc) => { - batch.update( - // Put a reference to the document. - firebase.firestore().collection('consents').doc(doc.id), - // Specify the updated fields and their new values. - data - ) - }) + // Find and update all matching documents in Firebase that match the given conditions. + const response = await firestoreQuery.get() + // Create a batch to perform all of the updates using a single request. + // Firebase will also execute the updates atomically according to the + // API specification. + const batch = firebase.firestore().batch() - // Commit the updates. - await batch.commit() - return undefined - } - ) - .catch((err) => { - logger.error(err) + // Iterate through all matching documents add them to the processing batch. + response.docs.forEach((doc) => { + batch.update( + // Put a reference to the document. + firebase.firestore().collection('consents').doc(doc.id), + // Specify the updated fields and their new values. + data + ) }) + + // Commit the updates. + await batch.commit() + } catch (error) { + logger.error(error) + } } } diff --git a/src/repositories/participants.ts b/src/repositories/participants.ts index 6006dc7a..a3e6fd21 100644 --- a/src/repositories/participants.ts +++ b/src/repositories/participants.ts @@ -42,40 +42,37 @@ export interface IParticipantRepository { export class FirebaseParticipantRepository implements IParticipantRepository { async replace(data: Participant[]): Promise { - const collectionRef: FirebaseFirestore.CollectionReference = firebase - .firestore() - .collection('participants') + try { + const collectionRef: FirebaseFirestore.CollectionReference = firebase + .firestore() + .collection('participants') - // Find and update all matching documents in Firebase that match the given conditions. - collectionRef - .get() - .then(async (response) => { - // Create a batch to perform all of the updates using a single request. - // Firebase will also execute the updates atomically according to the - // API specification. - const batch = firebase.firestore().batch() + // Find and update all matching documents in Firebase that match the given conditions. + const response = await collectionRef.get() + // Create a batch to perform all of the updates using a single request. + // Firebase will also execute the updates atomically according to the + // API specification. + const batch = firebase.firestore().batch() - const batchSize = response.size - if (batchSize > 0) { - // If previous participants list exists, delete it + const batchSize = response.size + if (batchSize > 0) { + // If previous participants list exists, delete it - // Iterate through all matching documents add them to the processing batch. - response.docs.forEach((doc) => { - batch.delete(doc.ref) - }) - } - // Iterate through received participants list and add them to the processing batch. - data.forEach((participant: Participant) => { - batch.set(collectionRef.doc(), participant) + // Iterate through all matching documents add them to the processing batch. + response.docs.forEach((doc) => { + batch.delete(doc.ref) }) - - // Commit the updates. - await batch.commit() - return undefined - }) - .catch((err) => { - logger.error(err) + } + // Iterate through received participants list and add them to the processing batch. + data.forEach((participant: Participant) => { + batch.set(collectionRef.doc(), participant) }) + + // Commit the updates. + await batch.commit() + } catch (error) { + logger.error(error) + } } } diff --git a/src/repositories/transaction.ts b/src/repositories/transaction.ts index 57e6ecae..c09e4ae4 100644 --- a/src/repositories/transaction.ts +++ b/src/repositories/transaction.ts @@ -59,41 +59,38 @@ export class FirebaseTransactionRepository implements ITransactionRepository { conditions: Record, data: Record ): Promise { - let firestoreQuery: FirebaseFirestore.Query = firebase - .firestore() - .collection('transactions') + try { + let firestoreQuery: FirebaseFirestore.Query = firebase + .firestore() + .collection('transactions') - // Chain all of the given conditions to the query - for (const key in conditions) { - firestoreQuery = firestoreQuery.where(key, '==', conditions[key]) - } - - // Find and update all matching documents in Firebase that match the given conditions. - firestoreQuery - .get() - .then(async (response) => { - // Create a batch to perform all of the updates using a single request. - // Firebase will also execute the updates atomically according to the - // API specification. - const batch = firebase.firestore().batch() + // Chain all of the given conditions to the query + for (const key in conditions) { + firestoreQuery = firestoreQuery.where(key, '==', conditions[key]) + } - // Iterate through all matching documents add them to the processing batch. - response.docs.forEach((doc) => { - batch.update( - // Put a reference to the document. - firebase.firestore().collection('transactions').doc(doc.id), - // Specify the updated fields and their new values. - data - ) - }) + // Find and update all matching documents in Firebase that match the given conditions. + const response = await firestoreQuery.get() + // Create a batch to perform all of the updates using a single request. + // Firebase will also execute the updates atomically according to the + // API specification. + const batch = firebase.firestore().batch() - // Commit the updates. - await batch.commit() - return undefined - }) - .catch((err) => { - logger.error(err) + // Iterate through all matching documents add them to the processing batch. + response.docs.forEach((doc) => { + batch.update( + // Put a reference to the document. + firebase.firestore().collection('transactions').doc(doc.id), + // Specify the updated fields and their new values. + data + ) }) + + // Commit the updates. + await batch.commit() + } catch (error) { + logger.error(error) + } } } From c52584d93cf554e99c6ba03a4ee994a3164462e9 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Mon, 21 Sep 2020 12:11:20 +0530 Subject: [PATCH 110/114] style: remove redundant comment --- ambient.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ambient.d.ts b/ambient.d.ts index 7ed3df50..6c511c6e 100644 --- a/ambient.d.ts +++ b/ambient.d.ts @@ -21,7 +21,6 @@ * Google - Abhimanyu Kapur - Steven Wijaya - - Abhimanyu Kapur -------------- ******/ From 06a21b4e8a06782152f633ca6a511a9369847fde Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 22 Sep 2020 11:36:23 +0530 Subject: [PATCH 111/114] build: Bump sdk-standard-components to v11.9.0 --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index b960d31e..f890c8df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2650,9 +2650,9 @@ } }, "@mojaloop/sdk-standard-components": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.8.0.tgz", - "integrity": "sha512-0Z4EgQDVOFt1ToRb5E0Eh/6lHFsksZ63HM10jm7n/RJ++AKDLso2WbfFtxkbsbAWkCC3dnfzsnE7KL9FLeWAeA==", + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/@mojaloop/sdk-standard-components/-/sdk-standard-components-11.9.0.tgz", + "integrity": "sha512-OArDwE4enEJHh5L6b+sp8VuIDei1hy/KWtER39hVAK9Zp7Pn+o+M+xw73qsjkzWYU/MOvK2bO2HEQX5sEkUXbw==", "requires": { "base64url": "3.0.1", "fast-safe-stringify": "^2.0.7", diff --git a/package.json b/package.json index 0dc04a90..b76d63aa 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "@hapi/vision": "^6.0.0", "@mojaloop/central-services-logger": "^10.6.0", "@mojaloop/central-services-shared": "^11.3.2", - "@mojaloop/sdk-standard-components": "^11.8.0", + "@mojaloop/sdk-standard-components": "^11.9.0", "@types/uuid": "^8.0.0", "convict": "^6.0.0", "dotenv": "^8.2.0", From 30f7fb75eaef40cbeb21254a372905cb89722b28 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Tue, 22 Sep 2020 11:44:35 +0530 Subject: [PATCH 112/114] feat: Implement getParties request in mojaloopClient --- src/shared/ml-thirdparty-client/index.ts | 12 +++++---- .../shared/ml-thirdparty-client/index.test.ts | 27 ++++++++----------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/shared/ml-thirdparty-client/index.ts b/src/shared/ml-thirdparty-client/index.ts index 503e7abc..21fd4736 100644 --- a/src/shared/ml-thirdparty-client/index.ts +++ b/src/shared/ml-thirdparty-client/index.ts @@ -110,12 +110,14 @@ export class Client { * @param _id the party identifier */ public async getParties( - _type: PartyIdType, - _id: string + idType: PartyIdType, + idValue: string, + idSubValue?: string ): Promise { - // TODO: Implement communication with Mojaloop. - // Placeholder below - throw new NotImplementedError() + if (idSubValue) { + return this.mojaloopRequests.getParties(idType, idValue, idSubValue) + } + return this.mojaloopRequests.getParties(idType, idValue) } /** diff --git a/test/unit/shared/ml-thirdparty-client/index.test.ts b/test/unit/shared/ml-thirdparty-client/index.test.ts index 807845d6..c88d4275 100644 --- a/test/unit/shared/ml-thirdparty-client/index.test.ts +++ b/test/unit/shared/ml-thirdparty-client/index.test.ts @@ -153,24 +153,19 @@ describe('Mojaloop third-party client', () => { }) }) - it('Should throw Not Implemented error, attempting to perform party lookup', (): void => { - expect( - client.getParties(PartyIdType.MSISDN, '+1-111-111-1111') - ).rejects.toThrow(new NotImplementedError()) - - // TODO: Use this test once implemented - // // Arrange - // const getPartiesSpy = jest - // .spyOn(client.mojaloopRequests.get, 'getParties') - // .mockImplementation() - // const type = PartyIdType.MSISDN - // const identifier = '+1-111-111-1111' + it('Should perform party lookup', (): void => { + // Arrange + const getPartiesSpy = jest + .spyOn(client.mojaloopRequests, 'getParties') + .mockImplementation() + const type = PartyIdType.MSISDN + const identifier = '+1-111-111-1111' - // // Act - // client.getParties(PartyIdType.MSISDN, '+1-111-111-1111') + // Act + client.getParties(PartyIdType.MSISDN, '+1-111-111-1111') - // // Assert - // expect(getPartiesSpy).toBeCalledWith(type, identifier) + // Assert + expect(getPartiesSpy).toBeCalledWith(type, identifier) }) it('Should perform transaction request', (): void => { From a201c95dbcdcd398ebc152c0ec4709a2d2082d56 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Thu, 24 Sep 2020 16:03:36 +0530 Subject: [PATCH 113/114] style: modified TODO comment --- src/server/handlers/firestore/transactions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/handlers/firestore/transactions.ts b/src/server/handlers/firestore/transactions.ts index d6ea1296..db28b588 100644 --- a/src/server/handlers/firestore/transactions.ts +++ b/src/server/handlers/firestore/transactions.ts @@ -43,7 +43,7 @@ import { transactionRepository } from '~/repositories/transaction' import * as validator from './transactions.validator' import { consentRepository } from '~/repositories/consent' -// TODO: Replace once decided how to implement +// TODO: Replace once design decision made on how we should be obtaining this const destParticipantId = 'PLACEHOLDER' async function handleNewTransaction(_: StateServer, transaction: Transaction) { From 38de745a4e8848ea5905675b5801b2882137af23 Mon Sep 17 00:00:00 2001 From: akapur99 Date: Fri, 25 Sep 2020 14:17:13 +0530 Subject: [PATCH 114/114] fix: removed unneeded comments --- src/repositories/participants.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/repositories/participants.ts b/src/repositories/participants.ts index a3e6fd21..754719d9 100644 --- a/src/repositories/participants.ts +++ b/src/repositories/participants.ts @@ -47,7 +47,6 @@ export class FirebaseParticipantRepository implements IParticipantRepository { .firestore() .collection('participants') - // Find and update all matching documents in Firebase that match the given conditions. const response = await collectionRef.get() // Create a batch to perform all of the updates using a single request. // Firebase will also execute the updates atomically according to the