From ab956900435387f49cb39d3859d128d07699cf5d Mon Sep 17 00:00:00 2001 From: Matthew Donoughe Date: Sat, 29 Oct 2022 08:07:31 -0400 Subject: [PATCH] CLI: Add Unicode support on Windows (#8618) --- src/cli/CMakeLists.txt | 3 +++ src/cli/Utils.cpp | 7 +++++++ src/cli/keepassxc-cli.exe.manifest | 8 ++++++++ tests/CMakeLists.txt | 1 + tests/TestCli.cpp | 26 ++++++++++++++++++++++++++ tests/TestCli.h | 2 ++ tests/data/NonAscii.kdbx | Bin 2862 -> 3886 bytes 7 files changed, 47 insertions(+) create mode 100644 src/cli/keepassxc-cli.exe.manifest diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 8f0b2854a..a3852c800 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -65,6 +65,9 @@ install(TARGETS keepassxc-cli RUNTIME DESTINATION ${CLI_INSTALL_DIR} COMPONENT Runtime) if(WIN32) + target_sources(keepassxc-cli + PRIVATE keepassxc-cli.exe.manifest) + # install(CODE "include(BundleUtilities) # fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/keepassxc-cli.exe\" \"\" \"\")" # COMPONENT Runtime) diff --git a/src/cli/Utils.cpp b/src/cli/Utils.cpp index 6c0b73e93..d8134de26 100644 --- a/src/cli/Utils.cpp +++ b/src/cli/Utils.cpp @@ -63,6 +63,13 @@ namespace Utils fd->open(fopen("/dev/null", "w"), QIODevice::WriteOnly); #endif DEVNULL.setDevice(fd); + +#ifdef Q_OS_WIN + // On Windows, we ask via keepassxc-cli.exe.manifest to use UTF-8, + // but the console code-page isn't automatically changed to match. + SetConsoleCP(GetACP()); + SetConsoleOutputCP(GetACP()); +#endif } void setStdinEcho(bool enable = true) diff --git a/src/cli/keepassxc-cli.exe.manifest b/src/cli/keepassxc-cli.exe.manifest new file mode 100644 index 000000000..9ef750e6f --- /dev/null +++ b/src/cli/keepassxc-cli.exe.manifest @@ -0,0 +1,8 @@ + + + + + UTF-8 + + + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 776c40d98..db82da163 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -235,6 +235,7 @@ endif() add_unit_test(NAME testcli SOURCES TestCli.cpp LIBS testsupport cli ${TEST_LIBRARIES}) +target_compile_definitions(testcli PRIVATE KEEPASSX_CLI_PATH="$") if(WITH_GUI_TESTS) add_subdirectory(gui) diff --git a/tests/TestCli.cpp b/tests/TestCli.cpp index 2ccda2e24..f179e6d25 100644 --- a/tests/TestCli.cpp +++ b/tests/TestCli.cpp @@ -102,6 +102,9 @@ void TestCli::init() m_yubiKeyProtectedDbFile.reset(new TemporaryFile()); m_yubiKeyProtectedDbFile->copyFromFile(file.arg("YubiKeyProtectedPasswords.kdbx")); + m_nonAsciiDbFile.reset(new TemporaryFile()); + m_nonAsciiDbFile->copyFromFile(file.arg("NonAscii.kdbx")); + m_stdout.reset(new QBuffer()); m_stdout->open(QIODevice::ReadWrite); Utils::STDOUT.setDevice(m_stdout.data()); @@ -2316,6 +2319,29 @@ void TestCli::testYubiKeyOption() QCOMPARE(m_stdout->readAll(), QByteArray()); } +void TestCli::testNonAscii() +{ + QProcess process; + process.setProcessChannelMode(QProcess::MergedChannels); + process.start( + KEEPASSX_CLI_PATH, + QStringList( + {"show", "-a", "password", m_nonAsciiDbFile->fileName(), QString::fromUtf8("\xe7\xa7\x98\xe5\xaf\x86")})); + process.waitForStarted(); + QCOMPARE(process.state(), QProcess::ProcessState::Running); + + // Write password. + process.write("\xce\x94\xc3\xb6\xd8\xb6\n"); + process.closeWriteChannel(); + + process.waitForFinished(); + + process.readLine(); // skip password prompt + QByteArray password = process.readLine(); + QCOMPARE(QString::fromUtf8(password).trimmed(), + QString::fromUtf8("\xf0\x9f\x9a\x97\xf0\x9f\x90\x8e\xf0\x9f\x94\x8b\xf0\x9f\x93\x8e")); +} + void TestCli::testCommandParsing_data() { QTest::addColumn("input"); diff --git a/tests/TestCli.h b/tests/TestCli.h index 3beb80724..d33dde26c 100644 --- a/tests/TestCli.h +++ b/tests/TestCli.h @@ -80,6 +80,7 @@ private slots: void testShow(); void testInvalidDbFiles(); void testYubiKeyOption(); + void testNonAscii(); private: QScopedPointer m_devNull; @@ -90,6 +91,7 @@ private: QScopedPointer m_keyFileProtectedDbFile; QScopedPointer m_keyFileProtectedNoPasswordDbFile; QScopedPointer m_yubiKeyProtectedDbFile; + QScopedPointer m_nonAsciiDbFile; QScopedPointer m_stdout; QScopedPointer m_stderr; diff --git a/tests/data/NonAscii.kdbx b/tests/data/NonAscii.kdbx index 06aa5bf2c8bba3faac9c998b2a0e39530be1c083..8ebaac249af5aaf9a47a306bc8f3e1d5ef3be3fd 100644 GIT binary patch delta 3882 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