Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement: Password input #770

Merged
merged 3 commits into from
Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,8 @@ endif
libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_cli_a_SOURCES = \
compat/stdin.h \
compat/stdin.cpp \
rpc/client.cpp \
$(BITCOIN_CORE_H)

Expand Down
72 changes: 72 additions & 0 deletions src/compat/stdin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) 2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/veil-config.h>
#endif

#include <cstdio> // for fileno(), stdin

#ifdef WIN32
#include <windows.h> // for SetStdinEcho()
#include <io.h> // for isatty()
#else
#include <termios.h> // for SetStdinEcho()
#include <unistd.h> // for SetStdinEcho(), isatty()
#include <sys/poll.h> // for StdinReady()
#endif

#include <compat/stdin.h>

// https://stackoverflow.com/questions/1413445/reading-a-password-from-stdcin
void SetStdinEcho(bool enable)
{
#ifdef WIN32
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode;
GetConsoleMode(hStdin, &mode);
if (!enable) {
mode &= ~ENABLE_ECHO_INPUT;
} else {
mode |= ENABLE_ECHO_INPUT;
}
SetConsoleMode(hStdin, mode);
#else
struct termios tty;
tcgetattr(STDIN_FILENO, &tty);
if (!enable) {
tty.c_lflag &= ~ECHO;
} else {
tty.c_lflag |= ECHO;
}
(void)tcsetattr(STDIN_FILENO, TCSANOW, &tty);
#endif
}

bool StdinTerminal()
{
#ifdef WIN32
return _isatty(_fileno(stdin));
#else
return isatty(fileno(stdin));
#endif
}

bool StdinReady()
{
if (!StdinTerminal()) {
return true;
}
#ifdef WIN32
return false;
#else
struct pollfd fds;
fds.fd = 0; /* this is STDIN */
fds.events = POLLIN;
return poll(&fds, 1, 0) == 1;
#endif
}

NoechoInst::NoechoInst() { SetStdinEcho(false); }
NoechoInst::~NoechoInst() { SetStdinEcho(true); }
18 changes: 18 additions & 0 deletions src/compat/stdin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_COMPAT_STDIN_H
#define BITCOIN_COMPAT_STDIN_H

struct NoechoInst {
NoechoInst();
~NoechoInst();
};

#define NO_STDIN_ECHO() NoechoInst _no_echo

bool StdinTerminal();
bool StdinReady();

#endif // BITCOIN_COMPAT_STDIN_H
27 changes: 26 additions & 1 deletion src/veil-cli.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Copyright (c) 2019-2020 The Veil developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

Expand All @@ -23,6 +24,7 @@
#include <support/events.h>

#include <univalue.h>
#include <compat/stdin.h>

static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
Expand Down Expand Up @@ -51,7 +53,8 @@ static void SetupCliArgs()
gArgs.AddArg("-rpcwait", "Wait for RPC server to start", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-rpcwallet=<walletname>", "Send RPC for non-default wallet on RPC server (needs to exactly match corresponding -wallet option passed to veild)", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-stdin", "Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password.", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-stdinrpcpass", "Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password.", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-stdinrpcpass", "Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password. When combined with -stdinwalletpassphrase, -stdinrpcpass consumes the first line, and -stdinwalletpassphrase consumes the second.", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-stdinwalletpassphrase", "Read wallet passphrase from standard input as a single line. When combined with -stdin, the first line from standard input is used for the wallet passphrase.", false, OptionsCategory::OPTIONS);

// Hidden
gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN);
Expand Down Expand Up @@ -420,12 +423,34 @@ static int CommandLineRPC(int argc, char *argv[])
}
std::string rpcPass;
if (gArgs.GetBoolArg("-stdinrpcpass", false)) {
NO_STDIN_ECHO();
if (!StdinReady()) {
fputs("RPC password> ", stderr);
fflush(stderr);
}
if (!std::getline(std::cin, rpcPass)) {
throw std::runtime_error("-stdinrpcpass specified but failed to read from standard input");
}
gArgs.ForceSetArg("-rpcpassword", rpcPass);
fputs("\n", stderr);
}
std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
if (gArgs.GetBoolArg("-stdinwalletpassphrase", false)) {
NO_STDIN_ECHO();
std::string walletPass;
if (args.size() < 1 || args[0].substr(0, 16) != "walletpassphrase") {
throw std::runtime_error("-stdinwalletpassphrase is only applicable for walletpassphrase(change)");
}
if (!StdinReady()) {
fputs("Wallet passphrase> ", stderr);
fflush(stderr);
}
if (!std::getline(std::cin, walletPass)) {
throw std::runtime_error("-stdinwalletpassphrase specified but failed to read from standard input");
}
args.insert(args.begin() + 1, walletPass);
fputs("\n", stderr);
}
if (gArgs.GetBoolArg("-stdin", false)) {
// Read one arg per line from stdin and append
std::string line;
Expand Down