diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..8809bae --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2025-02-14 - Prevent Internal RPC Error Leakage +**Vulnerability:** Internal errors from the RPC server (e.g. `bitcoind-rpc` daemon connections) were being directly passed to Discord channel messages using `message.reply(err.message)`, which risks leaking sensitive infrastructure details or paths. +**Learning:** Returning unhandled or verbose back-end error messages to front-end clients often provides attackers with information about internal workings. Always provide generic errors to the user while logging the actual details server-side. +**Prevention:** Catch errors internally and write them via `console.error` (so admins/developers can debug using logs), and send a generic failure message to the Discord user (`message.reply('An internal error occurred.')`). Added global '.catch()' to message deletion promises to prevent bot-crashing on unhandled rejections. diff --git a/bot/bot.js b/bot/bot.js index da72836..def00ab 100644 --- a/bot/bot.js +++ b/bot/bot.js @@ -12,25 +12,27 @@ config = config.get('bot'); var aliases; // check if any aliases are defined try { - var time = moment() - .tz('America/Los_Angeles') - .format('MM-DD-YYYY hh:mm a'); + var time = moment().tz('America/Los_Angeles').format('MM-DD-YYYY hh:mm a'); aliases = require('./alias.json'); - console.log('[' + time + ' PST][' + pm2Name + '] ' + Object.keys(aliases).length + ' aliases Loaded!'); + console.log( + '[' + + time + + ' PST][' + + pm2Name + + '] ' + + Object.keys(aliases).length + + ' aliases Loaded!', + ); } catch (e) { - var time = moment() - .tz('America/Los_Angeles') - .format('MM-DD-YYYY hh:mm a'); + var time = moment().tz('America/Los_Angeles').format('MM-DD-YYYY hh:mm a'); console.log('[' + time + ' PST][' + pm2Name + '] No aliases defined'); } var commands = {}; var bot = new Discord.Client(); -bot.on('ready', function() { - var time = moment() - .tz('America/Los_Angeles') - .format('MM-DD-YYYY hh:mm a'); +bot.on('ready', function () { + var time = moment().tz('America/Los_Angeles').format('MM-DD-YYYY hh:mm a'); console.log( '[' + time + @@ -40,21 +42,19 @@ bot.on('ready', function() { bot.user.username + 'Logged in! Serving in ' + bot.guilds.size + // ⚡ Bolt: O(1) property lookup vs O(N) array creation - ' servers' + ' servers', + ); + bot.channels.get(logChannel).send( + '[' + + time + + ' PST][' + + pm2Name + + '] ' + + bot.user.username + + 'Logged in! Serving in ' + + bot.guilds.size + // ⚡ Bolt: O(1) property lookup vs O(N) array creation + ' servers', ); - bot.channels - .get(logChannel) - .send( - '[' + - time + - ' PST][' + - pm2Name + - '] ' + - bot.user.username + - 'Logged in! Serving in ' + - bot.guilds.size + // ⚡ Bolt: O(1) property lookup vs O(N) array creation - ' servers' - ); require('./plugins.js').init(); console.log( '[' + @@ -63,7 +63,7 @@ bot.on('ready', function() { pm2Name + '] type ' + config.prefix + - 'tiphelp in Discord for a commands list.' + 'tiphelp in Discord for a commands list.', ); bot.channels .get(logChannel) @@ -74,10 +74,19 @@ bot.on('ready', function() { pm2Name + '] type ' + config.prefix + - 'tiphelp in Discord for a commands list.' + 'tiphelp in Discord for a commands list.', ); bot.user.setActivity(config.prefix + 'Intialized!'); - var text = ['tiprvn', 'tipdoge', 'tiplbc', 'tipufo', 'tipproton', 'tippxc', 'tipftc', 'tiphelp']; + var text = [ + 'tiprvn', + 'tipdoge', + 'tiplbc', + 'tipufo', + 'tipproton', + 'tippxc', + 'tipftc', + 'tiphelp', + ]; var counter = 0; setInterval(change, 10000); @@ -90,10 +99,8 @@ bot.on('ready', function() { } }); -process.on('uncaughtException', err => { - var time = moment() - .tz('America/Los_Angeles') - .format('MM-DD-YYYY hh:mm a'); +process.on('uncaughtException', (err) => { + var time = moment().tz('America/Los_Angeles').format('MM-DD-YYYY hh:mm a'); console.log('[' + time + ' PST][' + pm2Name + '] uncaughtException: ' + err); bot.channels .get(logChannel) @@ -101,10 +108,8 @@ process.on('uncaughtException', err => { process.exit(1); //exit node.js with an error }); -process.on('unhandledRejection', err => { - var time = moment() - .tz('America/Los_Angeles') - .format('MM-DD-YYYY hh:mm a'); +process.on('unhandledRejection', (err) => { + var time = moment().tz('America/Los_Angeles').format('MM-DD-YYYY hh:mm a'); console.log('[' + time + ' PST][' + pm2Name + '] unhandledRejection: ' + err); bot.channels .get(logChannel) @@ -112,18 +117,14 @@ process.on('unhandledRejection', err => { process.exit(1); //exit node.js with an error }); -bot.on('disconnected', function() { - var time = moment() - .tz('America/Los_Angeles') - .format('MM-DD-YYYY hh:mm a'); +bot.on('disconnected', function () { + var time = moment().tz('America/Los_Angeles').format('MM-DD-YYYY hh:mm a'); console.log('[' + time + ' PST][' + pm2Name + '] Disconnected!'); process.exit(1); //exit node.js with an error }); -bot.on('error', function(error) { - var time = moment() - .tz('America/Los_Angeles') - .format('MM-DD-YYYY hh:mm a'); +bot.on('error', function (error) { + var time = moment().tz('America/Los_Angeles').format('MM-DD-YYYY hh:mm a'); console.log('[' + time + ' PST][' + pm2Name + '] error: ' + error); process.exit(1); //exit node.js with an error }); @@ -139,29 +140,29 @@ function checkMessageForCommand(msg, isEdit) { ) { msg.author .send('Please set your Discord Presence to Online to talk to the bot!') - .catch(function(error) { + .catch(function (error) { msg.channel .send( msg.author + - ', Please enable Direct Messages from server members to communicate fully with our bot, it is located in the user setting area under Privacy & Safety tab, select the option allow direct messages from server members' + ', Please enable Direct Messages from server members to communicate fully with our bot, it is located in the user setting area under Privacy & Safety tab, select the option allow direct messages from server members', ) .then( msg.channel.send( - 'Please set your Discord Presence to Online to talk to the Bot!' - ) + 'Please set your Discord Presence to Online to talk to the Bot!', + ), ); return; }); } var cmdTxt = msg.content.split(' ')[0].substring(config.prefix.length); var suffix = msg.content.substring( - cmdTxt.length + config.prefix.length + 1 + cmdTxt.length + config.prefix.length + 1, ); //add one for the ! and one for the space if (msg.isMentioned(bot.user)) { try { cmdTxt = msg.content.split(' ')[1]; suffix = msg.content.substring( - bot.user.mention().length + cmdTxt.length + config.prefix.length + 1 + bot.user.mention().length + cmdTxt.length + config.prefix.length + 1, ); } catch (e) { //no command @@ -182,7 +183,7 @@ function checkMessageForCommand(msg, isEdit) { msg.content + ' from ' + msg.author.username + - ' as command' + ' as command', ); try { cmd.process(bot, msg, suffix, isEdit); @@ -214,37 +215,33 @@ function checkMessageForCommand(msg, isEdit) { } } -bot.on('message', msg => checkMessageForCommand(msg, false)); +bot.on('message', (msg) => checkMessageForCommand(msg, false)); -exports.addCommand = function(commandName, commandObject) { +exports.addCommand = function (commandName, commandObject) { try { commands[commandName] = commandObject; } catch (err) { - var time = moment() - .tz('America/Los_Angeles') - .format('MM-DD-YYYY hh:mm a'); + var time = moment().tz('America/Los_Angeles').format('MM-DD-YYYY hh:mm a'); console.log('[' + time + ' PST][' + pm2Name + '] Error addCommand: ' + err); bot.channels .get(logChannel) .send('[' + time + ' PST][' + pm2Name + '] Error addCommand: ' + err); } }; -exports.addCustomFunc = function(customFunc) { +exports.addCustomFunc = function (customFunc) { try { customFunc(bot); } catch (err) { - var time = moment() - .tz('America/Los_Angeles') - .format('MM-DD-YYYY hh:mm a'); + var time = moment().tz('America/Los_Angeles').format('MM-DD-YYYY hh:mm a'); console.log( - '[' + time + ' PST][' + pm2Name + '] Error addCustomFunc: ' + err + '[' + time + ' PST][' + pm2Name + '] Error addCustomFunc: ' + err, ); bot.channels .get(logChannel) .send('[' + time + ' PST][' + pm2Name + '] Error addCustomFunc: ' + err); } }; -exports.commandCount = function() { +exports.commandCount = function () { return Object.keys(commands).length; }; diff --git a/bot/modules/bot-uptime.js b/bot/modules/bot-uptime.js index 7df747a..69a2f8a 100644 --- a/bot/modules/bot-uptime.js +++ b/bot/modules/bot-uptime.js @@ -6,20 +6,20 @@ exports.commands = ['uptime']; exports.uptime = { usage: '', description: 'gets Uptime for Bot', - process: function(bot, msg, suffix) { + process: function (bot, msg, suffix) { if (suffix != pm2Name) { return; } msg.channel.send( 'i have been Online for ' + - Math.round(bot.uptime / (1000 * 60 * 60 * 24)) + - ' days, ' + - Math.round(bot.uptime / (1000 * 60 * 60)) + - ' hours, ' + - Math.round(bot.uptime / (1000 * 60)) % 60 + - ' minutes, and ' + - Math.round(bot.uptime / 1000) % 60 + - ' seconds' + Math.round(bot.uptime / (1000 * 60 * 60 * 24)) + + ' days, ' + + Math.round(bot.uptime / (1000 * 60 * 60)) + + ' hours, ' + + (Math.round(bot.uptime / (1000 * 60)) % 60) + + ' minutes, and ' + + (Math.round(bot.uptime / 1000) % 60) + + ' seconds', ); - } + }, }; diff --git a/bot/modules/dogeTipper.js b/bot/modules/dogeTipper.js index 54258df..98a75cd 100644 --- a/bot/modules/dogeTipper.js +++ b/bot/modules/dogeTipper.js @@ -158,7 +158,10 @@ function doWithdraw(message, tipper, words, helpmsg) { } doge.sendFrom(tipper, address, Number(amount), function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { message.channel.send({ embed: { @@ -263,7 +266,10 @@ function doTip(bot, message, tipper, words, helpmsg) { function sendDOGE(bot, message, tipper, recipient, amount, privacyFlag) { getAddress(recipient.toString(), function (err, address) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { doge.sendFrom( tipper, @@ -274,7 +280,10 @@ function sendDOGE(bot, message, tipper, recipient, amount, privacyFlag) { null, function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { if (privacyFlag) { let userProfile = message.guild.members.get(recipient); // ⚡ Bolt: O(1) direct ID lookup vs O(N) linear search; diff --git a/bot/modules/exampleTipper.js b/bot/modules/exampleTipper.js index 25be559..93a1040 100644 --- a/bot/modules/exampleTipper.js +++ b/bot/modules/exampleTipper.js @@ -143,7 +143,8 @@ function doWithdraw(message, tipper, words, helpmsg) { } ltc.sendFrom(tipper, address, Number(amount), function(err, txId) { if (err) { - message.reply(err.message).then(message => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message.reply('An internal error occurred.').then((m) => m.delete(10000).catch(() => {})); } else { message.channel.send({embed:{ title: '**:outbox_tray::money_with_wings::moneybag:Litecoin (LTC) Transaction Completed!:moneybag::money_with_wings::outbox_tray:**', @@ -228,11 +229,13 @@ function doTip(bot, message, tipper, words, helpmsg) { function sendLTC(bot, message, tipper, recipient, amount, privacyFlag) { getAddress(recipient.toString(), function(err, address) { if (err) { - message.reply(err.message).then(message => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message.reply('An internal error occurred.').then((m) => m.delete(10000).catch(() => {})); } else { ltc.sendFrom(tipper, address, Number(amount), 1, null, null, function(err, txId) { if (err) { - message.reply(err.message).then(message => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message.reply('An internal error occurred.').then((m) => m.delete(10000).catch(() => {})); } else { if (privacyFlag) { let userProfile = message.guild.members.get(recipient) // ⚡ Bolt: O(1) direct ID lookup vs O(N) linear search; diff --git a/bot/modules/ftcTipper.js b/bot/modules/ftcTipper.js index 22bb0b9..312cfcb 100644 --- a/bot/modules/ftcTipper.js +++ b/bot/modules/ftcTipper.js @@ -158,7 +158,10 @@ function doWithdraw(message, tipper, words, helpmsg) { } ftc.sendFrom(tipper, address, Number(amount), function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { message.channel.send({ embed: { @@ -263,7 +266,10 @@ function doTip(bot, message, tipper, words, helpmsg) { function sendFTC(bot, message, tipper, recipient, amount, privacyFlag) { getAddress(recipient.toString(), function (err, address) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { ftc.sendFrom( tipper, @@ -274,7 +280,10 @@ function sendFTC(bot, message, tipper, recipient, amount, privacyFlag) { null, function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { if (privacyFlag) { let userProfile = message.guild.members.get(recipient); // ⚡ Bolt: O(1) direct ID lookup vs O(N) linear search; diff --git a/bot/modules/helpTipper.js b/bot/modules/helpTipper.js index 95041c9..f87ef49 100644 --- a/bot/modules/helpTipper.js +++ b/bot/modules/helpTipper.js @@ -11,27 +11,41 @@ exports.commands = ['tiphelp']; exports.tiphelp = { usage: '', description: 'This commands has been changed to currency specific commands!', - process: function(bot, message) { + process: function (bot, message) { message.author.send( - '__**Ravencoin (RVN) Tipper**__\nTransaction Fees: **' + ravenFee + '**\n **!tiprvn balance** : get your balance\n **!tiprvn deposit** : get address for your deposits\n **!tiprvn withdraw
** : withdraw coins to specified address\n **!tiprvn <@user> ** :mention a user with @ and then the amount to tip them\n **!tiprvn private ** : put private before Mentioning a user to tip them privately.\n' + '__**Ravencoin (RVN) Tipper**__\nTransaction Fees: **' + + ravenFee + + '**\n **!tiprvn balance** : get your balance\n **!tiprvn deposit** : get address for your deposits\n **!tiprvn withdraw
** : withdraw coins to specified address\n **!tiprvn <@user> ** :mention a user with @ and then the amount to tip them\n **!tiprvn private ** : put private before Mentioning a user to tip them privately.\n', ); message.author.send( - '__**Dogecoin (DOGE) Tipper**__\nTransaction Fees: **' + dogeFee + '**\n **!tipdoge balance** : get your balance\n **!tipdoge deposit** : get address for your deposits\n **!tipdoge withdraw
** : withdraw coins to specified address\n **!tipdoge <@user> ** :mention a user with @ and then the amount to tip them\n **!tipdoge private ** : put private before Mentioning a user to tip them privately.\n' + '__**Dogecoin (DOGE) Tipper**__\nTransaction Fees: **' + + dogeFee + + '**\n **!tipdoge balance** : get your balance\n **!tipdoge deposit** : get address for your deposits\n **!tipdoge withdraw
** : withdraw coins to specified address\n **!tipdoge <@user> ** :mention a user with @ and then the amount to tip them\n **!tipdoge private ** : put private before Mentioning a user to tip them privately.\n', ); message.author.send( - '__**LBRY Credit (LBC) Tipper**__\nTransaction Fees: **' + lbryFee + '**\n **!tiplbc balance** : get your balance\n **!tiplbc deposit** : get address for your deposits\n **!tiplbc withdraw
** : withdraw coins to specified address\n **!tiplbc <@user> ** :mention a user with @ and then the amount to tip them\n **!tiplbc private ** : put private before Mentioning a user to tip them privately.\n' + '__**LBRY Credit (LBC) Tipper**__\nTransaction Fees: **' + + lbryFee + + '**\n **!tiplbc balance** : get your balance\n **!tiplbc deposit** : get address for your deposits\n **!tiplbc withdraw
** : withdraw coins to specified address\n **!tiplbc <@user> ** :mention a user with @ and then the amount to tip them\n **!tiplbc private ** : put private before Mentioning a user to tip them privately.\n', ); message.author.send( - '__**Proton (PROTON) Tipper**__\nTransaction Fees: **' + protonFee + '**\n **!tipproton balance** : get your balance\n **!tipproton deposit** : get address for your deposits\n **!tipproton withdraw
** : withdraw coins to specified address\n **!tipproton <@user> ** :mention a user with @ and then the amount to tip them\n **!tipproton private ** : put private before Mentioning a user to tip them privately.\n' + '__**Proton (PROTON) Tipper**__\nTransaction Fees: **' + + protonFee + + '**\n **!tipproton balance** : get your balance\n **!tipproton deposit** : get address for your deposits\n **!tipproton withdraw
** : withdraw coins to specified address\n **!tipproton <@user> ** :mention a user with @ and then the amount to tip them\n **!tipproton private ** : put private before Mentioning a user to tip them privately.\n', ); message.author.send( - '__**Uniform Fiscal Object (UFO) Tipper**__\nTransaction Fees: **' + ufoFee + '**\n **!tipufo balance** : get your balance\n **!tipufo deposit** : get address for your deposits\n **!tipufo withdraw
** : withdraw coins to specified address\n **!tipufo <@user> ** :mention a user with @ and then the amount to tip them\n **!tipufo private ** : put private before Mentioning a user to tip them privately.\n' + '__**Uniform Fiscal Object (UFO) Tipper**__\nTransaction Fees: **' + + ufoFee + + '**\n **!tipufo balance** : get your balance\n **!tipufo deposit** : get address for your deposits\n **!tipufo withdraw
** : withdraw coins to specified address\n **!tipufo <@user> ** :mention a user with @ and then the amount to tip them\n **!tipufo private ** : put private before Mentioning a user to tip them privately.\n', ); message.author.send( - '__**Phoenixcoin (PXC) Tipper**__\nTransaction Fees: **' + phoenixFee + '**\n **!tippxc balance** : get your balance\n **!tippxc deposit** : get address for your deposits\n **!tippxc withdraw
** : withdraw coins to specified address\n **!tippxc <@user> ** :mention a user with @ and then the amount to tip them\n **!tippxc private ** : put private before Mentioning a user to tip them privately.\n' + '__**Phoenixcoin (PXC) Tipper**__\nTransaction Fees: **' + + phoenixFee + + '**\n **!tippxc balance** : get your balance\n **!tippxc deposit** : get address for your deposits\n **!tippxc withdraw
** : withdraw coins to specified address\n **!tippxc <@user> ** :mention a user with @ and then the amount to tip them\n **!tippxc private ** : put private before Mentioning a user to tip them privately.\n', ); message.author.send( - '__**Feathercoin (FTC) Tipper**__\nTransaction Fees: **' + featherFee + '**\n **!tipftc balance** : get your balance\n **!tipftc deposit** : get address for your deposits\n **!tipufo withdraw
** : withdraw coins to specified address\n **!tipftc <@user> ** :mention a user with @ and then the amount to tip them\n **!tipftc private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**' + '__**Feathercoin (FTC) Tipper**__\nTransaction Fees: **' + + featherFee + + '**\n **!tipftc balance** : get your balance\n **!tipftc deposit** : get address for your deposits\n **!tipufo withdraw
** : withdraw coins to specified address\n **!tipftc <@user> ** :mention a user with @ and then the amount to tip them\n **!tipftc private ** : put private before Mentioning a user to tip them privately.\n\n **<> : Replace with appropriate value.**', ); - } + }, }; diff --git a/bot/modules/lbcTipper.js b/bot/modules/lbcTipper.js index 09ff576..5514ccc 100644 --- a/bot/modules/lbcTipper.js +++ b/bot/modules/lbcTipper.js @@ -158,7 +158,10 @@ function doWithdraw(message, tipper, words, helpmsg) { } lbc.sendFrom(tipper, address, Number(amount), function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { message.channel.send({ embed: { @@ -263,7 +266,10 @@ function doTip(bot, message, tipper, words, helpmsg) { function sendLBC(bot, message, tipper, recipient, amount, privacyFlag) { getAddress(recipient.toString(), function (err, address) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { lbc.sendFrom( tipper, @@ -274,7 +280,10 @@ function sendLBC(bot, message, tipper, recipient, amount, privacyFlag) { null, function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { if (privacyFlag) { let userProfile = message.guild.members.get(recipient); // ⚡ Bolt: O(1) direct ID lookup vs O(N) linear search; diff --git a/bot/modules/protonTipper.js b/bot/modules/protonTipper.js index 53da2cd..51d1ed5 100644 --- a/bot/modules/protonTipper.js +++ b/bot/modules/protonTipper.js @@ -158,7 +158,10 @@ function doWithdraw(message, tipper, words, helpmsg) { } proton.sendFrom(tipper, address, Number(amount), function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { message.channel.send({ embed: { @@ -263,7 +266,10 @@ function doTip(bot, message, tipper, words, helpmsg) { function sendPROTON(bot, message, tipper, recipient, amount, privacyFlag) { getAddress(recipient.toString(), function (err, address) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { proton.sendFrom( tipper, @@ -274,7 +280,10 @@ function sendPROTON(bot, message, tipper, recipient, amount, privacyFlag) { null, function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { if (privacyFlag) { let userProfile = message.guild.members.get(recipient); // ⚡ Bolt: O(1) direct ID lookup vs O(N) linear search; diff --git a/bot/modules/pxcTipper.js b/bot/modules/pxcTipper.js index db95dc4..4cbb978 100644 --- a/bot/modules/pxcTipper.js +++ b/bot/modules/pxcTipper.js @@ -158,7 +158,10 @@ function doWithdraw(message, tipper, words, helpmsg) { } pxc.sendFrom(tipper, address, Number(amount), function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { message.channel.send({ embed: { @@ -263,7 +266,10 @@ function doTip(bot, message, tipper, words, helpmsg) { function sendPXC(bot, message, tipper, recipient, amount, privacyFlag) { getAddress(recipient.toString(), function (err, address) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { pxc.sendFrom( tipper, @@ -274,7 +280,10 @@ function sendPXC(bot, message, tipper, recipient, amount, privacyFlag) { null, function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { if (privacyFlag) { let userProfile = message.guild.members.get(recipient); // ⚡ Bolt: O(1) direct ID lookup vs O(N) linear search; diff --git a/bot/modules/rvnTipper.js b/bot/modules/rvnTipper.js index 814abc4..5016614 100644 --- a/bot/modules/rvnTipper.js +++ b/bot/modules/rvnTipper.js @@ -158,7 +158,10 @@ function doWithdraw(message, tipper, words, helpmsg) { } rvn.sendFrom(tipper, address, Number(amount), function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { message.channel.send({ embed: { @@ -263,7 +266,10 @@ function doTip(bot, message, tipper, words, helpmsg) { function sendRVN(bot, message, tipper, recipient, amount, privacyFlag) { getAddress(recipient.toString(), function (err, address) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { rvn.sendFrom( tipper, @@ -274,7 +280,10 @@ function sendRVN(bot, message, tipper, recipient, amount, privacyFlag) { null, function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { if (privacyFlag) { let userProfile = message.guild.members.get(recipient); // ⚡ Bolt: O(1) direct ID lookup vs O(N) linear search; diff --git a/bot/modules/ufoTipper.js b/bot/modules/ufoTipper.js index 74c1cd5..202daf6 100644 --- a/bot/modules/ufoTipper.js +++ b/bot/modules/ufoTipper.js @@ -162,7 +162,10 @@ function doWithdraw(message, tipper, words, helpmsg) { } ufo.sendFrom(tipper, address, Number(amount), function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { message.channel.send({ embed: { @@ -267,7 +270,10 @@ function doTip(bot, message, tipper, words, helpmsg) { function sendUFO(bot, message, tipper, recipient, amount, privacyFlag) { getAddress(recipient.toString(), function (err, address) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { ufo.sendFrom( tipper, @@ -278,7 +284,10 @@ function sendUFO(bot, message, tipper, recipient, amount, privacyFlag) { null, function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { if (privacyFlag) { let userProfile = message.guild.members.get(recipient); // ⚡ Bolt: O(1) direct ID lookup vs O(N) linear search; diff --git a/bot/modules/vtlTipper.js b/bot/modules/vtlTipper.js index 040a3fa..49c9a5c 100644 --- a/bot/modules/vtlTipper.js +++ b/bot/modules/vtlTipper.js @@ -158,7 +158,10 @@ function doWithdraw(message, tipper, words, helpmsg) { } vtl.sendFrom(tipper, address, Number(amount), function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { message.channel.send({ embed: { @@ -263,7 +266,10 @@ function doTip(bot, message, tipper, words, helpmsg) { function sendVTL(bot, message, tipper, recipient, amount, privacyFlag) { getAddress(recipient.toString(), function (err, address) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { vtl.sendFrom( tipper, @@ -274,7 +280,10 @@ function sendVTL(bot, message, tipper, recipient, amount, privacyFlag) { null, function (err, txId) { if (err) { - message.reply(err.message).then((message) => message.delete(10000)); + console.error(err); // Security: Prevent internal RPC error leakage + message + .reply('An internal error occurred.') + .then((m) => m.delete(10000).catch(() => {})); } else { if (privacyFlag) { let userProfile = message.guild.members.get(recipient); // ⚡ Bolt: O(1) direct ID lookup vs O(N) linear search; diff --git a/bot/plugins.js b/bot/plugins.js index a314cd1..30bbf5d 100644 --- a/bot/plugins.js +++ b/bot/plugins.js @@ -44,6 +44,6 @@ function load_plugins() { } } console.log( - `Loaded ${dbot.commandCount()} chat commands and ${otherFunc} custom functions.` + `Loaded ${dbot.commandCount()} chat commands and ${otherFunc} custom functions.`, ); }