From 9176ddc3e14d00ab3c1b62f153c9be3af59efa8a 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 325ff880e..b84869c19 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -233,6 +233,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 c560f4c25..5b136ca83 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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 delta 2850 zcmV+-3*Gdt96lOHVB1Hh)p}8XPPMAOMh1Xcr=A zn_jbRX4^TkRm+}wMhp`OIn(Any2X7dpi~M300IC2000C44GIkkQ^l2dXH0N4P`qP< zqd3SZPD}ag?pJCWFHyNcy~H1Jl1ElnRH^aJtwX#LAEt$C=1O%v!4)QH{dVB;yrRT` zat%QP` z)Qsj=EQY}qW^l~!C_;F`DZ2W^34vq(9SUoxK^PHsGXyC7R({dYB+&DSp)Eb?PSG1! z@vb~KwWc0s8T1f`Da2{;a@fwY^-9|=1E1)huUKrA}0<^CVLwNwD!;-F|qG z%HU&}E#$0CpO^UPWPscSJ#K2ZG1Z%p!QrCrdj53_?!M9d@IWq2VXdKy z!N45ghFy|5i#uuE$ba&?>y67vmIu{{i{HsQa{6GU@V5>Uc3$gB zfm?7)44)bF81aB+m8<;s#ommZx|;4@VSx-r+O@Q~<+l3a#Ro#!|mE!c^CWM5g#Ong;Hk)vDt?{Yi8jF|p$2_C5OytsCEIve;S zvo%IMkqKGzkhbjUdCz&MD8funcJ*oQ3wE77T~bCLI2r?DtRrNn2s;rmQZ__1;iMKrPnuVS-ggpKUC?BHiqR- zfktkAYr*u!d?S0oL+sSL^~_(q{j$lLyDj9&91=Oo)O!v_w0qp*=r66sQ-7`%R6Is* z>;~8w>_~5{CN@#&SPby&cQ$I97TsPJfSG>(*>E#-7BHzhY}Fz7+ytt%+Aa0QZ=!Sf z9R2EWGdDD@h$$W>VdR1qm`Pd6wIZ@<8g8O!S zT#U?Ptv+Q;I%i2v3Kqr*G@Rye*#iz#%8u~(W$d!{osU{Hr$|uWKs*PCD46A5lmenn zE(k#`r({_4&B^htp<9>V%*lh<@IU7zag?-zzYfR(+-h063rNL)hkt2Z+T4;m--#SU z1rf_GPnpWXnOUfKfRv|_B=GnufUrKdx;G3b1Fi%d$GgxTdHXSVOZHT=sJ9mtqbW`w z$JSPLvN-F<&p&hn$5Oipcd;5^poUHXw;qP*qR*fvX@GWu4U^`RFgN+kCm7@mkGH!o zGc(sQ+^{5M6XV=wYk${aV)!k*fHZn(HZE_MAm8YEYgwsSyM`@@ z^2n{IN1>N=%U~&=8rb_kwWIjD+IVu<1Hg;Gmtk9Qiv{R`R)6p)^|>*fDxUvB5hfCX z%n5Ju;~Re2urAei3>32Mc74m?;=GL$%v&*$s*30^WNC(ozEgR1^QFCq#3s=z*>THa zS%(!lOZkdb1;hf2Ed_b3;Tezcedq`+G)!ra#NJhkeO$~ng1m7H^OaSP-^B!Yt9pId z-e0_lh?N5;?tj2xS59N57W>ybYa%~;h9F^3FI*HXk75PQ=GUp!n}$WFY0SFv9{O}! z5vl0Yx@vjnxQtt_k!9GKb1a`XD0Z-m3G7+ z)9CI2RA_^lq!gOhXsg9%)bf&YHrZtr*~4f)Jww&#B>M%wMZ}_Vw$eQaLpGa{yS@!%qvy_B36H+Z-3(a#%nXf+c+D8IsMt-i;rRgZe34q z`<3qnyj=sxrVrmWBAJ$AytmRrVEGp{DH2^p`pA*Z5@uH;j#cNN)3?lAk~I4OfT>A8 zJq;(^5XdgMaOF#u;}8#tm=28TAg4OWPRtY7Iw1(A#Ou*T)kC|r> zFn|4kH@PA<8v10;Sbd$d$B!AqM7U5R@$r05jDI4tWG3z!M%?dZ3i}b`l-_Fa_^=z?(p867 zw_u}~0#H)alVquZJmVOg3EC)PWjt;mB<%Y5G+3XZlDF}uq14F*8IL&%B5(NZ$LiPX&+ZbvDj{NfnPGcfH-B1* ze$r?qjo@HZ5&6DhXmG6X3`#AJi4!%e_sGGg$>ByQ0=>3)%;x|n zHBYUQPiCuC>=s?TWHE)9Fep|l@9b=F`LsYrXes-<`FFA{Mea;XTJzGPZ(fg3EloV+ zhncV@30|HfwFYNr3Rr^DbAifR&KtoZRA>Snf~V>{z#dzk9vr}!Fr~%@7;}gH8M(r3 AJpcdz