Skip to content

Commit 629cd42

Browse files
committed
Qt/RPCConsole: Teach RPCParseCommandLine how to filter out arguments to sensitive commands
1 parent e2d9213 commit 629cd42

File tree

2 files changed

+33
-5
lines changed

2 files changed

+33
-5
lines changed

src/qt/rpcconsole.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,10 @@ class QtRPCTimerInterface: public RPCTimerInterface
151151
* @param[out] result stringified Result from the executed command(chain)
152152
* @param[in] strCommand Command line to split
153153
* @param[in] fExecute set true if you want the command to be executed
154+
* @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data
154155
*/
155156

156-
bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &strCommand, const bool fExecute)
157+
bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut)
157158
{
158159
std::vector< std::vector<std::string> > stack;
159160
stack.push_back(std::vector<std::string>());
@@ -173,12 +174,16 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
173174
} state = STATE_EATING_SPACES;
174175
std::string curarg;
175176
UniValue lastResult;
177+
unsigned nDepthInsideSensitive = 0;
178+
size_t filter_begin_pos = 0;
179+
std::vector<std::pair<size_t, size_t>> filter_ranges;
176180

177181
std::string strCommandTerminated = strCommand;
178182
if (strCommandTerminated.back() != '\n')
179183
strCommandTerminated += "\n";
180-
for(char ch: strCommandTerminated)
184+
for (size_t chpos = 0; chpos < strCommandTerminated.size(); ++chpos)
181185
{
186+
char ch = strCommandTerminated[chpos];
182187
switch(state)
183188
{
184189
case STATE_COMMAND_EXECUTED_INNER:
@@ -222,6 +227,13 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
222227
breakParsing = false;
223228

224229
// 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+
}
225237
stack.pop_back();
226238

227239
// don't stringify the json in case of a string to avoid doublequotes
@@ -260,7 +272,12 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
260272
if (state == STATE_ARGUMENT)
261273
{
262274
if (ch == '(' && stack.size() && stack.back().size() > 0)
275+
{
276+
if (nDepthInsideSensitive) {
277+
++nDepthInsideSensitive;
278+
}
263279
stack.push_back(std::vector<std::string>());
280+
}
264281

265282
// don't allow commands after executed commands on baselevel
266283
if (!stack.size())
@@ -291,6 +308,11 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
291308

292309
else if(state == STATE_ARGUMENT) // Space ends argument
293310
{
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+
}
294316
stack.back().push_back(curarg);
295317
curarg.clear();
296318
}
@@ -328,6 +350,12 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &
328350
break;
329351
}
330352
}
353+
if (pstrFilteredOut) {
354+
*pstrFilteredOut = strCommand;
355+
for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) {
356+
pstrFilteredOut->replace(i->first, i->second - i->first, "...");
357+
}
358+
}
331359
switch(state) // final state
332360
{
333361
case STATE_COMMAND_EXECUTED:

src/qt/rpcconsole.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ class RPCConsole: public QWidget
3636
explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent);
3737
~RPCConsole();
3838

39-
static bool RPCParseCommandLine(std::string &strResult, const std::string &strCommand, bool fExecute);
40-
static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand) {
41-
return RPCParseCommandLine(strResult, strCommand, true);
39+
static bool RPCParseCommandLine(std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = NULL);
40+
static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = NULL) {
41+
return RPCParseCommandLine(strResult, strCommand, true, pstrFilteredOut);
4242
}
4343

4444
void setClientModel(ClientModel *model);

0 commit comments

Comments
 (0)