From 7df568f8746f04cdda5c625e67f43472a7a4e504 Mon Sep 17 00:00:00 2001 From: "geka.evk" Date: Thu, 15 Aug 2024 16:27:39 +0100 Subject: [PATCH] feat(iprod-416): updated from main --- .github/workflows/releaseWorkflow.yml | 18 +++++----- .gitignore | 1 + .ncurc.yaml | 1 + package-lock.json | 16 ++++----- package.json | 2 +- src/api/swagger.yaml | 10 +++++- src/controllers/JWSCerts.js | 2 +- .../20240801112400_add_isProxy_to_dfsp.js | 11 +++++++ src/db/seeds/03_dfsp.js | 33 +++++++++++++++++++ src/models/DFSPModel.js | 1 + src/pki_engine/VaultPKIEngine.js | 11 ++++--- src/service/DfspOnboardService.js | 4 +-- src/service/JWSCertsService.js | 4 +-- src/service/PkiService.js | 3 ++ .../tests/mcm-api-endpoint.test.ts | 5 ++- 15 files changed, 92 insertions(+), 30 deletions(-) create mode 100644 src/db/migrations/20240801112400_add_isProxy_to_dfsp.js create mode 100644 src/db/seeds/03_dfsp.js diff --git a/.github/workflows/releaseWorkflow.yml b/.github/workflows/releaseWorkflow.yml index 33370103..f77e48a8 100644 --- a/.github/workflows/releaseWorkflow.yml +++ b/.github/workflows/releaseWorkflow.yml @@ -8,39 +8,39 @@ on: - main ## -# Re-usable workflows can be found at https://github.com/modusbox/github-actions-node +# Re-usable workflows can be found at https://github.com/infitx-org/github-actions-node ## jobs: test_lint: - uses: modusbox/github-actions-node/.github/workflows/testLintJob.yml@v0.0.4 + uses: infitx-org/github-actions-node/.github/workflows/testLintJob.yml@v0.0.4 test_dependencies: - uses: modusbox/github-actions-node/.github/workflows/testDependencyJob.yml@v0.0.4 + uses: infitx-org/github-actions-node/.github/workflows/testDependencyJob.yml@v0.0.4 test_audit: - uses: modusbox/github-actions-node/.github/workflows/testAuditJob.yml@v0.0.4 + uses: infitx-org/github-actions-node/.github/workflows/testAuditJob.yml@v0.0.4 test_license: - uses: modusbox/github-actions-node/.github/workflows/testLicenseJob.yml@v0.0.4 + uses: infitx-org/github-actions-node/.github/workflows/testLicenseJob.yml@v0.0.4 # TODO: Enable when there are unit tests # test_unit: - # uses: modusbox/github-actions-node/.github/workflows/testUnitJob.yml@v0.0.4 + # uses: infitx-org/github-actions-node/.github/workflows/testUnitJob.yml@v0.0.4 # TODO: Enable when there is coveragte for unit tests # test_coverage: - # uses: modusbox/github-actions-node/.github/workflows/testCoverageJob.yml@v0.0.4 + # uses: infitx-org/github-actions-node/.github/workflows/testCoverageJob.yml@v0.0.4 test_int: - uses: modusbox/github-actions-node/.github/workflows/testIntJob.yml@v0.0.4 + uses: infitx-org/github-actions-node/.github/workflows/testIntJob.yml@v0.0.4 test_func: uses: ./.github/workflows/testFuncJob.yml publish_image: - uses: modusbox/github-actions-node/.github/workflows/publishImageJob.yml@v0.0.2 + uses: infitx-org/github-actions-node/.github/workflows/publishImageJob.yml@v0.0.2 with: RELEASE_VERSION: ${{ github.event.release.tag_name }} RELEASE_URL: ${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ github.event.release.tag_name }} diff --git a/.gitignore b/.gitignore index 6c4ce3f4..9fd98920 100644 --- a/.gitignore +++ b/.gitignore @@ -113,3 +113,4 @@ localEnvs # tests **/junit.xml +.token diff --git a/.ncurc.yaml b/.ncurc.yaml index ebc958a7..76f8b2de 100644 --- a/.ncurc.yaml +++ b/.ncurc.yaml @@ -2,4 +2,5 @@ reject: [ "chai", # Chai v.5 now only supports EcmaScript Modules (ESM) - no require('chi') "eslint", # Upgrade is breaking due to peer dependencies + "eslint-plugin-promise" # Upgrade is breaking due to peer dependencies ] diff --git a/package-lock.json b/package-lock.json index b8254ee5..305720da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.29.1", "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^7.1.0", + "eslint-plugin-promise": "^6.4.0", "husky": "^9.1.4", "jshint": "^2.13.6", "mocha": "^10.7.3", @@ -4701,12 +4701,12 @@ } }, "node_modules/eslint-plugin-promise": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.1.0.tgz", - "integrity": "sha512-8trNmPxdAy3W620WKDpaS65NlM5yAumod6XeC4LOb+jxlkG4IVcp68c6dXY2ev+uT4U1PtG57YDV6EGAXN0GbQ==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz", + "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", "dev": true, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -16778,9 +16778,9 @@ } }, "eslint-plugin-promise": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.1.0.tgz", - "integrity": "sha512-8trNmPxdAy3W620WKDpaS65NlM5yAumod6XeC4LOb+jxlkG4IVcp68c6dXY2ev+uT4U1PtG57YDV6EGAXN0GbQ==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz", + "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index 59f10dd9..498f2f6f 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.29.1", "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^7.1.0", + "eslint-plugin-promise": "^6.4.0", "husky": "^9.1.4", "jshint": "^2.13.6", "mocha": "^10.7.3", diff --git a/src/api/swagger.yaml b/src/api/swagger.yaml index 14cd4a68..4c703fce 100644 --- a/src/api/swagger.yaml +++ b/src/api/swagger.yaml @@ -2715,7 +2715,6 @@ components: BaseJWSCert: required: - publicKey - - createdAt type: object properties: publicKey: @@ -2777,6 +2776,9 @@ components: monetaryZoneId: type: string description: The monetary Zone + isProxy: + type: boolean + description: Proxy flag securityGroup: type: string description: OAuth role/group owner @@ -2793,6 +2795,9 @@ components: monetaryZoneId: type: string description: The monetary Zone + isProxy: + type: boolean + description: Proxy flag example: name: DFSP 1 monetaryZoneId: EUR @@ -2808,6 +2813,9 @@ components: monetaryZoneId: type: string description: The monetary Zone + isProxy: + type: boolean + description: Proxy flag securityGroup: type: string description: DFSP Security group diff --git a/src/controllers/JWSCerts.js b/src/controllers/JWSCerts.js index 736da4cb..5f88fb46 100644 --- a/src/controllers/JWSCerts.js +++ b/src/controllers/JWSCerts.js @@ -29,7 +29,7 @@ exports.createDfspJWSCerts = (req, res, next, body, dfspId) => { }; exports.createDfspExternalJWSCerts = (req, res, next, body) => { - const sourceDfspId = req.headers['X-Source-DFSP-ID']; + const sourceDfspId = req.headers['X-DFSP-ID']; JWSCertsService.createDfspExternalJWSCerts(req.context, body, sourceDfspId) .then(response => { utils.writeJson(res, response); diff --git a/src/db/migrations/20240801112400_add_isProxy_to_dfsp.js b/src/db/migrations/20240801112400_add_isProxy_to_dfsp.js new file mode 100644 index 00000000..c5e0aacc --- /dev/null +++ b/src/db/migrations/20240801112400_add_isProxy_to_dfsp.js @@ -0,0 +1,11 @@ +exports.up = function (knex, Promise) { + return knex.schema.table('dfsps', function (table) { + table.boolean('isProxy'); + }); +}; + +exports.down = function (knex, Promise) { + return knex.schema.table('dfsps', function (table) { + table.dropColumn('isProxy'); + }); +}; diff --git a/src/db/seeds/03_dfsp.js b/src/db/seeds/03_dfsp.js new file mode 100644 index 00000000..ec824b64 --- /dev/null +++ b/src/db/seeds/03_dfsp.js @@ -0,0 +1,33 @@ +// pass DFSP_SEED=DFSP1:KES,DFSP2:MWK,DFSP3:UGX to seed the dfsp with the given monetary zones +exports.seed = async (knex) => { + if (process.env.DFSP_SEED) { + const Constants = require('../../constants/Constants'); + const { createCSRAndDFSPOutboundEnrollment, getDFSPOutboundEnrollments } = require('../../service/DfspOutboundService'); + const PKIEngine = require('../../pki_engine/VaultPKIEngine'); + const dfsps = process.env.DFSP_SEED.split(',') + .map(dfsp => dfsp.split(':').map(s => s.trim())); + + await knex('dfsps').insert( + dfsps.map(([dfsp_id, monetaryZoneId, isProxy]) => ({ + dfsp_id, + name: dfsp_id, + monetaryZoneId: monetaryZoneId || null, + security_group: `Application/DFSP:${dfsp_id}`, + isProxy: isProxy === 'proxy' + })) + ).onConflict('dfsp_id').merge(); + + const pkiEngine = new PKIEngine(Constants.vault); + await pkiEngine.connect(); + for (const [dfsp_id] of dfsps) { + const exists = await getDFSPOutboundEnrollments({pkiEngine}, dfsp_id); + if (exists.length === 0) { + await createCSRAndDFSPOutboundEnrollment( + {pkiEngine}, + dfsp_id, + Constants.clientCsrParameters + ); + } + } + } +}; diff --git a/src/models/DFSPModel.js b/src/models/DFSPModel.js index 82391021..741acf9f 100644 --- a/src/models/DFSPModel.js +++ b/src/models/DFSPModel.js @@ -91,6 +91,7 @@ const rowToObject = (dfsp) => { dfspId: dfsp.dfsp_id, name: dfsp.name, monetaryZoneId: dfsp.monetaryZoneId ? dfsp.monetaryZoneId : undefined, + isProxy: dfsp.isProxy, securityGroup: dfsp.security_group }; }; diff --git a/src/pki_engine/VaultPKIEngine.js b/src/pki_engine/VaultPKIEngine.js index 8cc34107..930618bc 100644 --- a/src/pki_engine/VaultPKIEngine.js +++ b/src/pki_engine/VaultPKIEngine.js @@ -306,7 +306,7 @@ class VaultPKIEngine extends PKIEngine { } // endregion - async populateDFSPClientCertBundle (dfspId, dfspName, dfspMonetaryZoneId) { + async populateDFSPClientCertBundle (dfspId, dfspName, dfspMonetaryZoneId, isProxy) { this.validateId(dfspId, 'dfspId'); const dfspCA = await this.getDFSPCA(dfspId); const enrollments = await this.getDFSPOutboundEnrollments(dfspId); @@ -321,6 +321,7 @@ class VaultPKIEngine extends PKIEngine { fqdn: cert.subject.CN, host: dfspName, currency_code: dfspMonetaryZoneId, + isProxy, }; await this.client.write(`${this.mounts.dfspClientCertBundle}/${dfspName}`, bundle); } @@ -603,7 +604,7 @@ class VaultPKIEngine extends PKIEngine { const validation = new Validation(code, true); if (valid) { validation.result = ValidationCodes.VALID_STATES.VALID; - + validation.messageTemplate = 'Certificate is valid for ${data.currentDate}'; validation.data = { currentDate: { @@ -614,7 +615,7 @@ class VaultPKIEngine extends PKIEngine { validation.message = `Certificate is valid for ${moment(validation.data.currentDate.value).format()}`; } else { validation.result = ValidationCodes.VALID_STATES.INVALID; - + validation.messageTemplate = 'Certificate is not valid for ${data.currentDate}. It is not valid before ${data.notBeforeDate} and after ${data.notAfterDate}'; validation.data = { currentDate: { @@ -702,10 +703,10 @@ class VaultPKIEngine extends PKIEngine { validateCertificateKeyLength (serverCert, keyLength, code) { const { valid, reason } = this.verifyCertKeyLength(serverCert, keyLength); if (!valid) { - + const validation = new Validation(code, true); validation.result = ValidationCodes.VALID_STATES.INVALID; - + validation.messageTemplate = 'Certificate key length ${data.actualKeySize.value} invalid, should be ${data.keyLength.value}'; validation.details = reason; validation.data = { diff --git a/src/service/DfspOnboardService.js b/src/service/DfspOnboardService.js index d0c44450..a899ced0 100644 --- a/src/service/DfspOnboardService.js +++ b/src/service/DfspOnboardService.js @@ -28,8 +28,8 @@ const getIPsBundle = async () => { exports.onboardDFSP = async (ctx, dfspId) => { await PkiService.validateDfsp(ctx, dfspId); const { pkiEngine } = ctx; - const { id, monetaryZoneId } = await DFSPModel.findByDfspId(dfspId); - await pkiEngine.populateDFSPClientCertBundle(id, dfspId, monetaryZoneId); + const { id, monetaryZoneId, isProxy } = await DFSPModel.findByDfspId(dfspId); + await pkiEngine.populateDFSPClientCertBundle(id, dfspId, monetaryZoneId, !!isProxy); const ipsBundle = await getIPsBundle(); await pkiEngine.populateDFSPInternalIPWhitelistBundle(ipsBundle); diff --git a/src/service/JWSCertsService.js b/src/service/JWSCertsService.js index 2607d6dc..4fe9349a 100644 --- a/src/service/JWSCertsService.js +++ b/src/service/JWSCertsService.js @@ -58,12 +58,12 @@ exports.createDfspExternalJWSCerts = async (ctx, body, sourceDfspId) => { const result = []; for(let i = 0; i < externalDfspList.length; i++) { const dfspJwsItem = externalDfspList[i]; - const { dfspId, publicKey, createdAt } = dfspJwsItem; + const { dfspId, publicKey } = dfspJwsItem; const { validations, validationState } = pkiEngine.validateJWSCertificate(publicKey); const jwsData = { dfspId, publicKey, - createdAt, + createdAt: dfspJwsItem.createdAt || 0, validations, validationState, }; diff --git a/src/service/PkiService.js b/src/service/PkiService.js index 849771d8..10b86608 100644 --- a/src/service/PkiService.js +++ b/src/service/PkiService.js @@ -40,6 +40,7 @@ exports.createDFSP = async (ctx, body) => { dfsp_id: body.dfspId, name: body.name, monetaryZoneId: body.monetaryZoneId ? body.monetaryZoneId : undefined, + isProxy: body.isProxy, security_group: body.securityGroup || 'Application/DFSP:' + dfspIdNoSpaces }; @@ -108,6 +109,7 @@ exports.updateDFSP = async (ctx, dfspId, newDfsp) => { const values = { name: newDfsp.name, monetaryZoneId: newDfsp.monetaryZoneId, + isProxy: newDfsp.isProxy, security_group: newDfsp.securityGroup }; @@ -205,6 +207,7 @@ const dfspRowToObject = (row) => { id: row.dfsp_id, name: row.name, monetaryZoneId: row.monetaryZoneId ? row.monetaryZoneId : undefined, + isProxy: row.isProxy, securityGroup: row.security_group, }; }; diff --git a/test/functional-tests/tests/mcm-api-endpoint.test.ts b/test/functional-tests/tests/mcm-api-endpoint.test.ts index f852eb19..ca4b908b 100644 --- a/test/functional-tests/tests/mcm-api-endpoint.test.ts +++ b/test/functional-tests/tests/mcm-api-endpoint.test.ts @@ -21,6 +21,8 @@ * Miguel de Barros - miguel.debarros@modusbox.com ** ************************************************************************* */ +import { isProxy } from "util/types"; + jest.setTimeout(999999) const { ApiHelper, MethodEnum, ApiHelperOptions } = require('../util/api-helper'); @@ -35,7 +37,8 @@ describe('MCM API Tests', () => { const dfspObject = { dfspId: `test${randomSeed}`, name: `test${randomSeed}`, - monetaryZoneId: 'XTS' + monetaryZoneId: 'XTS', + isProxy: false } const apiHelperOptions: typeof ApiHelperOptions = {};