clickhouse-client: option --ask-password for interactively ask for credentials #1044

This commit is contained in:
proller 2018-05-21 20:27:18 +03:00
parent 8349d2b9a0
commit 051395a761
5 changed files with 84 additions and 3 deletions

11
CHANGELOG.draft.md Normal file
View File

@ -0,0 +1,11 @@
en:
## Improvements:
* `clickhouse-client`: option --ask-password for interactively ask for credentials #1044
ru:
## Улучшения:
* `clickhouse-client`: опция --ask-password для интерактивного ввода пароля #1044

View File

@ -15,6 +15,7 @@
#include <Poco/Util/Application.h>
#include <common/readline_use.h>
#include <common/find_first_symbols.h>
#include <common/SetTerminalEcho.h>
#include <Common/ClickHouseRevision.h>
#include <Common/Stopwatch.h>
#include <Common/Exception.h>
@ -52,6 +53,7 @@
#include "InterruptListener.h"
#include <Functions/registerFunctions.h>
#include <AggregateFunctions/registerAggregateFunctions.h>
#include <ext/scope_guard.h>
/// http://en.wikipedia.org/wiki/ANSI_escape_code
@ -197,7 +199,25 @@ private:
default_database = config.getString("database", "");
user = config.getString("user", "");
password = config.getString("password", "");
if (config.getBool("ask-password", false))
{
if (config.has("password"))
throw Exception("Specified both --password and --ask-password. Remove one of them", ErrorCodes::BAD_ARGUMENTS);
std::cout << "Password for user " << user << ": ";
SetTerminalEcho(false);
SCOPE_EXIT({
SetTerminalEcho(true);
});
std::getline(std::cin, password);
std::cout << std::endl;
}
else
{
password = config.getString("password", "");
}
compression = config.getBool("compression", true)
? Protocol::Compression::Enable
@ -1375,8 +1395,9 @@ public:
("host,h", boost::program_options::value<std::string>()->default_value("localhost"), "server host")
("port", boost::program_options::value<int>()->default_value(9000), "server port")
("secure,s", "secure")
("user,u", boost::program_options::value<std::string>(), "user")
("user,u", boost::program_options::value<std::string>()->default_value("default"), "user")
("password", boost::program_options::value<std::string>(), "password")
("ask-password", "ask-password")
("query_id", boost::program_options::value<std::string>(), "query_id")
("query,q", boost::program_options::value<std::string>(), "query")
("database,d", boost::program_options::value<std::string>(), "database")
@ -1483,7 +1504,8 @@ public:
config().setString("user", options["user"].as<std::string>());
if (options.count("password"))
config().setString("password", options["password"].as<std::string>());
if (options.count("ask-password"))
config().setBool("ask-password", true);
if (options.count("multiline"))
config().setBool("multiline", true);
if (options.count("multiquery"))

View File

@ -27,6 +27,7 @@ add_library (common ${SPLIT_SHARED}
src/getMemoryAmount.cpp
src/ThreadPool.cpp
src/demangle.cpp
src/SetTerminalEcho.cpp
include/common/Types.h
include/common/DateLUT.h
@ -46,6 +47,7 @@ add_library (common ${SPLIT_SHARED}
include/common/getMemoryAmount.h
include/common/ThreadPool.h
include/common/demangle.h
include/common/SetTerminalEcho.h
include/ext/bit_cast.h
include/ext/collection_cast.h

View File

@ -0,0 +1,4 @@
#pragma once
/// Enable or disable echoing of typed characters. Throws std::runtime_error on error.
void SetTerminalEcho(bool enable);

View File

@ -0,0 +1,42 @@
// https://stackoverflow.com/questions/1413445/reading-a-password-from-stdcin
#include <common/SetTerminalEcho.h>
#include <stdexcept>
#include <cstring>
#ifdef WIN32
#include <windows.h>
#else
#include <termios.h>
#include <unistd.h>
#endif
void SetTerminalEcho(bool enable)
{
#ifdef WIN32
auto handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode;
if (!GetConsoleMode(handle, &mode))
throw std::runtime_error(std::string("SetTerminalEcho failed get:") + std::to_string(GetLastError()));
if (!enable)
mode &= ~ENABLE_ECHO_INPUT;
else
mode |= ENABLE_ECHO_INPUT;
if (!SetConsoleMode(handle, mode))
throw std::runtime_error(std::string("SetTerminalEcho failed set:") + std::to_string(GetLastError()));
#else
struct termios tty;
if (tcgetattr(STDIN_FILENO, &tty))
throw std::runtime_error(std::string("SetTerminalEcho failed get:") + strerror(errno));
if (!enable)
tty.c_lflag &= ~ECHO;
else
tty.c_lflag |= ECHO;
auto ret = tcsetattr(STDIN_FILENO, TCSANOW, &tty);
if (ret)
throw std::runtime_error(std::string("SetTerminalEcho failed set:") + strerror(errno));
#endif
}