Browse Source

Qt/RPCConsole: Use RPCParseCommandLine to perform command filtering

0.14
Luke Dashjr 8 years ago
parent
commit
ff77faf480
  1. 77
      src/qt/rpcconsole.cpp

77
src/qt/rpcconsole.cpp

@ -31,6 +31,7 @@
#include <QKeyEvent> #include <QKeyEvent>
#include <QMenu> #include <QMenu>
#include <QMessageBox>
#include <QScrollBar> #include <QScrollBar>
#include <QSettings> #include <QSettings>
#include <QSignalMapper> #include <QSignalMapper>
@ -74,16 +75,6 @@ const QStringList historyFilter = QStringList()
<< "walletpassphrasechange" << "walletpassphrasechange"
<< "encryptwallet"; << "encryptwallet";
QString command_filter_sensitive_data(const QString cmd)
{
Q_FOREACH(QString unallowedCmd, historyFilter) {
if (cmd.trimmed().startsWith(unallowedCmd)) {
return unallowedCmd;
}
}
return cmd;
}
} }
/* Object for executing console RPC commands in a separate thread. /* Object for executing console RPC commands in a separate thread.
@ -175,13 +166,32 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
std::string curarg; std::string curarg;
UniValue lastResult; UniValue lastResult;
unsigned nDepthInsideSensitive = 0; unsigned nDepthInsideSensitive = 0;
size_t filter_begin_pos = 0; size_t filter_begin_pos = 0, chpos;
std::vector<std::pair<size_t, size_t>> filter_ranges; std::vector<std::pair<size_t, size_t>> filter_ranges;
auto add_to_current_stack = [&](const std::string& curarg) {
if (stack.back().empty() && (!nDepthInsideSensitive) && historyFilter.contains(QString::fromStdString(curarg), Qt::CaseInsensitive)) {
nDepthInsideSensitive = 1;
filter_begin_pos = chpos;
}
stack.back().push_back(curarg);
};
auto close_out_params = [&]() {
if (nDepthInsideSensitive) {
if (!--nDepthInsideSensitive) {
assert(filter_begin_pos);
filter_ranges.push_back(std::make_pair(filter_begin_pos, chpos));
filter_begin_pos = 0;
}
}
stack.pop_back();
};
std::string strCommandTerminated = strCommand; std::string strCommandTerminated = strCommand;
if (strCommandTerminated.back() != '\n') if (strCommandTerminated.back() != '\n')
strCommandTerminated += "\n"; strCommandTerminated += "\n";
for (size_t chpos = 0; chpos < strCommandTerminated.size(); ++chpos) for (chpos = 0; chpos < strCommandTerminated.size(); ++chpos)
{ {
char ch = strCommandTerminated[chpos]; char ch = strCommandTerminated[chpos];
switch(state) switch(state)
@ -227,14 +237,7 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
breakParsing = false; breakParsing = false;
// pop the stack and return the result to the current command arguments // pop the stack and return the result to the current command arguments
if (nDepthInsideSensitive) { close_out_params();
if (!--nDepthInsideSensitive) {
assert(filter_begin_pos);
filter_ranges.push_back(std::make_pair(filter_begin_pos, chpos));
filter_begin_pos = 0;
}
}
stack.pop_back();
// don't stringify the json in case of a string to avoid doublequotes // don't stringify the json in case of a string to avoid doublequotes
if (lastResult.isStr()) if (lastResult.isStr())
@ -246,7 +249,7 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
if (curarg.size()) if (curarg.size())
{ {
if (stack.size()) if (stack.size())
stack.back().push_back(curarg); add_to_current_stack(curarg);
else else
strResult = curarg; strResult = curarg;
} }
@ -283,7 +286,7 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
if (!stack.size()) if (!stack.size())
throw std::runtime_error("Invalid Syntax"); throw std::runtime_error("Invalid Syntax");
stack.back().push_back(curarg); add_to_current_stack(curarg);
curarg.clear(); curarg.clear();
state = STATE_EATING_SPACES_IN_BRACKETS; state = STATE_EATING_SPACES_IN_BRACKETS;
} }
@ -308,12 +311,7 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
else if(state == STATE_ARGUMENT) // Space ends argument else if(state == STATE_ARGUMENT) // Space ends argument
{ {
// This is the only place where the method name should get pushed (as the first stack item) add_to_current_stack(curarg);
if ((!nDepthInsideSensitive) && historyFilter.contains(QString::fromStdString(curarg), Qt::CaseInsensitive)) {
nDepthInsideSensitive = 1;
filter_begin_pos = chpos;
}
stack.back().push_back(curarg);
curarg.clear(); curarg.clear();
} }
if ((state == STATE_EATING_SPACES_IN_BRACKETS || state == STATE_ARGUMENT) && ch == ',') if ((state == STATE_EATING_SPACES_IN_BRACKETS || state == STATE_ARGUMENT) && ch == ',')
@ -351,9 +349,13 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
} }
} }
if (pstrFilteredOut) { if (pstrFilteredOut) {
if (STATE_COMMAND_EXECUTED == state) {
assert(!stack.empty());
close_out_params();
}
*pstrFilteredOut = strCommand; *pstrFilteredOut = strCommand;
for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) { for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) {
pstrFilteredOut->replace(i->first, i->second - i->first, "..."); pstrFilteredOut->replace(i->first, i->second - i->first, "(…)");
} }
} }
switch(state) // final state switch(state) // final state
@ -800,16 +802,29 @@ void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage)
void RPCConsole::on_lineEdit_returnPressed() void RPCConsole::on_lineEdit_returnPressed()
{ {
QString cmd = ui->lineEdit->text(); QString cmd = ui->lineEdit->text();
ui->lineEdit->clear();
if(!cmd.isEmpty()) if(!cmd.isEmpty())
{ {
std::string strFilteredCmd;
try {
std::string dummy;
if (!RPCParseCommandLine(dummy, cmd.toStdString(), false, &strFilteredCmd)) {
// Failed to parse command, so we cannot even filter it for the history
throw std::runtime_error("Invalid command line");
}
} catch (const std::exception& e) {
QMessageBox::critical(this, "Error", QString("Error: ") + QString::fromStdString(e.what()));
return;
}
ui->lineEdit->clear();
cmdBeforeBrowsing = QString(); cmdBeforeBrowsing = QString();
message(CMD_REQUEST, cmd); message(CMD_REQUEST, cmd);
Q_EMIT cmdRequest(cmd); Q_EMIT cmdRequest(cmd);
cmd = command_filter_sensitive_data(cmd); cmd = QString::fromStdString(strFilteredCmd);
// Remove command, if already in history // Remove command, if already in history
history.removeOne(cmd); history.removeOne(cmd);

Loading…
Cancel
Save