Merge pull request #4390
a0613532
secure_pwd_reader: Add proper Unicode handling [Ryo contribution] (fireice-uk)579383c2
simplewallet: Add Unicode input_line [Ryo backport] (fireice-uk)
This commit is contained in:
commit
445d9c86f2
|
@ -56,8 +56,6 @@ namespace
|
||||||
|
|
||||||
bool read_from_tty(epee::wipeable_string& pass, bool hide_input)
|
bool read_from_tty(epee::wipeable_string& pass, bool hide_input)
|
||||||
{
|
{
|
||||||
static constexpr const char BACKSPACE = 8;
|
|
||||||
|
|
||||||
HANDLE h_cin = ::GetStdHandle(STD_INPUT_HANDLE);
|
HANDLE h_cin = ::GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
|
||||||
DWORD mode_old;
|
DWORD mode_old;
|
||||||
|
@ -67,32 +65,46 @@ namespace
|
||||||
|
|
||||||
bool r = true;
|
bool r = true;
|
||||||
pass.reserve(tools::password_container::max_password_size);
|
pass.reserve(tools::password_container::max_password_size);
|
||||||
|
std::vector<int> chlen;
|
||||||
|
chlen.reserve(tools::password_container::max_password_size);
|
||||||
while (pass.size() < tools::password_container::max_password_size)
|
while (pass.size() < tools::password_container::max_password_size)
|
||||||
{
|
{
|
||||||
DWORD read;
|
DWORD read;
|
||||||
char ch;
|
wchar_t ucs2_ch;
|
||||||
r = (TRUE == ::ReadConsoleA(h_cin, &ch, 1, &read, NULL));
|
r = (TRUE == ::ReadConsoleW(h_cin, &ucs2_ch, 1, &read, NULL));
|
||||||
r &= (1 == read);
|
r &= (1 == read);
|
||||||
|
|
||||||
if (!r)
|
if (!r)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (ch == '\n' || ch == '\r')
|
else if (ucs2_ch == L'\n' || ucs2_ch == L'\r')
|
||||||
{
|
{
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (ch == BACKSPACE)
|
else if (ucs2_ch == L'\b')
|
||||||
{
|
{
|
||||||
if (!pass.empty())
|
if (!pass.empty())
|
||||||
{
|
{
|
||||||
pass.pop_back();
|
int len = chlen.back();
|
||||||
|
chlen.pop_back();
|
||||||
|
while(len-- > 0)
|
||||||
|
pass.pop_back();
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
char utf8_ch[8] = {0};
|
||||||
pass.push_back(ch);
|
int len;
|
||||||
}
|
if((len = WideCharToMultiByte(CP_UTF8, 0, &ucs2_ch, 1, utf8_ch, sizeof(utf8_ch), NULL, NULL)) <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(pass.size() + len >= tools::password_container::max_password_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
chlen.push_back(len);
|
||||||
|
pass += utf8_ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
::SetConsoleMode(h_cin, mode_old);
|
::SetConsoleMode(h_cin, mode_old);
|
||||||
|
|
|
@ -939,4 +939,32 @@ std::string get_nix_version_display_string()
|
||||||
}
|
}
|
||||||
return newval;
|
return newval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::string input_line_win()
|
||||||
|
{
|
||||||
|
HANDLE hConIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||||
|
DWORD oldMode;
|
||||||
|
|
||||||
|
FlushConsoleInputBuffer(hConIn);
|
||||||
|
GetConsoleMode(hConIn, &oldMode);
|
||||||
|
SetConsoleMode(hConIn, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
|
||||||
|
|
||||||
|
wchar_t buffer[1024];
|
||||||
|
DWORD read;
|
||||||
|
|
||||||
|
ReadConsoleW(hConIn, buffer, sizeof(buffer)/sizeof(wchar_t)-1, &read, nullptr);
|
||||||
|
buffer[read] = 0;
|
||||||
|
|
||||||
|
SetConsoleMode(hConIn, oldMode);
|
||||||
|
CloseHandle(hConIn);
|
||||||
|
|
||||||
|
int size_needed = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL);
|
||||||
|
std::string buf(size_needed, '\0');
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, buffer, -1, &buf[0], size_needed, NULL, NULL);
|
||||||
|
buf.pop_back(); //size_needed includes null that we needed to have space for
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,4 +235,7 @@ namespace tools
|
||||||
boost::optional<std::pair<uint32_t, uint32_t>> parse_subaddress_lookahead(const std::string& str);
|
boost::optional<std::pair<uint32_t, uint32_t>> parse_subaddress_lookahead(const std::string& str);
|
||||||
|
|
||||||
std::string glob_to_regex(const std::string &val);
|
std::string glob_to_regex(const std::string &val);
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::string input_line_win();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,47 +137,6 @@ namespace
|
||||||
|
|
||||||
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
|
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
// Translate from CP850 to UTF-8;
|
|
||||||
// std::getline for a Windows console returns a string in CP437 or CP850; as simplewallet,
|
|
||||||
// like all of Monero, is assumed to work internally with UTF-8 throughout, even on Windows
|
|
||||||
// (although only implemented partially), a translation to UTF-8 is needed for input.
|
|
||||||
//
|
|
||||||
// Note that if a program is started inside the MSYS2 shell somebody already translates
|
|
||||||
// console input to UTF-8, but it's not clear how one could detect that in order to avoid
|
|
||||||
// double-translation; this code here thus breaks UTF-8 input within a MSYS2 shell,
|
|
||||||
// unfortunately.
|
|
||||||
//
|
|
||||||
// Note also that input for passwords is NOT translated, to remain compatible with any
|
|
||||||
// passwords containing special characters that predate this switch to UTF-8 support.
|
|
||||||
template<typename T>
|
|
||||||
static T cp850_to_utf8(const T &cp850_str)
|
|
||||||
{
|
|
||||||
boost::locale::generator gen;
|
|
||||||
gen.locale_cache_enabled(true);
|
|
||||||
std::locale loc = gen("en_US.CP850");
|
|
||||||
const boost::locale::conv::method_type how = boost::locale::conv::default_method;
|
|
||||||
T result;
|
|
||||||
const char *begin = cp850_str.data();
|
|
||||||
const char *end = begin + cp850_str.size();
|
|
||||||
result.reserve(end-begin);
|
|
||||||
typedef std::back_insert_iterator<T> inserter_type;
|
|
||||||
inserter_type inserter(result);
|
|
||||||
boost::locale::utf::code_point c;
|
|
||||||
while(begin!=end) {
|
|
||||||
c=boost::locale::utf::utf_traits<char>::template decode<char const *>(begin,end);
|
|
||||||
if(c==boost::locale::utf::illegal || c==boost::locale::utf::incomplete) {
|
|
||||||
if(how==boost::locale::conv::stop)
|
|
||||||
throw boost::locale::conv::conversion_error();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
boost::locale::utf::utf_traits<char>::template encode<inserter_type>(c,inserter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::string input_line(const std::string& prompt)
|
std::string input_line(const std::string& prompt)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_READLINE
|
#ifdef HAVE_READLINE
|
||||||
|
@ -186,9 +145,10 @@ namespace
|
||||||
std::cout << prompt;
|
std::cout << prompt;
|
||||||
|
|
||||||
std::string buf;
|
std::string buf;
|
||||||
|
#ifdef _WIN32
|
||||||
|
buf = tools::input_line_win();
|
||||||
|
#else
|
||||||
std::getline(std::cin, buf);
|
std::getline(std::cin, buf);
|
||||||
#ifdef WIN32
|
|
||||||
buf = cp850_to_utf8(buf);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return epee::string_tools::trim(buf);
|
return epee::string_tools::trim(buf);
|
||||||
|
@ -208,10 +168,6 @@ namespace
|
||||||
|
|
||||||
epee::wipeable_string buf = pwd_container->password();
|
epee::wipeable_string buf = pwd_container->password();
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
buf = cp850_to_utf8(buf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
buf.trim();
|
buf.trim();
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue