diff --git a/CMakeLists.txt b/CMakeLists.txt index e7183f1691..251b043873 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2018 KeePassXC Team +# Copyright (C) 2023 KeePassXC Team # Copyright (C) 2010 Felix Geyer # # This program is free software: you can redistribute it and/or modify @@ -205,6 +205,9 @@ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0") check_pie_supported() endif() +# Find Qt6 compatibility library +find_package(Qt6 REQUIRED COMPONENTS Core5Compat) + # Find Botan early since the version affects subsequent compiler options find_package(Botan REQUIRED) if(BOTAN_VERSION VERSION_GREATER_EQUAL "3.0.0") @@ -496,31 +499,22 @@ if(UNIX AND NOT APPLE) if(WITH_XC_X11) list(APPEND QT_COMPONENTS X11Extras) endif() - find_package(Qt5 COMPONENTS ${QT_COMPONENTS} DBus REQUIRED) + find_package(Qt6 COMPONENTS ${QT_COMPONENTS} DBus REQUIRED) elseif(APPLE) - find_package(Qt5 COMPONENTS ${QT_COMPONENTS} REQUIRED HINTS - /usr/local/opt/qt@5/lib/cmake - /usr/local/Cellar/qt@5/*/lib/cmake - /opt/homebrew/opt/qt@5/lib/cmake - ENV PATH) - find_package(Qt5 COMPONENTS MacExtras HINTS - /usr/local/opt/qt@5/lib/cmake - /usr/local/Cellar/qt@5/*/lib/cmake - /opt/homebrew/opt/qt@5/lib/cmake + find_package(Qt6 COMPONENTS ${QT_COMPONENTS} REQUIRED HINTS + /usr/local/opt/qt/lib/cmake + /usr/local/Cellar/qt/*/lib/cmake + /opt/homebrew/opt/qt/lib/cmake ENV PATH) else() - find_package(Qt5 COMPONENTS ${QT_COMPONENTS} REQUIRED) + find_package(Qt6 COMPONENTS ${QT_COMPONENTS} REQUIRED) endif() -if(Qt5Core_VERSION VERSION_LESS "5.12.0") - message(FATAL_ERROR "Qt version 5.12.0 or higher is required") +if(Qt6Core_VERSION VERSION_LESS "6.6.0") + message(FATAL_ERROR "Qt version 6.6.0 or higher is required") endif() -get_filename_component(Qt5_PREFIX ${Qt5_DIR}/../../.. REALPATH) -if(APPLE) - # Add includes under Qt5 Prefix in case Qt6 is also installed - include_directories(SYSTEM ${Qt5_PREFIX}/include) -endif() +get_filename_component(Qt6_PREFIX ${Qt6_DIR}/../../.. REALPATH) # Process moc automatically set(CMAKE_AUTOMOC ON) @@ -531,18 +525,18 @@ set(CMAKE_AUTORCC ON) if(APPLE) set(CMAKE_MACOSX_RPATH TRUE) - find_program(MACDEPLOYQT_EXE macdeployqt HINTS ${Qt5_PREFIX}/bin ${Qt5_PREFIX}/tools/qt5/bin ENV PATH) + find_program(MACDEPLOYQT_EXE macdeployqt6 HINTS ${Qt6_PREFIX}/bin ${Qt6_PREFIX}/tools/qt/bin ENV PATH) if(NOT MACDEPLOYQT_EXE) - message(FATAL_ERROR "macdeployqt is required to build on macOS") + message(FATAL_ERROR "macdeployqt6 is required to build on macOS") endif() - message(STATUS "Using macdeployqt: ${MACDEPLOYQT_EXE}") + message(STATUS "Using macdeployqt6: ${MACDEPLOYQT_EXE}") set(MACDEPLOYQT_EXTRA_BINARIES "") elseif(WIN32) - find_program(WINDEPLOYQT_EXE windeployqt HINTS ${Qt5_PREFIX}/bin ${Qt5_PREFIX}/tools/qt5/bin ENV PATH) + find_program(WINDEPLOYQT_EXE windeployqt6 HINTS ${Qt6_PREFIX}/bin ${Qt6_PREFIX}/tools/qt/bin ENV PATH) if(NOT WINDEPLOYQT_EXE) - message(FATAL_ERROR "windeployqt is required to build on Windows") + message(FATAL_ERROR "windeployqt6 is required to build on Windows") endif() - message(STATUS "Using windeployqt: ${WINDEPLOYQT_EXE}") + message(STATUS "Using windeployq6t: ${WINDEPLOYQT_EXE}") endif() # Debian sets the build type to None for package builds. diff --git a/release-tool b/release-tool index 43f0580006..85780dfbc4 100755 --- a/release-tool +++ b/release-tool @@ -360,10 +360,10 @@ checkXcodeSetup() { fi } -checkQt5LUpdateExists() { +checkQt6LUpdateExists() { if cmdExists lupdate && ! $(lupdate -version | grep -q "lupdate version 5\."); then - if ! cmdExists lupdate-qt5; then - exitError "Qt Linguist tool (lupdate-qt5) is not installed! Please install using 'apt install qttools5-dev-tools'" + if ! cmdExists lupdate-qt6; then + exitError "Qt Linguist tool (lupdate-qt6) is not installed! Please install using 'apt install qttools6-dev-tools'" fi fi } @@ -379,7 +379,7 @@ performChecks() { logInfo "Validating toolset and repository..." checkTransifexCommandExists - checkQt5LUpdateExists + checkQt6LUpdateExists checkGitRepository checkReleaseDoesNotExist checkWorkingTreeClean @@ -955,7 +955,7 @@ build() { export MACOSX_DEPLOYMENT_TARGET logInfo "Configuring build..." - cmake -G "${CMAKE_GENERATOR}" -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="$(uname -m)" \ + cmake -G "${CMAKE_GENERATOR}" -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" \ -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" ${CMAKE_OPTIONS} "$SRC_DIR" logInfo "Compiling and packaging sources..." @@ -1404,10 +1404,10 @@ i18n() { exit 1 fi - checkQt5LUpdateExists + checkQt6LUpdateExists logInfo "Updating source translation file..." - LUPDATE=lupdate-qt5 + LUPDATE=lupdate-qt6 if ! command -v $LUPDATE > /dev/null; then LUPDATE=lupdate fi diff --git a/share/translations/CMakeLists.txt b/share/translations/CMakeLists.txt index bf18700421..33f2ca7fdc 100644 --- a/share/translations/CMakeLists.txt +++ b/share/translations/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2017 KeePassXC Team +# Copyright (C) 2023 KeePassXC Team # Copyright (C) 2014 Felix Geyer # # This program is free software: you can redistribute it and/or modify @@ -20,15 +20,15 @@ list(REMOVE_ITEM TRANSLATION_FILES keepassxc_en.ts) list(REMOVE_ITEM TRANSLATION_FILES ${TRANSLATION_EN_ABS}) message(STATUS "Including translations...\n") -qt5_add_translation(QM_FILES ${TRANSLATION_FILES}) +qt6_add_translation(QM_FILES ${TRANSLATION_FILES}) if(WIN32) - file(GLOB QTBASE_TRANSLATIONS ${Qt5_PREFIX}/share/qt5/translations/qtbase_*.qm) + file(GLOB QTBASE_TRANSLATIONS ${Qt6_PREFIX}/share/qt/translations/qtbase_*.qm) elseif(APPLE OR KEEPASSXC_DIST_APPIMAGE) file(GLOB QTBASE_TRANSLATIONS /usr/share/qt/translations/qtbase_*.qm - /usr/share/qt5/translations/qtbase_*.qm - ${Qt5_PREFIX}/translations/qtbase_*.qm) + /usr/share/qt6/translations/qtbase_*.qm + ${Qt6_PREFIX}/translations/qtbase_*.qm) endif() set(QM_FILES ${QM_FILES} ${QTBASE_TRANSLATIONS}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5c7326b5c5..fc64819fe0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2023 KeePassXC Team +# Copyright (C) 2025 KeePassXC Team # Copyright (C) 2010 Felix Geyer # # This program is free software: you can redistribute it and/or modify @@ -233,26 +233,26 @@ if(UNIX AND NOT APPLE) endif() if(WITH_XC_X11) list(APPEND gui_SOURCES - gui/osutils/nixutils/X11Funcs.cpp) + gui/osutils/nixutils/X11Funcs.cpp) endif() - qt5_add_dbus_adaptor(gui_SOURCES + qt6_add_dbus_adaptor(gui_SOURCES gui/org.keepassxc.KeePassXC.MainWindow.xml gui/MainWindow.h MainWindow) set_source_files_properties( - quickunlock/dbus/org.freedesktop.PolicyKit1.Authority.xml - PROPERTIES - INCLUDE "quickunlock/PolkitDbusTypes.h" - ) - qt5_add_dbus_interface(core_SOURCES - quickunlock/dbus/org.freedesktop.PolicyKit1.Authority.xml - polkit_dbus + quickunlock/dbus/org.freedesktop.PolicyKit1.Authority.xml + PROPERTIES + INCLUDE "quickunlock/PolkitDbusTypes.h" + ) + qt6_add_dbus_interface(core_SOURCES + quickunlock/dbus/org.freedesktop.PolicyKit1.Authority.xml + polkit_dbus ) find_library(KEYUTILS_LIBRARIES NAMES keyutils) if(NOT KEYUTILS_LIBRARIES) - message(FATAL_ERROR "Could not find libkeyutils") + message(FATAL_ERROR "Could not find libkeyutils") endif() endif() @@ -329,19 +329,19 @@ set(autotype_SOURCES autotype/WindowSelectComboBox.cpp) add_library(autotype STATIC ${autotype_SOURCES}) -target_link_libraries(autotype Qt5::Core Qt5::Widgets) +target_link_libraries(autotype Qt6::Core Qt6::Widgets) if(WITH_XC_YUBIKEY) list(APPEND core_SOURCES - keys/drivers/YubiKey.h - keys/drivers/YubiKey.cpp - keys/drivers/YubiKeyInterface.cpp - keys/drivers/YubiKeyInterfaceUSB.cpp - keys/drivers/YubiKeyInterfacePCSC.cpp) + keys/drivers/YubiKey.h + keys/drivers/YubiKey.cpp + keys/drivers/YubiKeyInterface.cpp + keys/drivers/YubiKeyInterfaceUSB.cpp + keys/drivers/YubiKeyInterfacePCSC.cpp) else() list(APPEND core_SOURCES - keys/drivers/YubiKey.h - keys/drivers/YubiKeyStub.cpp) + keys/drivers/YubiKey.h + keys/drivers/YubiKeyStub.cpp) endif() if(WITH_XC_NETWORKING) @@ -360,10 +360,10 @@ configure_file(git-info.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/git-info.h) # Core Library Definition add_library(keepassxc_core STATIC ${core_SOURCES}) set_target_properties(keepassxc_core PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUILDING_CORE) -target_link_libraries(keepassxc_core +target_link_libraries(keepassxc_core ${qrcode_LIB} - Qt5::Core - Qt5::Concurrent + Qt6::Core + Qt6::Concurrent ${BOTAN_LIBRARIES} ${PCSC_LIBRARIES} ${ZXCVBN_LIBRARIES} @@ -375,11 +375,13 @@ target_link_libraries(keepassxc_core # GUI Library Definition add_library(keepassxc_gui STATIC ${gui_SOURCES}) +find_package(Qt6 REQUIRED COMPONENTS SvgWidgets) set_target_properties(keepassxc_gui PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUILDING_CORE) target_link_libraries(keepassxc_gui keepassxc_core - Qt5::Network - Qt5::Widgets + Qt6::Network + Qt6::SvgWidgets + Qt6::Widgets autotype ${browser_LIB} ${fdosecrets_LIB} @@ -388,19 +390,19 @@ target_link_libraries(keepassxc_gui if(APPLE) target_link_libraries(keepassxc_gui "-framework Foundation -framework AppKit -framework Carbon -framework Security -framework LocalAuthentication -framework ScreenCaptureKit") - if(Qt5MacExtras_FOUND) - target_link_libraries(keepassxc_gui Qt5::MacExtras) + if(Qt6MacExtras_FOUND) + target_link_libraries(keepassxc_gui Qt6::MacExtras) endif() endif() if(HAIKU) target_link_libraries(keepassxc_gui network) endif() if(UNIX AND NOT APPLE) - target_link_libraries(keepassxc_core Qt5::DBus ${LIBUSB_LIBRARIES}) + target_link_libraries(keepassxc_core Qt6::DBus ${LIBUSB_LIBRARIES}) if(WITH_XC_X11) - target_link_libraries(keepassxc_gui Qt5::X11Extras X11) + target_link_libraries(keepassxc_gui Qt6::X11Extras X11) endif() - include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) + include_directories(${Qt6Gui_PRIVATE_INCLUDE_DIRS}) endif() if(WIN32) target_link_libraries(keepassxc_gui Wtsapi32.lib Ws2_32.lib) @@ -524,7 +526,7 @@ if(WIN32) COMPONENT Runtime) # Use windeployqt.exe to setup Qt dependencies - if(Qt5Core_VERSION VERSION_LESS "5.14.1") + if(Qt6Core_VERSION VERSION_LESS "6.6.0") set(WINDEPLOYQT_MODE "--release") if(CMAKE_BUILD_TYPE_LOWER STREQUAL "debug") set(WINDEPLOYQT_MODE "--debug") @@ -539,7 +541,7 @@ if(WIN32) find_file(OPENSSL_DLL NAMES libssl-3.dll libssl-3-x64.dll HINTS "${OPENSSL_ROOT_DIR}/bin" - ) + ) if (NOT OPENSSL_DLL) message(FATAL_ERROR "Cannot find libssl dll, ensure openssl is properly installed.") endif() @@ -547,7 +549,7 @@ if(WIN32) find_file(CRYPTO_DLL NAMES libcrypto-3.dll libcrypto-3-x64.dll HINTS "${OPENSSL_ROOT_DIR}/bin" - ) + ) if (NOT CRYPTO_DLL) message(FATAL_ERROR "Cannot find libcrypto dll, ensure openssl is properly installed.") endif() @@ -557,7 +559,7 @@ if(WIN32) endif() # install CA cert chains - find_file(SSL_CA_BUNDLE ca-bundle.crt PATHS "${Qt5_PREFIX}/ssl/certs") + find_file(SSL_CA_BUNDLE ca-bundle.crt PATHS "${Qt6_PREFIX}/ssl/certs") if(SSL_CA_BUNDLE) install(FILES ${SSL_CA_BUNDLE} DESTINATION "ssl/certs") else() diff --git a/src/autotype/AutoTypeMatch.h b/src/autotype/AutoTypeMatch.h index 1b8f2c740f..c202ada339 100644 --- a/src/autotype/AutoTypeMatch.h +++ b/src/autotype/AutoTypeMatch.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,10 +18,10 @@ #ifndef KPXC_AUTOTYPEMATCH_H #define KPXC_AUTOTYPEMATCH_H +#include "core/Entry.h" #include #include -class Entry; typedef QPair, QString> AutoTypeMatch; #endif // KPXC_AUTOTYPEMATCH_H diff --git a/src/autotype/AutoTypeMatchView.cpp b/src/autotype/AutoTypeMatchView.cpp index 91f9ce0838..12cab3ff1e 100644 --- a/src/autotype/AutoTypeMatchView.cpp +++ b/src/autotype/AutoTypeMatchView.cpp @@ -1,6 +1,6 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2015 David Wu - * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,9 +38,9 @@ class CustomSortFilterProxyModel : public QSortFilterProxyModel auto index1 = sourceModel()->index(sourceRow, 1, sourceParent); auto index2 = sourceModel()->index(sourceRow, 2, sourceParent); - return sourceModel()->data(index0).toString().contains(filterRegExp()) - || sourceModel()->data(index1).toString().contains(filterRegExp()) - || sourceModel()->data(index2).toString().contains(filterRegExp()); + return sourceModel()->data(index0).toString().contains(filterRegularExpression()) + || sourceModel()->data(index1).toString().contains(filterRegularExpression()) + || sourceModel()->data(index2).toString().contains(filterRegularExpression()); } }; diff --git a/src/autotype/AutoTypeSelectDialog.cpp b/src/autotype/AutoTypeSelectDialog.cpp index 46422102d5..6ad1865643 100644 --- a/src/autotype/AutoTypeSelectDialog.cpp +++ b/src/autotype/AutoTypeSelectDialog.cpp @@ -296,7 +296,7 @@ void AutoTypeSelectDialog::buildActionMenu() m_actionMenu->addAction(copyPasswordAction); m_actionMenu->addAction(copyTotpAction); - typeUsernameAction->setShortcut(Qt::CTRL + Qt::Key_1); + typeUsernameAction->setShortcut(Qt::CTRL | Qt::Key_1); typeUsernameAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::USERNAME); connect(typeUsernameAction, &QAction::triggered, this, [&] { auto match = m_ui->view->currentMatch(); @@ -304,7 +304,7 @@ void AutoTypeSelectDialog::buildActionMenu() submitAutoTypeMatch(match); }); - typePasswordAction->setShortcut(Qt::CTRL + Qt::Key_2); + typePasswordAction->setShortcut(Qt::CTRL | Qt::Key_2); typePasswordAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::PASSWORD); connect(typePasswordAction, &QAction::triggered, this, [&] { auto match = m_ui->view->currentMatch(); @@ -312,7 +312,7 @@ void AutoTypeSelectDialog::buildActionMenu() submitAutoTypeMatch(match); }); - typeTotpAction->setShortcut(Qt::CTRL + Qt::Key_3); + typeTotpAction->setShortcut(Qt::CTRL | Qt::Key_3); typeTotpAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::TOTP); connect(typeTotpAction, &QAction::triggered, this, [&] { auto match = m_ui->view->currentMatch(); @@ -330,7 +330,7 @@ void AutoTypeSelectDialog::buildActionMenu() }); #endif - copyUsernameAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_1); + copyUsernameAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_1); copyUsernameAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::USERNAME); connect(copyUsernameAction, &QAction::triggered, this, [&] { auto entry = m_ui->view->currentMatch().first; @@ -340,7 +340,7 @@ void AutoTypeSelectDialog::buildActionMenu() } }); - copyPasswordAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_2); + copyPasswordAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_2); copyPasswordAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::PASSWORD); connect(copyPasswordAction, &QAction::triggered, this, [&] { auto entry = m_ui->view->currentMatch().first; @@ -350,7 +350,7 @@ void AutoTypeSelectDialog::buildActionMenu() } }); - copyTotpAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_3); + copyTotpAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_3); copyTotpAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::TOTP); connect(copyTotpAction, &QAction::triggered, this, [&] { auto entry = m_ui->view->currentMatch().first; diff --git a/src/autotype/CMakeLists.txt b/src/autotype/CMakeLists.txt index 79bb503722..6fbb7635c1 100644 --- a/src/autotype/CMakeLists.txt +++ b/src/autotype/CMakeLists.txt @@ -1,11 +1,9 @@ if(WITH_XC_AUTOTYPE) if(UNIX AND NOT APPLE AND NOT HAIKU) find_package(X11 REQUIRED COMPONENTS Xi XTest) - find_package(Qt5X11Extras 5.2 REQUIRED) if(PRINT_SUMMARY) add_feature_info(libXi X11_Xi_FOUND "The X11 Xi Protocol library is required for auto-type") add_feature_info(libXtst X11_XTest_FOUND "The X11 XTEST Protocol library is required for auto-type") - add_feature_info(Qt5X11Extras Qt5X11Extras_FOUND "The Qt5X11Extras library is required for auto-type") endif() add_subdirectory(xcb) diff --git a/src/autotype/mac/AutoTypeMac.h b/src/autotype/mac/AutoTypeMac.h index 54805a4e98..949d590088 100644 --- a/src/autotype/mac/AutoTypeMac.h +++ b/src/autotype/mac/AutoTypeMac.h @@ -1,6 +1,6 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2016 Lennart Glauer - * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,8 +23,8 @@ #include #include -#include "autotype/AutoTypePlatformPlugin.h" #include "autotype/AutoTypeAction.h" +#include "autotype/AutoTypePlatformPlugin.h" class AutoTypePlatformMac : public QObject, public AutoTypePlatformInterface { @@ -45,7 +45,7 @@ class AutoTypePlatformMac : public QObject, public AutoTypePlatformInterface bool raiseOwnWindow() override; void sendChar(const QChar& ch, bool isKeyDown); - void sendKey(Qt::Key key, bool isKeyDown, Qt::KeyboardModifiers modifiers = 0); + void sendKey(Qt::Key key, bool isKeyDown, Qt::KeyboardModifiers modifiers = Qt::NoModifier); private: static int windowLayer(CFDictionaryRef window); @@ -65,4 +65,4 @@ class AutoTypeExecutorMac : public AutoTypeExecutor AutoTypePlatformMac* const m_platform; }; -#endif // KEEPASSX_AUTOTYPEMAC_H +#endif // KEEPASSX_AUTOTYPEMAC_H diff --git a/src/autotype/mac/CMakeLists.txt b/src/autotype/mac/CMakeLists.txt index ae1f5187f5..538bfdf86c 100644 --- a/src/autotype/mac/CMakeLists.txt +++ b/src/autotype/mac/CMakeLists.txt @@ -1,8 +1,8 @@ set(autotype_mac_SOURCES AutoTypeMac.cpp) add_library(keepassxc-autotype-cocoa MODULE ${autotype_mac_SOURCES}) -set_target_properties(keepassxc-autotype-cocoa PROPERTIES LINK_FLAGS "-framework Foundation -framework AppKit -framework Carbon -framework ScreenCaptureKit") -target_link_libraries(keepassxc-autotype-cocoa ${PROGNAME} Qt5::Core Qt5::Widgets) +set_target_properties(keepassxc-autotype-cocoa PROPERTIES LINK_FLAGS "-framework Foundation -framework AppKit -framework Carbon") +target_link_libraries(keepassxc-autotype-cocoa ${PROGNAME} Qt6::Core Qt6::Widgets) install(TARGETS keepassxc-autotype-cocoa LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR} COMPONENT Runtime) diff --git a/src/autotype/test/CMakeLists.txt b/src/autotype/test/CMakeLists.txt index e27f2b1d98..27211fa4c7 100644 --- a/src/autotype/test/CMakeLists.txt +++ b/src/autotype/test/CMakeLists.txt @@ -1,4 +1,4 @@ set(autotype_test_SOURCES AutoTypeTest.cpp) add_library(keepassxc-autotype-test MODULE ${autotype_test_SOURCES}) -target_link_libraries(keepassxc-autotype-test keepassxc_gui ${autotype_LIB} Qt5::Core Qt5::Widgets) +target_link_libraries(keepassxc-autotype-test keepassxc_core ${autotype_LIB} Qt6::Core Qt6::Widgets) diff --git a/src/autotype/windows/CMakeLists.txt b/src/autotype/windows/CMakeLists.txt index 5b9cbecff9..6ed316e2d5 100644 --- a/src/autotype/windows/CMakeLists.txt +++ b/src/autotype/windows/CMakeLists.txt @@ -1,7 +1,7 @@ set(autotype_win_SOURCES AutoTypeWindows.cpp) add_library(keepassxc-autotype-windows MODULE ${autotype_win_SOURCES}) -target_link_libraries(keepassxc-autotype-windows keepassxc_gui ${autotype_LIB} Qt5::Core Qt5::Widgets) +target_link_libraries(keepassxc-autotype-windows keepassxc_gui ${autotype_LIB} Qt6::Core Qt6::Widgets) install(TARGETS keepassxc-autotype-windows BUNDLE DESTINATION . COMPONENT Runtime LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR} COMPONENT Runtime) diff --git a/src/autotype/xcb/CMakeLists.txt b/src/autotype/xcb/CMakeLists.txt index f14017f63a..6d89737e62 100644 --- a/src/autotype/xcb/CMakeLists.txt +++ b/src/autotype/xcb/CMakeLists.txt @@ -3,7 +3,7 @@ include_directories(SYSTEM ${X11_X11_INCLUDE_PATH}) set(autotype_XCB_SOURCES AutoTypeXCB.cpp) add_library(keepassxc-autotype-xcb MODULE ${autotype_XCB_SOURCES}) -target_link_libraries(keepassxc-autotype-xcb keepassxc_gui Qt5::Core Qt5::Widgets Qt5::X11Extras ${X11_X11_LIB} ${X11_Xi_LIB} ${X11_XTest_LIB}) +target_link_libraries(keepassxc-autotype-xcb keepassxc_gui Qt6::Core Qt6::Widgets Qt6::X11Extras ${X11_X11_LIB} ${X11_Xi_LIB} ${X11_XTest_LIB}) install(TARGETS keepassxc-autotype-xcb BUNDLE DESTINATION . COMPONENT Runtime LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR} COMPONENT Runtime) diff --git a/src/browser/BrowserService.cpp b/src/browser/BrowserService.cpp index 1854f26894..db9fedb73a 100644 --- a/src/browser/BrowserService.cpp +++ b/src/browser/BrowserService.cpp @@ -43,7 +43,6 @@ #include #include -#include #include #include #include @@ -1447,7 +1446,7 @@ bool BrowserService::isPasskeyCredentialExcluded(const QJsonArray& excludeCreden { QStringList allIds; for (const auto& cred : excludeCredentials) { - allIds << cred["id"].toString(); + allIds << cred.toObject().value("id").toString(); } const auto passkeyEntries = getPasskeyEntries(rpId, keyList); @@ -1705,7 +1704,7 @@ void BrowserService::processClientMessage(QLocalSocket* socket, const QJsonObjec m_browserClients.insert(clientID, QSharedPointer::create()); } - auto& action = m_browserClients.value(clientID); + const auto& action = m_browserClients.value(clientID); auto response = action->processClientMessage(socket, message); m_browserHost->sendClientMessage(socket, response); } diff --git a/src/browser/CMakeLists.txt b/src/browser/CMakeLists.txt index 7942be430e..a1e35b15fa 100644 --- a/src/browser/CMakeLists.txt +++ b/src/browser/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2024 KeePassXC Team +# Copyright (C) 2025 KeePassXC Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -41,5 +41,5 @@ if(WITH_XC_BROWSER) endif() add_library(browser STATIC ${browser_SOURCES}) - target_link_libraries(browser Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network ${BOTAN_LIBRARIES}) + target_link_libraries(browser Qt6::Core Qt6::Concurrent Qt6::Widgets Qt6::Network ${BOTAN_LIBRARIES}) endif() diff --git a/src/browser/PasskeyUtils.cpp b/src/browser/PasskeyUtils.cpp index 41fc942212..cc9d31b303 100644 --- a/src/browser/PasskeyUtils.cpp +++ b/src/browser/PasskeyUtils.cpp @@ -158,18 +158,19 @@ QJsonArray PasskeyUtils::parseCredentialTypes(const QJsonArray& credentialTypes) })); } else { for (const auto current : credentialTypes) { - if (current["type"] != BrowserPasskeys::PUBLIC_KEY || current["alg"].isUndefined()) { + const auto currentObject = current.toObject(); + if (currentObject["type"] != BrowserPasskeys::PUBLIC_KEY || currentObject["alg"].isUndefined()) { continue; } - const auto currentAlg = current["alg"].toInt(); + const auto currentAlg = currentObject["alg"].toInt(); if (currentAlg != WebAuthnAlgorithms::ES256 && currentAlg != WebAuthnAlgorithms::RS256 && currentAlg != WebAuthnAlgorithms::EDDSA) { continue; } credTypesAndPubKeyAlgs.push_back(QJsonObject({ - {"type", current["type"]}, + {"type", currentObject["type"]}, {"alg", currentAlg}, })); } diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index ecd5da2847..2b4b3ff1e4 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2019 KeePassXC Team +# Copyright (C) 2023 KeePassXC Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -45,7 +45,7 @@ set(cli_SOURCES Show.cpp) add_library(cli STATIC ${cli_SOURCES}) -target_link_libraries(cli ${ZXCVBN_LIBRARIES} Qt5::Core) +target_link_libraries(cli Qt6::Core) find_package(Readline) diff --git a/src/cli/DatabaseInfo.cpp b/src/cli/DatabaseInfo.cpp index 0b205157ca..c240ace512 100644 --- a/src/cli/DatabaseInfo.cpp +++ b/src/cli/DatabaseInfo.cpp @@ -21,7 +21,6 @@ #include "core/Clock.h" #include "core/DatabaseStats.h" #include "core/Global.h" -#include "core/Group.h" #include "core/Metadata.h" #include diff --git a/src/cli/TextStream.cpp b/src/cli/TextStream.cpp index e2e6e15f46..b596f6ff47 100644 --- a/src/cli/TextStream.cpp +++ b/src/cli/TextStream.cpp @@ -18,7 +18,7 @@ #include "TextStream.h" #include -#include +#include #ifdef Q_OS_WIN #include #endif @@ -87,13 +87,44 @@ void TextStream::detectCodec() // Only override codec if LANG is set, otherwise Qt will assume // US-ASCII, which is almost always wrong and results in // Unicode passwords being displayed as question marks. - codecName = QTextCodec::codecForLocale()->name(); + codecName = "System"; } #endif codecName = env.value("ENCODING_OVERRIDE", codecName); - auto* codec = QTextCodec::codecForName(codecName.toLatin1()); - if (codec) { - setCodec(codec); + + QStringConverter::Encoding codec = QStringConverter::Utf8; + if (codecName.toLatin1().compare(QByteArray("UTF-8"), Qt::CaseInsensitive) == 0 + || codecName.toLatin1().compare(QByteArray("Utf8"), Qt::CaseInsensitive) == 0) { + codec = QStringConverter::Utf8; + } else if (codecName.toLatin1().compare(QByteArray("UTF-16"), Qt::CaseInsensitive) == 0 + || codecName.toLatin1().compare(QByteArray("Utf16"), Qt::CaseInsensitive) == 0) { + codec = QStringConverter::Utf16; + } else if (codecName.toLatin1().compare(QByteArray("UTF-16BE"), Qt::CaseInsensitive) == 0 + || codecName.toLatin1().compare(QByteArray("Utf16BE"), Qt::CaseInsensitive) == 0) { + codec = QStringConverter::Utf16BE; + } else if (codecName.toLatin1().compare(QByteArray("UTF-16LE"), Qt::CaseInsensitive) == 0 + || codecName.toLatin1().compare(QByteArray("Utf16LE"), Qt::CaseInsensitive) == 0) { + codec = QStringConverter::Utf16LE; + } else if (codecName.toLatin1().compare(QByteArray("UTF-32"), Qt::CaseInsensitive) == 0 + || codecName.toLatin1().compare(QByteArray("Utf32"), Qt::CaseInsensitive) == 0) { + codec = QStringConverter::Utf32; + } else if (codecName.toLatin1().compare(QByteArray("UTF-32BE"), Qt::CaseInsensitive) == 0 + || codecName.toLatin1().compare(QByteArray("Utf32BE"), Qt::CaseInsensitive) == 0) { + codec = QStringConverter::Utf32BE; + } else if (codecName.toLatin1().compare(QByteArray("UTF-32LE"), Qt::CaseInsensitive) == 0 + || codecName.toLatin1().compare(QByteArray("Utf32LE"), Qt::CaseInsensitive) == 0) { + codec = QStringConverter::Utf32LE; + } else if (codecName.toLatin1().compare(QByteArray("ISO 8859-1"), Qt::CaseInsensitive) == 0 + || codecName.toLatin1().compare(QByteArray("Latin1"), Qt::CaseInsensitive) == 0) { + codec = QStringConverter::Latin1; + } else if (codecName.toLatin1().compare(QByteArray("Windows-850"), Qt::CaseInsensitive) == 0 + || codecName.toLatin1().compare(QByteArray("Windows-1252"), Qt::CaseInsensitive) == 0 + || codecName.toLatin1().compare(QByteArray("System"), Qt::CaseInsensitive) == 0) { + codec = QStringConverter::System; + } else { + return; } + + setEncoding(codec); } diff --git a/src/cli/TextStream.h b/src/cli/TextStream.h index 0091ec1087..99b0b60022 100644 --- a/src/cli/TextStream.h +++ b/src/cli/TextStream.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ #ifndef KEEPASSXC_TEXTSTREAM_H #define KEEPASSXC_TEXTSTREAM_H +#include #include /** diff --git a/src/cli/Utils.h b/src/cli/Utils.h index 6a272fc620..e8a37770a8 100644 --- a/src/cli/Utils.h +++ b/src/cli/Utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,9 @@ #define KEEPASSXC_UTILS_H #include +#include +#include +#include class CompositeKey; class Database; diff --git a/src/core/Base32.cpp b/src/core/Base32.cpp index d0a148eec6..01ded4697c 100644 --- a/src/core/Base32.cpp +++ b/src/core/Base32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,7 +24,6 @@ #include "Base32.h" #include -#include constexpr quint64 MASK_40BIT = quint64(0xF8) << 32; constexpr quint64 MASK_35BIT = quint64(0x7C0000000); @@ -43,10 +42,10 @@ constexpr quint8 ASCII_a = static_cast('a'); constexpr quint8 ASCII_z = static_cast('z'); constexpr quint8 ASCII_EQ = static_cast('='); -QVariant Base32::decode(const QByteArray& encodedData) +QByteArray Base32::decode(const QByteArray& encodedData) { if (encodedData.size() <= 0) { - return QVariant::fromValue(QByteArray("")); + return {}; } if (encodedData.size() % 8 != 0) { @@ -139,7 +138,7 @@ QVariant Base32::decode(const QByteArray& encodedData) Q_ASSERT(encodedData.size() == i); Q_ASSERT(nBytes == o); - return QVariant::fromValue(data); + return data; } QByteArray Base32::encode(const QByteArray& data) diff --git a/src/core/Base32.h b/src/core/Base32.h index 07b16a0cc7..5af9e444c4 100644 --- a/src/core/Base32.h +++ b/src/core/Base32.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,13 +25,12 @@ #define BASE32_H #include -#include class Base32 { public: Base32() = default; - Q_REQUIRED_RESULT static QVariant decode(const QByteArray&); + Q_REQUIRED_RESULT static QByteArray decode(const QByteArray&); Q_REQUIRED_RESULT static QByteArray encode(const QByteArray&); Q_REQUIRED_RESULT static QByteArray addPadding(const QByteArray&); Q_REQUIRED_RESULT static QByteArray removePadding(const QByteArray&); diff --git a/src/core/Clock.cpp b/src/core/Clock.cpp index f501daee73..991783f559 100644 --- a/src/core/Clock.cpp +++ b/src/core/Clock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,8 +32,7 @@ QDateTime Clock::currentDateTime() uint Clock::currentSecondsSinceEpoch() { - // TODO: change to toSecsSinceEpoch() when min Qt >= 5.8 - return instance().currentDateTimeImpl().toTime_t(); + return instance().currentDateTimeImpl().toSecsSinceEpoch(); } qint64 Clock::currentMilliSecondsSinceEpoch() diff --git a/src/core/Endian.h b/src/core/Endian.h index ed5f41945c..1cfc97f3bc 100644 --- a/src/core/Endian.h +++ b/src/core/Endian.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2010 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -30,9 +30,9 @@ namespace Endian Q_ASSERT(ba.size() == sizeof(SizedQInt)); if (byteOrder == QSysInfo::LittleEndian) { - return qFromLittleEndian(reinterpret_cast(ba.constData())); + return qFromLittleEndian(ba.constData()); } - return qFromBigEndian(reinterpret_cast(ba.constData())); + return qFromBigEndian(ba.constData()); } template SizedQInt readSizedInt(QIODevice* device, QSysInfo::Endian byteOrder, bool* ok) @@ -53,9 +53,9 @@ namespace Endian ba.resize(sizeof(SizedQInt)); if (byteOrder == QSysInfo::LittleEndian) { - qToLittleEndian(num, reinterpret_cast(ba.data())); + qToLittleEndian(num, ba.data()); } else { - qToBigEndian(num, reinterpret_cast(ba.data())); + qToBigEndian(num, ba.data()); } return ba; diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 9587e8d67e..3feaf17cd5 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -28,6 +28,7 @@ #include "core/Totp.h" #include +#include #include #include #include @@ -439,11 +440,14 @@ QString Entry::attribute(const QString& key) const int Entry::size() const { int size = 0; - size += attributes()->attributesSize(); - size += autoTypeAssociations()->associationsSize(); - size += attachments()->attachmentsSize(); - size += customData()->dataSize(); - for (const QString& tag : tags().split(TagDelimiterRegex, Qt::SkipEmptyParts)) { + const QRegularExpression delimiter(",|:|;"); + + size += this->attributes()->attributesSize(); + size += this->autoTypeAssociations()->associationsSize(); + size += this->attachments()->attachmentsSize(); + size += this->customData()->dataSize(); + const QStringList tags = this->tags().split(delimiter, Qt::SkipEmptyParts); + for (const QString& tag : tags) { size += tag.toUtf8().size(); } @@ -677,39 +681,40 @@ void Entry::setOverrideUrl(const QString& url) void Entry::setTags(const QString& tags) { - auto taglist = tags.split(TagDelimiterRegex, Qt::SkipEmptyParts); + static QRegularExpression rx(R"(\\,|\\t|\\;)"); + auto tagList = tags.split(rx, Qt::SkipEmptyParts); // Trim whitespace before/after tag text - for (auto& tag : taglist) { - tag = tag.trimmed(); + for (auto itr = tagList.begin(); itr != tagList.end(); ++itr) { + *itr = itr->trimmed(); } // Remove duplicates - taglist = Tools::asSet(taglist).values(); + tagList = Tools::asSet(tagList).values(); // Sort alphabetically - taglist.sort(); - set(m_data.tags, taglist); + tagList.sort(); + set(m_data.tags, tagList); } void Entry::addTag(const QString& tag) { auto cleanTag = tag.trimmed(); - cleanTag.remove(TagDelimiterRegex); + cleanTag.remove(QRegularExpression(R"(\\,|\\t|\\;)")); - auto taglist = m_data.tags; - if (!taglist.contains(cleanTag)) { - taglist.append(cleanTag); - taglist.sort(); - set(m_data.tags, taglist); + auto tagList = m_data.tags; + if (!tagList.contains(cleanTag)) { + tagList.append(cleanTag); + tagList.sort(); + set(m_data.tags, tagList); } } void Entry::removeTag(const QString& tag) { auto cleanTag = tag.trimmed(); - cleanTag.remove(TagDelimiterRegex); + cleanTag.remove(QRegularExpression(R"(\\,|\\t|\\;)")); - auto taglist = m_data.tags; - if (taglist.removeAll(tag) > 0) { - set(m_data.tags, taglist); + auto tagList = m_data.tags; + if (tagList.removeAll(tag) > 0) { + set(m_data.tags, tagList); } } @@ -1042,11 +1047,11 @@ QString Entry::resolveMultiplePlaceholdersRecursive(const QString& str, int maxD int capEnd = 0; while (matches.hasNext()) { const auto match = matches.next(); - result += str.midRef(capEnd, match.capturedStart() - capEnd); + result += QStringView{str}.mid(capEnd, match.capturedStart() - capEnd); result += resolvePlaceholderRecursive(match.captured(), maxDepth); capEnd = match.capturedEnd(); } - result += str.rightRef(str.length() - capEnd); + result += QStringView{str}.right(str.length() - capEnd); return result; } @@ -1391,7 +1396,9 @@ Database* Entry::database() QString Entry::maskPasswordPlaceholders(const QString& str) const { - return QString{str}.replace(QStringLiteral("{PASSWORD}"), QStringLiteral("******"), Qt::CaseInsensitive); + QString result = str; + result.replace(QRegularExpression(R"(\\{PASSWORD\\})", QRegularExpression::CaseInsensitiveOption), "******"); + return result; } Entry* Entry::resolveReference(const QString& str) const @@ -1460,10 +1467,10 @@ Entry::PlaceholderType Entry::placeholderType(const QString& placeholder) const if (!placeholder.startsWith(QStringLiteral("{")) || !placeholder.endsWith(QStringLiteral("}"))) { return PlaceholderType::NotPlaceholder; } - if (placeholder.startsWith(QStringLiteral("{S:"))) { + if (placeholder.startsWith(QLatin1StringView("{S:"))) { return PlaceholderType::CustomAttribute; } - if (placeholder.startsWith(QStringLiteral("{REF:"))) { + if (placeholder.startsWith(QLatin1StringView("{REF:"))) { return PlaceholderType::Reference; } if (placeholder.startsWith(QStringLiteral("{T-CONV:"), Qt::CaseInsensitive)) { @@ -1515,19 +1522,17 @@ QString Entry::resolveUrl(const QString& url) const { QString newUrl = url; - static const QRegularExpression fileRegEx(R"(^(?:[A-Za-z]:)?[\\/])"); - if (url.contains(fileRegEx)) { + QRegularExpression fileRegEx(R"(^([a-z]:)?[\\\\/])", QRegularExpression::CaseInsensitiveOption); + if (fileRegEx.match(newUrl).hasMatch()) { // Match possible file paths without the scheme and convert it to a file URL newUrl = QDir::fromNativeSeparators(newUrl); newUrl = QUrl::fromLocalFile(newUrl).toString(); } else if (url.startsWith("cmd://")) { QStringList cmdList = newUrl.split(" "); for (int i = 1; i < cmdList.size(); ++i) { - QString& cmd = cmdList[i]; // Don't pass arguments to the resolveUrl function (they look like URL's) - if (!cmd.startsWith("-") && !cmd.startsWith("/")) { - static const QRegularExpression quotesRegEx("['\"]"); - return resolveUrl(cmd.remove(quotesRegEx)); + if (!cmdList[i].startsWith("-") && !cmdList[i].startsWith("/")) { + return resolveUrl(cmdList[i].remove(QRegularExpression("'|\""))); } } diff --git a/src/core/EntryAttachments.h b/src/core/EntryAttachments.h index c07c9cbf7d..4dbe70b216 100644 --- a/src/core/EntryAttachments.h +++ b/src/core/EntryAttachments.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Felix Geyer + * Copyright (C) 2023 Felix Geyer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,8 +25,7 @@ #include #include #include - -class QStringList; +#include class EntryAttachments : public ModifiableObject { diff --git a/src/core/Group.cpp b/src/core/Group.cpp index b7182740fb..b4b24452fd 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -20,11 +20,6 @@ #include "config-keepassx.h" #include "core/Config.h" - -#ifdef WITH_XC_KEESHARE -#include "keeshare/KeeShare.h" -#endif - #include "core/Global.h" #include "core/Metadata.h" #include "core/Tools.h" @@ -875,7 +870,7 @@ QList Group::usernamesRecursive(int topN) const // Take first topN usernames if set QList usernames; - int actualUsernames = topN < 0 ? sortedUsernames.size() : std::min(topN, sortedUsernames.size()); + int actualUsernames = topN < 0 ? sortedUsernames.size() : qMin(topN, sortedUsernames.size()); for (int i = 0; i < actualUsernames; i++) { usernames.append(sortedUsernames[i].first); } diff --git a/src/core/Metadata.cpp b/src/core/Metadata.cpp index 8e714e0f22..18abd1edaf 100644 --- a/src/core/Metadata.cpp +++ b/src/core/Metadata.cpp @@ -19,10 +19,8 @@ #include "Metadata.h" #include "core/Clock.h" -#include "core/Entry.h" #include "core/Group.h" -#include #include #include diff --git a/src/core/PassphraseGenerator.cpp b/src/core/PassphraseGenerator.cpp index d8116c8275..cd448a0925 100644 --- a/src/core/PassphraseGenerator.cpp +++ b/src/core/PassphraseGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -72,7 +73,6 @@ void PassphraseGenerator::setWordList(const QString& path) } QTextStream in(&file); - in.setCodec("UTF-8"); QString line = in.readLine(); bool isSigned = line.startsWith("-----BEGIN PGP SIGNED MESSAGE-----"); if (isSigned) { @@ -80,7 +80,8 @@ void PassphraseGenerator::setWordList(const QString& path) line = in.readLine(); } } - QRegExp rx("^[0-9]+(-[0-9]+)*\\s+([^\\s]+)$"); + + QRegularExpression rx("^[0-9]+(-[0-9]+)*\\s+([^\\s]+)$"); while (!line.isNull()) { if (isSigned && line.startsWith("-----BEGIN PGP SIGNATURE-----")) { break; @@ -97,7 +98,7 @@ void PassphraseGenerator::setWordList(const QString& path) line = in.readLine(); } - m_wordlist = wordset.toList(); + m_wordlist = wordset.values(); if (m_wordlist.size() < m_minimum_wordlist_length) { qWarning("Wordlist is less than minimum acceptable size: %s", qPrintable(path)); diff --git a/src/core/PasswordGenerator.cpp b/src/core/PasswordGenerator.cpp index aa0f3e7172..538b741e5d 100644 --- a/src/core/PasswordGenerator.cpp +++ b/src/core/PasswordGenerator.cpp @@ -132,7 +132,7 @@ QVector PasswordGenerator::passwordGroups() const continue; } - group.append(i); + group.append(QChar(i)); } passwordGroups.append(group); @@ -146,7 +146,7 @@ QVector PasswordGenerator::passwordGroups() const continue; } - group.append(i); + group.append(QChar(i)); } passwordGroups.append(group); @@ -159,7 +159,7 @@ QVector PasswordGenerator::passwordGroups() const continue; } - group.append(i); + group.append(QChar(i)); } passwordGroups.append(group); @@ -168,12 +168,12 @@ QVector PasswordGenerator::passwordGroups() const PasswordGroup group; // ()[]{} - group.append(40); - group.append(41); - group.append(91); - group.append(93); - group.append(123); - group.append(125); + group.append(QChar(40)); + group.append(QChar(41)); + group.append(QChar(91)); + group.append(QChar(93)); + group.append(QChar(123)); + group.append(QChar(125)); passwordGroups.append(group); } @@ -181,10 +181,10 @@ QVector PasswordGenerator::passwordGroups() const PasswordGroup group; // .,:; - group.append(44); - group.append(46); - group.append(58); - group.append(59); + group.append(QChar(44)); + group.append(QChar(46)); + group.append(QChar(58)); + group.append(QChar(59)); passwordGroups.append(group); } @@ -192,8 +192,8 @@ QVector PasswordGenerator::passwordGroups() const PasswordGroup group; // "' - group.append(34); - group.append(39); + group.append(QChar(34)); + group.append(QChar(39)); passwordGroups.append(group); } @@ -201,12 +201,12 @@ QVector PasswordGenerator::passwordGroups() const PasswordGroup group; // -/\_| - group.append(45); - group.append(47); - group.append(92); - group.append(95); + group.append(QChar(45)); + group.append(QChar(47)); + group.append(QChar(92)); + group.append(QChar(95)); if (!(m_flags & ExcludeLookAlike)) { - group.append(124); // "|" + group.append(QChar(124)); // "|" } passwordGroups.append(group); @@ -215,13 +215,13 @@ QVector PasswordGenerator::passwordGroups() const PasswordGroup group; // !*+<=>? - group.append(33); - group.append(42); - group.append(43); - group.append(60); - group.append(61); - group.append(62); - group.append(63); + group.append(QChar(33)); + group.append(QChar(42)); + group.append(QChar(43)); + group.append(QChar(60)); + group.append(QChar(61)); + group.append(QChar(62)); + group.append(QChar(63)); passwordGroups.append(group); } @@ -230,13 +230,13 @@ QVector PasswordGenerator::passwordGroups() const // #$%& for (int i = 35; i <= 38; i++) { - group.append(i); + group.append(QChar(i)); } // @^`~ - group.append(64); - group.append(94); - group.append(96); - group.append(126); + group.append(QChar(64)); + group.append(QChar(94)); + group.append(QChar(96)); + group.append(QChar(126)); passwordGroups.append(group); } @@ -246,14 +246,14 @@ QVector PasswordGenerator::passwordGroups() const // [U+0080, U+009F] are C1 control characters, // U+00A0 is non-breaking space for (int i = 161; i <= 172; i++) { - group.append(i); + group.append(QChar(i)); } // U+00AD is soft hyphen (format character) for (int i = 174; i <= 255; i++) { if ((m_flags & ExcludeLookAlike) && (i == 249)) { // "﹒" continue; } - group.append(i); + group.append(QChar(i)); } passwordGroups.append(group); diff --git a/src/core/SignalMultiplexer.h b/src/core/SignalMultiplexer.h index 727c4a3a35..6cca1dcd7a 100644 --- a/src/core/SignalMultiplexer.h +++ b/src/core/SignalMultiplexer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Felix Geyer + * Copyright (C) 2023 Felix Geyer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +18,8 @@ #ifndef KEEPASSX_SIGNALMULTIPLEXER_H #define KEEPASSX_SIGNALMULTIPLEXER_H +#include +#include #include class SignalMultiplexer diff --git a/src/core/Tools.cpp b/src/core/Tools.cpp index 5ee4c72984..0d7c16c2fc 100644 --- a/src/core/Tools.cpp +++ b/src/core/Tools.cpp @@ -28,6 +28,7 @@ #include "core/Clock.h" +#include #include #include #include @@ -220,11 +221,11 @@ namespace Tools bool isBase64(const QByteArray& ba) { constexpr auto pattern = R"(^(?:[a-z0-9+/]{4})*(?:[a-z0-9+/]{3}=|[a-z0-9+/]{2}==)?$)"; - QRegExp regexp(pattern, Qt::CaseInsensitive, QRegExp::RegExp2); + QRegularExpression regexp(pattern, QRegularExpression::CaseInsensitiveOption); QString base64 = QString::fromLatin1(ba.constData(), ba.size()); - return regexp.exactMatch(base64); + return regexp.match(base64).hasMatch(); } bool isAsciiString(const QString& str) diff --git a/src/core/Tools.h b/src/core/Tools.h index d170d76d0d..389f639423 100644 --- a/src/core/Tools.h +++ b/src/core/Tools.h @@ -28,6 +28,7 @@ class QIODevice; class QRegularExpression; +class QUrl; namespace Tools { diff --git a/src/core/Totp.cpp b/src/core/Totp.cpp index 9d1e004403..e11d9344fe 100644 --- a/src/core/Totp.cpp +++ b/src/core/Totp.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2017 Weslly Honorato - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team + * Copyright (C) 2017 Weslly Honorato <weslly@protonmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -228,8 +228,8 @@ QString Totp::generateTotp(const QSharedPointer& settings, const current = qToBigEndian(time / step); } - QVariant secret = Base32::decode(Base32::sanitizeInput(settings->key.toLatin1())); - if (secret.isNull()) { + const auto secret = Base32::decode(Base32::sanitizeInput(settings->key.toLatin1())); + if (secret.isEmpty()) { return QObject::tr("Invalid Key", "TOTP"); } @@ -246,7 +246,7 @@ QString Totp::generateTotp(const QSharedPointer& settings, const break; } QMessageAuthenticationCode code(cryptoHash); - code.setKey(secret.toByteArray()); + code.setKey(secret); code.addData(QByteArray(reinterpret_cast(¤t), sizeof(current))); QByteArray hmac = code.result(); diff --git a/src/crypto/Crypto.cpp b/src/crypto/Crypto.cpp index 233c89907a..2c156bb594 100644 --- a/src/crypto/Crypto.cpp +++ b/src/crypto/Crypto.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2010 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -23,6 +23,7 @@ #include "crypto/CryptoHash.h" #include "crypto/SymmetricCipher.h" +#include #include namespace diff --git a/src/crypto/SymmetricCipher.cpp b/src/crypto/SymmetricCipher.cpp index 33e61aa4f7..f19114bde7 100644 --- a/src/crypto/SymmetricCipher.cpp +++ b/src/crypto/SymmetricCipher.cpp @@ -65,7 +65,7 @@ bool SymmetricCipher::init(Mode mode, Direction direction, const QByteArray& key bool SymmetricCipher::isInitialized() const { - return m_cipher; + return !m_cipher.isNull(); } bool SymmetricCipher::process(char* data, int len) diff --git a/src/fdosecrets/CMakeLists.txt b/src/fdosecrets/CMakeLists.txt index 7489debef2..86d7a1c0f0 100644 --- a/src/fdosecrets/CMakeLists.txt +++ b/src/fdosecrets/CMakeLists.txt @@ -30,5 +30,5 @@ if(WITH_XC_FDOSECRETS) objects/Prompt.cpp dbus/DBusTypes.cpp ) - target_link_libraries(fdosecrets Qt5::Core Qt5::Widgets Qt5::DBus ${BOTAN_LIBRARIES}) + target_link_libraries(fdosecrets Qt6::Core Qt6::Widgets Qt6::DBus ${BOTAN_LIBRARIES}) endif() diff --git a/src/format/BitwardenReader.cpp b/src/format/BitwardenReader.cpp index 5f729aa776..12d9a5cc72 100644 --- a/src/format/BitwardenReader.cpp +++ b/src/format/BitwardenReader.cpp @@ -90,8 +90,11 @@ namespace // Change from UUID to base64 byte array const auto credentialIdValue = passkey.value("credentialId").toString(); if (!credentialIdValue.isEmpty()) { - const auto credentialUuid = Tools::uuidToHex(credentialIdValue); - const auto credentialIdArray = QByteArray::fromHex(credentialUuid.toUtf8()); + const auto uuid = Tools::hexToUuid(credentialIdValue); + // What? + //const auto credentialUuid = Tools::uuidToHex(credentialIdValue); + //const auto credentialIdArray = QByteArray::fromHex(credentialUuid.toUtf8()); + const auto credentialIdArray = QByteArray::fromHex(uuid.toByteArray()); const auto credentialId = credentialIdArray.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); entry->attributes()->set(EntryAttributes::KPEX_PASSKEY_CREDENTIAL_ID, credentialId, true); diff --git a/src/format/CsvParser.cpp b/src/format/CsvParser.cpp index 0e174fe350..db9002a6be 100644 --- a/src/format/CsvParser.cpp +++ b/src/format/CsvParser.cpp @@ -1,6 +1,6 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2016 Enrico Mariotti - * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,7 +19,7 @@ #include "CsvParser.h" #include -#include +//#include #include "core/Tools.h" @@ -34,7 +34,6 @@ CsvParser::CsvParser() m_csv.setBuffer(&m_array); m_ts.setDevice(&m_csv); m_csv.open(QIODevice::ReadOnly); - m_ts.setCodec("UTF-8"); } CsvParser::~CsvParser() @@ -91,7 +90,7 @@ bool CsvParser::readFile(QFile* device) void CsvParser::reset() { - m_ch = 0; + m_ch = QChar(0); m_currCol = 1; m_currRow = 1; m_isEof = false; @@ -348,7 +347,15 @@ void CsvParser::setComment(const QChar& c) void CsvParser::setCodec(const QString& s) { - m_ts.setCodec(QTextCodec::codecForName(s.toLocal8Bit())); + if (s.toLocal8Bit().compare(QByteArray("UTF-8"), Qt::CaseInsensitive) == 0) { + m_ts.setEncoding(QStringConverter::Utf8); + } else if (s.toLocal8Bit().compare(QByteArray("Windows-1252"), Qt::CaseInsensitive) == 0) { + m_ts.setEncoding(QStringConverter::System); + } else if (s.toLocal8Bit().compare(QByteArray("UTF-16"), Qt::CaseInsensitive) == 0) { + m_ts.setEncoding(QStringConverter::Utf16); + } else if (s.toLocal8Bit().compare(QByteArray("UTF-16LE"), Qt::CaseInsensitive) == 0) { + m_ts.setEncoding(QStringConverter::Utf16LE); + } } void CsvParser::setFieldSeparator(const QChar& c) @@ -391,6 +398,6 @@ int CsvParser::getCsvRows() const void CsvParser::appendStatusMsg(const QString& s, bool isCritical) { - m_statusMsg += QObject::tr("%1: (row, col) %2,%3").arg(s, m_currRow, m_currCol).append("\n"); + m_statusMsg += QObject::tr("%1: (row, col) %2,%3").arg(s, m_currRow, QChar(m_currCol)).append("\n"); m_isGood = !isCritical; } diff --git a/src/format/Kdbx3Reader.cpp b/src/format/Kdbx3Reader.cpp index 7634beb313..5b6adcc9cd 100644 --- a/src/format/Kdbx3Reader.cpp +++ b/src/format/Kdbx3Reader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2010 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -70,7 +70,7 @@ bool Kdbx3Reader::readDatabaseImpl(QIODevice* device, raiseError(cipherStream.errorString()); return false; } - if (!cipherStream.open(QIODevice::ReadOnly)) { + if (!cipherStream.open(QIODeviceBase::ReadOnly)) { raiseError(cipherStream.errorString()); return false; } @@ -84,7 +84,7 @@ bool Kdbx3Reader::readDatabaseImpl(QIODevice* device, } HashedBlockStream hashedStream(&cipherStream); - if (!hashedStream.open(QIODevice::ReadOnly)) { + if (!hashedStream.open(QIODeviceBase::ReadOnly)) { raiseError(hashedStream.errorString()); return false; } @@ -97,7 +97,7 @@ bool Kdbx3Reader::readDatabaseImpl(QIODevice* device, } else { ioCompressor.reset(new QtIOCompressor(&hashedStream)); ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat); - if (!ioCompressor->open(QIODevice::ReadOnly)) { + if (!ioCompressor->open(QIODeviceBase::ReadOnly)) { raiseError(ioCompressor->errorString()); return false; } diff --git a/src/format/Kdbx3Writer.cpp b/src/format/Kdbx3Writer.cpp index 2770239a7b..eac10e3138 100644 --- a/src/format/Kdbx3Writer.cpp +++ b/src/format/Kdbx3Writer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2010 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -66,7 +66,7 @@ bool Kdbx3Writer::writeDatabase(QIODevice* device, Database* db) // write header QBuffer header; - header.open(QIODevice::WriteOnly); + header.open(QIODeviceBase::WriteOnly); writeMagicNumbers(&header, KeePass2::SIGNATURE_1, KeePass2::SIGNATURE_2, db->formatVersion()); @@ -102,14 +102,14 @@ bool Kdbx3Writer::writeDatabase(QIODevice* device, Database* db) // write cipher stream SymmetricCipherStream cipherStream(device); cipherStream.init(mode, SymmetricCipher::Encrypt, finalKey, encryptionIV); - if (!cipherStream.open(QIODevice::WriteOnly)) { + if (!cipherStream.open(QIODeviceBase::WriteOnly)) { raiseError(cipherStream.errorString()); return false; } CHECK_RETURN_FALSE(writeData(&cipherStream, startBytes)); HashedBlockStream hashedStream(&cipherStream); - if (!hashedStream.open(QIODevice::WriteOnly)) { + if (!hashedStream.open(QIODeviceBase::WriteOnly)) { raiseError(hashedStream.errorString()); return false; } @@ -122,7 +122,7 @@ bool Kdbx3Writer::writeDatabase(QIODevice* device, Database* db) } else { ioCompressor.reset(new QtIOCompressor(&hashedStream)); ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat); - if (!ioCompressor->open(QIODevice::WriteOnly)) { + if (!ioCompressor->open(QIODeviceBase::WriteOnly)) { raiseError(ioCompressor->errorString()); return false; } @@ -141,7 +141,7 @@ bool Kdbx3Writer::writeDatabase(QIODevice* device, Database* db) xmlWriter.writeDatabase(outputDevice, db, &randomStream, headerHash); // Explicitly close/reset streams so they are flushed and we can detect - // errors. QIODevice::close() resets errorString() etc. + // errors. QIODeviceBase::close() resets errorString() etc. if (ioCompressor) { ioCompressor->close(); } diff --git a/src/format/Kdbx4Reader.cpp b/src/format/Kdbx4Reader.cpp index 0698a0b2bd..156ffcede5 100644 --- a/src/format/Kdbx4Reader.cpp +++ b/src/format/Kdbx4Reader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -80,7 +80,7 @@ bool Kdbx4Reader::readDatabaseImpl(QIODevice* device, return false; } HmacBlockStream hmacStream(device, hmacKey); - if (!hmacStream.open(QIODevice::ReadOnly)) { + if (!hmacStream.open(QIODeviceBase::ReadOnly)) { raiseError(hmacStream.errorString()); return false; } @@ -95,7 +95,7 @@ bool Kdbx4Reader::readDatabaseImpl(QIODevice* device, raiseError(cipherStream.errorString()); return false; } - if (!cipherStream.open(QIODevice::ReadOnly)) { + if (!cipherStream.open(QIODeviceBase::ReadOnly)) { raiseError(cipherStream.errorString()); return false; } @@ -109,7 +109,7 @@ bool Kdbx4Reader::readDatabaseImpl(QIODevice* device, } else { ioCompressor.reset(new QtIOCompressor(&cipherStream)); ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat); - if (!ioCompressor->open(QIODevice::ReadOnly)) { + if (!ioCompressor->open(QIODeviceBase::ReadOnly)) { raiseError(ioCompressor->errorString()); return false; } @@ -204,7 +204,7 @@ bool Kdbx4Reader::readHeaderField(StoreDataStream& device, Database* db) case KeePass2::HeaderFieldID::KdfParameters: { QBuffer bufIoDevice(&fieldData); - if (!bufIoDevice.open(QIODevice::ReadOnly)) { + if (!bufIoDevice.open(QIODeviceBase::ReadOnly)) { raiseError(tr("Failed to open buffer for KDF parameters in header")); return false; } @@ -342,7 +342,7 @@ QVariantMap Kdbx4Reader::readVariantMap(QIODevice* device) return {}; } } - QString name = QString::fromUtf8(nameBytes); + QString name = QString::fromUtf8(nameBytes.toStdString().c_str()); auto valueLen = Endian::readSizedInt(device, KeePass2::BYTEORDER, &ok); if (!ok) { @@ -412,7 +412,7 @@ QVariantMap Kdbx4Reader::readVariantMap(QIODevice* device) break; case KeePass2::VariantMapFieldType::String: - vm.insert(name, QVariant(QString::fromUtf8(valueBytes))); + vm.insert(name, QVariant(QString::fromUtf8(valueBytes.toStdString().c_str()))); break; case KeePass2::VariantMapFieldType::ByteArray: diff --git a/src/format/Kdbx4Writer.cpp b/src/format/Kdbx4Writer.cpp index 1c728ac81c..fe0022cfff 100644 --- a/src/format/Kdbx4Writer.cpp +++ b/src/format/Kdbx4Writer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -64,7 +64,7 @@ bool Kdbx4Writer::writeDatabase(QIODevice* device, Database* db) QByteArray headerData; { QBuffer header; - header.open(QIODevice::WriteOnly); + header.open(QIODeviceBase::WriteOnly); writeMagicNumbers(&header, KeePass2::SIGNATURE_1, KeePass2::SIGNATURE_2, db->formatVersion()); @@ -115,7 +115,7 @@ bool Kdbx4Writer::writeDatabase(QIODevice* device, Database* db) QScopedPointer cipherStream; hmacBlockStream.reset(new HmacBlockStream(device, hmacKey)); - if (!hmacBlockStream->open(QIODevice::WriteOnly)) { + if (!hmacBlockStream->open(QIODeviceBase::WriteOnly)) { raiseError(hmacBlockStream->errorString()); return false; } @@ -126,7 +126,7 @@ bool Kdbx4Writer::writeDatabase(QIODevice* device, Database* db) raiseError(cipherStream->errorString()); return false; } - if (!cipherStream->open(QIODevice::WriteOnly)) { + if (!cipherStream->open(QIODeviceBase::WriteOnly)) { raiseError(cipherStream->errorString()); return false; } @@ -139,7 +139,7 @@ bool Kdbx4Writer::writeDatabase(QIODevice* device, Database* db) } else { ioCompressor.reset(new QtIOCompressor(cipherStream.data())); ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat); - if (!ioCompressor->open(QIODevice::WriteOnly)) { + if (!ioCompressor->open(QIODeviceBase::WriteOnly)) { raiseError(ioCompressor->errorString()); return false; } @@ -170,7 +170,7 @@ bool Kdbx4Writer::writeDatabase(QIODevice* device, Database* db) xmlWriter.writeDatabase(outputDevice, db, &randomStream, headerHash); // Explicitly close/reset streams so they are flushed and we can detect - // errors. QIODevice::close() resets errorString() etc. + // errors. QIODeviceBase::close() resets errorString() etc. if (ioCompressor) { ioCompressor->close(); } @@ -263,7 +263,7 @@ KdbxXmlWriter::BinaryIdxMap Kdbx4Writer::writeAttachments(QIODevice* device, Dat bool Kdbx4Writer::serializeVariantMap(const QVariantMap& map, QByteArray& outputBytes) { QBuffer buf(&outputBytes); - buf.open(QIODevice::WriteOnly); + buf.open(QIODeviceBase::WriteOnly); CHECK_RETURN_FALSE(buf.write(Endian::sizedIntToBytes(KeePass2::VARIANTMAP_VERSION, KeePass2::BYTEORDER)) == 2); bool ok; @@ -316,9 +316,9 @@ bool Kdbx4Writer::serializeVariantMap(const QVariantMap& map, QByteArray& output QByteArray dataLenBytes = Endian::sizedIntToBytes(data.size(), KeePass2::BYTEORDER); CHECK_RETURN_FALSE(buf.write(typeBytes) == 1); - CHECK_RETURN_FALSE(buf.write(nameLenBytes) == 4); + CHECK_RETURN_FALSE(buf.write(nameLenBytes) == sizeof(qsizetype)); CHECK_RETURN_FALSE(buf.write(nameBytes) == nameBytes.size()); - CHECK_RETURN_FALSE(buf.write(dataLenBytes) == 4); + CHECK_RETURN_FALSE(buf.write(dataLenBytes) == sizeof(qsizetype)); CHECK_RETURN_FALSE(buf.write(data) == data.size()); } diff --git a/src/format/KdbxReader.cpp b/src/format/KdbxReader.cpp index b552bd1cbe..4558720a65 100644 --- a/src/format/KdbxReader.cpp +++ b/src/format/KdbxReader.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -75,7 +75,7 @@ bool KdbxReader::readDatabase(QIODevice* device, QSharedPointer + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -70,9 +70,8 @@ void KdbxWriter::extractDatabase(QByteArray& xmlOutput, Database* db) { QBuffer buffer; buffer.setBuffer(&xmlOutput); - buffer.open(QIODevice::WriteOnly); - KdbxXmlWriter::BinaryIdxMap idxMap; - KdbxXmlWriter writer(db->formatVersion(), idxMap); + buffer.open(QIODeviceBase::WriteOnly); + KdbxXmlWriter writer(db->formatVersion()); writer.disableInnerStreamProtection(true); writer.writeDatabase(&buffer, db); } diff --git a/src/format/KdbxXmlReader.cpp b/src/format/KdbxXmlReader.cpp index e6c212bbcf..9fcded5043 100644 --- a/src/format/KdbxXmlReader.cpp +++ b/src/format/KdbxXmlReader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,7 +56,7 @@ KdbxXmlReader::KdbxXmlReader(quint32 version, QHash binaryP QSharedPointer KdbxXmlReader::readDatabase(const QString& filename) { QFile file(filename); - file.open(QIODevice::ReadOnly); + file.open(QIODeviceBase::ReadOnly); return readDatabase(&file); } @@ -104,7 +104,7 @@ void KdbxXmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Random return; } - if (m_xml.readNextStartElement() && m_xml.name() == "KeePassFile") { + if (m_xml.readNextStartElement() && m_xml.name().toString() == "KeePassFile") { rootGroupParsed = parseKeePassFile(); } @@ -114,11 +114,13 @@ void KdbxXmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Random } if (!m_tmpParent->children().isEmpty()) { - qWarning("KdbxXmlReader::readDatabase: found %d invalid group reference(s)", m_tmpParent->children().size()); + qWarning("KdbxXmlReader::readDatabase: found %" PRIdQSIZETYPE " invalid group reference(s)", + m_tmpParent->children().size()); } if (!m_tmpParent->entries().isEmpty()) { - qWarning("KdbxXmlReader::readDatabase: found %d invalid entry reference(s)", m_tmpParent->children().size()); + qWarning("KdbxXmlReader::readDatabase: found %" PRIdQSIZETYPE " invalid entry reference(s)", + m_tmpParent->children().size()); } const QSet poolKeys = Tools::asSet(m_binaryPool.keys()); @@ -187,9 +189,9 @@ QString KdbxXmlReader::errorString() const return {}; } -bool KdbxXmlReader::isTrueValue(const QStringRef& value) +bool KdbxXmlReader::isTrueValue(QStringView value) { - return value.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0 || value == "1"; + return value.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0 || value.toString() == "1"; } void KdbxXmlReader::raiseError(const QString& errorMessage) @@ -205,18 +207,18 @@ QByteArray KdbxXmlReader::headerHash() const bool KdbxXmlReader::parseKeePassFile() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "KeePassFile"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "KeePassFile"); bool rootElementFound = false; bool rootParsedSuccessfully = false; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "Meta") { + if (m_xml.name().toString() == "Meta") { parseMeta(); continue; } - if (m_xml.name() == "Root") { + if (m_xml.name().toString() == "Root") { if (rootElementFound) { rootParsedSuccessfully = false; qWarning("Multiple root elements"); @@ -235,72 +237,72 @@ bool KdbxXmlReader::parseKeePassFile() void KdbxXmlReader::parseMeta() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Meta"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "Meta"); while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "Generator") { + if (m_xml.name().toString() == "Generator") { m_meta->setGenerator(readString()); - } else if (m_xml.name() == "HeaderHash") { + } else if (m_xml.name().toString() == "HeaderHash") { m_headerHash = readBinary(); - } else if (m_xml.name() == "DatabaseName") { + } else if (m_xml.name().toString() == "DatabaseName") { m_meta->setName(readString()); - } else if (m_xml.name() == "DatabaseNameChanged") { + } else if (m_xml.name().toString() == "DatabaseNameChanged") { m_meta->setNameChanged(readDateTime()); - } else if (m_xml.name() == "DatabaseDescription") { + } else if (m_xml.name().toString() == "DatabaseDescription") { m_meta->setDescription(readString()); - } else if (m_xml.name() == "DatabaseDescriptionChanged") { + } else if (m_xml.name().toString() == "DatabaseDescriptionChanged") { m_meta->setDescriptionChanged(readDateTime()); - } else if (m_xml.name() == "DefaultUserName") { + } else if (m_xml.name().toString() == "DefaultUserName") { m_meta->setDefaultUserName(readString()); - } else if (m_xml.name() == "DefaultUserNameChanged") { + } else if (m_xml.name().toString() == "DefaultUserNameChanged") { m_meta->setDefaultUserNameChanged(readDateTime()); - } else if (m_xml.name() == "MaintenanceHistoryDays") { + } else if (m_xml.name().toString() == "MaintenanceHistoryDays") { m_meta->setMaintenanceHistoryDays(readNumber()); - } else if (m_xml.name() == "Color") { + } else if (m_xml.name().toString() == "Color") { m_meta->setColor(readColor()); - } else if (m_xml.name() == "MasterKeyChanged") { + } else if (m_xml.name().toString() == "MasterKeyChanged") { m_meta->setDatabaseKeyChanged(readDateTime()); - } else if (m_xml.name() == "MasterKeyChangeRec") { + } else if (m_xml.name().toString() == "MasterKeyChangeRec") { m_meta->setMasterKeyChangeRec(readNumber()); - } else if (m_xml.name() == "MasterKeyChangeForce") { + } else if (m_xml.name().toString() == "MasterKeyChangeForce") { m_meta->setMasterKeyChangeForce(readNumber()); - } else if (m_xml.name() == "MemoryProtection") { + } else if (m_xml.name().toString() == "MemoryProtection") { parseMemoryProtection(); - } else if (m_xml.name() == "CustomIcons") { + } else if (m_xml.name().toString() == "CustomIcons") { parseCustomIcons(); - } else if (m_xml.name() == "RecycleBinEnabled") { + } else if (m_xml.name().toString() == "RecycleBinEnabled") { m_meta->setRecycleBinEnabled(readBool()); - } else if (m_xml.name() == "RecycleBinUUID") { + } else if (m_xml.name().toString() == "RecycleBinUUID") { m_meta->setRecycleBin(getGroup(readUuid())); - } else if (m_xml.name() == "RecycleBinChanged") { + } else if (m_xml.name().toString() == "RecycleBinChanged") { m_meta->setRecycleBinChanged(readDateTime()); - } else if (m_xml.name() == "EntryTemplatesGroup") { + } else if (m_xml.name().toString() == "EntryTemplatesGroup") { m_meta->setEntryTemplatesGroup(getGroup(readUuid())); - } else if (m_xml.name() == "EntryTemplatesGroupChanged") { + } else if (m_xml.name().toString() == "EntryTemplatesGroupChanged") { m_meta->setEntryTemplatesGroupChanged(readDateTime()); - } else if (m_xml.name() == "LastSelectedGroup") { + } else if (m_xml.name().toString() == "LastSelectedGroup") { m_meta->setLastSelectedGroup(getGroup(readUuid())); - } else if (m_xml.name() == "LastTopVisibleGroup") { + } else if (m_xml.name().toString() == "LastTopVisibleGroup") { m_meta->setLastTopVisibleGroup(getGroup(readUuid())); - } else if (m_xml.name() == "HistoryMaxItems") { + } else if (m_xml.name().toString() == "HistoryMaxItems") { int value = readNumber(); if (value >= -1) { m_meta->setHistoryMaxItems(value); } else { qWarning("HistoryMaxItems invalid number"); } - } else if (m_xml.name() == "HistoryMaxSize") { + } else if (m_xml.name().toString() == "HistoryMaxSize") { int value = readNumber(); if (value >= -1) { m_meta->setHistoryMaxSize(value); } else { qWarning("HistoryMaxSize invalid number"); } - } else if (m_xml.name() == "Binaries") { + } else if (m_xml.name().toString() == "Binaries") { parseBinaries(); - } else if (m_xml.name() == "CustomData") { + } else if (m_xml.name().toString() == "CustomData") { parseCustomData(m_meta->customData()); - } else if (m_xml.name() == "SettingsChanged") { + } else if (m_xml.name().toString() == "SettingsChanged") { m_meta->setSettingsChanged(readDateTime()); } else { skipCurrentElement(); @@ -310,18 +312,18 @@ void KdbxXmlReader::parseMeta() void KdbxXmlReader::parseMemoryProtection() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "MemoryProtection"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "MemoryProtection"); while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "ProtectTitle") { + if (m_xml.name().toString() == "ProtectTitle") { m_meta->setProtectTitle(readBool()); - } else if (m_xml.name() == "ProtectUserName") { + } else if (m_xml.name().toString() == "ProtectUserName") { m_meta->setProtectUsername(readBool()); - } else if (m_xml.name() == "ProtectPassword") { + } else if (m_xml.name().toString() == "ProtectPassword") { m_meta->setProtectPassword(readBool()); - } else if (m_xml.name() == "ProtectURL") { + } else if (m_xml.name().toString() == "ProtectURL") { m_meta->setProtectUrl(readBool()); - } else if (m_xml.name() == "ProtectNotes") { + } else if (m_xml.name().toString() == "ProtectNotes") { m_meta->setProtectNotes(readBool()); } else { skipCurrentElement(); @@ -331,10 +333,10 @@ void KdbxXmlReader::parseMemoryProtection() void KdbxXmlReader::parseCustomIcons() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomIcons"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "CustomIcons"); while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "Icon") { + if (m_xml.name().toString() == "Icon") { parseIcon(); } else { skipCurrentElement(); @@ -344,7 +346,7 @@ void KdbxXmlReader::parseCustomIcons() void KdbxXmlReader::parseIcon() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Icon"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "Icon"); QUuid uuid; QByteArray iconData; @@ -354,15 +356,15 @@ void KdbxXmlReader::parseIcon() bool iconSet = false; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "UUID") { + if (m_xml.name().toString() == "UUID") { uuid = readUuid(); uuidSet = !uuid.isNull(); - } else if (m_xml.name() == "Data") { + } else if (m_xml.name().toString() == "Data") { iconData = readBinary(); iconSet = true; - } else if (m_xml.name() == "Name") { + } else if (m_xml.name().toString() == "Name") { name = readString(); - } else if (m_xml.name() == "LastModificationTime") { + } else if (m_xml.name().toString() == "LastModificationTime") { lastModified = readDateTime(); } else { skipCurrentElement(); @@ -383,10 +385,10 @@ void KdbxXmlReader::parseIcon() void KdbxXmlReader::parseBinaries() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Binaries"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "Binaries"); while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() != "Binary") { + if (m_xml.name().toString() != "Binary") { skipCurrentElement(); continue; } @@ -405,10 +407,10 @@ void KdbxXmlReader::parseBinaries() void KdbxXmlReader::parseCustomData(CustomData* customData) { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomData"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "CustomData"); while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "Item") { + if (m_xml.name().toString() == "Item") { parseCustomDataItem(customData); continue; } @@ -418,7 +420,7 @@ void KdbxXmlReader::parseCustomData(CustomData* customData) void KdbxXmlReader::parseCustomDataItem(CustomData* customData) { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Item"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "Item"); QString key; CustomData::CustomDataItem item; @@ -426,13 +428,13 @@ void KdbxXmlReader::parseCustomDataItem(CustomData* customData) bool valueSet = false; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "Key") { + if (m_xml.name().toString() == "Key") { key = readString(); keySet = true; - } else if (m_xml.name() == "Value") { + } else if (m_xml.name().toString() == "Value") { item.value = readString(); valueSet = true; - } else if (m_xml.name() == "LastModificationTime") { + } else if (m_xml.name().toString() == "LastModificationTime") { item.lastModified = readDateTime(); } else { skipCurrentElement(); @@ -449,13 +451,13 @@ void KdbxXmlReader::parseCustomDataItem(CustomData* customData) bool KdbxXmlReader::parseRoot() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Root"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "Root"); bool groupElementFound = false; bool groupParsedSuccessfully = false; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "Group") { + if (m_xml.name().toString() == "Group") { if (groupElementFound) { groupParsedSuccessfully = false; raiseError(tr("Multiple group elements")); @@ -470,7 +472,7 @@ bool KdbxXmlReader::parseRoot() } groupElementFound = true; - } else if (m_xml.name() == "DeletedObjects") { + } else if (m_xml.name().toString() == "DeletedObjects") { parseDeletedObjects(); } else { skipCurrentElement(); @@ -482,14 +484,14 @@ bool KdbxXmlReader::parseRoot() Group* KdbxXmlReader::parseGroup() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Group"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "Group"); auto group = new Group(); group->setUpdateTimeinfo(false); QList children; QList entries; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "UUID") { + if (m_xml.name().toString() == "UUID") { QUuid uuid = readUuid(); if (uuid.isNull()) { if (m_strictMode) { @@ -502,19 +504,19 @@ Group* KdbxXmlReader::parseGroup() } continue; } - if (m_xml.name() == "Name") { + if (m_xml.name().toString() == "Name") { group->setName(readString()); continue; } - if (m_xml.name() == "Notes") { + if (m_xml.name().toString() == "Notes") { group->setNotes(readString()); continue; } - if (m_xml.name() == "Tags") { + if (m_xml.name().toString() == "Tags") { group->setTags(readString()); continue; } - if (m_xml.name() == "IconID") { + if (m_xml.name().toString() == "IconID") { int iconId = readNumber(); if (iconId < 0) { if (m_strictMode) { @@ -526,26 +528,26 @@ Group* KdbxXmlReader::parseGroup() group->setIcon(iconId); continue; } - if (m_xml.name() == "CustomIconUUID") { + if (m_xml.name().toString() == "CustomIconUUID") { QUuid uuid = readUuid(); if (!uuid.isNull()) { group->setIcon(uuid); } continue; } - if (m_xml.name() == "Times") { + if (m_xml.name().toString() == "Times") { group->setTimeInfo(parseTimes()); continue; } - if (m_xml.name() == "IsExpanded") { + if (m_xml.name().toString() == "IsExpanded") { group->setExpanded(readBool()); continue; } - if (m_xml.name() == "DefaultAutoTypeSequence") { + if (m_xml.name().toString() == "DefaultAutoTypeSequence") { group->setDefaultAutoTypeSequence(readString()); continue; } - if (m_xml.name() == "EnableAutoType") { + if (m_xml.name().toString() == "EnableAutoType") { QString str = readString(); if (str.compare("null", Qt::CaseInsensitive) == 0) { @@ -559,7 +561,7 @@ Group* KdbxXmlReader::parseGroup() } continue; } - if (m_xml.name() == "EnableSearching") { + if (m_xml.name().toString() == "EnableSearching") { QString str = readString(); if (str.compare("null", Qt::CaseInsensitive) == 0) { @@ -573,29 +575,29 @@ Group* KdbxXmlReader::parseGroup() } continue; } - if (m_xml.name() == "LastTopVisibleEntry") { + if (m_xml.name().toString() == "LastTopVisibleEntry") { group->setLastTopVisibleEntry(getEntry(readUuid())); continue; } - if (m_xml.name() == "Group") { + if (m_xml.name().toString() == "Group") { Group* newGroup = parseGroup(); if (newGroup) { children.append(newGroup); } continue; } - if (m_xml.name() == "Entry") { + if (m_xml.name().toString() == "Entry") { Entry* newEntry = parseEntry(false); if (newEntry) { entries.append(newEntry); } continue; } - if (m_xml.name() == "CustomData") { + if (m_xml.name().toString() == "CustomData") { parseCustomData(group->customData()); continue; } - if (m_xml.name() == "PreviousParentGroup") { + if (m_xml.name().toString() == "PreviousParentGroup") { group->setPreviousParentGroupUuid(readUuid()); continue; } @@ -630,10 +632,10 @@ Group* KdbxXmlReader::parseGroup() void KdbxXmlReader::parseDeletedObjects() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "DeletedObjects"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "DeletedObjects"); while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "DeletedObject") { + if (m_xml.name().toString() == "DeletedObject") { parseDeletedObject(); } else { skipCurrentElement(); @@ -643,12 +645,12 @@ void KdbxXmlReader::parseDeletedObjects() void KdbxXmlReader::parseDeletedObject() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "DeletedObject"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "DeletedObject"); DeletedObject delObj{{}, {}}; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "UUID") { + if (m_xml.name().toString() == "UUID") { QUuid uuid = readUuid(); if (uuid.isNull()) { if (m_strictMode) { @@ -660,7 +662,7 @@ void KdbxXmlReader::parseDeletedObject() delObj.uuid = uuid; continue; } - if (m_xml.name() == "DeletionTime") { + if (m_xml.name().toString() == "DeletionTime") { delObj.deletionTime = readDateTime(); continue; } @@ -679,7 +681,7 @@ void KdbxXmlReader::parseDeletedObject() Entry* KdbxXmlReader::parseEntry(bool history) { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Entry"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "Entry"); auto entry = new Entry(); entry->setUpdateTimeinfo(false); @@ -687,7 +689,7 @@ Entry* KdbxXmlReader::parseEntry(bool history) QList binaryRefs; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "UUID") { + if (m_xml.name().toString() == "UUID") { QUuid uuid = readUuid(); if (uuid.isNull()) { if (m_strictMode) { @@ -700,7 +702,7 @@ Entry* KdbxXmlReader::parseEntry(bool history) } continue; } - if (m_xml.name() == "IconID") { + if (m_xml.name().toString() == "IconID") { int iconId = readNumber(); if (iconId < 0) { if (m_strictMode) { @@ -711,53 +713,53 @@ Entry* KdbxXmlReader::parseEntry(bool history) entry->setIcon(iconId); continue; } - if (m_xml.name() == "CustomIconUUID") { + if (m_xml.name().toString() == "CustomIconUUID") { QUuid uuid = readUuid(); if (!uuid.isNull()) { entry->setIcon(uuid); } continue; } - if (m_xml.name() == "ForegroundColor") { + if (m_xml.name().toString() == "ForegroundColor") { entry->setForegroundColor(readColor()); continue; } - if (m_xml.name() == "BackgroundColor") { + if (m_xml.name().toString() == "BackgroundColor") { entry->setBackgroundColor(readColor()); continue; } - if (m_xml.name() == "OverrideURL") { + if (m_xml.name().toString() == "OverrideURL") { entry->setOverrideUrl(readString()); continue; } - if (m_xml.name() == "Tags") { + if (m_xml.name().toString() == "Tags") { entry->setTags(readString()); continue; } - if (m_xml.name() == "Times") { + if (m_xml.name().toString() == "Times") { entry->setTimeInfo(parseTimes()); continue; } - if (m_xml.name() == "String") { + if (m_xml.name().toString() == "String") { parseEntryString(entry); continue; } - if (m_xml.name() == "QualityCheck") { + if (m_xml.name().toString() == "QualityCheck") { entry->setExcludeFromReports(!readBool()); continue; } - if (m_xml.name() == "Binary") { + if (m_xml.name().toString() == "Binary") { QPair ref = parseEntryBinary(entry); if (!ref.first.isEmpty() && !ref.second.isEmpty()) { binaryRefs.append(ref); } continue; } - if (m_xml.name() == "AutoType") { + if (m_xml.name().toString() == "AutoType") { parseAutoType(entry); continue; } - if (m_xml.name() == "History") { + if (m_xml.name().toString() == "History") { if (history) { raiseError(tr("History element in history entry")); } else { @@ -765,7 +767,7 @@ Entry* KdbxXmlReader::parseEntry(bool history) } continue; } - if (m_xml.name() == "CustomData") { + if (m_xml.name().toString() == "CustomData") { parseCustomData(entry->customData()); // Upgrade pre-KDBX-4.1 password report exclude flag @@ -776,7 +778,7 @@ Entry* KdbxXmlReader::parseEntry(bool history) } continue; } - if (m_xml.name() == "PreviousParentGroup") { + if (m_xml.name().toString() == "PreviousParentGroup") { entry->setPreviousParentGroupUuid(readUuid()); continue; } @@ -823,7 +825,7 @@ Entry* KdbxXmlReader::parseEntry(bool history) void KdbxXmlReader::parseEntryString(Entry* entry) { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "String"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "String"); QString key; QString value; @@ -832,13 +834,13 @@ void KdbxXmlReader::parseEntryString(Entry* entry) bool valueSet = false; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "Key") { + if (m_xml.name().toString() == "Key") { key = readString(); keySet = true; continue; } - if (m_xml.name() == "Value") { + if (m_xml.name().toString() == "Value") { QXmlStreamAttributes attr = m_xml.attributes(); bool isProtected; bool protectInMemory; @@ -866,7 +868,7 @@ void KdbxXmlReader::parseEntryString(Entry* entry) QPair KdbxXmlReader::parseEntryBinary(Entry* entry) { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Binary"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "Binary"); QPair poolRef; @@ -876,12 +878,12 @@ QPair KdbxXmlReader::parseEntryBinary(Entry* entry) bool valueSet = false; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "Key") { + if (m_xml.name().toString() == "Key") { key = readString(); keySet = true; continue; } - if (m_xml.name() == "Value") { + if (m_xml.name().toString() == "Value") { QXmlStreamAttributes attr = m_xml.attributes(); if (attr.hasAttribute("Ref")) { @@ -915,16 +917,16 @@ QPair KdbxXmlReader::parseEntryBinary(Entry* entry) void KdbxXmlReader::parseAutoType(Entry* entry) { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "AutoType"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "AutoType"); while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "Enabled") { + if (m_xml.name().toString() == "Enabled") { entry->setAutoTypeEnabled(readBool()); - } else if (m_xml.name() == "DataTransferObfuscation") { + } else if (m_xml.name().toString() == "DataTransferObfuscation") { entry->setAutoTypeObfuscation(readNumber()); - } else if (m_xml.name() == "DefaultSequence") { + } else if (m_xml.name().toString() == "DefaultSequence") { entry->setDefaultAutoTypeSequence(readString()); - } else if (m_xml.name() == "Association") { + } else if (m_xml.name().toString() == "Association") { parseAutoTypeAssoc(entry); } else { skipCurrentElement(); @@ -934,17 +936,17 @@ void KdbxXmlReader::parseAutoType(Entry* entry) void KdbxXmlReader::parseAutoTypeAssoc(Entry* entry) { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Association"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "Association"); AutoTypeAssociations::Association assoc; bool windowSet = false; bool sequenceSet = false; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "Window") { + if (m_xml.name().toString() == "Window") { assoc.window = readString(); windowSet = true; - } else if (m_xml.name() == "KeystrokeSequence") { + } else if (m_xml.name().toString() == "KeystrokeSequence") { assoc.sequence = readString(); sequenceSet = true; } else { @@ -961,12 +963,12 @@ void KdbxXmlReader::parseAutoTypeAssoc(Entry* entry) QList KdbxXmlReader::parseEntryHistory() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "History"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "History"); QList historyItems; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "Entry") { + if (m_xml.name().toString() == "Entry") { historyItems.append(parseEntry(true)); } else { skipCurrentElement(); @@ -978,23 +980,23 @@ QList KdbxXmlReader::parseEntryHistory() TimeInfo KdbxXmlReader::parseTimes() { - Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Times"); + Q_ASSERT(m_xml.isStartElement() && m_xml.name().toString() == "Times"); TimeInfo timeInfo; while (!m_xml.hasError() && m_xml.readNextStartElement()) { - if (m_xml.name() == "LastModificationTime") { + if (m_xml.name().toString() == "LastModificationTime") { timeInfo.setLastModificationTime(readDateTime()); - } else if (m_xml.name() == "CreationTime") { + } else if (m_xml.name().toString() == "CreationTime") { timeInfo.setCreationTime(readDateTime()); - } else if (m_xml.name() == "LastAccessTime") { + } else if (m_xml.name().toString() == "LastAccessTime") { timeInfo.setLastAccessTime(readDateTime()); - } else if (m_xml.name() == "ExpiryTime") { + } else if (m_xml.name().toString() == "ExpiryTime") { timeInfo.setExpiryTime(readDateTime()); - } else if (m_xml.name() == "Expires") { + } else if (m_xml.name().toString() == "Expires") { timeInfo.setExpires(readBool()); - } else if (m_xml.name() == "UsageCount") { + } else if (m_xml.name().toString() == "UsageCount") { timeInfo.setUsageCount(readNumber()); - } else if (m_xml.name() == "LocationChanged") { + } else if (m_xml.name().toString() == "LocationChanged") { timeInfo.setLocationChanged(readDateTime()); } else { skipCurrentElement(); @@ -1029,7 +1031,7 @@ QString KdbxXmlReader::readString(bool& isProtected, bool& protectInMemory) return value; } - value = QString::fromUtf8(plaintext); + value = QString::fromUtf8(plaintext.toStdString().c_str()); } return value; @@ -1155,11 +1157,11 @@ QByteArray KdbxXmlReader::readCompressedBinary() QByteArray rawData = readBinary(); QBuffer buffer(&rawData); - buffer.open(QIODevice::ReadOnly); + buffer.open(QIODeviceBase::ReadOnly); QtIOCompressor compressor(&buffer); compressor.setStreamFormat(QtIOCompressor::GzipFormat); - compressor.open(QIODevice::ReadOnly); + compressor.open(QIODeviceBase::ReadOnly); QByteArray result; if (!Tools::readAllFromDevice(&compressor, result)) { diff --git a/src/format/KdbxXmlReader.h b/src/format/KdbxXmlReader.h index 1b6305eeaf..30966cd1ba 100644 --- a/src/format/KdbxXmlReader.h +++ b/src/format/KdbxXmlReader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include #include +#include #include class QIODevice; @@ -93,7 +94,7 @@ class KdbxXmlReader virtual Group* getGroup(const QUuid& uuid); virtual Entry* getEntry(const QUuid& uuid); - virtual bool isTrueValue(const QStringRef& value); + virtual bool isTrueValue(QStringView value); virtual void raiseError(const QString& errorMessage); const quint32 m_kdbxVersion; diff --git a/src/format/KdbxXmlWriter.cpp b/src/format/KdbxXmlWriter.cpp index 142f4b7e37..e6c0511c38 100644 --- a/src/format/KdbxXmlWriter.cpp +++ b/src/format/KdbxXmlWriter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,7 +55,6 @@ void KdbxXmlWriter::writeDatabase(QIODevice* device, m_xml.setAutoFormatting(true); m_xml.setAutoFormattingIndent(-1); // 1 tab - m_xml.setCodec("UTF-8"); if (m_kdbxVersion < KeePass2::FILE_VERSION_4) { fillBinaryIdxMap(); @@ -79,7 +78,7 @@ void KdbxXmlWriter::writeDatabase(QIODevice* device, void KdbxXmlWriter::writeDatabase(const QString& filename, Database* db) { QFile file(filename); - file.open(QIODevice::WriteOnly | QIODevice::Truncate); + file.open(QIODeviceBase::WriteOnly | QIODeviceBase::Truncate); writeDatabase(&file, db); } @@ -237,11 +236,11 @@ void KdbxXmlWriter::writeBinaries() m_xml.writeAttribute("Compressed", "True"); QBuffer buffer; - buffer.open(QIODevice::ReadWrite); + buffer.open(QIODeviceBase::ReadWrite); QtIOCompressor compressor(&buffer); compressor.setStreamFormat(QtIOCompressor::GzipFormat); - compressor.open(QIODevice::WriteOnly); + compressor.open(QIODeviceBase::WriteOnly); qint64 bytesWritten = compressor.write(i.value()); Q_ASSERT(bytesWritten == i.value().size()); diff --git a/src/format/KeePass1Reader.cpp b/src/format/KeePass1Reader.cpp index a7d8038dfb..6cb3468841 100644 --- a/src/format/KeePass1Reader.cpp +++ b/src/format/KeePass1Reader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Felix Geyer + * Copyright (C) 2023 Felix Geyer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,7 +19,8 @@ #include #include -#include +#include +#include #include "core/Endian.h" #include "core/Group.h" @@ -468,7 +469,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream) groupIdSet = true; break; case 0x0002: - group->setName(QString::fromUtf8(fieldData.constData())); + group->setName(QString::fromUtf8(fieldData.toStdString().c_str())); break; case 0x0003: { if (fieldSize != 5) { @@ -617,19 +618,19 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream) break; } case 0x0004: - entry->setTitle(QString::fromUtf8(fieldData.constData())); + entry->setTitle(QString::fromUtf8(fieldData.toStdString().c_str())); break; case 0x0005: - entry->setUrl(QString::fromUtf8(fieldData.constData())); + entry->setUrl(QString::fromUtf8(fieldData.toStdString().c_str())); break; case 0x0006: - entry->setUsername(QString::fromUtf8(fieldData.constData())); + entry->setUsername(QString::fromUtf8(fieldData.toStdString().c_str())); break; case 0x0007: - entry->setPassword(QString::fromUtf8(fieldData.constData())); + entry->setPassword(QString::fromUtf8(fieldData.toStdString().c_str())); break; case 0x0008: - parseNotes(QString::fromUtf8(fieldData.constData()), entry.data()); + parseNotes(QString::fromUtf8(fieldData.toStdString().c_str()), entry.data()); break; case 0x0009: { if (fieldSize != 5) { @@ -677,7 +678,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream) break; } case 0x000D: - binaryName = QString::fromUtf8(fieldData.constData()); + binaryName = QString::fromUtf8(fieldData.toStdString().c_str()); break; case 0x000E: if (fieldSize != 0) { @@ -701,8 +702,8 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream) void KeePass1Reader::parseNotes(const QString& rawNotes, Entry* entry) { - QRegExp sequenceRegexp("Auto-Type(?:-(\\d+))?: (.+)", Qt::CaseInsensitive, QRegExp::RegExp2); - QRegExp windowRegexp("Auto-Type-Window(?:-(\\d+))?: (.+)", Qt::CaseInsensitive, QRegExp::RegExp2); + QRegularExpression sequenceRegexp("Auto-Type(?:-(\\d+))?: (.+)", QRegularExpression::CaseInsensitiveOption); + QRegularExpression windowRegexp("Auto-Type-Window(?:-(\\d+))?: (.+)", QRegularExpression::CaseInsensitiveOption); QHash sequences; QMap windows; @@ -713,23 +714,25 @@ void KeePass1Reader::parseNotes(const QString& rawNotes, Entry* entry) for (QString line : rawNotesLines) { line.remove("\r"); - if (sequenceRegexp.exactMatch(line)) { - if (sequenceRegexp.cap(1).isEmpty()) { - entry->setDefaultAutoTypeSequence(sequenceRegexp.cap(2)); + auto sequenceMatch = sequenceRegexp.match(line); + auto windowMatch = windowRegexp.match(line); + if (sequenceMatch.hasMatch()) { + if (sequenceMatch.captured(1).isEmpty()) { + entry->setDefaultAutoTypeSequence(sequenceMatch.captured(2)); } else { - sequences[sequenceRegexp.cap(1).toInt()] = sequenceRegexp.cap(2); + sequences[sequenceMatch.captured(1).toInt()] = sequenceMatch.captured(2); } lastLineAutoType = true; - } else if (windowRegexp.exactMatch(line)) { + } else if (windowMatch.hasMatch()) { int nr; - if (windowRegexp.cap(1).isEmpty()) { + if (windowMatch.captured(1).isEmpty()) { nr = -1; // special number that matches no other sequence } else { - nr = windowRegexp.cap(1).toInt(); + nr = windowMatch.captured(1).toInt(); } - windows[nr].append(windowRegexp.cap(2)); + windows[nr].append(windowMatch.captured(2)); lastLineAutoType = true; } else { diff --git a/src/format/OpVaultReader.cpp b/src/format/OpVaultReader.cpp index 779e25fda1..b27c78cc59 100644 --- a/src/format/OpVaultReader.cpp +++ b/src/format/OpVaultReader.cpp @@ -158,9 +158,9 @@ bool OpVaultReader::processProfileJson(QJsonObject& profileJson, const QString& } auto rootGroupTime = rootGroup->timeInfo(); auto createdAt = static_cast(profileJson["createdAt"].toInt()); - rootGroupTime.setCreationTime(QDateTime::fromTime_t(createdAt, Qt::UTC)); + rootGroupTime.setCreationTime(QDateTime::fromSecsSinceEpoch(createdAt, Qt::UTC)); auto updatedAt = static_cast(profileJson["updatedAt"].toInt()); - rootGroupTime.setLastModificationTime(QDateTime::fromTime_t(updatedAt, Qt::UTC)); + rootGroupTime.setLastModificationTime(QDateTime::fromSecsSinceEpoch(updatedAt, Qt::UTC)); rootGroup->setUuid(Tools::hexToUuid(profileJson["uuid"].toString())); QScopedPointer derivedKeys(deriveKeysFromPassPhrase(salt, password, iterations)); @@ -238,12 +238,12 @@ bool OpVaultReader::processFolderJson(QJsonObject& foldersJson, Group* rootGroup bool timeInfoOk = false; if (folder.contains("created")) { auto createdTime = static_cast(folder["created"].toInt()); - ti.setCreationTime(QDateTime::fromTime_t(createdTime, Qt::UTC)); + ti.setCreationTime(QDateTime::fromSecsSinceEpoch(createdTime, Qt::UTC)); timeInfoOk = true; } if (folder.contains("updated")) { auto updateTime = static_cast(folder["updated"].toInt()); - ti.setLastModificationTime(QDateTime::fromTime_t(updateTime, Qt::UTC)); + ti.setLastModificationTime(QDateTime::fromSecsSinceEpoch(updateTime, Qt::UTC)); timeInfoOk = true; } // "tx" is modified by sync, not by user; maybe a custom attribute? diff --git a/src/format/OpVaultReaderBandEntry.cpp b/src/format/OpVaultReaderBandEntry.cpp index 3a9774b68a..3cfa0c5e09 100644 --- a/src/format/OpVaultReaderBandEntry.cpp +++ b/src/format/OpVaultReaderBandEntry.cpp @@ -61,7 +61,7 @@ bool OpVaultReader::decryptBandEntry(const QJsonObject& bandEntry, QByteArray kBA = QByteArray::fromBase64(entKStr.toUtf8()); const int wantKsize = 16 + 32 + 32 + 32; if (kBA.size() != wantKsize) { - qCritical("Malformed \"k\" size; expected %d got %d\n", wantKsize, kBA.size()); + qCritical("Malformed \"k\" size; expected %d got %" PRIdQPTRDIFF "\n", wantKsize, kBA.size()); return false; } @@ -150,12 +150,12 @@ Entry* OpVaultReader::processBandEntry(const QJsonObject& bandEntry, const QDir& bool timeInfoOk = false; if (bandEntry.contains("created")) { auto createdTime = static_cast(bandEntry["created"].toInt()); - ti.setCreationTime(QDateTime::fromTime_t(createdTime, Qt::UTC)); + ti.setCreationTime(QDateTime::fromSecsSinceEpoch(createdTime, Qt::UTC)); timeInfoOk = true; } if (bandEntry.contains("updated")) { auto updateTime = static_cast(bandEntry["updated"].toInt()); - ti.setLastModificationTime(QDateTime::fromTime_t(updateTime, Qt::UTC)); + ti.setLastModificationTime(QDateTime::fromSecsSinceEpoch(updateTime, Qt::UTC)); timeInfoOk = true; } // "tx" is modified by sync, not by user; maybe a custom attribute? diff --git a/src/format/OpVaultReaderSections.cpp b/src/format/OpVaultReaderSections.cpp index 02566a5426..d63c97667c 100644 --- a/src/format/OpVaultReaderSections.cpp +++ b/src/format/OpVaultReaderSections.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,9 +37,9 @@ namespace date = QDateTime::fromString(dateValue, "yyyyMM"); date.setTimeSpec(Qt::UTC); } else if (value.isString()) { - date = QDateTime::fromTime_t(value.toString().toUInt(), Qt::UTC); + date = QDateTime::fromSecsSinceEpoch(value.toString().toUInt(), Qt::UTC); } else { - date = QDateTime::fromTime_t(value.toInt(), Qt::UTC); + date = QDateTime::fromSecsSinceEpoch(value.toInt(), Qt::UTC); } return date; } diff --git a/src/gui/Clipboard.cpp b/src/gui/Clipboard.cpp index 1c699f67e4..2b0a278287 100644 --- a/src/gui/Clipboard.cpp +++ b/src/gui/Clipboard.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2012 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -23,12 +23,13 @@ #include #include #include +#include #include "core/Config.h" Clipboard* Clipboard::m_instance(nullptr); #ifdef Q_OS_MACOS -QPointer Clipboard::m_pasteboard(nullptr); +//QPointer Clipboard::m_pasteboard(nullptr); #endif Clipboard::Clipboard(QObject* parent) @@ -36,9 +37,9 @@ Clipboard::Clipboard(QObject* parent) , m_timer(new QTimer(this)) { #ifdef Q_OS_MACOS - if (!m_pasteboard) { - m_pasteboard = new MacPasteboard(); - } + /*if (!m_pasteboard) { + m_pasteboard = new QUtiMimeConverter(); + }*/ #endif connect(m_timer, SIGNAL(timeout()), SLOT(countdownTick())); connect(qApp, SIGNAL(aboutToQuit()), SLOT(clearCopiedText())); diff --git a/src/gui/Clipboard.h b/src/gui/Clipboard.h index 147b65aff5..f0376dff7a 100644 --- a/src/gui/Clipboard.h +++ b/src/gui/Clipboard.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2012 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -22,8 +22,8 @@ #include #include #ifdef Q_OS_MACOS -#include "gui/osutils/macutils/MacPasteboard.h" #include +#include #endif class QTimer; @@ -60,7 +60,7 @@ private slots: #ifdef Q_OS_MACOS // This object lives for the whole program lifetime and we cannot delete it on exit, // so ignore leak warnings. See https://bugreports.qt.io/browse/QTBUG-54832 - static QPointer m_pasteboard; + static QPointer m_pasteboard; #endif QString m_lastCopied; }; diff --git a/src/gui/DatabaseIcons.h b/src/gui/DatabaseIcons.h index 38d1590c79..e39eacfac5 100644 --- a/src/gui/DatabaseIcons.h +++ b/src/gui/DatabaseIcons.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2010 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -18,7 +19,9 @@ #ifndef KEEPASSX_DATABASEICONS_H #define KEEPASSX_DATABASEICONS_H +#include #include +#include enum IconSize { diff --git a/src/gui/DatabaseOpenDialog.cpp b/src/gui/DatabaseOpenDialog.cpp index fa9383ac2e..1c2eef3417 100644 --- a/src/gui/DatabaseOpenDialog.cpp +++ b/src/gui/DatabaseOpenDialog.cpp @@ -69,13 +69,13 @@ DatabaseOpenDialog::DatabaseOpenDialog(QWidget* parent) auto* shortcut = new QShortcut(Qt::CTRL + Qt::Key_PageUp, this); shortcut->setContext(Qt::WidgetWithChildrenShortcut); connect(shortcut, &QShortcut::activated, this, [this]() { selectTabOffset(-1); }); - shortcut = new QShortcut(dbTabModifier + Qt::SHIFT + Qt::Key_Tab, this); + shortcut = new QShortcut(dbTabModifier | Qt::SHIFT | Qt::Key_Tab, this); shortcut->setContext(Qt::WidgetWithChildrenShortcut); connect(shortcut, &QShortcut::activated, this, [this]() { selectTabOffset(-1); }); - shortcut = new QShortcut(Qt::CTRL + Qt::Key_PageDown, this); + shortcut = new QShortcut(Qt::CTRL | Qt::Key_PageDown, this); shortcut->setContext(Qt::WidgetWithChildrenShortcut); connect(shortcut, &QShortcut::activated, this, [this]() { selectTabOffset(1); }); - shortcut = new QShortcut(dbTabModifier + Qt::Key_Tab, this); + shortcut = new QShortcut(dbTabModifier | Qt::Key_Tab, this); shortcut->setContext(Qt::WidgetWithChildrenShortcut); connect(shortcut, &QShortcut::activated, this, [this]() { selectTabOffset(1); }); } @@ -142,7 +142,7 @@ void DatabaseOpenDialog::tabChanged(int index) setTarget(dbWidget, dbWidget->database()->filePath()); } else { // if these list sizes don't match, there's a bug somewhere nearby - qWarning("DatabaseOpenDialog: mismatch between tab count %d and DB count %d", + qWarning("DatabaseOpenDialog: mismatch between tab count %d and DB count %" PRIdQSIZETYPE "", m_tabBar->count(), m_tabDbWidgets.count()); } diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index b651b52850..1be72fbc85 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -119,7 +119,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) tagsWidget->setLayout(tagsLayout); tagsLayout->addWidget(tagsTitle); tagsLayout->addWidget(m_tagView); - tagsLayout->setMargin(0); + tagsLayout->setContentsMargins(0, 0, 0, 0); m_groupSplitter->setOrientation(Qt::Vertical); m_groupSplitter->setChildrenCollapsible(true); @@ -133,7 +133,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) auto rightHandSideWidget = new QWidget(m_mainSplitter); auto rightHandSideVBox = new QVBoxLayout(); - rightHandSideVBox->setMargin(0); + rightHandSideVBox->setContentsMargins(0, 0, 0, 0); rightHandSideVBox->addWidget(m_searchingLabel); #ifdef WITH_XC_KEESHARE rightHandSideVBox->addWidget(m_shareLabel); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 20872d82a5..74d0415a29 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -304,18 +304,18 @@ MainWindow::MainWindow() connect(m_ui->menuGroups, SIGNAL(aboutToHide()), SLOT(releaseContextFocusLock())); // Control window state - new QShortcut(Qt::CTRL + Qt::Key_M, this, SLOT(minimizeOrHide())); - new QShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_M, this, SLOT(hideWindow())); + new QShortcut(Qt::CTRL | Qt::Key_M, this, SLOT(minimizeOrHide())); + new QShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_M, this, SLOT(hideWindow())); // Control database tabs // Ctrl+Tab is broken on Mac, so use Alt (i.e. the Option key) - https://bugreports.qt.io/browse/QTBUG-8596 auto dbTabModifier2 = Qt::CTRL; #ifdef Q_OS_MACOS dbTabModifier2 = Qt::ALT; #endif - new QShortcut(dbTabModifier2 + Qt::Key_Tab, this, SLOT(selectNextDatabaseTab())); - new QShortcut(Qt::CTRL + Qt::Key_PageDown, this, SLOT(selectNextDatabaseTab())); - new QShortcut(dbTabModifier2 + Qt::SHIFT + Qt::Key_Tab, this, SLOT(selectPreviousDatabaseTab())); - new QShortcut(Qt::CTRL + Qt::Key_PageUp, this, SLOT(selectPreviousDatabaseTab())); + new QShortcut(dbTabModifier2 | Qt::Key_Tab, this, SLOT(selectNextDatabaseTab())); + new QShortcut(Qt::CTRL | Qt::Key_PageDown, this, SLOT(selectNextDatabaseTab())); + new QShortcut(dbTabModifier2 | Qt::SHIFT | Qt::Key_Tab, this, SLOT(selectPreviousDatabaseTab())); + new QShortcut(Qt::CTRL | Qt::Key_PageUp, this, SLOT(selectPreviousDatabaseTab())); // Tab selection by number, Windows uses Ctrl, macOS uses Command, // and Linux uses Alt to emulate a browser-like experience @@ -323,23 +323,23 @@ MainWindow::MainWindow() #ifdef Q_OS_LINUX dbTabModifier = Qt::ALT; #endif - auto shortcut = new QShortcut(dbTabModifier + Qt::Key_1, this); + auto shortcut = new QShortcut(dbTabModifier | Qt::Key_1, this); connect(shortcut, &QShortcut::activated, [this]() { selectDatabaseTab(0); }); - shortcut = new QShortcut(dbTabModifier + Qt::Key_2, this); + shortcut = new QShortcut(dbTabModifier | Qt::Key_2, this); connect(shortcut, &QShortcut::activated, [this]() { selectDatabaseTab(1); }); - shortcut = new QShortcut(dbTabModifier + Qt::Key_3, this); + shortcut = new QShortcut(dbTabModifier | Qt::Key_3, this); connect(shortcut, &QShortcut::activated, [this]() { selectDatabaseTab(2); }); - shortcut = new QShortcut(dbTabModifier + Qt::Key_4, this); + shortcut = new QShortcut(dbTabModifier | Qt::Key_4, this); connect(shortcut, &QShortcut::activated, [this]() { selectDatabaseTab(3); }); - shortcut = new QShortcut(dbTabModifier + Qt::Key_5, this); + shortcut = new QShortcut(dbTabModifier | Qt::Key_5, this); connect(shortcut, &QShortcut::activated, [this]() { selectDatabaseTab(4); }); - shortcut = new QShortcut(dbTabModifier + Qt::Key_6, this); + shortcut = new QShortcut(dbTabModifier | Qt::Key_6, this); connect(shortcut, &QShortcut::activated, [this]() { selectDatabaseTab(5); }); - shortcut = new QShortcut(dbTabModifier + Qt::Key_7, this); + shortcut = new QShortcut(dbTabModifier | Qt::Key_7, this); connect(shortcut, &QShortcut::activated, [this]() { selectDatabaseTab(6); }); - shortcut = new QShortcut(dbTabModifier + Qt::Key_8, this); + shortcut = new QShortcut(dbTabModifier | Qt::Key_8, this); connect(shortcut, &QShortcut::activated, [this]() { selectDatabaseTab(7); }); - shortcut = new QShortcut(dbTabModifier + Qt::Key_9, this); + shortcut = new QShortcut(dbTabModifier | Qt::Key_9, this); connect(shortcut, &QShortcut::activated, [this]() { selectDatabaseTab(m_ui->tabWidget->count() - 1); }); m_ui->actionDatabaseNew->setIcon(icons()->icon("document-new")); @@ -2110,8 +2110,7 @@ void MainWindow::initActionCollection() } } - // Actions with standard shortcuts (if no standard shortcut exists, leave the existing - // shortcuts from the .ui file in place) + // Actions with standard shortcuts ac->setDefaultShortcut(m_ui->actionDatabaseOpen, QKeySequence::Open); ac->setDefaultShortcut(m_ui->actionDatabaseSave, QKeySequence::Save); ac->setDefaultShortcut(m_ui->actionDatabaseSaveAs, QKeySequence::SaveAs); @@ -2123,8 +2122,8 @@ void MainWindow::initActionCollection() // Prevent conflicts with global Mac shortcuts (force Control on all platforms) // Note: Qt::META means Ctrl on Mac. #ifdef Q_OS_MAC - ac->setDefaultShortcut(m_ui->actionEntryAddToAgent, Qt::META + Qt::Key_H); - ac->setDefaultShortcut(m_ui->actionEntryRemoveFromAgent, Qt::META + Qt::SHIFT + Qt::Key_H); + ac->setDefaultShortcut(m_ui->actionEntryAddToAgent, Qt::META | Qt::Key_H); + ac->setDefaultShortcut(m_ui->actionEntryRemoveFromAgent, Qt::META | Qt::SHIFT | Qt::Key_H); #endif QTimer::singleShot(1, ac, &ActionCollection::restoreShortcuts); diff --git a/src/gui/csvImport/CsvImportWidget.cpp b/src/gui/csvImport/CsvImportWidget.cpp index 49bee2447c..7b9def844e 100644 --- a/src/gui/csvImport/CsvImportWidget.cpp +++ b/src/gui/csvImport/CsvImportWidget.cpp @@ -1,6 +1,6 @@ -/* +/* * Copyright (C) 2016 Enrico Mariotti - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.cpp index a74b20ead6..3263fb398d 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.cpp @@ -55,7 +55,7 @@ DatabaseSettingsWidgetDatabaseKey::DatabaseSettingsWidgetDatabaseKey(QWidget* pa vbox->addWidget(m_additionalKeyOptions); vbox->setSizeConstraint(QLayout::SetMinimumSize); m_additionalKeyOptions->setLayout(new QVBoxLayout()); - m_additionalKeyOptions->layout()->setMargin(0); + m_additionalKeyOptions->layout()->setContentsMargins(0, 0, 0, 0); m_additionalKeyOptions->layout()->setSpacing(20); m_additionalKeyOptions->layout()->addWidget(m_keyFileEditWidget); #ifdef WITH_XC_YUBIKEY diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.ui b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.ui index dd5efe6710..581bc6ca2a 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.ui +++ b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.ui @@ -537,7 +537,6 @@ transformBenchmarkButton memorySpinBox parallelismSpinBox - advancedSettingsButton diff --git a/src/gui/entry/EntryModel.cpp b/src/gui/entry/EntryModel.cpp index 1a5e42c173..41da521dcb 100644 --- a/src/gui/entry/EntryModel.cpp +++ b/src/gui/entry/EntryModel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Felix Geyer + * Copyright (C) 2023 Felix Geyer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ #include "EntryModel.h" #include +#include #include #include diff --git a/src/gui/entry/EntryView.cpp b/src/gui/entry/EntryView.cpp index 1d7aa02b64..95e7690b92 100644 --- a/src/gui/entry/EntryView.cpp +++ b/src/gui/entry/EntryView.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2010 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -19,13 +19,13 @@ #include "EntryView.h" #include +#include #include #include #include #include #include #include -#include #include #include #include diff --git a/src/gui/group/GroupView.cpp b/src/gui/group/GroupView.cpp index 46cc0af6af..51ac46ffd1 100644 --- a/src/gui/group/GroupView.cpp +++ b/src/gui/group/GroupView.cpp @@ -44,16 +44,16 @@ GroupView::GroupView(Database* db, QWidget* parent) connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), SIGNAL(groupSelectionChanged())); // clang-format on - new QShortcut(Qt::CTRL + Qt::Key_F10, this, SLOT(contextMenuShortcutPressed()), nullptr, Qt::WidgetShortcut); + new QShortcut(Qt::CTRL | Qt::Key_F10, this, SLOT(contextMenuShortcutPressed()), nullptr, Qt::WidgetShortcut); new QShortcut( - Qt::CTRL + Qt::SHIFT + Qt::Key_PageUp, this, SLOT(selectPreviousGroup()), nullptr, Qt::WindowShortcut); - new QShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_PageDown, this, SLOT(selectNextGroup()), nullptr, Qt::WindowShortcut); + Qt::CTRL | Qt::SHIFT | Qt::Key_PageUp, this, SLOT(selectPreviousGroup()), nullptr, Qt::WindowShortcut); + new QShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_PageDown, this, SLOT(selectNextGroup()), nullptr, Qt::WindowShortcut); // keyboard shortcuts to sort children of a group - auto shortcut = new QShortcut(Qt::CTRL + Qt::Key_Down, this, nullptr, nullptr, Qt::WidgetShortcut); + auto shortcut = new QShortcut(Qt::CTRL | Qt::Key_Down, this, nullptr, nullptr, Qt::WidgetShortcut); connect(shortcut, &QShortcut::activated, this, [this]() { sortGroups(false); }); - shortcut = new QShortcut(Qt::CTRL + Qt::Key_Up, this, nullptr, nullptr, Qt::WidgetShortcut); + shortcut = new QShortcut(Qt::CTRL | Qt::Key_Up, this, nullptr, nullptr, Qt::WidgetShortcut); connect(shortcut, &QShortcut::activated, this, [this]() { sortGroups(true); }); modelReset(); diff --git a/src/gui/osutils/macutils/MacPasteboard.cpp b/src/gui/osutils/macutils/MacPasteboard.cpp index ae63ea4e49..c3483e35f3 100644 --- a/src/gui/osutils/macutils/MacPasteboard.cpp +++ b/src/gui/osutils/macutils/MacPasteboard.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,24 +16,20 @@ */ #include "MacPasteboard.h" +#include -QString MacPasteboard::convertorName() +QString MacPasteboard::utiForMime(const QString& mime) const { - return QLatin1String("MacPasteboard"); -} - -QString MacPasteboard::flavorFor(const QString& mimetype) -{ - if (mimetype == QLatin1String("text/plain")) { + if (mime == QLatin1String("text/plain")) { return QLatin1String("public.utf8-plain-text"); - } else if (mimetype == QLatin1String("application/x-nspasteboard-concealed-type")) { + } else if (mime == QLatin1String("application/x-nspasteboard-concealed-type")) { return QLatin1String("org.nspasteboard.ConcealedType"); } - int i = mimetype.indexOf(QLatin1String("charset=")); + int i = mime.indexOf(QLatin1String("charset=")); if (i >= 0) { - QString cs(mimetype.mid(i + 8).toLower()); + QString cs(mime.mid(i + 8).toLower()); i = cs.indexOf(QLatin1Char(';')); if (i >= 0) { @@ -46,54 +42,61 @@ QString MacPasteboard::flavorFor(const QString& mimetype) return QLatin1String("public.utf16-plain-text"); } } - return QString(); + return {}; } -QString MacPasteboard::mimeFor(QString flavor) +QString MacPasteboard::mimeForUti(const QString& uti) const { - if (flavor == QLatin1String("public.utf8-plain-text")) + if (uti == QLatin1String("public.utf8-plain-text")) return QLatin1String("text/plain"); - if (flavor == QLatin1String("org.nspasteboard.ConcealedType")) + if (uti == QLatin1String("org.nspasteboard.ConcealedType")) return QLatin1String("application/x-nspasteboard-concealed-type"); - if (flavor == QLatin1String("public.utf16-plain-text")) + if (uti == QLatin1String("public.utf16-plain-text")) return QLatin1String("text/plain;charset=utf16"); - return QString(); + return {}; } -bool MacPasteboard::canConvert(const QString& mimetype, QString flavor) +bool MacPasteboard::canConvert(const QString& mime, const QString& uti) const { - Q_UNUSED(mimetype); - Q_UNUSED(flavor); + Q_UNUSED(mime); + Q_UNUSED(uti); return true; } -QVariant MacPasteboard::convertToMime(const QString& mimetype, QList data, QString flavor) +QVariant MacPasteboard::convertToMime(const QString& mime, const QList& data, const QString& uti) const { if (data.count() > 1) qWarning("QMime::convertToMime: Cannot handle multiple member data"); const QByteArray& firstData = data.first(); QVariant ret; - if (flavor == QLatin1String("public.utf8-plain-text")) { + if (uti == QLatin1String("public.utf8-plain-text")) { ret = QString::fromUtf8(firstData); - } else if (flavor == QLatin1String("org.nspasteboard.ConcealedType")) { + } else if (uti == QLatin1String("org.nspasteboard.ConcealedType")) { ret = QString::fromUtf8(firstData); - } else if (flavor == QLatin1String("public.utf16-plain-text")) { - ret = QTextCodec::codecForName("UTF-16")->toUnicode(firstData); + } else if (uti == QLatin1String("public.utf16-plain-text")) { + auto toUtf16 = QStringDecoder(QStringDecoder::Utf16); + QVariant var{toUtf16(firstData)}; + return var; } else { - qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype)); + qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mime)); } return ret; } -QList MacPasteboard::convertFromMime(const QString&, QVariant data, QString flavor) +QList MacPasteboard::convertFromMime(const QString& mime, const QVariant& data, const QString& uti) const { + Q_UNUSED(mime); + QList ret; - QString string = data.toString(); - if (flavor == QLatin1String("public.utf8-plain-text")) - ret.append(string.toUtf8()); - else if (flavor == QLatin1String("org.nspasteboard.ConcealedType")) - ret.append(string.toUtf8()); - else if (flavor == QLatin1String("public.utf16-plain-text")) - ret.append(QTextCodec::codecForName("UTF-16")->fromUnicode(string)); + QString dataString = data.toString(); + if (uti == QLatin1String("public.utf8-plain-text")) { + ret.append(dataString.toUtf8()); + } else if (uti == QLatin1String("org.nspasteboard.ConcealedType")) { + ret.append(dataString.toUtf8()); + } else if (uti == QLatin1String("public.utf16-plain-text")) { + auto toUtf16 = QStringEncoder(QStringDecoder::Utf16); + QByteArray baUtf16 = toUtf16(dataString); + ret.append(baUtf16); + } return ret; } diff --git a/src/gui/osutils/macutils/MacPasteboard.h b/src/gui/osutils/macutils/MacPasteboard.h index 503741ca88..6ab6d7c882 100644 --- a/src/gui/osutils/macutils/MacPasteboard.h +++ b/src/gui/osutils/macutils/MacPasteboard.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,23 +19,23 @@ #define KEEPASSXC_MACPASTEBOARD_H #include -#include -#include +#include +#include +#include -class MacPasteboard : public QObject, public QMacPasteboardMime +class MacPasteboard : public QObject, public QUtiMimeConverter { public: explicit MacPasteboard() - : QMacPasteboardMime(MIME_ALL) + : QUtiMimeConverter() { } - QString convertorName() override; - bool canConvert(const QString& mime, QString flav) override; - QString mimeFor(QString flav) override; - QString flavorFor(const QString& mime) override; - QVariant convertToMime(const QString& mime, QList data, QString flav) override; - QList convertFromMime(const QString& mime, QVariant data, QString flav) override; + bool canConvert(const QString& mime, const QString& uti) const; + QString mimeForUti(const QString& uti) const override; + QString utiForMime(const QString& mime) const override; + QVariant convertToMime(const QString& mime, const QList& data, const QString& uti) const override; + QList convertFromMime(const QString& mime, const QVariant& data, const QString& uti) const override; }; #endif // KEEPASSXC_MACPASTEBOARD_H diff --git a/src/gui/osutils/macutils/MacUtils.h b/src/gui/osutils/macutils/MacUtils.h index 5e0e121d5e..8cd1a67ec4 100644 --- a/src/gui/osutils/macutils/MacUtils.h +++ b/src/gui/osutils/macutils/MacUtils.h @@ -24,8 +24,11 @@ #include #include +#include #include #include +#include +#include #include class MacUtils : public OSUtilsBase diff --git a/src/gui/remote/DatabaseSettingsWidgetRemote.cpp b/src/gui/remote/DatabaseSettingsWidgetRemote.cpp index f66edba7e7..d69e6b4f49 100644 --- a/src/gui/remote/DatabaseSettingsWidgetRemote.cpp +++ b/src/gui/remote/DatabaseSettingsWidgetRemote.cpp @@ -25,6 +25,8 @@ #include "RemoteSettings.h" #include "gui/MessageBox.h" +#include + DatabaseSettingsWidgetRemote::DatabaseSettingsWidgetRemote(QWidget* parent) : DatabaseSettingsWidget(parent) , m_remoteSettings(new RemoteSettings(nullptr, this)) diff --git a/src/gui/remote/RemoteSettings.h b/src/gui/remote/RemoteSettings.h index 4b414494c6..5c9c299d11 100644 --- a/src/gui/remote/RemoteSettings.h +++ b/src/gui/remote/RemoteSettings.h @@ -19,6 +19,7 @@ #define KEEPASSXC_REMOTESETTINGS_H #include +#include #include class Database; diff --git a/src/gui/styles/base/BaseStyle.cpp b/src/gui/styles/base/BaseStyle.cpp index 9cb844d700..c9a74d69a0 100644 --- a/src/gui/styles/base/BaseStyle.cpp +++ b/src/gui/styles/base/BaseStyle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2019 Andrew Richards * * Derived from Phantomstyle and relicensed under the GPLv2 or v3. @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -512,7 +513,7 @@ namespace Phantom // generated changes. If that happens, change to use the definition of // `fastfragile_hash_qpalette` below, which is less likely to collide with an // arbitrarily numbered key but also does more work. -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) // TODO: What to do here? x.u = x.u ^ (static_cast(p.currentColorGroup()) << (64 - 3)); return x.u; #else @@ -521,11 +522,11 @@ namespace Phantom // guard for it, so that it will default to a more safe definition on the // next guaranteed big breaking change for Qt. A warning will hopefully get // someone to double-check it at some point in the future. -#warning "Verify contents and layout of QPalette::cacheKey() have not changed" +//#warning "Verify contents and layout of QPalette::cacheKey() have not changed" QtPrivate::QHashCombine c; uint h = qHash(p.currentColorGroup()); - h = c(h, (uint)(x.u & 0xFFFFFFFFu)); - h = c(h, (uint)((x.u >> 32) & 0xFFFFFFFFu)); + h = c(h, static_cast(x.u & 0xFFFFFFFFu)); + h = c(h, static_cast((x.u >> 32) & 0xFFFFFFFFu)); return h; #endif } @@ -871,7 +872,7 @@ namespace Phantom { QRect ra = bar->rect; QRect rb = ra; - bool isHorizontal = bar->orientation != Qt::Vertical; + bool isHorizontal = bar->state == QStyle::State_Horizontal; bool isInverted = bar->invertedAppearance; bool isIndeterminate = bar->minimum == 0 && bar->maximum == 0; bool isForward = !isHorizontal || bar->direction != Qt::RightToLeft; @@ -2570,7 +2571,7 @@ void BaseStyle::drawControl(ControlElement element, QRect r = bar->rect.adjusted(2, 2, -2, -2); if (r.isEmpty() || !r.isValid()) break; - QSize textSize = option->fontMetrics.size(Qt::TextBypassShaping, bar->text); + QSize textSize = option->fontMetrics.size(0, bar->text); QRect textRect = QStyle::alignedRect(option->direction, Qt::AlignCenter, textSize, option->rect); textRect &= r; if (textRect.isEmpty()) @@ -2730,10 +2731,10 @@ void BaseStyle::drawControl(ControlElement element, } // Draw main text and mnemonic text - QStringRef s(&menuItem->text); + QStringView s(menuItem->text); if (!s.isEmpty()) { - QRect textRect = - Ph::menuItemTextRect(metrics, option->direction, itemRect, hasSubMenu, hasIcon, menuItem->tabWidth); + QRect textRect = Ph::menuItemTextRect( + metrics, option->direction, itemRect, hasSubMenu, hasIcon, menuItem->reservedShortcutWidth); int t = s.indexOf(QLatin1Char('\t')); int text_flags = Qt::AlignLeft | Qt::AlignTop | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; @@ -2804,14 +2805,14 @@ void BaseStyle::drawControl(ControlElement element, // Draw mnemonic text if (t >= 0) { - QRect mnemonicR = - Ph::menuItemMnemonicRect(metrics, option->direction, itemRect, hasSubMenu, menuItem->tabWidth); - const QStringRef textToDrawRef = s.mid(t + 1); + QRect mnemonicR = Ph::menuItemMnemonicRect( + metrics, option->direction, itemRect, hasSubMenu, menuItem->reservedShortcutWidth); + const auto textToDrawRef = QStringView{s}.mid(t + 1); const QString unsafeTextToDraw = QString::fromRawData(textToDrawRef.constData(), textToDrawRef.size()); painter->drawText(mnemonicR, text_flags, unsafeTextToDraw); s = s.left(t); } - const QStringRef textToDrawRef = s.left(t); + const auto textToDrawRef = QStringView{s}.left(t); const QString unsafeTextToDraw = QString::fromRawData(textToDrawRef.constData(), textToDrawRef.size()); painter->drawText(textRect, text_flags, unsafeTextToDraw); @@ -4129,7 +4130,7 @@ QSize BaseStyle::sizeFromContents(ContentsType type, bool nullIcon = hdr->icon.isNull(); int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, hdr, widget); int iconSize = nullIcon ? 0 : option->fontMetrics.height(); - QSize txt = hdr->fontMetrics.size(Qt::TextSingleLine | Qt::TextBypassShaping, hdr->text); + QSize txt = hdr->fontMetrics.size(Qt::TextSingleLine, hdr->text); QSize sz; sz.setHeight(margin + qMax(iconSize, txt.height()) + margin); sz.setWidth((nullIcon ? 0 : margin) + iconSize + (hdr->text.isNull() ? 0 : margin) + txt.width() + margin); diff --git a/src/keeshare/CMakeLists.txt b/src/keeshare/CMakeLists.txt index 5fe739b36f..afe01f1b97 100644 --- a/src/keeshare/CMakeLists.txt +++ b/src/keeshare/CMakeLists.txt @@ -1,3 +1,18 @@ +# Copyright (C) 2024 KeePassXC Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 or (at your option) +# version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + if(WITH_XC_KEESHARE) set(keeshare_SOURCES SettingsPageKeeShare.cpp @@ -12,7 +27,9 @@ if(WITH_XC_KEESHARE) ShareObserver.cpp ) + find_package(Qt6 REQUIRED COMPONENTS Core5Compat) + add_library(keeshare STATIC ${keeshare_SOURCES}) - target_link_libraries(keeshare PUBLIC Qt5::Core Qt5::Widgets ${BOTAN_LIBRARIES} ${ZLIB_LIBRARIES} PRIVATE ${MINIZIP_LIBRARIES}) + target_link_libraries(keeshare PUBLIC Qt6::Core Qt6::Core5Compat Qt6::Widgets ${BOTAN_LIBRARIES} ${ZLIB_LIBRARIES} PRIVATE ${MINIZIP_LIBRARIES}) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) endif(WITH_XC_KEESHARE) diff --git a/src/keeshare/KeeShareSettings.cpp b/src/keeshare/KeeShareSettings.cpp index 4f53fc25fe..0088ab3e50 100644 --- a/src/keeshare/KeeShareSettings.cpp +++ b/src/keeshare/KeeShareSettings.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,7 +41,6 @@ namespace KeeShareSettings QString buffer; QXmlStreamWriter writer(&buffer); - writer.setCodec(QTextCodec::codecForName("UTF-8")); writer.writeStartDocument(); writer.writeStartElement("KeeShare"); specific(writer); @@ -53,7 +52,7 @@ namespace KeeShareSettings void xmlDeserialize(const QString& raw, std::function specific) { QXmlStreamReader reader(raw); - if (!reader.readNextStartElement() || reader.qualifiedName() != "KeeShare") { + if (!reader.readNextStartElement() || reader.qualifiedName().toString() != "KeeShare") { return; } specific(reader); @@ -106,9 +105,9 @@ namespace KeeShareSettings { Certificate certificate; while (!reader.error() && reader.readNextStartElement()) { - if (reader.name() == "Signer") { + if (reader.name().toString() == "Signer") { certificate.signer = reader.readElementText(); - } else if (reader.name() == "Key") { + } else if (reader.name().toString() == "Key") { auto rawKey = QByteArray::fromBase64(reader.readElementText().toLatin1()); if (!rawKey.isEmpty()) { try { @@ -200,12 +199,12 @@ namespace KeeShareSettings Active active; xmlDeserialize(raw, [&](QXmlStreamReader& reader) { while (!reader.error() && reader.readNextStartElement()) { - if (reader.name() == "Active") { + if (reader.name().toString() == "Active") { while (reader.readNextStartElement()) { - if (reader.name() == "Import") { + if (reader.name().toString() == "Import") { active.in = true; reader.skipCurrentElement(); - } else if (reader.name() == "Export") { + } else if (reader.name().toString() == "Export") { active.out = true; reader.skipCurrentElement(); } else { @@ -248,9 +247,9 @@ namespace KeeShareSettings Own own; xmlDeserialize(raw, [&](QXmlStreamReader& reader) { while (!reader.error() && reader.readNextStartElement()) { - if (reader.name() == "PrivateKey") { + if (reader.name().toString() == "PrivateKey") { own.key = Key::deserialize(reader); - } else if (reader.name() == "PublicKey") { + } else if (reader.name().toString() == "PublicKey") { own.certificate = Certificate::deserialize(reader); } else { qWarning("Unknown KeeShareSettings element %s", qPrintable(reader.name().toString())); @@ -328,23 +327,23 @@ namespace KeeShareSettings Reference reference; xmlDeserialize(raw, [&](QXmlStreamReader& reader) { while (!reader.error() && reader.readNextStartElement()) { - if (reader.name() == "Type") { + if (reader.name().toString() == "Type") { while (reader.readNextStartElement()) { - if (reader.name() == "Import") { + if (reader.name().toString() == "Import") { reference.type |= ImportFrom; reader.skipCurrentElement(); - } else if (reader.name() == "Export") { + } else if (reader.name().toString() == "Export") { reference.type |= ExportTo; reader.skipCurrentElement(); } else { break; } } - } else if (reader.name() == "Group") { + } else if (reader.name().toString() == "Group") { reference.uuid = QUuid::fromRfc4122(QByteArray::fromBase64(reader.readElementText().toLatin1())); - } else if (reader.name() == "Path") { + } else if (reader.name().toString() == "Path") { reference.path = QString::fromUtf8(QByteArray::fromBase64(reader.readElementText().toLatin1())); - } else if (reader.name() == "Password") { + } else if (reader.name().toString() == "Password") { reference.password = QString::fromUtf8(QByteArray::fromBase64(reader.readElementText().toLatin1())); } else { qWarning("Unknown Reference element %s", qPrintable(reader.name().toString())); diff --git a/src/keys/CompositeKey.cpp b/src/keys/CompositeKey.cpp index 7054916673..6270ca2659 100644 --- a/src/keys/CompositeKey.cpp +++ b/src/keys/CompositeKey.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2010 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -27,6 +27,7 @@ #include #include +#include QUuid CompositeKey::UUID("76a7ae25-a542-4add-9849-7c06be945b94"); diff --git a/src/keys/CompositeKey.h b/src/keys/CompositeKey.h index 451f88e4fd..74a0283265 100644 --- a/src/keys/CompositeKey.h +++ b/src/keys/CompositeKey.h @@ -19,6 +19,7 @@ #ifndef KEEPASSX_COMPOSITEKEY_H #define KEEPASSX_COMPOSITEKEY_H +#include #include #include "keys/Key.h" diff --git a/src/keys/FileKey.cpp b/src/keys/FileKey.cpp index 167b0462dd..bc5ecfd6f1 100644 --- a/src/keys/FileKey.cpp +++ b/src/keys/FileKey.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2011 Felix Geyer * * This program is free software: you can redistribute it and/or modify @@ -301,7 +301,7 @@ bool FileKey::loadXml(QIODevice* device, QString* errorMsg) if (xmlReader.error()) { return false; } - if (xmlReader.readNextStartElement() && xmlReader.name() != "KeyFile") { + if (xmlReader.readNextStartElement() && xmlReader.name().toString() != "KeyFile") { return false; } @@ -313,9 +313,9 @@ bool FileKey::loadXml(QIODevice* device, QString* errorMsg) } keyFileData; while (!xmlReader.error() && xmlReader.readNextStartElement()) { - if (xmlReader.name() == "Meta") { + if (xmlReader.name().toString() == "Meta") { while (!xmlReader.error() && xmlReader.readNextStartElement()) { - if (xmlReader.name() == "Version") { + if (xmlReader.name().toString() == "Version") { keyFileData.version = xmlReader.readElementText(); if (keyFileData.version.startsWith("1.0")) { m_type = KeePass2XML; @@ -329,9 +329,9 @@ bool FileKey::loadXml(QIODevice* device, QString* errorMsg) } } } - } else if (xmlReader.name() == "Key") { + } else if (xmlReader.name().toString() == "Key") { while (!xmlReader.error() && xmlReader.readNextStartElement()) { - if (xmlReader.name() == "Data") { + if (xmlReader.name().toString() == "Data") { keyFileData.hash = QByteArray::fromHex(xmlReader.attributes().value("Hash").toLatin1()); keyFileData.data = xmlReader.readElementText().simplified().replace(" ", "").toLatin1(); @@ -362,7 +362,7 @@ bool FileKey::loadXml(QIODevice* device, QString* errorMsg) bool ok = false; if (!xmlReader.error() && !keyFileData.data.isEmpty()) { - std::memcpy(m_key.data(), keyFileData.data.data(), std::min(SHA256_SIZE, keyFileData.data.size())); + std::memcpy(m_key.data(), keyFileData.data.data(), qMin(SHA256_SIZE, keyFileData.data.size())); ok = true; } @@ -421,7 +421,7 @@ bool FileKey::loadHex(QIODevice* device) return false; } - std::memcpy(m_key.data(), data.data(), std::min(SHA256_SIZE, data.size())); + std::memcpy(m_key.data(), data.data(), qMin(SHA256_SIZE, data.size())); Botan::secure_scrub_memory(data.data(), static_cast(data.capacity())); m_type = FixedBinaryHex; @@ -447,7 +447,7 @@ bool FileKey::loadHashed(QIODevice* device) } while (!buffer.isEmpty()); buffer = cryptoHash.result(); - std::memcpy(m_key.data(), buffer.data(), std::min(SHA256_SIZE, buffer.size())); + std::memcpy(m_key.data(), buffer.data(), qMin(SHA256_SIZE, buffer.size())); Botan::secure_scrub_memory(buffer.data(), static_cast(buffer.capacity())); m_type = Hashed; diff --git a/src/keys/PasswordKey.cpp b/src/keys/PasswordKey.cpp index 7e06706472..4a4294a517 100644 --- a/src/keys/PasswordKey.cpp +++ b/src/keys/PasswordKey.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include "crypto/CryptoHash.h" #include +#include #include QUuid PasswordKey::UUID("77e90411-303a-43f2-b773-853b05635ead"); diff --git a/src/keys/drivers/YubiKey.cpp b/src/keys/drivers/YubiKey.cpp index 8d726727e8..fc8c3ff26f 100644 --- a/src/keys/drivers/YubiKey.cpp +++ b/src/keys/drivers/YubiKey.cpp @@ -1,6 +1,6 @@ /* + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2014 Kyle Manna - * Copyright (C) 2017-2021 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,8 +24,6 @@ #include #include -QMutex YubiKey::s_interfaceMutex; - YubiKey::YubiKey() { int num_interfaces = 0; @@ -73,7 +71,7 @@ bool YubiKey::isInitialized() bool YubiKey::findValidKeys() { - QMutexLocker lock(&s_interfaceMutex); + QMutexLocker lock(&m_interfaces_detect_mutex); m_connectedKeys = 0; m_usbKeys = YubiKeyInterfaceUSB::instance()->findValidKeys(m_connectedKeys); @@ -84,14 +82,21 @@ bool YubiKey::findValidKeys() void YubiKey::findValidKeysAsync() { - QtConcurrent::run([this] { emit detectComplete(findValidKeys()); }); + auto res = QtConcurrent::run([this] { emit detectComplete(findValidKeys()); }); } YubiKey::KeyMap YubiKey::foundKeys() { - QMutexLocker lock(&s_interfaceMutex); - KeyMap foundKeys = m_usbKeys; - foundKeys.unite(m_pcscKeys); + QMutexLocker lock(&m_interfaces_detect_mutex); + KeyMap foundKeys; + + for (auto i = m_usbKeys.cbegin(); i != m_usbKeys.cend(); ++i) { + foundKeys.insert(i.key(), i.value()); + } + + for (auto i = m_pcscKeys.cbegin(); i != m_pcscKeys.cend(); ++i) { + foundKeys.insert(i.key(), i.value()); + } return foundKeys; } @@ -103,7 +108,7 @@ int YubiKey::connectedKeys() QString YubiKey::errorMessage() { - QMutexLocker lock(&s_interfaceMutex); + QMutexLocker lock(&m_interfaces_detect_mutex); QString error; error.clear(); @@ -140,7 +145,7 @@ QString YubiKey::errorMessage() */ bool YubiKey::testChallenge(YubiKeySlot slot, bool* wouldBlock) { - QMutexLocker lock(&s_interfaceMutex); + QMutexLocker lock(&m_interfaces_detect_mutex); if (m_usbKeys.contains(slot)) { return YubiKeyInterfaceUSB::instance()->testChallenge(slot, wouldBlock); @@ -165,7 +170,7 @@ bool YubiKey::testChallenge(YubiKeySlot slot, bool* wouldBlock) YubiKey::ChallengeResult YubiKey::challenge(YubiKeySlot slot, const QByteArray& challenge, Botan::secure_vector& response) { - QMutexLocker lock(&s_interfaceMutex); + QMutexLocker lock(&m_interfaces_detect_mutex); m_error.clear(); diff --git a/src/keys/drivers/YubiKey.h b/src/keys/drivers/YubiKey.h index a36f8c30f7..e2865e9c25 100644 --- a/src/keys/drivers/YubiKey.h +++ b/src/keys/drivers/YubiKey.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 Kyle Manna - * Copyright (C) 2017-2021 KeePassXC Team + * Copyright (C) 2017-2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,8 +23,8 @@ #include #include #include +#include #include - #include typedef QPair YubiKeySlot; @@ -90,7 +90,7 @@ class YubiKey : public QObject bool m_initialized = false; QString m_error; - static QMutex s_interfaceMutex; + QRecursiveMutex m_interfaces_detect_mutex; KeyMap m_usbKeys; KeyMap m_pcscKeys; diff --git a/src/keys/drivers/YubiKeyInterface.h b/src/keys/drivers/YubiKeyInterface.h index 276f520a60..179b29b798 100644 --- a/src/keys/drivers/YubiKeyInterface.h +++ b/src/keys/drivers/YubiKeyInterface.h @@ -22,6 +22,12 @@ #include "YubiKey.h" #include +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) +#include +#else +#include +#endif + /** * Abstract base class to manage the interfaces to hardware key(s) */ diff --git a/src/networking/HibpDownloader.cpp b/src/networking/HibpDownloader.cpp index 8b09ce2c4c..130eef7726 100644 --- a/src/networking/HibpDownloader.cpp +++ b/src/networking/HibpDownloader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include #include +#include namespace { @@ -60,7 +61,7 @@ namespace } // Extract the count, remove remaining whitespace, and convert to int - return hibpResult.midRef(pos, end - pos).trimmed().toInt(); + return QStringView{hibpResult}.mid(pos, end - pos).trimmed().toInt(); } } // namespace diff --git a/src/networking/UpdateChecker.cpp b/src/networking/UpdateChecker.cpp index ea3d435dfc..3a4c08e69a 100644 --- a/src/networking/UpdateChecker.cpp +++ b/src/networking/UpdateChecker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -103,8 +103,7 @@ void UpdateChecker::fetchFinished() } // Check again in 7 days - // TODO: change to toSecsSinceEpoch() when min Qt >= 5.8 - config()->set(Config::GUI_CheckForUpdatesNextCheck, Clock::currentDateTime().addDays(7).toTime_t()); + config()->set(Config::GUI_CheckForUpdatesNextCheck, Clock::currentDateTime().addDays(7).toSecsSinceEpoch()); } else { version = ErrorVersion; } diff --git a/src/proxy/CMakeLists.txt b/src/proxy/CMakeLists.txt index be756672dd..15cf59a104 100644 --- a/src/proxy/CMakeLists.txt +++ b/src/proxy/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2020 KeePassXC Team +# Copyright (C) 2023 KeePassXC Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,10 +21,10 @@ if(WITH_XC_BROWSER) # Alloc must be defined in a static library to prevent clashing with clang ASAN definitions add_library(proxy_alloc STATIC ../core/Alloc.cpp) - target_link_libraries(proxy_alloc PRIVATE Qt5::Core ${BOTAN_LIBRARIES}) + target_link_libraries(proxy_alloc PRIVATE Qt6::Core ${BOTAN_LIBRARIES}) add_executable(keepassxc-proxy ${proxy_SOURCES}) - target_link_libraries(keepassxc-proxy proxy_alloc Qt5::Core Qt5::Network) + target_link_libraries(keepassxc-proxy proxy_alloc Qt6::Core Qt6::Network) install(TARGETS keepassxc-proxy BUNDLE DESTINATION . COMPONENT Runtime RUNTIME DESTINATION ${PROXY_INSTALL_DIR} COMPONENT Runtime) diff --git a/src/proxy/NativeMessagingProxy.cpp b/src/proxy/NativeMessagingProxy.cpp index 964383dc5d..86ff7aaaa9 100644 --- a/src/proxy/NativeMessagingProxy.cpp +++ b/src/proxy/NativeMessagingProxy.cpp @@ -57,7 +57,7 @@ void NativeMessagingProxy::setupStandardInput() #endif #endif - QtConcurrent::run([this] { + auto res = QtConcurrent::run([this] { while (std::cin.good()) { if (std::cin.peek() != EOF) { uint length = 0; @@ -68,7 +68,7 @@ void NativeMessagingProxy::setupStandardInput() QString msg; msg.reserve(length); for (uint i = 0; i < length; ++i) { - msg.append(getchar()); + msg.append(QChar(getchar())); } if (msg.length() > 0) { diff --git a/src/qrcode/CMakeLists.txt b/src/qrcode/CMakeLists.txt index 10e3684062..c5c145d7d7 100644 --- a/src/qrcode/CMakeLists.txt +++ b/src/qrcode/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2017 KeePassXC Team +# Copyright (C) 2023 KeePassXC Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,4 +21,4 @@ find_package(QREncode REQUIRED) add_library(qrcode STATIC ${qrcode_SOURCES}) target_include_directories(qrcode PRIVATE ${QRENCODE_INCLUDE_DIR}) -target_link_libraries(qrcode PUBLIC Qt5::Core Qt5::Svg ${QRENCODE_LIBRARY}) +target_link_libraries(qrcode PUBLIC Qt6::Core Qt6::Svg ${QRENCODE_LIBRARY}) diff --git a/src/quickunlock/TouchID.h b/src/quickunlock/TouchID.h index 74e5d94747..9b27cb8868 100644 --- a/src/quickunlock/TouchID.h +++ b/src/quickunlock/TouchID.h @@ -31,7 +31,7 @@ class TouchID : public QuickUnlockInterface bool getKey(const QUuid& dbUuid, QByteArray& passwordKey) override; bool hasKey(const QUuid& dbUuid) const override; - void reset(const QUuid& dbUuid = "") override; + void reset(const QUuid& dbUuid) override; void reset() override; private: diff --git a/src/sshagent/CMakeLists.txt b/src/sshagent/CMakeLists.txt index 6bbb9c94d2..9f2d74d922 100644 --- a/src/sshagent/CMakeLists.txt +++ b/src/sshagent/CMakeLists.txt @@ -1,3 +1,18 @@ +# Copyright (C) 2023 KeePassXC Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 or (at your option) +# version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + if(WITH_XC_SSHAGENT) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) @@ -13,6 +28,7 @@ if(WITH_XC_SSHAGENT) SSHAgent.cpp ) + find_package(Qt6 REQUIRED COMPONENTS Core5Compat) add_library(sshagent STATIC ${sshagent_SOURCES}) - target_link_libraries(sshagent Qt5::Core Qt5::Widgets Qt5::Network) + target_link_libraries(sshagent Qt6::Core Qt6::Core5Compat Qt6::Widgets Qt6::Network) endif() diff --git a/src/sshagent/KeeAgentSettings.cpp b/src/sshagent/KeeAgentSettings.cpp index a794eac936..660441b6e1 100644 --- a/src/sshagent/KeeAgentSettings.cpp +++ b/src/sshagent/KeeAgentSettings.cpp @@ -1,6 +1,6 @@ /* + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2017 Toni Spets - * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,10 +24,9 @@ #include "core/Tools.h" #include -#include #include #include -#include +#include #include KeeAgentSettings::KeeAgentSettings() @@ -203,7 +202,7 @@ void KeeAgentSettings::setFileName(const QString& fileName) bool KeeAgentSettings::readBool(QXmlStreamReader& reader) { reader.readNext(); - bool ret = (reader.text().startsWith("t", Qt::CaseInsensitive)); + bool ret = (reader.text().toString().startsWith("t", Qt::CaseInsensitive)); reader.readNext(); // tag end return ret; } @@ -234,37 +233,37 @@ bool KeeAgentSettings::fromXml(const QByteArray& ba) return false; } - if (reader.qualifiedName() != "EntrySettings") { + if (reader.qualifiedName().toString() != "EntrySettings") { m_error = QCoreApplication::translate("KeeAgentSettings", "Invalid KeeAgent settings file structure."); return false; } while (!reader.error() && reader.readNextStartElement()) { - if (reader.name() == "AllowUseOfSshKey") { + if (reader.name().toString() == "AllowUseOfSshKey") { m_allowUseOfSshKey = readBool(reader); - } else if (reader.name() == "AddAtDatabaseOpen") { + } else if (reader.name().toString() == "AddAtDatabaseOpen") { m_addAtDatabaseOpen = readBool(reader); - } else if (reader.name() == "RemoveAtDatabaseClose") { + } else if (reader.name().toString() == "RemoveAtDatabaseClose") { m_removeAtDatabaseClose = readBool(reader); - } else if (reader.name() == "UseConfirmConstraintWhenAdding") { + } else if (reader.name().toString() == "UseConfirmConstraintWhenAdding") { m_useConfirmConstraintWhenAdding = readBool(reader); - } else if (reader.name() == "UseLifetimeConstraintWhenAdding") { + } else if (reader.name().toString() == "UseLifetimeConstraintWhenAdding") { m_useLifetimeConstraintWhenAdding = readBool(reader); - } else if (reader.name() == "LifetimeConstraintDuration") { + } else if (reader.name().toString() == "LifetimeConstraintDuration") { m_lifetimeConstraintDuration = readInt(reader); - } else if (reader.name() == "Location") { + } else if (reader.name().toString() == "Location") { while (!reader.error() && reader.readNextStartElement()) { - if (reader.name() == "SelectedType") { + if (reader.name().toString() == "SelectedType") { reader.readNext(); m_selectedType = reader.text().toString(); reader.readNext(); - } else if (reader.name() == "AttachmentName") { + } else if (reader.name().toString() == "AttachmentName") { reader.readNext(); m_attachmentName = reader.text().toString(); reader.readNext(); - } else if (reader.name() == "SaveAttachmentToTempFile") { + } else if (reader.name().toString() == "SaveAttachmentToTempFile") { m_saveAttachmentToTempFile = readBool(reader); - } else if (reader.name() == "FileName") { + } else if (reader.name().toString() == "FileName") { reader.readNext(); m_fileName = reader.text().toString(); reader.readNext(); @@ -292,8 +291,6 @@ QByteArray KeeAgentSettings::toXml() const QByteArray ba; QXmlStreamWriter writer(&ba); - // real KeeAgent can only read UTF-16 - writer.setCodec(QTextCodec::codecForName("UTF-16")); writer.setAutoFormatting(true); writer.setAutoFormattingIndent(2); @@ -331,7 +328,12 @@ QByteArray KeeAgentSettings::toXml() const writer.writeEndElement(); // EntrySettings writer.writeEndDocument(); - return ba; + // Real KeeAgent can only read UTF-16 + auto toDecUtf16 = QStringDecoder(QStringConverter::Utf8); + auto sUtf16 = toDecUtf16(ba); + auto toEncUtf16 = QStringEncoder(QStringEncoder::Utf16); + auto baUtf16 = toEncUtf16(sUtf16); + return baUtf16; } /** diff --git a/src/sshagent/OpenSSHKey.cpp b/src/sshagent/OpenSSHKey.cpp index 7df1c42870..c4ffe1fdff 100644 --- a/src/sshagent/OpenSSHKey.cpp +++ b/src/sshagent/OpenSSHKey.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2017 Toni Spets - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ #include #include +#include #include @@ -180,7 +181,7 @@ const QString OpenSSHKey::privateKey() auto base64Key = QString::fromUtf8(sshKey.toBase64()); for (int i = 0; i < base64Key.size(); i += 70) { - out += base64Key.midRef(i, 70); + out += QStringView{base64Key}.mid(i, 70); out += "\n"; } @@ -307,7 +308,7 @@ bool OpenSSHKey::parsePKCS1PEM(const QByteArray& in) return false; } - if (QString::fromLatin1(magic) != "openssh-key-v1") { + if (QString::fromLatin1(magic.toStdString().c_str()) != "openssh-key-v1") { m_error = tr("Key file magic header id invalid"); return false; } diff --git a/src/streams/LayeredStream.cpp b/src/streams/LayeredStream.cpp index 8e254efbf3..1a46efbad9 100644 --- a/src/streams/LayeredStream.cpp +++ b/src/streams/LayeredStream.cpp @@ -34,15 +34,15 @@ bool LayeredStream::isSequential() const return true; } -bool LayeredStream::open(QIODevice::OpenMode mode) +bool LayeredStream::open(QIODeviceBase::OpenMode mode) { if (isOpen()) { qWarning("LayeredStream::open: Device is already open."); return false; } - bool readMode = (mode & QIODevice::ReadOnly); - bool writeMode = (mode & QIODevice::WriteOnly); + bool readMode = (mode & QIODeviceBase::ReadOnly); + bool writeMode = (mode & QIODeviceBase::WriteOnly); if (readMode && writeMode) { qWarning("LayeredStream::open: Reading and writing at the same time is not supported."); diff --git a/src/streams/LayeredStream.h b/src/streams/LayeredStream.h index 643ddfb458..1b71374e18 100644 --- a/src/streams/LayeredStream.h +++ b/src/streams/LayeredStream.h @@ -29,7 +29,7 @@ class LayeredStream : public QIODevice ~LayeredStream() override; bool isSequential() const override; - bool open(QIODevice::OpenMode mode) override; + bool open(QIODeviceBase::OpenMode mode) override; protected: qint64 readData(char* data, qint64 maxSize) override; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8ed6868df0..1c1b698c49 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2023 KeePassXC Team +# Copyright (C) 2025 KeePassXC Team # Copyright (C) 2010 Felix Geyer # # This program is free software: you can redistribute it and/or modify @@ -90,7 +90,7 @@ macro(add_unit_test) endif() endmacro(add_unit_test) -set(TEST_LIBRARIES keepassxc_gui Qt5::Test) +set(TEST_LIBRARIES keepassxc_core Qt6::Test) set(testsupport_SOURCES modeltest.cpp @@ -98,7 +98,7 @@ set(testsupport_SOURCES mock/MockClock.cpp util/TemporaryFile.cpp) add_library(testsupport STATIC ${testsupport_SOURCES}) -target_link_libraries(testsupport Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Test) +target_link_libraries(testsupport Qt6::Core Qt6::Concurrent Qt6::Widgets Qt6::Test) add_unit_test(NAME testgroup SOURCES TestGroup.cpp LIBS testsupport ${TEST_LIBRARIES}) diff --git a/tests/TestBase32.cpp b/tests/TestBase32.cpp index 4c14e4b46d..537fd60001 100644 --- a/tests/TestBase32.cpp +++ b/tests/TestBase32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,134 +26,134 @@ void TestBase32::testDecode() { // 3 quanta, all upper case + padding QByteArray encodedData = "JBSWY3DPEB3W64TMMQXC4LQ="; - QVariant data = Base32::decode(encodedData); + QByteArray data = Base32::decode(encodedData); QString expectedData = "Hello world..."; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 4 quanta, all upper case encodedData = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"; data = Base32::decode(encodedData); expectedData = "12345678901234567890"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 4 quanta, all lower case encodedData = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq"; data = Base32::decode(encodedData); expectedData = "12345678901234567890"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 4 quanta, mixed upper and lower case encodedData = "Gezdgnbvgy3tQojqgezdGnbvgy3tQojQ"; data = Base32::decode(encodedData); expectedData = "12345678901234567890"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 1 pad characters encodedData = "ORSXG5A="; data = Base32::decode(encodedData); expectedData = "test"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 3 pad characters encodedData = "L5PV6==="; data = Base32::decode(encodedData); expectedData = "___"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 4 pad characters encodedData = "MZXW6IDCMFZA===="; data = Base32::decode(encodedData); expectedData = "foo bar"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // six pad characters encodedData = "MZXW6YTBOI======"; data = Base32::decode(encodedData); expectedData = "foobar"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "IA======"; data = Base32::decode(encodedData); expectedData = "@"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // error: illegal character encodedData = "1MZXW6YTBOI====="; data = Base32::decode(encodedData); - QVERIFY(data.isNull()); + QVERIFY(data.isEmpty()); // error: missing pad character encodedData = "MZXW6YTBOI====="; data = Base32::decode(encodedData); - QVERIFY(data.isNull()); + QVERIFY(data.isEmpty()); // RFC 4648 test vectors encodedData = ""; data = Base32::decode(encodedData); expectedData = ""; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MY======"; data = Base32::decode(encodedData); expectedData = "f"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MZXQ===="; data = Base32::decode(encodedData); expectedData = "fo"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MZXW6==="; data = Base32::decode(encodedData); - QVERIFY(!data.isNull()); + QVERIFY(!data.isEmpty()); expectedData = "foo"; - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MZXW6YQ="; data = Base32::decode(encodedData); expectedData = "foob"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MZXW6YTB"; expectedData = "fooba"; data = Base32::decode(encodedData); - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MZXW6YTBOI======"; data = Base32::decode(encodedData); expectedData = "foobar"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); } void TestBase32::testEncode() @@ -307,25 +307,25 @@ void TestBase32::testSanitizeInput() // sanitize input (white space + missing padding) QByteArray encodedData = "JBSW Y3DP EB3W 64TM MQXC 4LQA"; auto data = Base32::decode(Base32::sanitizeInput(encodedData)); - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), QString("Hello world...")); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), QString("Hello world...")); // sanitize input (typo + missing padding) encodedData = "J8SWY3DPE83W64TMMQXC4LQA"; data = Base32::decode(Base32::sanitizeInput(encodedData)); - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), QString("Hello world...")); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), QString("Hello world...")); // sanitize input (other illegal characters) encodedData = "J8SWY3D[PE83W64TMMQ]XC!4LQA"; data = Base32::decode(Base32::sanitizeInput(encodedData)); - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), QString("Hello world...")); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), QString("Hello world...")); // sanitize input (NUL character) encodedData = "J8SWY3DPE83W64TMMQXC4LQA"; encodedData.insert(3, '\0'); data = Base32::decode(Base32::sanitizeInput(encodedData)); - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), QString("Hello world...")); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), QString("Hello world...")); } diff --git a/tests/TestCli.cpp b/tests/TestCli.cpp index 7200d21faf..3dc818879d 100644 --- a/tests/TestCli.cpp +++ b/tests/TestCli.cpp @@ -74,7 +74,7 @@ void TestCli::initTestCase() #ifdef Q_OS_WIN m_devNull->open(fopen("nul", "w"), QIODevice::WriteOnly); #else - m_devNull->open(fopen("/dev/null", "w"), QIODevice::WriteOnly); + m_devNull->open(fopen("/dev/null", "w"), QIODeviceBase::WriteOnly); #endif Utils::DEVNULL.setDevice(m_devNull.data()); } @@ -108,15 +108,15 @@ void TestCli::init() m_nonAsciiDbFile->copyFromFile(file.arg("NonAscii.kdbx")); m_stdout.reset(new QBuffer()); - m_stdout->open(QIODevice::ReadWrite); + m_stdout->open(QIODeviceBase::ReadWrite); Utils::STDOUT.setDevice(m_stdout.data()); m_stderr.reset(new QBuffer()); - m_stderr->open(QIODevice::ReadWrite); + m_stderr->open(QIODeviceBase::ReadWrite); Utils::STDERR.setDevice(m_stderr.data()); m_stdin.reset(new QBuffer()); - m_stdin->open(QIODevice::ReadWrite); + m_stdin->open(QIODeviceBase::ReadWrite); Utils::STDIN.setDevice(m_stdin.data()); } @@ -457,7 +457,7 @@ void TestCli::testAttachmentExport() QVERIFY(attachmentExportCmd.getDescriptionLine().contains(attachmentExportCmd.name)); TemporaryFile exportOutput; - exportOutput.open(QIODevice::WriteOnly); + exportOutput.open(QIODeviceBase::WriteOnly); exportOutput.close(); // Try exporting an attachment of a non-existent entry @@ -495,7 +495,7 @@ void TestCli::testAttachmentExport() QByteArray(qPrintable(QString("Successfully exported attachment %1 of entry %2 to %3.\n") .arg("Sample attachment.txt", "/Sample Entry", exportOutput.fileName())))); - exportOutput.open(QIODevice::ReadOnly); + exportOutput.open(QIODeviceBase::ReadOnly); QCOMPARE(exportOutput.readAll(), QByteArray("Sample content\n")); // Export an existing attachment to stdout @@ -688,9 +688,9 @@ void TestCli::testClip() // Password with timeout setInput("a"); // clang-format off - QFuture future = QtConcurrent::run(&clipCmd, - static_cast(&DatabaseCommand::execute), - QStringList{"clip", m_dbFile->fileName(), "/Sample Entry", "1"}); + auto future = QtConcurrent::run(static_cast(&DatabaseCommand::execute), + &clipCmd, + QStringList{"clip", m_dbFile->fileName(), "/Sample Entry", "1"}); // clang-format on QTRY_COMPARE(clipboard->text(), QString("Password")); @@ -700,8 +700,8 @@ void TestCli::testClip() // TOTP with timeout setInput("a"); - future = QtConcurrent::run(&clipCmd, - static_cast(&DatabaseCommand::execute), + future = QtConcurrent::run(static_cast(&DatabaseCommand::execute), + &clipCmd, QStringList{"clip", m_dbFile->fileName(), "/Sample Entry", "1", "-t"}); QTRY_VERIFY(isTotp(clipboard->text())); @@ -1279,7 +1279,7 @@ void TestCli::testExport() execCmd(exportCmd, {"export", m_dbFile->fileName()}); TemporaryFile xmlOutput; - xmlOutput.open(QIODevice::WriteOnly); + xmlOutput.open(QIODeviceBase::WriteOnly); xmlOutput.write(m_stdout->readAll()); xmlOutput.close(); @@ -1296,7 +1296,7 @@ void TestCli::testExport() execCmd(exportCmd, {"export", "-f", "xml", "-q", m_dbFile->fileName()}); QCOMPARE(m_stderr->readAll(), QByteArray()); - xmlOutput.open(QIODevice::WriteOnly); + xmlOutput.open(QIODeviceBase::WriteOnly); xmlOutput.write(m_stdout->readAll()); xmlOutput.close(); diff --git a/tests/TestCsvParser.cpp b/tests/TestCsvParser.cpp index 4c04504969..cb3ece1786 100644 --- a/tests/TestCsvParser.cpp +++ b/tests/TestCsvParser.cpp @@ -1,6 +1,6 @@ /* + * Copyright (C) 2023 KeePassXC Team * Copyright (C) 2015 Enrico Mariotti - * Copyright (C) 2017 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -330,7 +330,6 @@ void TestCsvParser::testUnicode() // ERROR QChar g("\u20AC"); parser->setFieldSeparator(QChar('A')); QTextStream out(file.data()); - out.setCodec("UTF-8"); out << QString("€1A2śA\"3śAż\"Ażac"); QVERIFY(parser->parse(file.data())); diff --git a/tests/TestPasskeys.cpp b/tests/TestPasskeys.cpp index 1618dce285..581d28d66d 100644 --- a/tests/TestPasskeys.cpp +++ b/tests/TestPasskeys.cpp @@ -282,17 +282,17 @@ void TestPasskeys::testCreatingAttestationObjectWithEC() browserPasskeys()->buildCredentialPrivateKey(alg, predefinedFirst, predefinedSecond); auto result = browserPasskeys()->buildAttestationObject( credentialCreationOptions, "", id, credentialPrivateKey.cborEncodedPublicKey, testingVariables); - QCOMPARE( - result, - QString("\xA3" - "cfmtdnonegattStmt\xA0hauthDataX\xA4t\xA6\xEA\x92\x13\xC9\x9C/t\xB2$\x92\xB3 \xCF@&*\x94\xC1\xA9P\xA0" - "9\x7F)%\x0B`\x84\x1E\xF0" - "E\x00\x00\x00\x01\x01\x02\x03\x04\x05\x06\x07\b\x01\x02\x03\x04\x05\x06\x07\b\x00 \x8B\xB0\xCA" - "6\x17\xD6\xDE\x01\x11|\xEA\x94\r\xA0R\xC0\x80_\xF3r\xFBr\xB5\x02\x03:" - "\xBAr\x0Fi\x81\xFE\xA5\x01\x02\x03& \x01!X " - "e\xE2\xF2\x1F:cq\xD3G\xEA\xE0\xF7\x1F\xCF\xFA\\\xABO\xF6\x86\x88\x80\t\xAE\x81\x8BT\xB2\x9B\x15\x85~" - "\"X \\\x8E\x1E@\xDB\x97T-\xF8\x9B\xB0\xAD" - "5\xDC\x12^\xC3\x95\x05\xC6\xDF^\x03\xCB\xB4Q\x91\xFF|\xDB\x94\xB7")); + QCOMPARE(result, + QString::fromUtf8( + "\xA3" + "cfmtdnonegattStmt\xA0hauthDataX\xA4t\xA6\xEA\x92\x13\xC9\x9C/t\xB2$\x92\xB3 \xCF@&*\x94\xC1\xA9P\xA0" + "9\x7F)%\x0B`\x84\x1E\xF0" + "E\x00\x00\x00\x01\x01\x02\x03\x04\x05\x06\x07\b\x01\x02\x03\x04\x05\x06\x07\b\x00 \x8B\xB0\xCA" + "6\x17\xD6\xDE\x01\x11|\xEA\x94\r\xA0R\xC0\x80_\xF3r\xFBr\xB5\x02\x03:" + "\xBAr\x0Fi\x81\xFE\xA5\x01\x02\x03& \x01!X " + "e\xE2\xF2\x1F:cq\xD3G\xEA\xE0\xF7\x1F\xCF\xFA\\\xABO\xF6\x86\x88\x80\t\xAE\x81\x8BT\xB2\x9B\x15\x85~" + "\"X \\\x8E\x1E@\xDB\x97T-\xF8\x9B\xB0\xAD" + "5\xDC\x12^\xC3\x95\x05\xC6\xDF^\x03\xCB\xB4Q\x91\xFF|\xDB\x94\xB7")); // Double check that the result can be decoded BrowserCbor browserCbor; diff --git a/tests/TestSharing.cpp b/tests/TestSharing.cpp index 0b5414ea8e..11a9b7e6b0 100644 --- a/tests/TestSharing.cpp +++ b/tests/TestSharing.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -83,7 +83,7 @@ void TestSharing::testKeySerialization() writer.writeEndDocument(); QXmlStreamReader reader(buffer); reader.readNextStartElement(); - QVERIFY(reader.name() == "Key"); + QVERIFY(reader.name().compare("Key") == 0); KeeShareSettings::Key restored = KeeShareSettings::Key::deserialize(reader); QCOMPARE(restored.key->private_key_bits(), original.key->private_key_bits()); diff --git a/tests/TestTools.cpp b/tests/TestTools.cpp index fd15128035..2c9cc6908f 100644 --- a/tests/TestTools.cpp +++ b/tests/TestTools.cpp @@ -233,11 +233,11 @@ void TestTools::testConvertToRegex_data() << "^(?:" + Tools::escapeRegex(input) + ")$"; // Exact match does not escape the pattern - QTest::newRow("Exact Match") << input << static_cast(Tools::RegexConvertOpts::EXACT_MATCH) + QTest::newRow("Exact Match 1") << input << static_cast(Tools::RegexConvertOpts::EXACT_MATCH) << QString(R"(^(?:te|st*t?[5]^(test);',.)$)"); // Exact match with improper regex - QTest::newRow("Exact Match") << ")av(" << static_cast(Tools::RegexConvertOpts::EXACT_MATCH) + QTest::newRow("Exact Match 2") << ")av(" << static_cast(Tools::RegexConvertOpts::EXACT_MATCH) << QString(R"(^(?:)av()$)"); QTest::newRow("Exact Match & Wildcard") diff --git a/tests/gui/TestGuiPixmaps.h b/tests/gui/TestGuiPixmaps.h index 4f73d7e0d8..3c095f77ea 100644 --- a/tests/gui/TestGuiPixmaps.h +++ b/tests/gui/TestGuiPixmaps.h @@ -19,6 +19,7 @@ #define KEEPASSX_TESTGUIPIXMAPS_H #include +#include class TestGuiPixmaps : public QObject {