diff --git a/package-lock.json b/package-lock.json index c394895..74277b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "connection-manager-api", - "version": "2.3.1", + "version": "2.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "connection-manager-api", - "version": "2.3.1", + "version": "2.4.0", "license": "Apache-2.0", "dependencies": { "@kubernetes/client-node": "^0.21.0", @@ -31,7 +31,7 @@ "passport-jwt": "^4.0.1", "request": "^2.88.2", "request-promise-native": "^1.0.9", - "soap": "^1.1.1", + "soap": "^1.1.2", "winston": "^3.14.2", "xml2js": "^0.6.2" }, @@ -45,7 +45,7 @@ "eslint-plugin-import": "^2.29.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^6.4.0", - "husky": "^9.1.4", + "husky": "^9.1.5", "jshint": "^2.13.6", "mocha": "^10.7.3", "npm-audit-resolver": "3.0.0-RC.0", @@ -2510,9 +2510,9 @@ "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" }, "node_modules/axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -6443,9 +6443,9 @@ } }, "node_modules/husky": { - "version": "9.1.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.4.tgz", - "integrity": "sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.5.tgz", + "integrity": "sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==", "dev": true, "bin": { "husky": "bin.js" @@ -10921,11 +10921,11 @@ } }, "node_modules/soap": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/soap/-/soap-1.1.1.tgz", - "integrity": "sha512-Mxj/nQ9oO+zYiVZqk9AiXgeHkX/xj8EAnbri9BkxGoMrWw3fKtQulaquSbIO+kgoZfm7g08xddtmpOG2H+Z0zQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/soap/-/soap-1.1.2.tgz", + "integrity": "sha512-MoyShH7aRb/3kjbUeD/zZQh3kEXlS6rTlDN94Io0pvoPotY0ga+PzJpE+FjV74I2LrTFfPFK0n53Mu3y2HkpRQ==", "dependencies": { - "axios": "^1.7.2", + "axios": "^1.7.4", "axios-ntlm": "^1.4.2", "debug": "^4.3.5", "formidable": "^3.5.1", @@ -14926,9 +14926,9 @@ "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" }, "axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "requires": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -17851,9 +17851,9 @@ "dev": true }, "husky": { - "version": "9.1.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.4.tgz", - "integrity": "sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.5.tgz", + "integrity": "sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==", "dev": true }, "iconv-lite": { @@ -21208,11 +21208,11 @@ } }, "soap": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/soap/-/soap-1.1.1.tgz", - "integrity": "sha512-Mxj/nQ9oO+zYiVZqk9AiXgeHkX/xj8EAnbri9BkxGoMrWw3fKtQulaquSbIO+kgoZfm7g08xddtmpOG2H+Z0zQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/soap/-/soap-1.1.2.tgz", + "integrity": "sha512-MoyShH7aRb/3kjbUeD/zZQh3kEXlS6rTlDN94Io0pvoPotY0ga+PzJpE+FjV74I2LrTFfPFK0n53Mu3y2HkpRQ==", "requires": { - "axios": "^1.7.2", + "axios": "^1.7.4", "axios-ntlm": "^1.4.2", "debug": "^4.3.5", "formidable": "^3.5.1", diff --git a/package.json b/package.json index dbbc972..843d9de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "connection-manager-api", - "version": "2.3.1", + "version": "2.4.0", "description": "ModusBox Connection Manager API", "license": "Apache-2.0", "author": "ModusBox", @@ -71,7 +71,7 @@ "passport-jwt": "^4.0.1", "request": "^2.88.2", "request-promise-native": "^1.0.9", - "soap": "^1.1.1", + "soap": "^1.1.2", "winston": "^3.14.2", "xml2js": "^0.6.2" }, @@ -85,7 +85,7 @@ "eslint-plugin-import": "^2.29.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^6.4.0", - "husky": "^9.1.4", + "husky": "^9.1.5", "jshint": "^2.13.6", "mocha": "^10.7.3", "npm-audit-resolver": "3.0.0-RC.0", diff --git a/src/api/swagger.yaml b/src/api/swagger.yaml index 4c703fc..5805154 100644 --- a/src/api/swagger.yaml +++ b/src/api/swagger.yaml @@ -2776,6 +2776,11 @@ components: monetaryZoneId: type: string description: The monetary Zone + fxpCurrencies: + type: array + description: List of FX currencies + items: + type: string isProxy: type: boolean description: Proxy flag diff --git a/src/db/migrations/20240820130000_create_fxp_supported_currencies_table.js b/src/db/migrations/20240820130000_create_fxp_supported_currencies_table.js new file mode 100644 index 0000000..d71660d --- /dev/null +++ b/src/db/migrations/20240820130000_create_fxp_supported_currencies_table.js @@ -0,0 +1,17 @@ +exports.up = function (knex, Promise) { + return knex.schema.createTable('fxp_supported_currencies', (table) => { + table.increments('id').primary(); + table.integer('dfspId').unsigned().notNullable(); + table.string('monetaryZoneId', 3); + table.foreign('monetaryZoneId').references('monetaryZoneId').inTable('monetaryZone'); + table.foreign('dfspId', 'FK_CURR_DFSP_ID').references('dfsps.id').onDelete('CASCADE').onUpdate('NO ACTION'); + table.index('dfspId', 'FK_CURR_DFSP_ID_idx'); + table.unique(['dfspId', 'monetaryZoneId']); + if (!process.env.TEST) table.engine('InnoDB'); + if (!process.env.TEST) table.charset('utf8mb4'); + }); +}; + +exports.down = function (knex, Promise) { + return knex.schema.dropTableIfExists('fxp_supported_currencies'); +}; diff --git a/src/db/seeds/03_dfsp.js b/src/db/seeds/03_dfsp.js index ec824b6..9ffbcaa 100644 --- a/src/db/seeds/03_dfsp.js +++ b/src/db/seeds/03_dfsp.js @@ -11,12 +11,28 @@ exports.seed = async (knex) => { dfsps.map(([dfsp_id, monetaryZoneId, isProxy]) => ({ dfsp_id, name: dfsp_id, - monetaryZoneId: monetaryZoneId || null, + monetaryZoneId: monetaryZoneId?.length === 3 ? monetaryZoneId : null, security_group: `Application/DFSP:${dfsp_id}`, isProxy: isProxy === 'proxy' })) ).onConflict('dfsp_id').merge(); + for (const [dfsp_id, monetaryZones] of dfsps) { + const supportedCurrencies = monetaryZones.split('/').map(s => s.trim()).filter(s => s.length === 3); + const dfspId = (await knex('dfsps').where({dfsp_id}).first('id')).id; + if (supportedCurrencies.length > 1) { + for (const monetaryZoneId of supportedCurrencies) { + await knex('fxp_supported_currencies').insert({ + dfspId, + monetaryZoneId + }).onConflict(['dfspId', 'monetaryZoneId']).ignore(); + } + await knex('fxp_supported_currencies').whereNotIn('monetaryZoneId', supportedCurrencies).andWhere({dfspId}).del(); + } else { + await knex('fxp_supported_currencies').where({dfspId}).del(); + } + } + const pkiEngine = new PKIEngine(Constants.vault); await pkiEngine.connect(); for (const [dfsp_id] of dfsps) { diff --git a/src/models/DFSPModel.js b/src/models/DFSPModel.js index 741acf9..0b38492 100644 --- a/src/models/DFSPModel.js +++ b/src/models/DFSPModel.js @@ -41,6 +41,16 @@ exports.getDfspsByMonetaryZones = async (monetaryZoneId) => { return findAllByField('monetaryZoneId', monetaryZoneId); }; +exports.getFxpSupportedCurrencies = async (dfspId) => { + return (await + knex + .table('fxp_supported_currencies') + .join(DFSP_TABLE, 'fxp_supported_currencies.dfspId', 'dfsps.id') + .where(DFSP_TABLE + '.dfsp_id', dfspId) + .select('fxp_supported_currencies.monetaryZoneId') + ).map((row) => row.monetaryZoneId); +}; + const findByField = async (columnName, value) => { const rows = await knex.table(DFSP_TABLE).where(columnName, value).select(); if (rows.length === 0) { @@ -65,6 +75,14 @@ exports.create = async (values) => { return knex.table(DFSP_TABLE).insert(values); }; +exports.createFxpSupportedCurrencies = async (dfsp_id, monetaryZoneIds) => { + if (!monetaryZoneIds?.length) return; + const dfspId = await findIdByDfspId(dfsp_id); + return knex.table('fxp_supported_currencies').insert( + monetaryZoneIds.map((monetaryZoneId) => ({ dfspId, monetaryZoneId })) + ); +}; + exports.deleteByRawId = async (id) => { return knex.table(DFSP_TABLE).where({ id }).del(); }; diff --git a/src/pki_engine/VaultPKIEngine.js b/src/pki_engine/VaultPKIEngine.js index 930618b..5c1f37d 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, isProxy) { + async populateDFSPClientCertBundle (dfspId, dfspName, dfspMonetaryZoneId, isProxy, fxpCurrencies) { 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, + fxpCurrencies: fxpCurrencies.join(' '), isProxy, }; await this.client.write(`${this.mounts.dfspClientCertBundle}/${dfspName}`, bundle); diff --git a/src/service/DfspOnboardService.js b/src/service/DfspOnboardService.js index a899ced..7015f6a 100644 --- a/src/service/DfspOnboardService.js +++ b/src/service/DfspOnboardService.js @@ -29,7 +29,8 @@ exports.onboardDFSP = async (ctx, dfspId) => { await PkiService.validateDfsp(ctx, dfspId); const { pkiEngine } = ctx; const { id, monetaryZoneId, isProxy } = await DFSPModel.findByDfspId(dfspId); - await pkiEngine.populateDFSPClientCertBundle(id, dfspId, monetaryZoneId, !!isProxy); + const fxpCurrencies = await DFSPModel.getFxpSupportedCurrencies(dfspId); + await pkiEngine.populateDFSPClientCertBundle(id, dfspId, monetaryZoneId, !!isProxy, fxpCurrencies); const ipsBundle = await getIPsBundle(); await pkiEngine.populateDFSPInternalIPWhitelistBundle(ipsBundle); diff --git a/src/service/PkiService.js b/src/service/PkiService.js index 10b8660..e47d610 100644 --- a/src/service/PkiService.js +++ b/src/service/PkiService.js @@ -46,6 +46,7 @@ exports.createDFSP = async (ctx, body) => { try { await DFSPModel.create(values); + await DFSPModel.createFxpSupportedCurrencies(body.dfspId, body.fxpCurrencies); return { id: body.dfspId }; } catch (err) { console.error(err);