From d0ce81ed3736deb9bea162360391b4ffd104a86e Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Wed, 12 Jun 2024 21:43:06 +0700 Subject: [PATCH] chore: platform services authentication for Core RPC --- .../configs/defaults/getBaseConfigFactory.js | 41 ++++++++++++++++++- .../configs/getConfigFileMigrationsFactory.js | 12 ++++++ packages/dashmate/docker-compose.yml | 8 ++-- .../dashmate/src/config/configJsonSchema.js | 38 +++++++++++++---- .../dashmate/src/core/startCoreFactory.js | 4 +- .../src/listr/tasks/reindexNodeTaskFactory.js | 4 +- .../setup/setupLocalPresetTaskFactory.js | 8 +++- .../setup/setupRegularPresetTaskFactory.js | 6 ++- .../listr/tasks/startGroupNodesTaskFactory.js | 4 +- .../src/listr/tasks/startNodeTaskFactory.js | 4 +- .../src/listr/tasks/stopNodeTaskFactory.js | 12 +++--- packages/dashmate/src/status/scopes/core.js | 4 +- .../dashmate/src/status/scopes/masternode.js | 8 ++-- .../dashmate/src/status/scopes/platform.js | 4 +- .../src/templates/renderTemplateFactory.js | 3 +- .../dashmate/templates/core/dash.conf.dot | 23 +++++++---- .../core/insight/dashcore-node.json.dot | 4 +- .../platform/drive/tenderdash/config.toml.dot | 4 +- .../dashmate/test/e2e/testnetEvonode.spec.js | 4 +- .../dashmate/test/e2e/testnetFullnode.spec.js | 4 +- scripts/configure_dotenv.sh | 4 +- 21 files changed, 144 insertions(+), 59 deletions(-) diff --git a/packages/dashmate/configs/defaults/getBaseConfigFactory.js b/packages/dashmate/configs/defaults/getBaseConfigFactory.js index 9459d657db5..0ccee864ed6 100644 --- a/packages/dashmate/configs/defaults/getBaseConfigFactory.js +++ b/packages/dashmate/configs/defaults/getBaseConfigFactory.js @@ -90,8 +90,45 @@ export default function getBaseConfigFactory(homeDir) { rpc: { host: '127.0.0.1', port: 9998, - user: 'dashrpc', - password: 'rpcpassword', + users: { + dashmate: { + password: 'rpcpassword', + whitelist: null, + lowPriority: false, + }, + dapi: { + password: 'rpcpassword', + whitelist: [ + 'getbestblockhash', 'getblockhash', 'sendrawtransaction', 'getrawtransaction', + 'getblockstats', 'getmerkleblocks', 'getrawtransactionmulti', 'getrawmempool', + 'getblockcount', 'getbestchainlock', 'getblock', 'getblockheader', 'getblockheaders', + 'protx diff', 'getnetworkinfo', 'getblockchaininfo', 'mnsync status', 'masternode status', + ], + lowPriority: true, + }, + drive_consensus: { + password: 'rpcpassword', + whitelist: [ + 'getbestchainlock', 'getblockchaininfo', 'getrawtransaction', 'submitchainlock', + 'verifychainlock', 'protx listdiff', 'quorum listextended', 'quorum info', + 'getassetunlockstatuses', 'sendrawtransaction', 'mnsync status', + ], + lowPriority: false, + }, + drive_other: { + password: 'rpcpassword', + whitelist: ['getrawtransaction'], + lowPriority: true, + }, + tenderdash: { + password: 'rpcpassword', + whitelist: [ + 'quorum info', 'quorum verify', 'quorum sign', 'masternode status', 'masternodelist', + 'ping', 'getnetworkinfo', + ], + lowPriority: false, + }, + }, allowIps: ['127.0.0.1', '172.16.0.0/12', '192.168.0.0/16'], }, spork: { diff --git a/packages/dashmate/configs/getConfigFileMigrationsFactory.js b/packages/dashmate/configs/getConfigFileMigrationsFactory.js index cdd3cd9405f..2a8f1d61546 100644 --- a/packages/dashmate/configs/getConfigFileMigrationsFactory.js +++ b/packages/dashmate/configs/getConfigFileMigrationsFactory.js @@ -613,6 +613,18 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) return configFile; }, + '1.0.0-dev.16': (configFile) => { + Object.entries(configFile.configs) + .forEach(([, options]) => { + options.core.rpc.users = base.get('core.rpc.users'); + options.core.rpc.users.dashmate = options.core.rpc.password; + + delete options.core.rpc.user; + delete options.core.rpc.password; + }); + + return configFile; + }, }; } diff --git a/packages/dashmate/docker-compose.yml b/packages/dashmate/docker-compose.yml index a2fad5c55ae..568823d24b9 100644 --- a/packages/dashmate/docker-compose.yml +++ b/packages/dashmate/docker-compose.yml @@ -125,8 +125,8 @@ services: - API_GRPC_PORT=3005 - DASHCORE_RPC_HOST=core - DASHCORE_RPC_PORT=${CORE_RPC_PORT:?err} - - DASHCORE_RPC_USER=${CORE_RPC_USER:?err} - - DASHCORE_RPC_PASS=${CORE_RPC_PASSWORD:?err} + - DASHCORE_RPC_USER=dapi + - DASHCORE_RPC_PASS=${CORE_RPC_USERS_DAPI_PASSWORD:?err} - DASHCORE_ZMQ_HOST=core - DASHCORE_ZMQ_PORT=29998 - DASHCORE_P2P_HOST=core @@ -158,8 +158,8 @@ services: - TX_FILTER_STREAM_GRPC_PORT=3006 - DASHCORE_RPC_HOST=core - DASHCORE_RPC_PORT=${CORE_RPC_PORT:?err} - - DASHCORE_RPC_USER=${CORE_RPC_USER:?err} - - DASHCORE_RPC_PASS=${CORE_RPC_PASSWORD:?err} + - DASHCORE_RPC_USER=dapi + - DASHCORE_RPC_PASS=${CORE_RPC_USERS_DAPI_PASSWORD:?err} - DASHCORE_ZMQ_HOST=core - DASHCORE_ZMQ_PORT=29998 - DASHCORE_P2P_HOST=core diff --git a/packages/dashmate/src/config/configJsonSchema.js b/packages/dashmate/src/config/configJsonSchema.js index b003a4aded4..2af2391fdc0 100644 --- a/packages/dashmate/src/config/configJsonSchema.js +++ b/packages/dashmate/src/config/configJsonSchema.js @@ -231,13 +231,35 @@ export default { port: { $ref: '#/definitions/port', }, - user: { - type: 'string', - minLength: 1, - }, - password: { - type: 'string', - minLength: 1, + users: { + type: 'object', + minProperties: 1, + propertyNames: { + type: 'string', + minLength: 1, + }, + additionalProperties: { + type: 'object', + properties: { + password: { + type: 'string', + minLength: 1, + }, + whitelist: { + type: ['null', 'array'], + items: { + type: 'string', + minLength: 1, + }, + minItems: 1, + }, + lowPriority: { + type: 'boolean', + }, + }, + required: ['password', 'whitelist', 'lowPriority'], + additionalProperties: false, + }, }, allowIps: { type: 'array', @@ -246,7 +268,7 @@ export default { }, }, }, - required: ['host', 'port', 'user', 'password'], + required: ['host', 'port', 'users', 'allowIps'], additionalProperties: false, }, spork: { diff --git a/packages/dashmate/src/core/startCoreFactory.js b/packages/dashmate/src/core/startCoreFactory.js index 71fe923e48a..86401ee6dfd 100644 --- a/packages/dashmate/src/core/startCoreFactory.js +++ b/packages/dashmate/src/core/startCoreFactory.js @@ -75,8 +75,8 @@ export default function startCoreFactory( const rpcClient = createRpcClient( { port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), host: await getConnectionHost(config, 'core', 'core.rpc.host'), }, ); diff --git a/packages/dashmate/src/listr/tasks/reindexNodeTaskFactory.js b/packages/dashmate/src/listr/tasks/reindexNodeTaskFactory.js index e666de51980..c2c5a487384 100644 --- a/packages/dashmate/src/listr/tasks/reindexNodeTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/reindexNodeTaskFactory.js @@ -115,8 +115,8 @@ export default function reindexNodeTaskFactory( // Wait until Core is started const rpcClient = createRpcClient({ port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), host: await getConnectionHost(config, 'core', 'core.rpc.host'), }); diff --git a/packages/dashmate/src/listr/tasks/setup/setupLocalPresetTaskFactory.js b/packages/dashmate/src/listr/tasks/setup/setupLocalPresetTaskFactory.js index 51e9918a06d..59de62641fd 100644 --- a/packages/dashmate/src/listr/tasks/setup/setupLocalPresetTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/setup/setupLocalPresetTaskFactory.js @@ -175,8 +175,12 @@ export default function setupLocalPresetTaskFactory( config.set('group', 'local'); config.set('core.p2p.port', config.get('core.p2p.port') + (i * 100)); config.set('core.rpc.port', config.get('core.rpc.port') + (i * 100)); - config.set('core.rpc.user', generateRandomString(8)); - config.set('core.rpc.password', generateRandomString(12)); + + Object.values(config.get('core.rpc.users')).forEach((options) => { + // eslint-disable-next-line no-param-reassign + options.password = generateRandomString(12); + }); + config.set('externalIp', hostDockerInternalIp); const subnet = config.get('docker.network.subnet') diff --git a/packages/dashmate/src/listr/tasks/setup/setupRegularPresetTaskFactory.js b/packages/dashmate/src/listr/tasks/setup/setupRegularPresetTaskFactory.js index 544ab8003f2..ced729a0d0d 100644 --- a/packages/dashmate/src/listr/tasks/setup/setupRegularPresetTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/setup/setupRegularPresetTaskFactory.js @@ -88,8 +88,10 @@ export default function setupRegularPresetTaskFactory( ctx.config.set('platform.drive.tenderdash.mode', 'full'); } - ctx.config.set('core.rpc.user', generateRandomString(8)); - ctx.config.set('core.rpc.password', generateRandomString(12)); + Object.values(ctx.config.get('core.rpc.users')).forEach((options) => { + // eslint-disable-next-line no-param-reassign + options.password = generateRandomString(12); + }); // eslint-disable-next-line no-param-reassign task.output = ctx.nodeType ? ctx.nodeType : nodeTypeName; diff --git a/packages/dashmate/src/listr/tasks/startGroupNodesTaskFactory.js b/packages/dashmate/src/listr/tasks/startGroupNodesTaskFactory.js index 8a923331132..eae01bd49e4 100644 --- a/packages/dashmate/src/listr/tasks/startGroupNodesTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/startGroupNodesTaskFactory.js @@ -70,8 +70,8 @@ export default function startGroupNodesTaskFactory( task: async () => { const rpcClient = createRpcClient({ port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), host: await getConnectionHost(config, 'core', 'core.rpc.host'), }); diff --git a/packages/dashmate/src/listr/tasks/startNodeTaskFactory.js b/packages/dashmate/src/listr/tasks/startNodeTaskFactory.js index 9c0308b28cb..94b0b5b6566 100644 --- a/packages/dashmate/src/listr/tasks/startNodeTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/startNodeTaskFactory.js @@ -119,8 +119,8 @@ export default function startNodeTaskFactory( task: async () => { const rpcClient = createRpcClient({ port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), host: await getConnectionHost(config, 'core', 'core.rpc.host'), }); diff --git a/packages/dashmate/src/listr/tasks/stopNodeTaskFactory.js b/packages/dashmate/src/listr/tasks/stopNodeTaskFactory.js index 12461d60b16..29bf6c175ee 100644 --- a/packages/dashmate/src/listr/tasks/stopNodeTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/stopNodeTaskFactory.js @@ -43,8 +43,8 @@ export default function stopNodeTaskFactory( task: async () => { const rpcClient = createRpcClient({ port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), host: await getConnectionHost(config, 'core', 'core.rpc.host'), }); @@ -62,8 +62,8 @@ export default function stopNodeTaskFactory( enabled: (ctx) => config.get('core.masternode.enable') && !ctx.isForce && ctx.isSafe, task: async () => waitForDKGWindowPass(createRpcClient({ port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), host: await getConnectionHost(config, 'core', 'core.rpc.host'), })), }, @@ -74,8 +74,8 @@ export default function stopNodeTaskFactory( task: async () => { const rpcClient = createRpcClient({ port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), host: await getConnectionHost(config, 'core', 'core.rpc.host'), }); diff --git a/packages/dashmate/src/status/scopes/core.js b/packages/dashmate/src/status/scopes/core.js index 339e4794011..d983bcd67c5 100644 --- a/packages/dashmate/src/status/scopes/core.js +++ b/packages/dashmate/src/status/scopes/core.js @@ -76,8 +76,8 @@ export default function getCoreScopeFactory( try { const rpcClient = createRpcClient({ port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), host: await getConnectionHost(config, 'core', 'core.rpc.host'), }); diff --git a/packages/dashmate/src/status/scopes/masternode.js b/packages/dashmate/src/status/scopes/masternode.js index 0a3cff387ae..b29a5bbfc6a 100644 --- a/packages/dashmate/src/status/scopes/masternode.js +++ b/packages/dashmate/src/status/scopes/masternode.js @@ -17,8 +17,8 @@ export default function getMasternodeScopeFactory( async function getSyncAsset(config) { const rpcClient = createRpcClient({ port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), host: await getConnectionHost(config, 'core', 'core.rpc.host'), }); @@ -31,8 +31,8 @@ export default function getMasternodeScopeFactory( async function getMasternodeInfo(config) { const rpcClient = createRpcClient({ port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), host: await getConnectionHost(config, 'core', 'core.rpc.host'), }); diff --git a/packages/dashmate/src/status/scopes/platform.js b/packages/dashmate/src/status/scopes/platform.js index b826775229d..08241ce60b8 100644 --- a/packages/dashmate/src/status/scopes/platform.js +++ b/packages/dashmate/src/status/scopes/platform.js @@ -18,8 +18,8 @@ export default function getPlatformScopeFactory( async function getMNSync(config) { const rpcClient = createRpcClient({ port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), host: await getConnectionHost(config, 'core', 'core.rpc.host'), }); diff --git a/packages/dashmate/src/templates/renderTemplateFactory.js b/packages/dashmate/src/templates/renderTemplateFactory.js index 6f69969579d..6f9f2ef9a85 100644 --- a/packages/dashmate/src/templates/renderTemplateFactory.js +++ b/packages/dashmate/src/templates/renderTemplateFactory.js @@ -1,5 +1,6 @@ import fs from 'fs'; import dots from 'dot'; +import crypto from 'crypto'; /** * @return {renderTemplate} @@ -18,7 +19,7 @@ export default function renderTemplateFactory() { const templateString = fs.readFileSync(templatePath, 'utf-8'); const template = dots.template(templateString); - return template(variables); + return template({ ...variables, crypto }); } return renderTemplate; diff --git a/packages/dashmate/templates/core/dash.conf.dot b/packages/dashmate/templates/core/dash.conf.dot index 08885afa6c6..76536fdf630 100644 --- a/packages/dashmate/templates/core/dash.conf.dot +++ b/packages/dashmate/templates/core/dash.conf.dot @@ -12,19 +12,28 @@ debuglogfile=/var/log/dash/{{= it.core.log.file.path.split('/').pop() }} logips={{=it.core.logIps }} fallbackfee=0.00001 -# JSONRPC +# JSON RPC server=1 -rpcuser={{=it.core.rpc.user}} -rpcpassword={{=it.core.rpc.password}} +rpcbind=0.0.0.0 +rpcport={{=it.core.rpc.port}} rpcwallet=main deprecatedrpc=hpmn +rpcworkqueue=96 +rpcthreads=12 +rpcwhitelistdefault=0 +rpcexternaluser={{= Object.entries(it.core.rpc.users).filter(([username, options]) => options.lowPriority).map(([username, options]) => username).join(',') }} +{{~ Object.keys(it.core.rpc.users) :user}} +{{ salt = it.crypto.randomBytes(16).toString('hex'); }} +{{ hmac = it.crypto.createHmac('sha256', salt).update(it.core.rpc.users[user].password); }} +rpcauth={{=user}}:{{=salt}}${{=hmac.digest('hex') }} +{{? it.core.rpc.users[user].whitelist !== null }} +rpcwhitelist={{=user}}:{{=it.core.rpc.users[user].whitelist.join(',')}} +{{?}} +{{~}} {{~it.core.rpc.allowIps :host}} rpcallowip={{=host}}{{~}} -rpcworkqueue=64 -rpcthreads=16 - # external network listen=1 dnsseed=0 @@ -94,6 +103,4 @@ addnode={{=seed.host}}:{{=seed.port}}{{~}} # network port={{=it.core.p2p.port}} bind=0.0.0.0 -rpcbind=0.0.0.0 -rpcport={{=it.core.rpc.port}} diff --git a/packages/dashmate/templates/core/insight/dashcore-node.json.dot b/packages/dashmate/templates/core/insight/dashcore-node.json.dot index fc42cca72b2..cfb92e73b14 100644 --- a/packages/dashmate/templates/core/insight/dashcore-node.json.dot +++ b/packages/dashmate/templates/core/insight/dashcore-node.json.dot @@ -12,8 +12,8 @@ "connect": [{ "rpchost": "core", "rpcport": {{= it.core.rpc.port }}, - "rpcuser": "{{= it.core.rpc.user }}", - "rpcpassword": "{{= it.core.rpc.password }}", + "rpcuser": "dashmate", + "rpcpassword": "{{= it.core.rpc.users.dashmate.password }}", "zmqpubrawtx": "tcp://core:29998", "zmqpubhashblock": "tcp://core:29998" }] diff --git a/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot b/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot index 3aad5cc204c..422171a8a13 100644 --- a/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot +++ b/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot @@ -121,10 +121,10 @@ laddr = "" core-rpc-host = "core:{{= it.core.rpc.port}}" # Local Dash Core RPC Username -core-rpc-username = "{{= it.core.rpc.user}}" +core-rpc-username = "tenderdash" # Local Dash Core RPC Password -core-rpc-password = "{{= it.core.rpc.password}}" +core-rpc-password = "{{= it.core.rpc.users.tenderdash.password}}" # Path to the client certificate generated while creating needed files for secure connection. # If a remote validator address is provided but no certificate, the connection will be insecure diff --git a/packages/dashmate/test/e2e/testnetEvonode.spec.js b/packages/dashmate/test/e2e/testnetEvonode.spec.js index 112bd769f43..8f3762bb47a 100644 --- a/packages/dashmate/test/e2e/testnetEvonode.spec.js +++ b/packages/dashmate/test/e2e/testnetEvonode.spec.js @@ -129,8 +129,8 @@ describe('Testnet Evonode', function main() { const coreRpcClient = createRpcClient({ host: config.get('core.rpc.host'), port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), }); waitForCoreData = waitForCoreDataFactory(coreRpcClient); diff --git a/packages/dashmate/test/e2e/testnetFullnode.spec.js b/packages/dashmate/test/e2e/testnetFullnode.spec.js index 965f6f78d6f..5a0cbcc30b3 100644 --- a/packages/dashmate/test/e2e/testnetFullnode.spec.js +++ b/packages/dashmate/test/e2e/testnetFullnode.spec.js @@ -122,8 +122,8 @@ describe('Testnet Fullnode', function main() { const coreRpcClient = createRpcClient({ host: config.get('core.rpc.host'), port: config.get('core.rpc.port'), - user: config.get('core.rpc.user'), - pass: config.get('core.rpc.password'), + user: 'dashmate', + pass: config.get('core.rpc.users.dashmate.password'), }); waitForCoreData = waitForCoreDataFactory(coreRpcClient); diff --git a/scripts/configure_dotenv.sh b/scripts/configure_dotenv.sh index ad6cac6a7b2..b343dc1f5a4 100755 --- a/scripts/configure_dotenv.sh +++ b/scripts/configure_dotenv.sh @@ -66,8 +66,8 @@ NETWORK=regtest" >>"${WALLET_LIB_ENV_FILE_PATH}" # DASH_SDK tests config CORE_RPC_PORT=$(get_config core.rpc.port) -CORE_RPC_USER=$(get_config core.rpc.user) -CORE_RPC_PASSWORD=$(get_config core.rpc.password) +CORE_RPC_USER=dashmate +CORE_RPC_PASSWORD=$(get_config core.rpc.users.dashmate.password) PLATFORM_RPC_PORT=$(get_config platform.gateway.listeners.dapiAndDrive.port) cat <"${DASH_SDK_PATH}"/tests/.env