Skip to content

Commit ff77faf

Browse files
committed
Qt/RPCConsole: Use RPCParseCommandLine to perform command filtering
1 parent a79598d commit ff77faf

File tree

1 file changed

+46
-31
lines changed

1 file changed

+46
-31
lines changed

src/qt/rpcconsole.cpp

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
#include <QKeyEvent>
3333
#include <QMenu>
34+
#include <QMessageBox>
3435
#include <QScrollBar>
3536
#include <QSettings>
3637
#include <QSignalMapper>
@@ -74,16 +75,6 @@ const QStringList historyFilter = QStringList()
7475
<< "walletpassphrasechange"
7576
<< "encryptwallet";
7677

77-
QString command_filter_sensitive_data(const QString cmd)
78-
{
79-
Q_FOREACH(QString unallowedCmd, historyFilter) {
80-
if (cmd.trimmed().startsWith(unallowedCmd)) {
81-
return unallowedCmd;
82-
}
83-
}
84-
return cmd;
85-
}
86-
8778
}
8879

8980
/* Object for executing console RPC commands in a separate thread.
@@ -175,13 +166,32 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
175166
std::string curarg;
176167
UniValue lastResult;
177168
unsigned nDepthInsideSensitive = 0;
178-
size_t filter_begin_pos = 0;
169+
size_t filter_begin_pos = 0, chpos;
179170
std::vector<std::pair<size_t, size_t>> filter_ranges;
180171

172+
auto add_to_current_stack = [&](const std::string& curarg) {
173+
if (stack.back().empty() && (!nDepthInsideSensitive) && historyFilter.contains(QString::fromStdString(curarg), Qt::CaseInsensitive)) {
174+
nDepthInsideSensitive = 1;
175+
filter_begin_pos = chpos;
176+
}
177+
stack.back().push_back(curarg);
178+
};
179+
180+
auto close_out_params = [&]() {
181+
if (nDepthInsideSensitive) {
182+
if (!--nDepthInsideSensitive) {
183+
assert(filter_begin_pos);
184+
filter_ranges.push_back(std::make_pair(filter_begin_pos, chpos));
185+
filter_begin_pos = 0;
186+
}
187+
}
188+
stack.pop_back();
189+
};
190+
181191
std::string strCommandTerminated = strCommand;
182192
if (strCommandTerminated.back() != '\n')
183193
strCommandTerminated += "\n";
184-
for (size_t chpos = 0; chpos < strCommandTerminated.size(); ++chpos)
194+
for (chpos = 0; chpos < strCommandTerminated.size(); ++chpos)
185195
{
186196
char ch = strCommandTerminated[chpos];
187197
switch(state)
@@ -227,14 +237,7 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
227237
breakParsing = false;
228238

229239
// pop the stack and return the result to the current command arguments
230-
if (nDepthInsideSensitive) {
231-
if (!--nDepthInsideSensitive) {
232-
assert(filter_begin_pos);
233-
filter_ranges.push_back(std::make_pair(filter_begin_pos, chpos));
234-
filter_begin_pos = 0;
235-
}
236-
}
237-
stack.pop_back();
240+
close_out_params();
238241

239242
// don't stringify the json in case of a string to avoid doublequotes
240243
if (lastResult.isStr())
@@ -246,7 +249,7 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
246249
if (curarg.size())
247250
{
248251
if (stack.size())
249-
stack.back().push_back(curarg);
252+
add_to_current_stack(curarg);
250253
else
251254
strResult = curarg;
252255
}
@@ -283,7 +286,7 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
283286
if (!stack.size())
284287
throw std::runtime_error("Invalid Syntax");
285288

286-
stack.back().push_back(curarg);
289+
add_to_current_stack(curarg);
287290
curarg.clear();
288291
state = STATE_EATING_SPACES_IN_BRACKETS;
289292
}
@@ -308,12 +311,7 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
308311

309312
else if(state == STATE_ARGUMENT) // Space ends argument
310313
{
311-
// This is the only place where the method name should get pushed (as the first stack item)
312-
if ((!nDepthInsideSensitive) && historyFilter.contains(QString::fromStdString(curarg), Qt::CaseInsensitive)) {
313-
nDepthInsideSensitive = 1;
314-
filter_begin_pos = chpos;
315-
}
316-
stack.back().push_back(curarg);
314+
add_to_current_stack(curarg);
317315
curarg.clear();
318316
}
319317
if ((state == STATE_EATING_SPACES_IN_BRACKETS || state == STATE_ARGUMENT) && ch == ',')
@@ -351,9 +349,13 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
351349
}
352350
}
353351
if (pstrFilteredOut) {
352+
if (STATE_COMMAND_EXECUTED == state) {
353+
assert(!stack.empty());
354+
close_out_params();
355+
}
354356
*pstrFilteredOut = strCommand;
355357
for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) {
356-
pstrFilteredOut->replace(i->first, i->second - i->first, "...");
358+
pstrFilteredOut->replace(i->first, i->second - i->first, "(…)");
357359
}
358360
}
359361
switch(state) // final state
@@ -800,16 +802,29 @@ void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage)
800802
void RPCConsole::on_lineEdit_returnPressed()
801803
{
802804
QString cmd = ui->lineEdit->text();
803-
ui->lineEdit->clear();
804805

805806
if(!cmd.isEmpty())
806807
{
808+
std::string strFilteredCmd;
809+
try {
810+
std::string dummy;
811+
if (!RPCParseCommandLine(dummy, cmd.toStdString(), false, &strFilteredCmd)) {
812+
// Failed to parse command, so we cannot even filter it for the history
813+
throw std::runtime_error("Invalid command line");
814+
}
815+
} catch (const std::exception& e) {
816+
QMessageBox::critical(this, "Error", QString("Error: ") + QString::fromStdString(e.what()));
817+
return;
818+
}
819+
820+
ui->lineEdit->clear();
821+
807822
cmdBeforeBrowsing = QString();
808823

809824
message(CMD_REQUEST, cmd);
810825
Q_EMIT cmdRequest(cmd);
811826

812-
cmd = command_filter_sensitive_data(cmd);
827+
cmd = QString::fromStdString(strFilteredCmd);
813828

814829
// Remove command, if already in history
815830
history.removeOne(cmd);

0 commit comments

Comments
 (0)